pdm-ui-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FIGMA_COMPONENT_AUDIT.md +154 -0
- package/README.md +72 -0
- package/ng-package.json +7 -0
- package/package.json +29 -0
- package/src/lib/components/accordion/accordion.component.html +34 -0
- package/src/lib/components/accordion/accordion.component.ts +38 -0
- package/src/lib/components/alert/alert.component.html +52 -0
- package/src/lib/components/alert/alert.component.ts +25 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.html +41 -0
- package/src/lib/components/alert-dialog/alert-dialog.component.ts +45 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.html +11 -0
- package/src/lib/components/aspect-ratio/aspect-ratio.component.ts +18 -0
- package/src/lib/components/avatar/avatar.component.html +21 -0
- package/src/lib/components/avatar/avatar.component.ts +32 -0
- package/src/lib/components/badge/badge.component.html +28 -0
- package/src/lib/components/badge/badge.component.ts +23 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.html +39 -0
- package/src/lib/components/breadcrumb/breadcrumb.component.ts +26 -0
- package/src/lib/components/button/button.component.html +15 -0
- package/src/lib/components/button/button.component.ts +84 -0
- package/src/lib/components/button-group/button-group.component.html +39 -0
- package/src/lib/components/button-group/button-group.component.ts +15 -0
- package/src/lib/components/calendar/calendar.component.html +73 -0
- package/src/lib/components/calendar/calendar.component.ts +78 -0
- package/src/lib/components/card/card.component.html +77 -0
- package/src/lib/components/card/card.component.ts +39 -0
- package/src/lib/components/carousel/carousel.component.html +86 -0
- package/src/lib/components/carousel/carousel.component.ts +100 -0
- package/src/lib/components/chart/chart.component.html +143 -0
- package/src/lib/components/chart/chart.component.ts +147 -0
- package/src/lib/components/checkbox/checkbox.component.html +38 -0
- package/src/lib/components/checkbox/checkbox.component.ts +32 -0
- package/src/lib/components/collapsible/collapsible.component.html +26 -0
- package/src/lib/components/collapsible/collapsible.component.ts +29 -0
- package/src/lib/components/combobox/combobox.component.html +42 -0
- package/src/lib/components/combobox/combobox.component.ts +32 -0
- package/src/lib/components/command/command.component.html +55 -0
- package/src/lib/components/command/command.component.ts +67 -0
- package/src/lib/components/context-menu/context-menu.component.html +47 -0
- package/src/lib/components/context-menu/context-menu.component.ts +67 -0
- package/src/lib/components/data-table/data-table.component.html +63 -0
- package/src/lib/components/data-table/data-table.component.ts +78 -0
- package/src/lib/components/date-picker/date-picker.component.html +38 -0
- package/src/lib/components/date-picker/date-picker.component.ts +34 -0
- package/src/lib/components/dialog/dialog.component.html +78 -0
- package/src/lib/components/dialog/dialog.component.ts +55 -0
- package/src/lib/components/drawer/drawer.component.html +56 -0
- package/src/lib/components/drawer/drawer.component.ts +43 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.html +56 -0
- package/src/lib/components/dropdown-menu/dropdown-menu.component.ts +126 -0
- package/src/lib/components/empty/empty.component.html +29 -0
- package/src/lib/components/empty/empty.component.ts +35 -0
- package/src/lib/components/field/field.component.html +22 -0
- package/src/lib/components/field/field.component.ts +28 -0
- package/src/lib/components/hover-card/hover-card.component.html +24 -0
- package/src/lib/components/hover-card/hover-card.component.ts +36 -0
- package/src/lib/components/icon/icon.component.html +286 -0
- package/src/lib/components/icon/icon.component.ts +133 -0
- package/src/lib/components/input/input.component.html +22 -0
- package/src/lib/components/input/input.component.ts +33 -0
- package/src/lib/components/input-group/input-group.component.html +31 -0
- package/src/lib/components/input-group/input-group.component.ts +26 -0
- package/src/lib/components/input-otp/input-otp.component.html +25 -0
- package/src/lib/components/input-otp/input-otp.component.ts +146 -0
- package/src/lib/components/input-password/input-password.component.html +64 -0
- package/src/lib/components/input-password/input-password.component.ts +46 -0
- package/src/lib/components/item/item.component.html +10 -0
- package/src/lib/components/item/item.component.ts +12 -0
- package/src/lib/components/kbd/kbd.component.html +3 -0
- package/src/lib/components/kbd/kbd.component.ts +10 -0
- package/src/lib/components/label/label.component.html +7 -0
- package/src/lib/components/label/label.component.ts +12 -0
- package/src/lib/components/menubar/menubar.component.html +16 -0
- package/src/lib/components/menubar/menubar.component.ts +29 -0
- package/src/lib/components/native-select/native-select.component.html +17 -0
- package/src/lib/components/native-select/native-select.component.ts +28 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.html +15 -0
- package/src/lib/components/navigation-menu/navigation-menu.component.ts +17 -0
- package/src/lib/components/pagination/pagination.component.html +30 -0
- package/src/lib/components/pagination/pagination.component.ts +37 -0
- package/src/lib/components/popover/popover.component.html +6 -0
- package/src/lib/components/popover/popover.component.ts +40 -0
- package/src/lib/components/progress/progress.component.html +9 -0
- package/src/lib/components/progress/progress.component.ts +20 -0
- package/src/lib/components/radio-group/radio-group.component.html +25 -0
- package/src/lib/components/radio-group/radio-group.component.ts +30 -0
- package/src/lib/components/scroll-area/scroll-area.component.html +5 -0
- package/src/lib/components/scroll-area/scroll-area.component.ts +11 -0
- package/src/lib/components/select/select.component.html +14 -0
- package/src/lib/components/select/select.component.ts +27 -0
- package/src/lib/components/separator/separator.component.html +5 -0
- package/src/lib/components/separator/separator.component.ts +16 -0
- package/src/lib/components/sheet/sheet.component.html +10 -0
- package/src/lib/components/sheet/sheet.component.ts +28 -0
- package/src/lib/components/sidebar/sidebar.component.html +3 -0
- package/src/lib/components/sidebar/sidebar.component.ts +11 -0
- package/src/lib/components/skeleton/skeleton.component.html +1 -0
- package/src/lib/components/skeleton/skeleton.component.ts +10 -0
- package/src/lib/components/slider/slider.component.html +15 -0
- package/src/lib/components/slider/slider.component.ts +31 -0
- package/src/lib/components/sonner/sonner.component.html +10 -0
- package/src/lib/components/sonner/sonner.component.ts +25 -0
- package/src/lib/components/spinner/spinner.component.html +6 -0
- package/src/lib/components/spinner/spinner.component.ts +11 -0
- package/src/lib/components/switch/switch.component.html +14 -0
- package/src/lib/components/switch/switch.component.ts +20 -0
- package/src/lib/components/table/table.component.html +5 -0
- package/src/lib/components/table/table.component.ts +10 -0
- package/src/lib/components/tabs/tabs.component.html +21 -0
- package/src/lib/components/tabs/tabs.component.ts +26 -0
- package/src/lib/components/textarea/textarea.component.html +21 -0
- package/src/lib/components/textarea/textarea.component.ts +28 -0
- package/src/lib/components/toggle/toggle.component.html +16 -0
- package/src/lib/components/toggle/toggle.component.ts +29 -0
- package/src/lib/components/toggle-group/toggle-group.component.html +17 -0
- package/src/lib/components/toggle-group/toggle-group.component.ts +26 -0
- package/src/lib/components/tooltip/tooltip.component.html +6 -0
- package/src/lib/components/tooltip/tooltip.component.ts +20 -0
- package/src/lib/pdm-ui-kit.module.ts +126 -0
- package/src/public-api.ts +58 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Figma Audit - shadcn/ui Design System (fileKey: YQaGNKBcNRSOIMSPIIAuiz)
|
|
2
|
+
|
|
3
|
+
Node analyzed: `2:287` (Cover) + component masters used in cover.
|
|
4
|
+
|
|
5
|
+
## Core tokens
|
|
6
|
+
|
|
7
|
+
### Colors
|
|
8
|
+
- `slate/900`: `#0F172A`
|
|
9
|
+
- `slate/700`: `#334155`
|
|
10
|
+
- `slate/600`: `#475569`
|
|
11
|
+
- `slate/500`: `#64748B`
|
|
12
|
+
- `slate/400`: `#94A3B8`
|
|
13
|
+
- `slate/200`: `#E2E8F0`
|
|
14
|
+
- `slate/100`: `#F1F5F9`
|
|
15
|
+
- `white`: `#FFFFFF`
|
|
16
|
+
- `red/500`: `#EF4444`
|
|
17
|
+
- `red/600`: `#DC2626`
|
|
18
|
+
|
|
19
|
+
### Typography
|
|
20
|
+
- `body-medium`: Inter 14/24, 500
|
|
21
|
+
- `small`: Inter 14/14, 500
|
|
22
|
+
- `subtle`: Inter 14/20, 400
|
|
23
|
+
- `subtle-medium`: Inter 14/20, 500
|
|
24
|
+
- `suble - semibold`: Inter 14/20, 600
|
|
25
|
+
- `detail`: Inter 12/20, 500
|
|
26
|
+
- `p`: Inter 16/28, 400
|
|
27
|
+
- `large`: Inter 18/28, 600
|
|
28
|
+
|
|
29
|
+
### Effects and shape
|
|
30
|
+
- Border radius common: `6px`
|
|
31
|
+
- Dropdown/tab inner radius: `3px`
|
|
32
|
+
- Shadow (menu/popover): `0 4px 6px 0 rgba(0, 0, 0, 0.09)`
|
|
33
|
+
|
|
34
|
+
## Components and variant/state matrix
|
|
35
|
+
|
|
36
|
+
### Button (`1:85`)
|
|
37
|
+
State set:
|
|
38
|
+
- `Default`
|
|
39
|
+
- `hover`
|
|
40
|
+
|
|
41
|
+
Type set:
|
|
42
|
+
- `default`
|
|
43
|
+
- `primary button`
|
|
44
|
+
- `destructive`
|
|
45
|
+
- `outline`
|
|
46
|
+
- `subtle`
|
|
47
|
+
- `ghost`
|
|
48
|
+
- `link`
|
|
49
|
+
- `with icon`
|
|
50
|
+
- `just icon`
|
|
51
|
+
- `just icon circle`
|
|
52
|
+
- `loading`
|
|
53
|
+
|
|
54
|
+
Notes:
|
|
55
|
+
- `primary button` appears as hover style in source file.
|
|
56
|
+
- Not all type/state combinations exist in Figma.
|
|
57
|
+
|
|
58
|
+
### Switch (`9:338`)
|
|
59
|
+
- State in cover: `on`
|
|
60
|
+
- Track: `44x24`
|
|
61
|
+
- Thumb: `20x20`
|
|
62
|
+
- Label uses token `small`
|
|
63
|
+
|
|
64
|
+
### Tabs (`6:212`)
|
|
65
|
+
- States displayed: `Selected`, `Unselected`
|
|
66
|
+
- Container: bg `slate/100`, `p=5`, `r=6`
|
|
67
|
+
- Active tab bg `white`, inactive text `slate/700`
|
|
68
|
+
|
|
69
|
+
### Radio group (`13:2543`)
|
|
70
|
+
- Options displayed: `Default`, `Comfortable`, `Compact`
|
|
71
|
+
- Dot size: `16x16`
|
|
72
|
+
- Label token: `small`
|
|
73
|
+
|
|
74
|
+
### Popover (`13:2311`)
|
|
75
|
+
- Surface: bg white, border `slate/200`, `r=6`
|
|
76
|
+
- Shadow: `shadow`
|
|
77
|
+
- Internal form rows with label + input field style
|
|
78
|
+
|
|
79
|
+
### Hover card (`13:2340`)
|
|
80
|
+
- Surface: bg white, subtle border/shadow
|
|
81
|
+
- Title `@nextjs`: semibold 14/20
|
|
82
|
+
- Description: regular 14/20
|
|
83
|
+
- Meta line: 12/16 in `slate/500`
|
|
84
|
+
|
|
85
|
+
### Dropdown menu (`13:2363`)
|
|
86
|
+
- Container: border `slate/100`, `r=6`, shadow
|
|
87
|
+
- Item rows with icon + label + optional shortcut
|
|
88
|
+
- Includes section labels and separators
|
|
89
|
+
- Disabled pattern shown (`API`) with reduced emphasis
|
|
90
|
+
|
|
91
|
+
## Implementation status in this repo
|
|
92
|
+
|
|
93
|
+
Updated components in `projects/pdm-ui-kit/src/lib/components`:
|
|
94
|
+
- `button`
|
|
95
|
+
- `switch`
|
|
96
|
+
- `radio-group`
|
|
97
|
+
- `tabs`
|
|
98
|
+
- `dropdown-menu`
|
|
99
|
+
- `popover`
|
|
100
|
+
- `hover-card`
|
|
101
|
+
|
|
102
|
+
These were adjusted to match Figma details from the analyzed nodes.
|
|
103
|
+
|
|
104
|
+
## Figma Desktop nodes used (line omitted)
|
|
105
|
+
|
|
106
|
+
- `Field`: `1188:4205`
|
|
107
|
+
- `Input Group`: `1188:5363`
|
|
108
|
+
- `Input OTP`: `101:698`
|
|
109
|
+
- `Input`: `73:1977`
|
|
110
|
+
- `Item`: `1196:923`
|
|
111
|
+
- `Kbd`: `1196:1097`
|
|
112
|
+
- `Label`: `73:1978`
|
|
113
|
+
- `Menubar`: `73:1979`
|
|
114
|
+
- `Native Select`: `1254:65`
|
|
115
|
+
- `Navigation Menu`: `73:1980`
|
|
116
|
+
- `Pagination`: `73:1981`
|
|
117
|
+
- `Popover`: `73:1982`
|
|
118
|
+
- `Progress`: `73:1983`
|
|
119
|
+
- `Radio Group`: `73:1984`
|
|
120
|
+
- `Scroll Area`: `73:1985`
|
|
121
|
+
- `Select`: `73:1986`
|
|
122
|
+
- `Separator`: `73:1987`
|
|
123
|
+
- `Sheet`: `73:1988`
|
|
124
|
+
- `Sidebar`: `269:32`
|
|
125
|
+
- `Skeleton`: `73:1989`
|
|
126
|
+
- `Slider`: `73:2895`
|
|
127
|
+
- `Sonner`: `73:2896`
|
|
128
|
+
- `Spinner`: `1196:1174`
|
|
129
|
+
- `Switch`: `73:2897`
|
|
130
|
+
- `Table`: `73:2898`
|
|
131
|
+
- `Tabs`: `73:2899`
|
|
132
|
+
- `Textarea`: `73:2900`
|
|
133
|
+
- `Toggle`: `73:2902`
|
|
134
|
+
- `Toggle Group`: `73:2903`
|
|
135
|
+
- `Tooltip`: `73:2904`
|
|
136
|
+
- `Chart Area`: `201:20`
|
|
137
|
+
- `Chart Bar`: `201:21`
|
|
138
|
+
- `Chart Line`: `201:22`
|
|
139
|
+
- `Chart Pie`: `201:23`
|
|
140
|
+
- `Chart Radar`: `201:24`
|
|
141
|
+
- `Chart Radial`: `257:13124`
|
|
142
|
+
- `Chart Tooltips`: `201:26`
|
|
143
|
+
- `Lucide Icons`: `135:2`
|
|
144
|
+
- `Tabler Icons`: `642:97`
|
|
145
|
+
- `HugeIcons`: `1361:5869`
|
|
146
|
+
- `Phosphor Icons`: `1528:9`
|
|
147
|
+
- `Remix Icons`: `1603:3`
|
|
148
|
+
|
|
149
|
+
### Implementation updates in this pass
|
|
150
|
+
|
|
151
|
+
- `chart`: added `type` variants `area`, `bar`, `line`, `pie`, `radar`, `radial`, `tooltips`.
|
|
152
|
+
- `chart`: aligned typography/colors to token-based theming and added variant-specific datasets.
|
|
153
|
+
- `icon`: added `library` support for `lucide`, `tabler`, `hugeicons`, `phosphor`, `remix`.
|
|
154
|
+
- `icon`: added `assetUrl` input to render direct Figma localhost SVG assets without adding icon packages.
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# PDM UI Kit
|
|
2
|
+
|
|
3
|
+
Base de componentes reutilizables compatible con Angular 13, 14 y 15.
|
|
4
|
+
|
|
5
|
+
## Objetivo
|
|
6
|
+
- Centralizar componentes UI nuevos.
|
|
7
|
+
- Mantener API estable para migrar a paquete remoto.
|
|
8
|
+
- Usar Tailwind CSS v3 y tokens CSS del proyecto consumidor.
|
|
9
|
+
|
|
10
|
+
## Compatibilidad
|
|
11
|
+
- Angular: 13, 14, 15 (NgModules, sin standalone).
|
|
12
|
+
- Tailwind: v3.
|
|
13
|
+
|
|
14
|
+
## Theming
|
|
15
|
+
Los componentes usan tokens por CSS variables tipo shadcn:
|
|
16
|
+
- `--background`, `--foreground`, `--primary`, `--border`, `--ring`, `--radius`, etc.
|
|
17
|
+
|
|
18
|
+
El look final lo define el proyecto que consume el kit (light/dark u otros temas).
|
|
19
|
+
|
|
20
|
+
## Tailwind en proyecto consumidor
|
|
21
|
+
Asegura que Tailwind escanee las plantillas del kit.
|
|
22
|
+
|
|
23
|
+
Ejemplo en `tailwind.config.js` del proyecto consumidor:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
module.exports = {
|
|
27
|
+
content: [
|
|
28
|
+
'./src/**/*.{html,ts}',
|
|
29
|
+
'./projects/pdm-ui-kit/src/**/*.{html,ts}',
|
|
30
|
+
'./node_modules/@corelusa/pdm-ui-kit/**/*.{mjs,js}'
|
|
31
|
+
]
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Estructura
|
|
36
|
+
- `src/public-api.ts`: exports públicos.
|
|
37
|
+
- `src/lib/pdm-ui-kit.module.ts`: módulo raíz.
|
|
38
|
+
- `src/lib/components/*`: componentes.
|
|
39
|
+
|
|
40
|
+
## Nuevas variantes Figma
|
|
41
|
+
- `pdm-chart` ahora soporta `type="area|bar|line|pie|radar|radial|tooltips"`.
|
|
42
|
+
- `pdm-icon` ahora soporta `library="lucide|tabler|hugeicons|phosphor|remix"`.
|
|
43
|
+
- `pdm-icon` soporta `assetUrl` para usar SVG/PNG expuestos por Figma MCP (`http://localhost:...`) sin dependencias extra.
|
|
44
|
+
|
|
45
|
+
## Publicación en npm
|
|
46
|
+
La librería ya está configurada con `ng-packagr` y se compila en modo `partial` (Ivy), compatible para consumo en Angular 13, 14 y 15.
|
|
47
|
+
|
|
48
|
+
### Scripts disponibles
|
|
49
|
+
- `npm run build:ui-kit`
|
|
50
|
+
- `npm run build:ui-kit:dev`
|
|
51
|
+
- `npm run pack:ui-kit`
|
|
52
|
+
|
|
53
|
+
### Flujo recomendado
|
|
54
|
+
1. Ajustar nombre/versión en `projects/pdm-ui-kit/package.json`.
|
|
55
|
+
2. Compilar:
|
|
56
|
+
- `npm run build:ui-kit`
|
|
57
|
+
3. Probar el paquete localmente:
|
|
58
|
+
- `cd dist/pdm-ui-kit && npm pack`
|
|
59
|
+
4. Login npm:
|
|
60
|
+
- `npm login`
|
|
61
|
+
5. Publicar desde `dist/pdm-ui-kit`:
|
|
62
|
+
- `cd dist/pdm-ui-kit && npm publish --access public`
|
|
63
|
+
|
|
64
|
+
### Nota sobre Tailwind en proyecto consumidor
|
|
65
|
+
Para que se apliquen las clases utility del kit en otro proyecto, incluye el paquete en `content` de `tailwind.config.js`, por ejemplo:
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
content: [
|
|
69
|
+
'./src/**/*.{html,ts}',
|
|
70
|
+
'./node_modules/pdm-ui-kit/**/*.{mjs,js}'
|
|
71
|
+
]
|
|
72
|
+
```
|
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pdm-ui-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reusable UI component library for PDM Director",
|
|
5
|
+
"author": "PDM Director Team",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"angular",
|
|
9
|
+
"ui",
|
|
10
|
+
"components",
|
|
11
|
+
"tailwind",
|
|
12
|
+
"design-system"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git"
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@angular/common": ">=13.0.0 <16.0.0",
|
|
20
|
+
"@angular/core": ">=13.0.0 <16.0.0",
|
|
21
|
+
"rxjs": ">=6.5.0 <8.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"tslib": "^2.3.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<div [ngClass]="['w-full', className]">
|
|
2
|
+
<div *ngFor="let item of items; let i = index" class="border-b border-[#e5e5e5]">
|
|
3
|
+
<h3>
|
|
4
|
+
<button
|
|
5
|
+
type="button"
|
|
6
|
+
class="flex h-[52px] w-full items-center justify-between py-4 text-left text-[14px] font-medium leading-5 text-[#0a0a0a] transition-colors"
|
|
7
|
+
[disabled]="item.disabled"
|
|
8
|
+
[attr.aria-expanded]="isExpanded(i)"
|
|
9
|
+
[attr.aria-controls]="item.id + '-panel'"
|
|
10
|
+
(click)="toggle(i)"
|
|
11
|
+
>
|
|
12
|
+
<span class="pr-[10px]">{{ item.title }}</span>
|
|
13
|
+
<span class="inline-flex h-6 w-6 items-center justify-center text-[#0a0a0a]" aria-hidden="true">
|
|
14
|
+
<svg
|
|
15
|
+
class="h-4 w-4 transition-transform"
|
|
16
|
+
[ngClass]="isExpanded(i) ? 'rotate-180' : ''"
|
|
17
|
+
viewBox="0 0 16 16"
|
|
18
|
+
fill="none"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
>
|
|
21
|
+
<path d="M3.5 6.5L8 11L12.5 6.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
|
22
|
+
</svg>
|
|
23
|
+
</span>
|
|
24
|
+
</button>
|
|
25
|
+
</h3>
|
|
26
|
+
<div
|
|
27
|
+
*ngIf="isExpanded(i)"
|
|
28
|
+
[id]="item.id + '-panel'"
|
|
29
|
+
class="flex flex-col gap-4 pb-4 text-[14px] font-normal leading-5 text-[#0a0a0a]"
|
|
30
|
+
>
|
|
31
|
+
<p *ngFor="let line of contentLines(item.content)" class="m-0">{{ line }}</p>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export interface PdmAccordionItem {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
content: string | string[];
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@Component({
|
|
11
|
+
selector: 'pdm-accordion',
|
|
12
|
+
templateUrl: './accordion.component.html',
|
|
13
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
14
|
+
})
|
|
15
|
+
export class PdmAccordionComponent {
|
|
16
|
+
@Input() items: PdmAccordionItem[] = [];
|
|
17
|
+
@Input() expandedIndex = -1;
|
|
18
|
+
@Input() className = '';
|
|
19
|
+
|
|
20
|
+
@Output() expandedIndexChange = new EventEmitter<number>();
|
|
21
|
+
|
|
22
|
+
isExpanded(index: number): boolean {
|
|
23
|
+
return this.expandedIndex === index;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
contentLines(content: string | string[]): string[] {
|
|
27
|
+
if (Array.isArray(content)) return content;
|
|
28
|
+
return content
|
|
29
|
+
.split('\n')
|
|
30
|
+
.map((line) => line.trim())
|
|
31
|
+
.filter((line) => line.length > 0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
toggle(index: number): void {
|
|
35
|
+
if (this.items[index]?.disabled) return;
|
|
36
|
+
this.expandedIndexChange.emit(this.expandedIndex === index ? -1 : index);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<section
|
|
2
|
+
role="alert"
|
|
3
|
+
[ngClass]="[
|
|
4
|
+
'w-full rounded-[10px] border border-[#e5e5e5] bg-white px-4 py-3',
|
|
5
|
+
className
|
|
6
|
+
]"
|
|
7
|
+
>
|
|
8
|
+
<div [ngClass]="['flex gap-3', isDestructive ? 'items-start' : 'items-center']">
|
|
9
|
+
<span class="inline-flex h-6 w-6 shrink-0 items-center justify-center">
|
|
10
|
+
<svg *ngIf="!isDestructive && !isTitleOnly" viewBox="0 0 24 24" class="h-5 w-5 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
11
|
+
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.5"></circle>
|
|
12
|
+
<path d="M8.5 12.5L10.8 14.8L15.8 9.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
13
|
+
</svg>
|
|
14
|
+
<svg *ngIf="isTitleOnly" viewBox="0 0 24 24" class="h-5 w-5 text-[#0a0a0a]" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
15
|
+
<path d="M5 8H19" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path>
|
|
16
|
+
<path d="M9 8V6.5C9 5.67 9.67 5 10.5 5H13.5C14.33 5 15 5.67 15 6.5V8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path>
|
|
17
|
+
<path d="M7 8L8 18.5C8.07 19.33 8.77 20 9.6 20H14.4C15.23 20 15.93 19.33 16 18.5L17 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path>
|
|
18
|
+
</svg>
|
|
19
|
+
<svg *ngIf="isDestructive" viewBox="0 0 24 24" class="h-5 w-5 text-[#dc2626]" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
20
|
+
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.5"></circle>
|
|
21
|
+
<path d="M12 8V12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"></path>
|
|
22
|
+
<circle cx="12" cy="16" r="1" fill="currentColor"></circle>
|
|
23
|
+
</svg>
|
|
24
|
+
</span>
|
|
25
|
+
|
|
26
|
+
<div class="min-w-0 flex-1">
|
|
27
|
+
<h4
|
|
28
|
+
[ngClass]="[
|
|
29
|
+
'm-0 text-[14px] font-medium leading-5',
|
|
30
|
+
isDestructive ? 'text-[#dc2626]' : 'text-[#0a0a0a]'
|
|
31
|
+
]"
|
|
32
|
+
>
|
|
33
|
+
{{ title }}
|
|
34
|
+
</h4>
|
|
35
|
+
|
|
36
|
+
<p
|
|
37
|
+
*ngIf="!isTitleOnly && description"
|
|
38
|
+
[ngClass]="[
|
|
39
|
+
'm-0 mt-0.5 text-[14px] leading-5',
|
|
40
|
+
isDestructive ? 'text-[#dc2626]' : 'text-[#0a0a0a] font-light'
|
|
41
|
+
]"
|
|
42
|
+
>
|
|
43
|
+
{{ description }}
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<ul *ngIf="isDestructive && details.length" class="m-0 mt-1 pl-5 text-[14px] leading-5 text-[#dc2626]">
|
|
47
|
+
<li *ngFor="let item of details">{{ item }}</li>
|
|
48
|
+
</ul>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmAlertVariant = 'default' | 'title-only' | 'destructive';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-alert',
|
|
7
|
+
templateUrl: './alert.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmAlertComponent {
|
|
11
|
+
@Input() variant: PdmAlertVariant = 'default';
|
|
12
|
+
@Input() title = 'Success! Your changes have been saved';
|
|
13
|
+
@Input() description = 'This is an alert with icon, title and description.';
|
|
14
|
+
@Input() details: string[] = [];
|
|
15
|
+
@Input() className = '';
|
|
16
|
+
|
|
17
|
+
get isDestructive(): boolean {
|
|
18
|
+
return this.variant === 'destructive';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get isTitleOnly(): boolean {
|
|
22
|
+
return this.variant === 'title-only';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<button
|
|
2
|
+
*ngIf="showTrigger && !open"
|
|
3
|
+
type="button"
|
|
4
|
+
class="inline-flex h-9 items-center justify-center rounded-[8px] border border-[#e5e5e5] bg-[#f5f5f5] px-4 py-2 text-[14px] font-medium leading-5 text-[#0a0a0a] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.1)]"
|
|
5
|
+
(click)="onTriggerClick()"
|
|
6
|
+
>
|
|
7
|
+
{{ triggerText }}
|
|
8
|
+
</button>
|
|
9
|
+
|
|
10
|
+
<div *ngIf="open" class="fixed inset-0 z-50 flex items-center justify-center p-5">
|
|
11
|
+
<div class="absolute inset-0 bg-[rgba(0,0,0,0.3)]" (click)="onCancel()"></div>
|
|
12
|
+
<section
|
|
13
|
+
role="alertdialog"
|
|
14
|
+
aria-modal="true"
|
|
15
|
+
[ngClass]="[
|
|
16
|
+
'relative z-10 w-full max-w-[552px] rounded-[10px] border border-[#e5e5e5] bg-white p-6 text-[#0a0a0a] shadow-[0px_10px_15px_0px_rgba(0,0,0,0.1),0px_4px_6px_0px_rgba(0,0,0,0.1)]',
|
|
17
|
+
className
|
|
18
|
+
]"
|
|
19
|
+
>
|
|
20
|
+
<div class="flex flex-col gap-2">
|
|
21
|
+
<h2 class="text-[18px] font-semibold leading-7 tracking-normal">{{ title }}</h2>
|
|
22
|
+
<p *ngIf="description" class="text-[14px] font-normal leading-5 text-[#737373]">{{ description }}</p>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="mt-4 flex items-center justify-end gap-2">
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
class="inline-flex h-9 items-center justify-center rounded-[10px] border border-[#e5e5e5] bg-white px-4 py-2 text-[14px] font-medium leading-5 text-[#0a0a0a] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.1)]"
|
|
28
|
+
(click)="onCancel()"
|
|
29
|
+
>
|
|
30
|
+
{{ cancelText }}
|
|
31
|
+
</button>
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
class="inline-flex h-9 items-center justify-center rounded-[10px] bg-[#171717] px-4 py-2 text-[14px] font-medium leading-5 text-[#fafafa] shadow-[0px_1px_2px_0px_rgba(0,0,0,0.1)]"
|
|
35
|
+
(click)="onConfirm()"
|
|
36
|
+
>
|
|
37
|
+
{{ confirmText }}
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'pdm-alert-dialog',
|
|
5
|
+
templateUrl: './alert-dialog.component.html',
|
|
6
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
7
|
+
})
|
|
8
|
+
export class PdmAlertDialogComponent {
|
|
9
|
+
@Input() open = false;
|
|
10
|
+
@Input() showTrigger = false;
|
|
11
|
+
@Input() triggerText = 'Show dialog';
|
|
12
|
+
@Input() title = 'Are you absolutely sure?';
|
|
13
|
+
@Input() description = '';
|
|
14
|
+
@Input() confirmText = 'Continue';
|
|
15
|
+
@Input() cancelText = 'Cancel';
|
|
16
|
+
@Input() className = '';
|
|
17
|
+
|
|
18
|
+
@Output() openChange = new EventEmitter<boolean>();
|
|
19
|
+
@Output() confirm = new EventEmitter<void>();
|
|
20
|
+
@Output() cancel = new EventEmitter<void>();
|
|
21
|
+
|
|
22
|
+
onTriggerClick(): void {
|
|
23
|
+
this.open = true;
|
|
24
|
+
this.openChange.emit(true);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
onCancel(): void {
|
|
28
|
+
this.cancel.emit();
|
|
29
|
+
this.open = false;
|
|
30
|
+
this.openChange.emit(false);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onConfirm(): void {
|
|
34
|
+
this.confirm.emit();
|
|
35
|
+
this.open = false;
|
|
36
|
+
this.openChange.emit(false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@HostListener('document:keydown.escape')
|
|
40
|
+
onEsc(): void {
|
|
41
|
+
if (this.open) {
|
|
42
|
+
this.onCancel();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div class="relative w-full" [ngClass]="className" [style.paddingTop]="paddingTop">
|
|
2
|
+
<div class="absolute inset-0 overflow-hidden rounded-[10px]">
|
|
3
|
+
<img
|
|
4
|
+
*ngIf="imageSrc"
|
|
5
|
+
[src]="imageSrc"
|
|
6
|
+
[alt]="imageAlt"
|
|
7
|
+
class="pointer-events-none h-full w-full rounded-[10px] object-cover"
|
|
8
|
+
/>
|
|
9
|
+
<ng-content></ng-content>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Component({
|
|
4
|
+
selector: 'pdm-aspect-ratio',
|
|
5
|
+
templateUrl: './aspect-ratio.component.html',
|
|
6
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
7
|
+
})
|
|
8
|
+
export class PdmAspectRatioComponent {
|
|
9
|
+
@Input() ratio = 16 / 9;
|
|
10
|
+
@Input() imageSrc = '';
|
|
11
|
+
@Input() imageAlt = '';
|
|
12
|
+
@Input() className = '';
|
|
13
|
+
|
|
14
|
+
get paddingTop(): string {
|
|
15
|
+
if (!this.ratio || this.ratio <= 0) return '56.25%';
|
|
16
|
+
return (100 / this.ratio).toFixed(4) + '%';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div *ngIf="!isGroup" [ngClass]="['relative flex shrink-0 overflow-hidden', radiusClass, sizeClasses[size], className]">
|
|
2
|
+
<img *ngIf="src" [src]="src" [alt]="alt" [ngClass]="['aspect-square h-full w-full object-cover', radiusClass]" />
|
|
3
|
+
<div
|
|
4
|
+
*ngIf="!src"
|
|
5
|
+
[ngClass]="['flex h-full w-full items-center justify-center bg-[hsl(var(--muted))] text-xs text-[hsl(var(--muted-foreground))]', radiusClass]"
|
|
6
|
+
>
|
|
7
|
+
{{ fallback }}
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div *ngIf="isGroup" [ngClass]="['inline-flex items-center pr-2', className]">
|
|
12
|
+
<div
|
|
13
|
+
*ngFor="let groupSrc of groupSources; let i = index"
|
|
14
|
+
[ngClass]="[
|
|
15
|
+
'relative h-8 w-8 shrink-0 overflow-hidden rounded-full',
|
|
16
|
+
i > 0 ? '-mr-2 border border-[#e5e5e5]' : '-mr-2'
|
|
17
|
+
]"
|
|
18
|
+
>
|
|
19
|
+
<img [src]="groupSrc" [alt]="alt + ' ' + (i + 1)" class="h-full w-full rounded-full object-cover" />
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmAvatarShape = 'circle' | 'square';
|
|
4
|
+
|
|
5
|
+
@Component({
|
|
6
|
+
selector: 'pdm-avatar',
|
|
7
|
+
templateUrl: './avatar.component.html',
|
|
8
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
9
|
+
})
|
|
10
|
+
export class PdmAvatarComponent {
|
|
11
|
+
@Input() src = '';
|
|
12
|
+
@Input() alt = 'Avatar';
|
|
13
|
+
@Input() fallback = 'U';
|
|
14
|
+
@Input() shape: PdmAvatarShape = 'circle';
|
|
15
|
+
@Input() size: 'sm' | 'md' | 'lg' = 'md';
|
|
16
|
+
@Input() groupSources: string[] = [];
|
|
17
|
+
@Input() className = '';
|
|
18
|
+
|
|
19
|
+
readonly sizeClasses = {
|
|
20
|
+
sm: 'h-8 w-8',
|
|
21
|
+
md: 'h-10 w-10',
|
|
22
|
+
lg: 'h-12 w-12'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
get isGroup(): boolean {
|
|
26
|
+
return this.groupSources.length > 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get radiusClass(): string {
|
|
30
|
+
return this.shape === 'square' ? 'rounded-[8px]' : 'rounded-full';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<span
|
|
2
|
+
[ngClass]="[
|
|
3
|
+
'inline-flex items-center justify-center text-center align-middle',
|
|
4
|
+
variant === 'default' ? 'h-[22px] rounded-[10px] bg-[#171717] px-[10px] py-[2px] text-[12px] font-medium leading-4 text-[#fafafa]' : '',
|
|
5
|
+
variant === 'secondary' ? 'h-[22px] rounded-[10px] bg-[#f5f5f5] px-[10px] py-[2px] text-[12px] font-medium leading-4 text-[#0a0a0a]' : '',
|
|
6
|
+
variant === 'destructive' ? 'h-[22px] rounded-[10px] bg-[#dc2626] px-[10px] py-[2px] text-[12px] font-medium leading-4 text-[rgba(255,255,255,0.95)]' : '',
|
|
7
|
+
variant === 'outline' ? 'h-[22px] rounded-[10px] border border-[#e5e5e5] px-[10px] py-[2px] text-[12px] font-medium leading-4 text-[#0a0a0a]' : '',
|
|
8
|
+
variant === 'icon' ? 'h-[22px] gap-1 rounded-[10px] bg-[#171717] px-[10px] py-[2px] text-[12px] font-medium leading-4 text-[#fafafa]' : '',
|
|
9
|
+
variant === 'number' ? 'h-5 min-w-[20px] rounded-full bg-[#171717] px-[6px] py-[2px] text-[12px] font-medium leading-4 text-[#fafafa]' : '',
|
|
10
|
+
variant === 'destructive-number' ? 'h-5 min-w-[20px] rounded-full bg-[#dc2626] px-[6px] py-[2px] text-[12px] font-medium leading-4 text-[rgba(255,255,255,0.95)]' : '',
|
|
11
|
+
variant === 'secondary-number' ? 'h-5 min-w-[20px] rounded-full border border-[#e5e5e5] px-1 py-[2px] text-[12px] font-medium leading-4 text-[#0a0a0a]' : '',
|
|
12
|
+
className
|
|
13
|
+
]"
|
|
14
|
+
>
|
|
15
|
+
<svg
|
|
16
|
+
*ngIf="variant === 'icon'"
|
|
17
|
+
viewBox="0 0 24 24"
|
|
18
|
+
class="h-4 w-4"
|
|
19
|
+
fill="none"
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
aria-hidden="true"
|
|
22
|
+
>
|
|
23
|
+
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="1.5"></circle>
|
|
24
|
+
<path d="M8.5 12.5L10.8 14.8L15.8 9.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
|
25
|
+
</svg>
|
|
26
|
+
<span [ngClass]="[variant === 'secondary-number' ? 'font-mono' : '']">{{ text }}</span>
|
|
27
|
+
</span>
|
|
28
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
export type PdmBadgeVariant =
|
|
4
|
+
| 'default'
|
|
5
|
+
| 'secondary'
|
|
6
|
+
| 'destructive'
|
|
7
|
+
| 'outline'
|
|
8
|
+
| 'icon'
|
|
9
|
+
| 'number'
|
|
10
|
+
| 'destructive-number'
|
|
11
|
+
| 'secondary-number';
|
|
12
|
+
|
|
13
|
+
@Component({
|
|
14
|
+
selector: 'pdm-badge',
|
|
15
|
+
templateUrl: './badge.component.html',
|
|
16
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
17
|
+
})
|
|
18
|
+
export class PdmBadgeComponent {
|
|
19
|
+
@Input() variant: PdmBadgeVariant = 'default';
|
|
20
|
+
@Input() text = 'Badge';
|
|
21
|
+
@Input() className = '';
|
|
22
|
+
}
|
|
23
|
+
|