From b309afbe8eb768ed3146e4b9159811ade8ff3894 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Wed, 15 Jul 2026 03:31:31 +0400 Subject: [PATCH] feat(design-system): add reusable Card primitive Standalone, OnPush, content-projection container. Padding none/sm/md/lg, bordered and interactive variants. Colors/radius/shadow/spacing consumed via existing tenant CSS vars with fallbacks. --- src/app/shared/ui/card/card.component.html | 1 + src/app/shared/ui/card/card.component.scss | 47 ++++++++++++++++++++++ src/app/shared/ui/card/card.component.ts | 24 +++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/app/shared/ui/card/card.component.html create mode 100644 src/app/shared/ui/card/card.component.scss create mode 100644 src/app/shared/ui/card/card.component.ts diff --git a/src/app/shared/ui/card/card.component.html b/src/app/shared/ui/card/card.component.html new file mode 100644 index 0000000..40b3726 --- /dev/null +++ b/src/app/shared/ui/card/card.component.html @@ -0,0 +1 @@ + diff --git a/src/app/shared/ui/card/card.component.scss b/src/app/shared/ui/card/card.component.scss new file mode 100644 index 0000000..0f94cdd --- /dev/null +++ b/src/app/shared/ui/card/card.component.scss @@ -0,0 +1,47 @@ +:host { + display: block; + background: var(--bg-primary, #fff); + border-radius: var(--radius-lg, 10px); + box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.06)); + transition: box-shadow var(--transition-fast, 120ms ease), + border-color var(--transition-fast, 120ms ease); +} + +:host.app-card--bordered { + border: 1px solid var(--border-color, #e4e4e7); +} + +:host.app-card--interactive { + cursor: pointer; + + &:hover { + box-shadow: var(--shadow-md, 0 4px 12px rgba(0, 0, 0, 0.08)); + } + + &:focus-visible { + outline: 2px solid var(--primary-color, #2f6e5d); + outline-offset: 2px; + } +} + +:host.app-card--pad-none { + padding: 0; +} + +:host.app-card--pad-sm { + padding: var(--space-sm, 0.5rem); +} + +:host.app-card--pad-md { + padding: var(--space-md, 1rem); +} + +:host.app-card--pad-lg { + padding: var(--space-lg, 1.5rem); +} + +@media (prefers-reduced-motion: reduce) { + :host { + transition: none; + } +} diff --git a/src/app/shared/ui/card/card.component.ts b/src/app/shared/ui/card/card.component.ts new file mode 100644 index 0000000..6bb63f1 --- /dev/null +++ b/src/app/shared/ui/card/card.component.ts @@ -0,0 +1,24 @@ +import { ChangeDetectionStrategy, Component, input } from '@angular/core'; + +export type CardPadding = 'none' | 'sm' | 'md' | 'lg'; + +@Component({ + selector: 'app-card', + standalone: true, + templateUrl: './card.component.html', + styleUrl: './card.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + '[class.app-card--bordered]': 'bordered()', + '[class.app-card--interactive]': 'interactive()', + '[class.app-card--pad-none]': "padding() === 'none'", + '[class.app-card--pad-sm]': "padding() === 'sm'", + '[class.app-card--pad-md]': "padding() === 'md'", + '[class.app-card--pad-lg]': "padding() === 'lg'" + } +}) +export class CardComponent { + readonly padding = input('md'); + readonly bordered = input(true); + readonly interactive = input(false); +}