@foxeltech/angular-ui 0.3.1 → 0.7.44
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/archivo/archivo-400-latin-ext.woff2 +0 -0
- package/archivo/archivo-400-latin.woff2 +0 -0
- package/archivo/archivo-400-vietnamese.woff2 +0 -0
- package/archivo/archivo-500-latin-ext.woff2 +0 -0
- package/archivo/archivo-500-latin.woff2 +0 -0
- package/archivo/archivo-500-vietnamese.woff2 +0 -0
- package/archivo/archivo-600-latin-ext.woff2 +0 -0
- package/archivo/archivo-600-latin.woff2 +0 -0
- package/archivo/archivo-600-vietnamese.woff2 +0 -0
- package/archivo/archivo-700-latin-ext.woff2 +0 -0
- package/archivo/archivo-700-latin.woff2 +0 -0
- package/archivo/archivo-700-vietnamese.woff2 +0 -0
- package/components.css +12 -12
- package/dialogs.css +2 -2
- package/fesm2022/foxeltech-angular-ui-chart.mjs +560 -0
- package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -0
- package/fesm2022/foxeltech-angular-ui-flow.mjs +211 -0
- package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -0
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs +156 -0
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs.map +1 -0
- package/fesm2022/foxeltech-angular-ui.mjs +1580 -1409
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
- package/fonts.css +462 -138
- package/fx-icons.svg +97 -0
- package/ibm-plex-mono/ibm-plex-mono-400-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-400-vietnamese.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-500-vietnamese.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-cyrillic-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-cyrillic.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-latin-ext.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-latin.woff2 +0 -0
- package/ibm-plex-mono/ibm-plex-mono-600-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-400-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-500-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-600-vietnamese.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-cyrillic-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-cyrillic.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-greek.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-latin-ext.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-latin.woff2 +0 -0
- package/jetbrains-mono/jetbrains-mono-700-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-400-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-400-latin.woff2 +0 -0
- package/newsreader/newsreader-400-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-500-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-500-latin.woff2 +0 -0
- package/newsreader/newsreader-500-vietnamese.woff2 +0 -0
- package/newsreader/newsreader-600-latin-ext.woff2 +0 -0
- package/newsreader/newsreader-600-latin.woff2 +0 -0
- package/newsreader/newsreader-600-vietnamese.woff2 +0 -0
- package/package.json +18 -9
- package/source-serif-4/source-serif-4-400-cyrillic-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-cyrillic.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-greek.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-latin-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-latin.woff2 +0 -0
- package/source-serif-4/source-serif-4-400-vietnamese.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-cyrillic-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-cyrillic.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-greek.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-latin-ext.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-latin.woff2 +0 -0
- package/source-serif-4/source-serif-4-600-vietnamese.woff2 +0 -0
- package/src/lib/styles/components.css +12 -12
- package/src/lib/styles/dialogs.css +2 -2
- package/src/lib/styles/fonts.css +462 -138
- package/src/lib/styles/tailwind.css +1 -2
- package/src/lib/styles/theme.css +596 -69
- package/src/lib/styles/tokens.css +56 -19
- package/src/lib/styles/utilities.css +4 -1
- package/src/lib/ui/components/bar-list/bar-list.component.html +29 -0
- package/src/lib/ui/components/button/button.component.html +20 -18
- package/src/lib/ui/components/checkbox/checkbox.component.html +3 -3
- package/src/lib/ui/components/circle-progress-bar/circle-progress-bar.component.html +2 -2
- package/src/lib/ui/components/code-block/code-block.component.html +8 -0
- package/src/lib/ui/components/datetime-picker/datetime-picker.component.html +49 -27
- package/src/lib/ui/components/datetime-picker/datetime-picker.component.scss +25 -137
- package/src/lib/ui/components/dnd-upload/dnd-upload.component.html +3 -3
- package/src/lib/ui/components/drawer/drawer.component.html +36 -13
- package/src/lib/ui/components/drawer/drawer.component.scss +104 -18
- package/src/lib/ui/components/empty-state/empty-state.component.html +2 -2
- package/src/lib/ui/components/facets-rail/facets-rail.component.html +42 -0
- package/src/lib/ui/components/filter-pills/filter-pills.component.html +16 -0
- package/src/lib/ui/components/hero-icon/hero-icon.component.html +10 -9
- package/src/lib/ui/components/info-field/info-field.component.html +1 -1
- package/src/lib/ui/components/input/input.component.html +6 -6
- package/src/lib/ui/components/kanban-board/kanban-board.component.html +1 -1
- package/src/lib/ui/components/kanban-board/kanban-board.component.scss +9 -9
- package/src/lib/ui/components/list-row/list-row.component.html +20 -0
- package/src/lib/ui/components/loading-panel/loading-panel.component.html +1 -1
- package/src/lib/ui/components/master-detail/master-detail.component.css +22 -0
- package/src/lib/ui/components/master-detail/master-detail.component.html +42 -10
- package/src/lib/ui/components/menu/menu.component.html +27 -0
- package/src/lib/ui/components/pending-badge/pending-badge.component.html +15 -0
- package/src/lib/ui/components/pipeline-stepper/pipeline-stepper.component.html +45 -0
- package/src/lib/ui/components/project-card/project-card.component.html +102 -0
- package/src/lib/ui/components/radio-button/radio-button.component.html +4 -4
- package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +4 -4
- package/src/lib/ui/components/sample-frame/sample-frame.component.html +18 -0
- package/src/lib/ui/components/score-badge/score-badge.component.html +7 -0
- package/src/lib/ui/components/screenshot-frame/screenshot-frame.component.html +40 -0
- package/src/lib/ui/components/search-bar/search-bar.component.html +1 -1
- package/src/lib/ui/components/section-card/section-card.component.html +19 -6
- package/src/lib/ui/components/segmented/segmented.component.html +42 -0
- package/src/lib/ui/components/segmented/segmented.component.scss +12 -0
- package/src/lib/ui/components/select/select.component.html +6 -6
- package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +2 -2
- package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +1 -1
- package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.html +5 -5
- package/src/lib/ui/components/slider/slider.component.html +8 -8
- package/src/lib/ui/components/sparkbar/sparkbar.component.html +14 -0
- package/src/lib/ui/components/stage-dots/stage-dots.component.html +13 -0
- package/src/lib/ui/components/stat-cards/stat-cards.component.html +45 -12
- package/src/lib/ui/components/status-dot/status-dot.component.html +13 -0
- package/src/lib/ui/components/switch/switch.component.html +1 -1
- package/src/lib/ui/components/tab-group/tab-group.component.html +41 -12
- package/src/lib/ui/components/tab-group/tab-group.component.scss +41 -1
- package/src/lib/ui/components/table-cell/table-cell.component.html +2 -2
- package/src/lib/ui/components/tag/tag.component.html +4 -4
- package/src/lib/ui/components/theme-picker/theme-picker.component.html +44 -0
- package/src/lib/ui/components/toast/toast.component.html +7 -7
- package/src/lib/ui/components/toast-container/toast-container.component.html +1 -0
- package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +5 -5
- package/tailwind.css +1 -2
- package/theme.css +596 -69
- package/tokens.css +56 -19
- package/types/foxeltech-angular-ui-chart.d.ts +65 -0
- package/types/foxeltech-angular-ui-flow.d.ts +96 -0
- package/types/foxeltech-angular-ui-rich-text.d.ts +35 -0
- package/types/foxeltech-angular-ui.d.ts +1018 -395
- package/utilities.css +4 -1
- package/BeVietnamPro/BeVietnamPro-Bold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-ExtraLight.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Light.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Medium.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Regular.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-SemiBold.woff2 +0 -0
- package/BeVietnamPro/BeVietnamPro-Thin.woff2 +0 -0
- package/SpaceMono-Regular.woff2 +0 -0
- package/dm-sans/DMSans-Bold.woff2 +0 -0
- package/dm-sans/DMSans-Light.woff2 +0 -0
- package/dm-sans/DMSans-Medium.woff2 +0 -0
- package/dm-sans/DMSans-Regular.woff2 +0 -0
- package/dm-sans/DMSans-SemiBold.woff2 +0 -0
- package/dm-sans/DMSans-Thin.woff2 +0 -0
- package/orbitron/Orbitron-Bold.woff2 +0 -0
- package/orbitron/Orbitron-Medium.woff2 +0 -0
- package/orbitron/Orbitron-Regular.woff2 +0 -0
- package/orbitron/Orbitron-SemiBold.woff2 +0 -0
- package/roboto/Roboto-Black.woff2 +0 -0
- package/roboto/Roboto-BlackItalic.woff2 +0 -0
- package/roboto/Roboto-Bold.woff2 +0 -0
- package/roboto/Roboto-BoldCondensed.woff2 +0 -0
- package/roboto/Roboto-BoldCondensedItalic.woff2 +0 -0
- package/roboto/Roboto-BoldItalic.woff2 +0 -0
- package/roboto/Roboto-Condensed.woff2 +0 -0
- package/roboto/Roboto-CondensedItalic.woff2 +0 -0
- package/roboto/Roboto-Italic.woff2 +0 -0
- package/roboto/Roboto-Light.woff2 +0 -0
- package/roboto/Roboto-LightItalic.woff2 +0 -0
- package/roboto/Roboto-Medium.woff2 +0 -0
- package/roboto/Roboto-MediumItalic.woff2 +0 -0
- package/roboto/Roboto-Regular.woff2 +0 -0
- package/roboto/Roboto-Thin.woff2 +0 -0
- package/roboto/Roboto-ThinItalic.woff2 +0 -0
- package/src/lib/ui/components/chart/chart.component.html +0 -20
- package/src/lib/ui/components/chart/chart.component.scss +0 -49
- package/src/lib/ui/components/flow-connection/flow-connection.component.html +0 -10
- package/src/lib/ui/components/flow-connection/flow-connection.component.scss +0 -0
- package/src/lib/ui/components/rich-text-area/rich-text-area.component.html +0 -3
- package/src/lib/ui/components/rich-text-area/rich-text-area.component.scss +0 -18
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<button
|
|
2
|
+
type="button"
|
|
3
|
+
class="card-common bg-surface w-full flex flex-col gap-normal hover:border-accent hover:shadow-md transition-all"
|
|
4
|
+
(click)="open.emit(card())"
|
|
5
|
+
>
|
|
6
|
+
<!-- Header: avatar + name/sub + score chip (design 12) -->
|
|
7
|
+
<div class="flex items-start justify-between gap-normal w-full">
|
|
8
|
+
<div class="flex items-start gap-normal min-w-0">
|
|
9
|
+
@if (card().avatar) {
|
|
10
|
+
<span
|
|
11
|
+
class="w-9 h-9 rounded-control bg-accent-soft text-accent flex items-center justify-center shrink-0 txt-utility-caption font-bold uppercase"
|
|
12
|
+
style="font-family: var(--og-font-figure)"
|
|
13
|
+
>{{ card().avatar }}</span
|
|
14
|
+
>
|
|
15
|
+
}
|
|
16
|
+
<div class="min-w-0">
|
|
17
|
+
<div class="txt-heading-06 truncate text-left">{{ card().name }}</div>
|
|
18
|
+
@if (card().sub; as sub) {
|
|
19
|
+
<div class="flex items-center gap-xs txt-utility-description mt-xs">
|
|
20
|
+
@if (sub.icon) {
|
|
21
|
+
<fx-ui-hero-icon [icon]="sub.icon" [size]="13" class="flex shrink-0" />
|
|
22
|
+
}
|
|
23
|
+
<span class="truncate">{{ sub.label }}</span>
|
|
24
|
+
</div>
|
|
25
|
+
} @else if (card().description) {
|
|
26
|
+
<div class="txt-card-content truncate mt-xs text-left">{{ card().description }}</div>
|
|
27
|
+
}
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
@if (card().score !== undefined) {
|
|
31
|
+
<div class="text-right shrink-0">
|
|
32
|
+
<span
|
|
33
|
+
class="txt-tag-label px-normal py-[2px] rounded-pill whitespace-nowrap"
|
|
34
|
+
[ngClass]="scoreChipClass()"
|
|
35
|
+
>{{ card().score }}</span
|
|
36
|
+
>
|
|
37
|
+
@if (card().scoreLabel) {
|
|
38
|
+
<div class="txt-utility-description mt-xs">{{ card().scoreLabel }}</div>
|
|
39
|
+
}
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
@if (card().chips?.length) {
|
|
45
|
+
<div class="flex flex-wrap gap-xs w-full">
|
|
46
|
+
@for (chip of card().chips; track chip.label) {
|
|
47
|
+
<span class="txt-tag-label px-normal py-[1px] rounded-pill" [ngClass]="chipClass(chip)">
|
|
48
|
+
{{ chip.label }}
|
|
49
|
+
</span>
|
|
50
|
+
}
|
|
51
|
+
</div>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
<!-- Design-12 risk trend: toned blocks + caption line -->
|
|
55
|
+
@if (card().trend; as trend) {
|
|
56
|
+
<div class="w-full">
|
|
57
|
+
<div class="flex gap-xs w-full">
|
|
58
|
+
@for (tone of trend.tones; track $index) {
|
|
59
|
+
<span class="flex-1 h-4 rounded-[2px]" [ngClass]="blockClass(tone)"></span>
|
|
60
|
+
}
|
|
61
|
+
</div>
|
|
62
|
+
@if (trend.caption || trend.aside) {
|
|
63
|
+
<div class="flex items-center justify-between mt-xs txt-utility-description font-mono">
|
|
64
|
+
<span>{{ trend.caption }}</span>
|
|
65
|
+
<span>{{ trend.aside }}</span>
|
|
66
|
+
</div>
|
|
67
|
+
}
|
|
68
|
+
</div>
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@if (card().spark?.length) {
|
|
72
|
+
<fx-ui-sparkbar class="w-full" [values]="card().spark!" [height]="24" />
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
<!-- Metric columns: figure + caption (design 12) -->
|
|
76
|
+
@if (card().metrics?.length) {
|
|
77
|
+
<div
|
|
78
|
+
class="grid gap-normal w-full"
|
|
79
|
+
[style.grid-template-columns]="'repeat(' + card().metrics!.length + ', minmax(0, 1fr))'"
|
|
80
|
+
>
|
|
81
|
+
@for (m of card().metrics; track m.label) {
|
|
82
|
+
<div class="min-w-0 text-left">
|
|
83
|
+
<div class="txt-heading-06" style="font-family: var(--og-font-figure)">{{ m.value }}</div>
|
|
84
|
+
<div class="txt-utility-description truncate">{{ m.label }}</div>
|
|
85
|
+
</div>
|
|
86
|
+
}
|
|
87
|
+
</div>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@if (card().meta || card().openLabel) {
|
|
91
|
+
<div
|
|
92
|
+
class="flex items-center justify-between w-full pt-normal border-t border-border-default"
|
|
93
|
+
>
|
|
94
|
+
<span class="txt-utility-description text-left">{{ card().meta }}</span>
|
|
95
|
+
@if (card().openLabel) {
|
|
96
|
+
<span class="txt-utility-caption font-bold text-accent whitespace-nowrap"
|
|
97
|
+
>{{ card().openLabel }} ›</span
|
|
98
|
+
>
|
|
99
|
+
}
|
|
100
|
+
</div>
|
|
101
|
+
}
|
|
102
|
+
</button>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div
|
|
2
2
|
class="w-full rounded-lg overflow-hidden"
|
|
3
|
-
[class]="class"
|
|
3
|
+
[class]="class()"
|
|
4
4
|
role="radiogroup"
|
|
5
5
|
[attr.aria-labelledby]="label ? groupId + '-label' : null"
|
|
6
6
|
>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
@if (label) {
|
|
9
9
|
<span class="txt-field-label block" [id]="groupId + '-label'">
|
|
10
10
|
{{ label }}
|
|
11
|
-
@if (required) {
|
|
11
|
+
@if (required()) {
|
|
12
12
|
<span class="txt-required" aria-hidden="true">*</span>
|
|
13
13
|
}
|
|
14
14
|
@if (tooltip) {
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
</span>
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
@for (opt of options; track opt) {
|
|
27
|
+
@for (opt of options(); track opt) {
|
|
28
28
|
<button
|
|
29
29
|
type="button"
|
|
30
30
|
role="radio"
|
|
31
31
|
[attr.aria-checked]="value === opt.value"
|
|
32
32
|
(click)="onSelectValue(opt.value)"
|
|
33
33
|
[disabled]="disabled"
|
|
34
|
-
[class.text-
|
|
34
|
+
[class.text-strong]="value !== opt.value"
|
|
35
35
|
class="flex-1 px-normal w-full flex items-center gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed"
|
|
36
36
|
[matTooltip]="opt.tooltip || ''"
|
|
37
37
|
matTooltipPosition="right"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<div class="flex flex-col text-left mb-4 w-full" [class]="class">
|
|
1
|
+
<div class="flex flex-col text-left mb-4 w-full" [class]="class()">
|
|
2
2
|
<!-- A radiogroup has no single control a <label> could point at — name it via aria-labelledby. -->
|
|
3
3
|
@if(label){<span class="txt-field-label" [id]="groupId + '-label'">
|
|
4
4
|
{{ label }}
|
|
5
|
-
@if(required) {<span class="txt-required" aria-hidden="true">*</span>} </span
|
|
5
|
+
@if(required()) {<span class="txt-required" aria-hidden="true">*</span>} </span
|
|
6
6
|
>}
|
|
7
7
|
|
|
8
8
|
<div
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
role="radiogroup"
|
|
11
11
|
[attr.aria-labelledby]="label ? groupId + '-label' : null"
|
|
12
12
|
>
|
|
13
|
-
@for(opt of options; track opt){<button
|
|
13
|
+
@for(opt of options(); track opt){<button
|
|
14
14
|
type="button"
|
|
15
15
|
role="radio"
|
|
16
16
|
[attr.aria-checked]="value === opt.value"
|
|
17
17
|
(click)="onSelectValue(opt.value)"
|
|
18
18
|
[disabled]="disabled"
|
|
19
|
-
[class.text-
|
|
19
|
+
[class.text-strong]="value !== opt.value"
|
|
20
20
|
class="flex-1 bg-bg-primary flex items-center pl-normal gap-normal h-10 rounded-md hover:bg-bg-hover transition-all duration-150 disabled:opacity-60 disabled:cursor-not-allowed"
|
|
21
21
|
>
|
|
22
22
|
<span
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<div class="relative rounded-lg border border-dashed border-warning/50 bg-warning/[0.03] p-normal">
|
|
2
|
+
<!-- flex-wrap + nowrap label: in narrow rails the chip drops to the next line
|
|
3
|
+
instead of the label breaking mid-word ("SAMPLE / LAYOUT"). -->
|
|
4
|
+
<div class="flex flex-wrap items-center gap-small mb-normal">
|
|
5
|
+
<span class="txt-tag-label text-warning uppercase tracking-wide whitespace-nowrap">{{ label() }}</span>
|
|
6
|
+
<span
|
|
7
|
+
class="inline-flex items-center gap-xs px-small py-[1px] rounded-pill border border-dashed border-warning/60 bg-warning/10 text-warning txt-tag-label whitespace-nowrap"
|
|
8
|
+
[attr.title]="tooltip"
|
|
9
|
+
>
|
|
10
|
+
<fx-ui-hero-icon icon="clock" [size]="11" class="flex" />
|
|
11
|
+
{{ pendingLabel() }}
|
|
12
|
+
</span>
|
|
13
|
+
</div>
|
|
14
|
+
<!-- Sample content is non-interactive: nothing here reflects real state. -->
|
|
15
|
+
<div class="pointer-events-none select-none opacity-90">
|
|
16
|
+
<ng-content></ng-content>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<span
|
|
2
|
+
class="inline-flex items-center justify-center rounded-control whitespace-nowrap"
|
|
3
|
+
[ngClass]="[badgeClass(), sizeClass()]"
|
|
4
|
+
style="font-family: var(--og-font-figure)"
|
|
5
|
+
>
|
|
6
|
+
{{ score() }}@if (outOf() !== null) {<span class="opacity-60"> / {{ outOf() }}</span>}
|
|
7
|
+
</span>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@if (label()) {
|
|
2
|
+
<div class="txt-utility-caption font-bold text-text-secondary mb-normal">{{ label() }}</div>
|
|
3
|
+
}
|
|
4
|
+
<div class="rounded-control border border-border bg-surface overflow-hidden">
|
|
5
|
+
<!-- Window chrome: traffic lights + mono file name + capture time -->
|
|
6
|
+
<div class="flex items-center gap-small px-normal py-small border-b border-border bg-surface-sunken">
|
|
7
|
+
<span class="flex items-center gap-xs shrink-0">
|
|
8
|
+
<span class="w-2 h-2 rounded-full bg-critical/70"></span>
|
|
9
|
+
<span class="w-2 h-2 rounded-full bg-warning/70"></span>
|
|
10
|
+
<span class="w-2 h-2 rounded-full bg-success/70"></span>
|
|
11
|
+
</span>
|
|
12
|
+
@if (fileName()) {
|
|
13
|
+
<span class="txt-utility-caption text-text-secondary truncate" style="font-family: var(--og-font-mono)">
|
|
14
|
+
{{ fileName() }}
|
|
15
|
+
</span>
|
|
16
|
+
}
|
|
17
|
+
@if (timestamp()) {
|
|
18
|
+
<span class="txt-utility-caption text-text-placeholder shrink-0" style="font-family: var(--og-font-mono)">
|
|
19
|
+
· {{ timestamp() }}
|
|
20
|
+
</span>
|
|
21
|
+
}
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
@if (src()) {
|
|
25
|
+
<img [src]="src()" [alt]="alt() || fileName()" class="block w-full object-cover" [style.height]="height()" />
|
|
26
|
+
} @else {
|
|
27
|
+
<div
|
|
28
|
+
class="flex flex-col items-center justify-center gap-normal px-large text-center"
|
|
29
|
+
[style.height]="height()"
|
|
30
|
+
>
|
|
31
|
+
<fx-ui-hero-icon icon="camera" [size]="22" class="flex text-text-placeholder"></fx-ui-hero-icon>
|
|
32
|
+
@if (caption()) {
|
|
33
|
+
<span class="txt-utility-caption text-text-placeholder max-w-[280px]">{{ caption() }}</span>
|
|
34
|
+
}
|
|
35
|
+
</div>
|
|
36
|
+
}
|
|
37
|
+
</div>
|
|
38
|
+
@if (src() && caption()) {
|
|
39
|
+
<div class="txt-utility-caption text-text-placeholder mt-normal">{{ caption() }}</div>
|
|
40
|
+
}
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
<div class="card-common">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
@if (titleStyle() === 'eyebrow') {
|
|
3
|
+
<div class="flex items-baseline justify-between gap-normal mb-large">
|
|
4
|
+
<span
|
|
5
|
+
class="txt-table-header uppercase"
|
|
6
|
+
style="letter-spacing: var(--og-tracking-label)"
|
|
7
|
+
>{{ title() }}</span
|
|
8
|
+
>
|
|
9
|
+
@if (aside()) {
|
|
10
|
+
<span class="txt-utility-description text-right">{{ aside() }}</span>
|
|
11
|
+
}
|
|
12
|
+
</div>
|
|
13
|
+
} @else {
|
|
14
|
+
<div class="flex items-center gap-normal mb-large">
|
|
15
|
+
@if (icon) {
|
|
16
|
+
<fx-ui-hero-icon [ngClass]="iconClass" [icon]="icon" [size]="18"></fx-ui-hero-icon>
|
|
17
|
+
}
|
|
18
|
+
<span class="txt-heading-06">{{ title() }}</span>
|
|
19
|
+
</div>
|
|
20
|
+
}
|
|
8
21
|
<ng-content></ng-content>
|
|
9
22
|
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="relative inline-grid max-w-full grid-flow-col auto-cols-fr items-stretch p-[3px] bg-surface-sunken border border-border rounded-full"
|
|
3
|
+
role="group"
|
|
4
|
+
[attr.aria-label]="ariaLabel()"
|
|
5
|
+
>
|
|
6
|
+
<!-- Sliding thumb: one element that translates to the active option -->
|
|
7
|
+
@if (activeIndex() >= 0) {
|
|
8
|
+
<span
|
|
9
|
+
aria-hidden="true"
|
|
10
|
+
class="fx-segmented__thumb absolute top-[3px] bottom-[3px] left-[3px] rounded-full pointer-events-none"
|
|
11
|
+
[class]="thumbClass()"
|
|
12
|
+
[style.width]="thumbWidth()"
|
|
13
|
+
[style.transform]="thumbTransform()"
|
|
14
|
+
></span>
|
|
15
|
+
}
|
|
16
|
+
@for (option of options(); track option.value) {
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
(click)="select(option)"
|
|
20
|
+
[disabled]="option.disabled"
|
|
21
|
+
[attr.aria-pressed]="option.value === value()"
|
|
22
|
+
class="relative z-[1] flex min-w-0 items-center justify-center gap-xs px-semi py-[5px] rounded-full text-[13px] leading-none font-medium whitespace-nowrap transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
23
|
+
[class]="optionClass(option)"
|
|
24
|
+
>
|
|
25
|
+
@if (option.icon) {
|
|
26
|
+
<fx-ui-hero-icon [icon]="option.icon" [size]="14" class="flex" />
|
|
27
|
+
}
|
|
28
|
+
<!-- text-box trims Archivo's uneven leading → true optical centering
|
|
29
|
+
(Chrome 128+/Safari 18.2+; older browsers ignore it harmlessly).
|
|
30
|
+
truncate adds overflow:hidden, and the trimmed box ends at cap
|
|
31
|
+
height / baseline — so the dot on "i" and the tail on "y" fall
|
|
32
|
+
outside it and get clipped. py/-my pair gives both back without
|
|
33
|
+
changing the control's height. -->
|
|
34
|
+
<span class="min-w-0 truncate py-[3px] -my-[3px] [text-box:trim-both_cap_alphabetic]">{{ option.label }}</span>
|
|
35
|
+
@if (option.count !== undefined) {
|
|
36
|
+
<span class="txt-tag-label px-small rounded-pill bg-neutral-soft text-neutral-soft-fg">
|
|
37
|
+
{{ option.count }}
|
|
38
|
+
</span>
|
|
39
|
+
}
|
|
40
|
+
</button>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* The thumb's motion is owned HERE, not by template utilities: consuming apps
|
|
2
|
+
can (and do — host theme fade) ship unlayered global `transition` rules that
|
|
3
|
+
override the Tailwind utilities layer and freeze the slide. Component styles
|
|
4
|
+
are unlayered + scoped, so they win. (anh Tú 29/08) */
|
|
5
|
+
.fx-segmented__thumb {
|
|
6
|
+
transition: transform 0.2s cubic-bezier(0.2, 0.9, 0.2, 1), width 0.2s cubic-bezier(0.2, 0.9, 0.2, 1);
|
|
7
|
+
will-change: transform;
|
|
8
|
+
|
|
9
|
+
@media (prefers-reduced-motion: reduce) {
|
|
10
|
+
transition: none;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
<div class="mb-4 text-left w-full" [class]="class">
|
|
1
|
+
<div class="mb-4 text-left w-full" [class]="class()">
|
|
2
2
|
@if (label) {
|
|
3
3
|
<label class="block txt-field-label" [attr.for]="fieldId">
|
|
4
4
|
{{ label }}
|
|
5
|
-
@if (required) {
|
|
5
|
+
@if (required()) {
|
|
6
6
|
<span class="txt-required" aria-hidden="true">*</span>
|
|
7
7
|
}
|
|
8
8
|
@if (tooltip) {
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
>
|
|
26
26
|
<mat-select
|
|
27
27
|
[id]="fieldId"
|
|
28
|
-
[required]="!!required"
|
|
28
|
+
[required]="!!required()"
|
|
29
29
|
[attr.aria-invalid]="invalid || null"
|
|
30
30
|
[attr.aria-describedby]="invalid ? fieldId + '-error' : null"
|
|
31
|
-
[placeholder]="placeholder"
|
|
31
|
+
[placeholder]="placeholder()"
|
|
32
32
|
[disabled]="disabled"
|
|
33
|
-
[multiple]="multiple"
|
|
33
|
+
[multiple]="multiple()"
|
|
34
34
|
[value]="value"
|
|
35
35
|
(selectionChange)="onSelectionChange($event.value)"
|
|
36
36
|
(openedChange)="onOpened($event)"
|
|
37
37
|
(blur)="onTouched()"
|
|
38
38
|
>
|
|
39
|
-
@if (enableSearch) {
|
|
39
|
+
@if (enableSearch()) {
|
|
40
40
|
<div class="px-semi w-full">
|
|
41
41
|
<input
|
|
42
42
|
type="text"
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
|
-
@for (c of range(cards); track c) {
|
|
12
|
+
@for (c of range(cards()); track c) {
|
|
13
13
|
<div class="card-common flex flex-col gap-large">
|
|
14
14
|
<div class="h-4 w-1/3 rounded bg-bg-hover"></div>
|
|
15
15
|
<div class="flex flex-col gap-normal">
|
|
16
|
-
@for (r of range(rows); track r) {
|
|
16
|
+
@for (r of range(rows()); track r) {
|
|
17
17
|
<div class="h-3 rounded bg-bg-hover" [style.width.%]="rowWidth(r)"></div>
|
|
18
18
|
}
|
|
19
19
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="flex flex-col gap-normal animate-pulse">
|
|
2
|
-
@for (r of range(rows); track r) {
|
|
2
|
+
@for (r of range(rows()); track r) {
|
|
3
3
|
<div class="rounded-lg border border-border-default p-semi">
|
|
4
4
|
<div class="flex items-center gap-normal mb-small">
|
|
5
5
|
<div class="w-8 h-8 rounded-lg bg-bg-hover shrink-0"></div>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<div class="w-full animate-pulse space-y-normal">
|
|
2
2
|
<div
|
|
3
3
|
class="grid gap-small"
|
|
4
|
-
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }"
|
|
4
|
+
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns() + ', minmax(0, 1fr))' }"
|
|
5
5
|
>
|
|
6
|
-
@for(col of [].constructor(columns); track col) {
|
|
6
|
+
@for(col of [].constructor(columns()); track col) {
|
|
7
7
|
<div class="h-6 bg-bg-hover rounded"></div>
|
|
8
8
|
}
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
@for(row of [].constructor(rows); track row) {
|
|
11
|
+
@for(row of [].constructor(rows()); track row) {
|
|
12
12
|
<div
|
|
13
13
|
class="grid gap-small"
|
|
14
|
-
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns + ', minmax(0, 1fr))' }"
|
|
14
|
+
[ngStyle]="{ 'grid-template-columns': 'repeat(' + columns() + ', minmax(0, 1fr))' }"
|
|
15
15
|
>
|
|
16
|
-
@for(col of [].constructor(columns); track col) {
|
|
16
|
+
@for(col of [].constructor(columns()); track col) {
|
|
17
17
|
<div class="h-7 bg-bg-hover rounded"></div>
|
|
18
18
|
}
|
|
19
19
|
</div>
|
|
@@ -11,24 +11,24 @@
|
|
|
11
11
|
class="relative touch-none py-4"
|
|
12
12
|
(click)="onTrackClick($event)"
|
|
13
13
|
[attr.aria-disabled]="disabled"
|
|
14
|
-
[attr.aria-orientation]="vertical ? 'vertical' : 'horizontal'"
|
|
14
|
+
[attr.aria-orientation]="vertical() ? 'vertical' : 'horizontal'"
|
|
15
15
|
>
|
|
16
16
|
<div
|
|
17
17
|
class="relative flex items-center"
|
|
18
|
-
[ngClass]="{ 'flex-col h-48': vertical }"
|
|
18
|
+
[ngClass]="{ 'flex-col h-48': vertical() }"
|
|
19
19
|
>
|
|
20
20
|
<div
|
|
21
|
-
class="relative flex-1 rounded-full bg-
|
|
22
|
-
[ngClass]="{ 'w-1 rotate-0 h-full w-auto bg-
|
|
21
|
+
class="relative flex-1 rounded-full bg-track h-2"
|
|
22
|
+
[ngClass]="{ 'w-1 rotate-0 h-full w-auto bg-track': vertical() }"
|
|
23
23
|
>
|
|
24
|
-
@if (!vertical) {
|
|
24
|
+
@if (!vertical()) {
|
|
25
25
|
<div
|
|
26
26
|
class="absolute left-0 top-0 h-full rounded-full bg-primary"
|
|
27
27
|
[style.width.%]="percent"
|
|
28
28
|
></div>
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
@if (vertical) {
|
|
31
|
+
@if (vertical()) {
|
|
32
32
|
<div
|
|
33
33
|
class="absolute bottom-0 left-0 w-full rounded-full bg-primary"
|
|
34
34
|
[style.height.%]="percent"
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
[ngStyle]="thumbStyle()"
|
|
44
44
|
role="slider"
|
|
45
45
|
aria-label="Slider"
|
|
46
|
-
[attr.aria-valuemin]="min"
|
|
47
|
-
[attr.aria-valuemax]="max"
|
|
46
|
+
[attr.aria-valuemin]="min()"
|
|
47
|
+
[attr.aria-valuemax]="max()"
|
|
48
48
|
[attr.aria-valuenow]="value"
|
|
49
49
|
[attr.aria-disabled]="disabled"
|
|
50
50
|
tabindex="0"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="flex items-end gap-[2px]"
|
|
3
|
+
[style.height.px]="height()"
|
|
4
|
+
role="img"
|
|
5
|
+
[attr.aria-label]="'Trend: ' + values().join(', ')"
|
|
6
|
+
>
|
|
7
|
+
@for (bar of bars(); track $index) {
|
|
8
|
+
<div
|
|
9
|
+
class="flex-1 min-w-[3px] rounded-[1px] opacity-80"
|
|
10
|
+
[ngClass]="barClass()"
|
|
11
|
+
[style.height.%]="bar"
|
|
12
|
+
></div>
|
|
13
|
+
}
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="flex items-center gap-xs" role="tablist">
|
|
2
|
+
@for (i of dots(); track i) {
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
role="tab"
|
|
6
|
+
[attr.aria-selected]="i === current()"
|
|
7
|
+
[attr.aria-label]="'Stage ' + (i + 1)"
|
|
8
|
+
class="h-1.5 rounded-full cursor-pointer transition-all duration-150 hover:opacity-70"
|
|
9
|
+
[ngClass]="dotClass(i)"
|
|
10
|
+
(click)="dotClick.emit(i)"
|
|
11
|
+
></button>
|
|
12
|
+
}
|
|
13
|
+
</div>
|
|
@@ -1,18 +1,51 @@
|
|
|
1
1
|
<div class="grid gap-normal" [ngStyle]="{ 'grid-template-columns': gridColumns }">
|
|
2
|
-
@for (card of cards; track card.label) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
@for (card of cards(); track card.label) {
|
|
3
|
+
@if (variant() === 'figure') {
|
|
4
|
+
<div class="card-common flex flex-col gap-small min-w-0">
|
|
5
|
+
<span class="txt-utility-caption text-text-secondary truncate">{{ card.label }}</span>
|
|
6
|
+
<span
|
|
7
|
+
class="txt-heading-03"
|
|
8
|
+
[ngClass]="numClass(card)"
|
|
9
|
+
style="font-family: var(--og-font-figure)"
|
|
10
|
+
>{{ card.value }}</span
|
|
8
11
|
>
|
|
9
|
-
|
|
12
|
+
@if (card.sub) {
|
|
13
|
+
<span class="txt-utility-caption" [ngClass]="subClass(card)">{{ card.sub }}</span>
|
|
14
|
+
}
|
|
15
|
+
@if (card.spark?.length) {
|
|
16
|
+
<fx-ui-sparkbar class="mt-xs" [values]="card.spark!" [height]="16" [tone]="card.tone ?? null" />
|
|
17
|
+
}
|
|
18
|
+
</div>
|
|
19
|
+
} @else {
|
|
20
|
+
<div class="card-common flex items-center gap-normal">
|
|
21
|
+
@if (card.icon) {
|
|
22
|
+
<div
|
|
23
|
+
class="w-10 h-10 rounded-lg flex items-center justify-center shrink-0"
|
|
24
|
+
[ngClass]="boxClass(card)"
|
|
25
|
+
>
|
|
26
|
+
<fx-ui-hero-icon [icon]="card.icon" [size]="20"></fx-ui-hero-icon>
|
|
27
|
+
</div>
|
|
28
|
+
}
|
|
29
|
+
<div class="flex flex-col min-w-0 flex-1">
|
|
30
|
+
<div class="flex items-baseline gap-small">
|
|
31
|
+
<span
|
|
32
|
+
class="txt-heading-04"
|
|
33
|
+
[ngClass]="numClass(card)"
|
|
34
|
+
style="font-family: var(--og-font-figure)"
|
|
35
|
+
>{{ card.value }}</span
|
|
36
|
+
>
|
|
37
|
+
@if (card.delta) {
|
|
38
|
+
<span class="text-xs font-semibold" [ngClass]="deltaClass(card)">
|
|
39
|
+
{{ card.delta.direction === 'up' ? '▲' : '▼' }} {{ card.delta.value }}
|
|
40
|
+
</span>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
43
|
+
<span class="txt-utility-caption text-text-secondary truncate">{{ card.label }}</span>
|
|
44
|
+
@if (card.spark?.length) {
|
|
45
|
+
<fx-ui-sparkbar class="mt-xs" [values]="card.spark!" [height]="16" [tone]="card.tone ?? null" />
|
|
46
|
+
}
|
|
10
47
|
</div>
|
|
11
|
-
}
|
|
12
|
-
<div class="flex flex-col min-w-0">
|
|
13
|
-
<span class="txt-heading-04" [ngClass]="numClass(card)">{{ card.value }}</span>
|
|
14
|
-
<span class="txt-utility-caption text-text-secondary truncate">{{ card.label }}</span>
|
|
15
48
|
</div>
|
|
16
|
-
|
|
49
|
+
}
|
|
17
50
|
}
|
|
18
51
|
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<span
|
|
2
|
+
class="relative inline-flex shrink-0"
|
|
3
|
+
[style.width.px]="size()"
|
|
4
|
+
[style.height.px]="size()"
|
|
5
|
+
>
|
|
6
|
+
@if (pulse()) {
|
|
7
|
+
<span
|
|
8
|
+
class="absolute inline-flex h-full w-full rounded-full opacity-60 animate-ping motion-reduce:animate-none"
|
|
9
|
+
[ngClass]="dotClass()"
|
|
10
|
+
></span>
|
|
11
|
+
}
|
|
12
|
+
<span class="relative inline-flex h-full w-full rounded-full" [ngClass]="dotClass()"></span>
|
|
13
|
+
</span>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type="button"
|
|
3
3
|
role="switch"
|
|
4
4
|
[attr.aria-checked]="!!value"
|
|
5
|
-
[attr.aria-label]="ariaLabel || null"
|
|
5
|
+
[attr.aria-label]="ariaLabel() || null"
|
|
6
6
|
[disabled]="disabled"
|
|
7
7
|
class="relative flex items-center w-10 h-5 rounded-full transition-colors duration-300 cursor-pointer disabled:cursor-not-allowed focus-visible:ring-2 focus-visible:ring-primary/50"
|
|
8
8
|
[ngClass]="{
|