@foxeltech/angular-ui 0.4.0 → 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 +185 -17
- package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui-flow.mjs +176 -3
- package/fesm2022/foxeltech-angular-ui-flow.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs +2 -2
- package/fesm2022/foxeltech-angular-ui-rich-text.mjs.map +1 -1
- package/fesm2022/foxeltech-angular-ui.mjs +849 -69
- package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
- package/fonts.css +462 -138
- 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 +5 -2
- 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 -1
- 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 +7 -5
- package/src/lib/ui/components/checkbox/checkbox.component.html +1 -1
- package/src/lib/ui/components/code-block/code-block.component.html +8 -0
- package/src/lib/ui/components/drawer/drawer.component.html +35 -12
- package/src/lib/ui/components/drawer/drawer.component.scss +104 -18
- 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/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/master-detail/master-detail.component.css +22 -0
- package/src/lib/ui/components/master-detail/master-detail.component.html +33 -1
- 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 +1 -1
- package/src/lib/ui/components/radio-button-toggle/radio-button-toggle.component.html +1 -1
- 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/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/slider/slider.component.html +2 -2
- 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 +44 -11
- package/src/lib/ui/components/status-dot/status-dot.component.html +13 -0
- package/src/lib/ui/components/tab-group/tab-group.component.html +37 -8
- package/src/lib/ui/components/tab-group/tab-group.component.scss +41 -1
- package/src/lib/ui/components/tag/tag.component.html +2 -2
- package/src/lib/ui/components/theme-picker/theme-picker.component.html +44 -0
- package/src/lib/ui/components/tree-diagram/tree-diagram.component.html +3 -3
- package/tailwind.css +1 -1
- package/theme.css +596 -69
- package/tokens.css +56 -19
- package/types/foxeltech-angular-ui-chart.d.ts +14 -2
- package/types/foxeltech-angular-ui-flow.d.ts +83 -1
- package/types/foxeltech-angular-ui.d.ts +636 -20
- 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
|
@@ -3,16 +3,43 @@
|
|
|
3
3
|
* Replaces the old JS preset (tailwind.config.js / lodash.merge sharing).
|
|
4
4
|
*
|
|
5
5
|
* Colour tokens point at the runtime RGB-triplet variables from theme.css
|
|
6
|
-
* (
|
|
7
|
-
* working; opacity modifiers like bg-critical/10 are
|
|
8
|
-
* color-mix() and need no <alpha-value> plumbing.
|
|
6
|
+
* (OgeniumDashboards --og-* per [data-og-theme] on <html>, porcelain default)
|
|
7
|
+
* so theme switching keeps working; opacity modifiers like bg-critical/10 are
|
|
8
|
+
* handled by v4's color-mix() and need no <alpha-value> plumbing.
|
|
9
9
|
*/
|
|
10
10
|
/* `inline` is load-bearing: without it the rgb(var(--x)) values are baked
|
|
11
|
-
into :root once, so
|
|
11
|
+
into :root once, so [data-og-theme]'s runtime triplet overrides never reach
|
|
12
12
|
the utilities. inline makes every utility carry rgb(var(--x)) itself and
|
|
13
13
|
resolve at the element that uses it — same behavior as v3. */
|
|
14
14
|
@theme inline {
|
|
15
|
-
/*
|
|
15
|
+
/* ---- OG palette — use these in new/restyled markup ---- */
|
|
16
|
+
--color-page: rgb(var(--og-page-bg));
|
|
17
|
+
--color-surface: rgb(var(--og-surface));
|
|
18
|
+
--color-surface-raised: rgb(var(--og-surface-raised));
|
|
19
|
+
--color-surface-sunken: rgb(var(--og-surface-sunken));
|
|
20
|
+
--color-border: rgb(var(--og-border));
|
|
21
|
+
--color-border-subtle: rgb(var(--og-border-subtle));
|
|
22
|
+
--color-strong: rgb(var(--og-text));
|
|
23
|
+
--color-body: rgb(var(--og-text-body));
|
|
24
|
+
--color-muted: rgb(var(--og-text-muted));
|
|
25
|
+
--color-faint: rgb(var(--og-text-faint));
|
|
26
|
+
--color-accent: rgb(var(--og-accent));
|
|
27
|
+
--color-accent-fg: rgb(var(--og-accent-fg));
|
|
28
|
+
--color-accent-contrast: rgb(var(--og-accent-contrast));
|
|
29
|
+
--color-accent-soft: rgb(var(--og-accent-soft-bg));
|
|
30
|
+
--color-accent-soft-fg: rgb(var(--og-accent-soft-fg));
|
|
31
|
+
--color-positive: rgb(var(--og-positive));
|
|
32
|
+
--color-positive-soft: rgb(var(--og-positive-soft-bg));
|
|
33
|
+
--color-negative: rgb(var(--og-negative));
|
|
34
|
+
--color-negative-soft: rgb(var(--og-negative-soft-bg));
|
|
35
|
+
--color-warning-soft: rgb(var(--og-warning-soft-bg));
|
|
36
|
+
--color-neutral-soft: rgb(var(--og-neutral-soft-bg));
|
|
37
|
+
--color-neutral-soft-fg: rgb(var(--og-neutral-soft-fg));
|
|
38
|
+
--color-track: rgb(var(--og-track));
|
|
39
|
+
|
|
40
|
+
/* ---- Legacy colour names (@deprecated — remove after the V2 campaign;
|
|
41
|
+
they resolve through the alias layer in theme.css, so every existing
|
|
42
|
+
class already renders the OG palette) ---- */
|
|
16
43
|
--color-gradient-primary-start: rgb(var(--gradient-primary-start));
|
|
17
44
|
--color-gradient-primary-end: rgb(var(--gradient-primary-end));
|
|
18
45
|
--color-gradient-success-start: rgb(var(--gradient-success-start));
|
|
@@ -61,14 +88,22 @@
|
|
|
61
88
|
--shadow-2xl: 0 25px 50px -12px rgb(var(--shadow-color) / 0.25);
|
|
62
89
|
--inset-shadow-sm: inset 0 2px 4px 0 rgb(var(--shadow-color) / 0.05);
|
|
63
90
|
|
|
64
|
-
/*
|
|
65
|
-
|
|
66
|
-
--radius:
|
|
67
|
-
--radius-
|
|
68
|
-
--radius-
|
|
69
|
-
--radius-
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
/* Radius is a THEME variable in V2 (blueprint/terminal are square, ivory
|
|
92
|
+
controls are pills) — never hardcode border-radius in components. */
|
|
93
|
+
--radius-frame: var(--og-radius-frame);
|
|
94
|
+
--radius-card: var(--og-radius-card);
|
|
95
|
+
--radius-control: var(--og-radius-control);
|
|
96
|
+
--radius-pill: var(--og-radius-pill);
|
|
97
|
+
/* Legacy fixed scale remapped onto the theme radii so blueprint/terminal go
|
|
98
|
+
square with zero template edits. `rounded-full` stays Tailwind-native
|
|
99
|
+
9999px — avatars/dots must remain circular in every theme. */
|
|
100
|
+
--radius-sm: var(--og-radius-control);
|
|
101
|
+
--radius: var(--og-radius-control);
|
|
102
|
+
--radius-md: var(--og-radius-control);
|
|
103
|
+
--radius-lg: var(--og-radius-card);
|
|
104
|
+
--radius-xl: var(--og-radius-card);
|
|
105
|
+
--radius-2xl: var(--og-radius-card);
|
|
106
|
+
--radius-3xl: var(--og-radius-frame);
|
|
72
107
|
|
|
73
108
|
/* Named spacing scale (gap-small, p-semi, mb-large, …) */
|
|
74
109
|
--spacing-xs: 0.125rem;
|
|
@@ -79,12 +114,14 @@
|
|
|
79
114
|
--spacing-xl: 1.25rem;
|
|
80
115
|
--spacing-2xl: 1.5rem;
|
|
81
116
|
|
|
82
|
-
/* Font families
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
--font-
|
|
86
|
-
--font-
|
|
87
|
-
--font-
|
|
117
|
+
/* Font families — theme variables (blueprint/terminal switch to mono).
|
|
118
|
+
V2 set: Archivo (body/display), JetBrains Mono / IBM Plex Mono (mono),
|
|
119
|
+
Source Serif 4 (prose), Newsreader (ivory/blueprint display). */
|
|
120
|
+
--font-body: var(--og-font-body);
|
|
121
|
+
--font-display: var(--og-font-display);
|
|
122
|
+
--font-mono: var(--og-font-mono);
|
|
123
|
+
--font-prose: var(--og-font-prose);
|
|
124
|
+
--font-figure: var(--og-font-figure);
|
|
88
125
|
|
|
89
126
|
/* Font-size overrides (v3 preset values) */
|
|
90
127
|
--text-xs: 0.75rem;
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
@utility btn-common {
|
|
11
|
-
|
|
11
|
+
/* Compact size (anh Tú 29/08): h-8 + 13px label — the pre-V2 h-10 read too
|
|
12
|
+
large against the V2 density. leading-none: arbitrary text-[13px] inherits
|
|
13
|
+
lh 1.5 and Archivo's uneven leading floats the ink ~1px above center. */
|
|
14
|
+
@apply flex text-[13px] leading-none h-8 font-semibold px-large py-small items-center justify-center rounded-lg shadow-sm transition-all duration-200 disabled:opacity-50 disabled:pointer-events-none disabled:cursor-not-allowed;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
@utility btn-menu-common {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<div class="flex flex-col gap-small">
|
|
2
|
+
@for (item of items(); track item.label) {
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
class="text-left rounded-control px-normal py-small -mx-normal transition-colors"
|
|
6
|
+
[class.hover:bg-surface-sunken]="interactive()"
|
|
7
|
+
[class.cursor-default]="!interactive()"
|
|
8
|
+
[tabindex]="interactive() ? 0 : -1"
|
|
9
|
+
(click)="onSelect(item)"
|
|
10
|
+
>
|
|
11
|
+
<div class="flex items-baseline justify-between gap-normal">
|
|
12
|
+
<span class="txt-body-medium-01 truncate">{{ item.label }}</span>
|
|
13
|
+
<span class="text-sm font-semibold text-strong shrink-0" style="font-family: var(--og-font-figure)">
|
|
14
|
+
{{ item.valueLabel ?? item.value }}
|
|
15
|
+
</span>
|
|
16
|
+
</div>
|
|
17
|
+
@if (item.meta) {
|
|
18
|
+
<div class="txt-utility-description truncate">{{ item.meta }}</div>
|
|
19
|
+
}
|
|
20
|
+
<div class="mt-xs h-[var(--og-track-h)] rounded-pill bg-track overflow-hidden">
|
|
21
|
+
<div
|
|
22
|
+
class="h-full rounded-pill transition-all duration-500"
|
|
23
|
+
[ngClass]="barClass(item)"
|
|
24
|
+
[style.width.%]="widthOf(item)"
|
|
25
|
+
></div>
|
|
26
|
+
</div>
|
|
27
|
+
</button>
|
|
28
|
+
}
|
|
29
|
+
</div>
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
[attr.fill]="
|
|
19
19
|
buttonVariant() !== 'alternative' ? 'rgb(var(--text-primary))' : 'rgb(var(--primary))'
|
|
20
20
|
"
|
|
21
|
-
width="
|
|
22
|
-
height="
|
|
21
|
+
width="16"
|
|
22
|
+
height="16"
|
|
23
23
|
viewBox="0 0 24 24"
|
|
24
24
|
xmlns="http://www.w3.org/2000/svg"
|
|
25
25
|
>
|
|
@@ -219,17 +219,19 @@
|
|
|
219
219
|
@if (icon) {
|
|
220
220
|
<fx-ui-hero-icon
|
|
221
221
|
[icon]="icon"
|
|
222
|
-
[size]="
|
|
222
|
+
[size]="16"
|
|
223
223
|
class="flex"
|
|
224
224
|
[ngClass]="{
|
|
225
225
|
'text-text-inverse': buttonVariant() === 'default',
|
|
226
226
|
'text-text-primary': buttonVariant() === 'alternative',
|
|
227
|
-
'text-
|
|
227
|
+
'text-accent-contrast': buttonVariant() === 'primary',
|
|
228
|
+
'text-surface': buttonVariant() === 'success',
|
|
228
229
|
}"
|
|
229
230
|
></fx-ui-hero-icon>
|
|
230
231
|
}
|
|
231
232
|
@if (label) {
|
|
232
|
-
|
|
233
|
+
<!-- text-box: optical centering — Archivo's leading floats ink up otherwise -->
|
|
234
|
+
<div class="[text-box:trim-both_cap_alphabetic]">{{ label }}</div>
|
|
233
235
|
}
|
|
234
236
|
</div>
|
|
235
237
|
</ng-container>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<span class="absolute inset-0 flex items-center justify-center">
|
|
26
26
|
<svg
|
|
27
27
|
xmlns="http://www.w3.org/2000/svg"
|
|
28
|
-
class="text-
|
|
28
|
+
class="text-accent-contrast w-4 h-4 transition-opacity duration-150"
|
|
29
29
|
viewBox="0 0 24 24"
|
|
30
30
|
fill="none"
|
|
31
31
|
stroke="currentColor"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
@if (label()) {
|
|
2
|
+
<div class="txt-utility-caption font-bold text-text-secondary mb-normal">{{ label() }}</div>
|
|
3
|
+
}
|
|
4
|
+
<pre
|
|
5
|
+
class="m-0 p-large rounded-control border border-border bg-surface overflow-auto txt-body-compact-01 text-strong"
|
|
6
|
+
[style.max-height]="maxHeight() || null"
|
|
7
|
+
style="font-family: var(--og-font-mono); white-space: pre; tab-size: 2"
|
|
8
|
+
>{{ code() }}</pre>
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
<div class="drawer-host-wrapper">
|
|
2
|
-
<a
|
|
3
|
-
href="/"
|
|
4
|
-
class="h-[60px]"
|
|
5
|
-
[ngClass]="{ 'flex items-center justify-center': !isExpanded, 'p-4': isExpanded }"
|
|
6
|
-
>
|
|
2
|
+
<a href="/" class="drawer-brand" [class.is-collapsed]="!isExpanded">
|
|
7
3
|
@if (logo) {
|
|
8
|
-
<img
|
|
9
|
-
[src]="logo"
|
|
10
|
-
alt="Home"
|
|
11
|
-
class="h-[20px] w-auto transition-all duration-300 ease-in-out"
|
|
12
|
-
[ngClass]="{ 'scale-90': !isExpanded, 'ml-5': isExpanded }"
|
|
13
|
-
/>
|
|
4
|
+
<img [src]="logo" alt="Home" class="drawer-brand-mark" />
|
|
14
5
|
} @else {
|
|
15
|
-
<div class="
|
|
6
|
+
<div class="drawer-brand-mark"></div>
|
|
7
|
+
}
|
|
8
|
+
@if (isExpanded && (logoText || logoSubtext)) {
|
|
9
|
+
<span class="drawer-brand-copy">
|
|
10
|
+
@if (logoText) {
|
|
11
|
+
<span class="drawer-brand-text">{{ logoText }}</span>
|
|
12
|
+
}
|
|
13
|
+
@if (logoSubtext) {
|
|
14
|
+
<span class="drawer-brand-subtext">{{ logoSubtext }}</span>
|
|
15
|
+
}
|
|
16
|
+
</span>
|
|
16
17
|
}
|
|
17
18
|
</a>
|
|
18
19
|
<div class="drawer-container" [@drawerExpand]="getDrawerState()">
|
|
@@ -25,6 +26,20 @@
|
|
|
25
26
|
}
|
|
26
27
|
</nav>
|
|
27
28
|
|
|
29
|
+
<!-- V2: bottom section (Administration group, user block, …) -->
|
|
30
|
+
<div class="mt-auto">
|
|
31
|
+
@if (footerItems().length) {
|
|
32
|
+
<nav class="drawer-footer-nav">
|
|
33
|
+
@for (item of footerItems(); track item) {
|
|
34
|
+
<ng-container
|
|
35
|
+
*ngTemplateOutlet="drawerItem; context: { $implicit: item, level: 0 }"
|
|
36
|
+
></ng-container>
|
|
37
|
+
}
|
|
38
|
+
</nav>
|
|
39
|
+
}
|
|
40
|
+
<ng-content select="[drawerFooter]"></ng-content>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
28
43
|
<!-- Version -->
|
|
29
44
|
@if (version) {
|
|
30
45
|
<div class="drawer-version" [matTooltip]="!isExpanded ? version : ''" matTooltipPosition="right">
|
|
@@ -59,6 +74,13 @@
|
|
|
59
74
|
|
|
60
75
|
<!-- Recursive Template for Drawer Items -->
|
|
61
76
|
<ng-template #drawerItem let-item let-level="level">
|
|
77
|
+
@if (item.heading) {
|
|
78
|
+
@if (isExpanded) {
|
|
79
|
+
<div class="drawer-section-label">{{ item.label }}</div>
|
|
80
|
+
} @else {
|
|
81
|
+
<div class="drawer-section-rule"></div>
|
|
82
|
+
}
|
|
83
|
+
} @else {
|
|
62
84
|
<div class="drawer-item-wrapper">
|
|
63
85
|
<!-- Item Button/Link -->
|
|
64
86
|
@if (item.route && !item.children) {
|
|
@@ -125,4 +147,5 @@
|
|
|
125
147
|
</div>
|
|
126
148
|
}
|
|
127
149
|
</div>
|
|
150
|
+
}
|
|
128
151
|
</ng-template>
|
|
@@ -6,11 +6,75 @@
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
.drawer-host-wrapper {
|
|
9
|
-
|
|
9
|
+
/* Column flex: logo (fixed) + container (flex-1). The container was h-full
|
|
10
|
+
UNDER a 60px logo -> the drawer overflowed the viewport by 60px and the
|
|
11
|
+
footer (account block) sagged below the fold; opening its menu then
|
|
12
|
+
scroll-jumped the page. */
|
|
13
|
+
/* Nền SECONDARY (--og-page-bg) đặt ở WRAPPER chứ không ở .drawer-container:
|
|
14
|
+
hàng brand nằm ngoài container, nếu tô ở container thì 60px trên cùng
|
|
15
|
+
lộ nền của trang. Sáng: drawer xám, nội dung trắng; tối: drawer tối hơn
|
|
16
|
+
surface — đúng quy ước sidebar của cả hai chiều. */
|
|
17
|
+
@apply relative h-full border-r border-border-default flex flex-col bg-page;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Brand row — phải thẳng hàng với icon của nav item.
|
|
21
|
+
Icon nav nằm ở 24px tính từ mép drawer: 8px của .drawer-container (px-2)
|
|
22
|
+
+ 16px padding-left inline của .drawer-item. Brand nằm NGOÀI container
|
|
23
|
+
nên phải tự cộng đủ 24px (trước đây p-4 + ml-5 = 36px → lệch 12px). */
|
|
24
|
+
.drawer-brand {
|
|
25
|
+
@apply h-[60px] shrink-0 flex items-center gap-3 no-underline overflow-hidden;
|
|
26
|
+
padding-left: 24px;
|
|
27
|
+
padding-right: 8px;
|
|
28
|
+
transition: padding 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
29
|
+
/* max-width là BẮT BUỘC: .drawer-host-wrapper là flex column có width auto
|
|
30
|
+
nên bề rộng của nó = max bề rộng các con. Chỉ .drawer-container được
|
|
31
|
+
animate 70/260px, còn hàng brand thì tự do — một tagline dài (VD "Binary
|
|
32
|
+
Exploit Intelligence Platform") sẽ NỚI RỘNG cả drawer thay vì xuống dòng.
|
|
33
|
+
Hai con số dưới đây phải khớp trigger drawerExpand trong drawer.component.ts. */
|
|
34
|
+
max-width: 260px;
|
|
35
|
+
|
|
36
|
+
/* Thu gọn: drawer rộng 70px, icon nav (20px @ 24px) có tâm 34px ≈ tâm
|
|
37
|
+
drawer 35px → căn giữa là khớp, không cần trừ bì. */
|
|
38
|
+
&.is-collapsed {
|
|
39
|
+
@apply justify-center;
|
|
40
|
+
padding-left: 0;
|
|
41
|
+
padding-right: 0;
|
|
42
|
+
max-width: 70px;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.drawer-brand-mark {
|
|
47
|
+
@apply h-[20px] w-auto shrink-0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Cột chữ: title + subtitle xếp dọc. min-w-0 để truncate hoạt động khi
|
|
51
|
+
drawer bị bóp — thiếu nó thì chữ đẩy tràn ra ngoài thay vì cắt. */
|
|
52
|
+
.drawer-brand-copy {
|
|
53
|
+
@apply flex flex-col min-w-0 leading-tight;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Wordmark: dùng CHỮ THẬT chứ không phải ảnh text_logo.png — ảnh đó là
|
|
57
|
+
navy đặc nên chìm hẳn trên theme dark; chữ ăn --og-text nên đúng cả 6. */
|
|
58
|
+
.drawer-brand-text {
|
|
59
|
+
@apply truncate text-[15px] font-semibold text-text-primary select-none;
|
|
60
|
+
font-family: var(--og-font-display);
|
|
61
|
+
letter-spacing: -0.01em;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Subtitle: 11px muted, cùng cỡ với .drawer-version và caption
|
|
65
|
+
ADMINISTRATION nên không tự sinh ra một bậc typography mới. */
|
|
66
|
+
/* line-clamp-2 chứ không phải truncate: tagline dài (VD "Binary Exploit
|
|
67
|
+
Intelligence Platform") không lọt một dòng trong cột chữ ~188px của drawer
|
|
68
|
+
260px, truncate sẽ cắt mất chữ. Hai dòng vẫn nằm gọn trong 60px của
|
|
69
|
+
.drawer-brand (18.75 + 1 + 27.5 = 47px). */
|
|
70
|
+
.drawer-brand-subtext {
|
|
71
|
+
@apply line-clamp-2 text-[11px] text-text-placeholder select-none mt-[1px];
|
|
72
|
+
letter-spacing: var(--og-tracking-label);
|
|
10
73
|
}
|
|
11
74
|
|
|
12
75
|
.drawer-container {
|
|
13
|
-
|
|
76
|
+
/* Nền do .drawer-host-wrapper lo — container để trong suốt. */
|
|
77
|
+
@apply px-2 flex-1 min-h-0 flex flex-col overflow-hidden;
|
|
14
78
|
transition: width 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
15
79
|
}
|
|
16
80
|
|
|
@@ -33,6 +97,10 @@
|
|
|
33
97
|
}
|
|
34
98
|
}
|
|
35
99
|
|
|
100
|
+
.drawer-footer-nav {
|
|
101
|
+
@apply border-t border-border-default pt-2 pb-1 px-0;
|
|
102
|
+
}
|
|
103
|
+
|
|
36
104
|
.drawer-nav {
|
|
37
105
|
@apply flex-1 overflow-y-auto overflow-x-hidden py-2;
|
|
38
106
|
|
|
@@ -54,6 +122,15 @@
|
|
|
54
122
|
}
|
|
55
123
|
}
|
|
56
124
|
|
|
125
|
+
.drawer-section-label {
|
|
126
|
+
@apply px-large pt-4 pb-1 text-[11px] font-semibold uppercase text-faint select-none;
|
|
127
|
+
letter-spacing: var(--og-tracking-label);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.drawer-section-rule {
|
|
131
|
+
@apply mx-3 my-3 border-t border-border-default;
|
|
132
|
+
}
|
|
133
|
+
|
|
57
134
|
.drawer-item-wrapper {
|
|
58
135
|
@apply relative;
|
|
59
136
|
}
|
|
@@ -62,15 +139,35 @@
|
|
|
62
139
|
@apply flex items-center mt-1 w-full min-h-8 py-2 px-large border-none bg-transparent cursor-pointer no-underline text-text-primary relative rounded;
|
|
63
140
|
transition: all 200ms ease;
|
|
64
141
|
|
|
142
|
+
/* Hover = glass mờ hơn: chỉ translucent, chưa có viền/shadow, để không
|
|
143
|
+
nhầm với hàng đang chọn. */
|
|
65
144
|
&:hover {
|
|
66
|
-
@apply
|
|
145
|
+
@apply text-text-primary scale-95;
|
|
146
|
+
background: rgb(var(--og-surface-raised) / 0.5);
|
|
67
147
|
}
|
|
68
148
|
|
|
149
|
+
/* Hàng đang chọn = GLASS, KHÔNG dùng màu primary (anh Tú chốt 31/08):
|
|
150
|
+
một tấm surface trong suốt nổi trên nền secondary của drawer + viền
|
|
151
|
+
hairline + shadow nhẹ. Chữ/icon giữ màu text thường.
|
|
152
|
+
- surface-RAISED (không phải surface) vì ở charcoal raised (#211c1b)
|
|
153
|
+
sáng hơn page-bg (#0e0e10) nên tấm kính vẫn nổi; ở porcelain cả hai
|
|
154
|
+
đều là trắng nên không khác gì.
|
|
155
|
+
- Viền vẽ bằng inset box-shadow chứ không phải `border`: .drawer-item
|
|
156
|
+
khai border-none, thêm border thật sẽ đẩy layout 1px.
|
|
157
|
+
- backdrop-blur chỉ có tác dụng khi nền sau có hoạ tiết/gradient; nền
|
|
158
|
+
phẳng thì hiệu ứng đến từ độ trong + viền + shadow. */
|
|
69
159
|
&.active {
|
|
70
|
-
@apply
|
|
160
|
+
@apply text-text-primary font-medium;
|
|
161
|
+
background: rgb(var(--og-surface-raised) / 0.8);
|
|
162
|
+
backdrop-filter: blur(12px);
|
|
163
|
+
/* shadow viết literal chứ không dùng var(--shadow-sm): biến đó do @theme
|
|
164
|
+
của Tailwind sinh, không chắc có mặt trong scope của component SCSS. */
|
|
165
|
+
box-shadow:
|
|
166
|
+
inset 0 0 0 1px rgb(var(--og-border)),
|
|
167
|
+
0 1px 2px 0 rgb(var(--shadow-color) / 0.05);
|
|
71
168
|
|
|
72
|
-
|
|
73
|
-
|
|
169
|
+
&:hover {
|
|
170
|
+
background: rgb(var(--og-surface-raised) / 0.95);
|
|
74
171
|
}
|
|
75
172
|
}
|
|
76
173
|
|
|
@@ -114,21 +211,10 @@
|
|
|
114
211
|
|
|
115
212
|
.drawer-version {
|
|
116
213
|
@apply flex items-center justify-center py-3 px-4 text-text-placeholder text-[11px] border-t border-border-default select-none;
|
|
117
|
-
font-family:
|
|
214
|
+
font-family: var(--og-font-mono);
|
|
118
215
|
}
|
|
119
216
|
|
|
120
217
|
.drawer-version-dot {
|
|
121
218
|
@apply block w-1.5 h-1.5 rounded-full bg-text-placeholder;
|
|
122
219
|
}
|
|
123
220
|
|
|
124
|
-
/* Collapsed mode: center the icons */
|
|
125
|
-
.drawer-container[style*='width: 64px'] {
|
|
126
|
-
.drawer-item {
|
|
127
|
-
@apply justify-center;
|
|
128
|
-
padding-left: 16px !important;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.item-content {
|
|
132
|
-
@apply justify-center;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<div class="flex flex-col gap-large">
|
|
2
|
+
@if (hasSelection()) {
|
|
3
|
+
<button type="button" class="txt-link self-end" (click)="reset()">
|
|
4
|
+
{{ resetLabel() }}
|
|
5
|
+
</button>
|
|
6
|
+
}
|
|
7
|
+
@for (group of groups(); track group.id) {
|
|
8
|
+
<div role="group" [attr.aria-label]="group.label">
|
|
9
|
+
<div
|
|
10
|
+
class="txt-table-header uppercase mb-small"
|
|
11
|
+
[style.letter-spacing]="'var(--og-tracking-label)'"
|
|
12
|
+
>
|
|
13
|
+
{{ group.label }}
|
|
14
|
+
</div>
|
|
15
|
+
<div class="flex flex-col gap-xs">
|
|
16
|
+
@for (option of group.options; track option.value) {
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
(click)="toggle(group, option)"
|
|
20
|
+
[attr.aria-pressed]="isSelected(group, option)"
|
|
21
|
+
class="flex items-center gap-normal px-normal py-small rounded-control text-left transition-colors"
|
|
22
|
+
[ngClass]="
|
|
23
|
+
isSelected(group, option)
|
|
24
|
+
? 'bg-accent-soft text-accent-soft-fg font-medium'
|
|
25
|
+
: 'text-body hover:bg-surface-sunken'
|
|
26
|
+
"
|
|
27
|
+
>
|
|
28
|
+
@if (option.tone) {
|
|
29
|
+
<fx-ui-status-dot [tone]="option.tone" [size]="7" />
|
|
30
|
+
}
|
|
31
|
+
<span class="text-sm truncate flex-1">{{ option.label }}</span>
|
|
32
|
+
@if (option.count !== undefined) {
|
|
33
|
+
<span class="txt-tag-label text-faint" style="font-family: var(--og-font-figure)">
|
|
34
|
+
{{ option.count }}
|
|
35
|
+
</span>
|
|
36
|
+
}
|
|
37
|
+
</button>
|
|
38
|
+
}
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div class="flex flex-wrap items-center gap-small">
|
|
2
|
+
@for (option of options(); track option.value) {
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
[attr.aria-pressed]="isActive(option)"
|
|
6
|
+
class="flex items-center gap-small px-semi py-xs rounded-full border txt-utility-caption font-bold cursor-pointer transition-colors"
|
|
7
|
+
[ngClass]="pillClass(option)"
|
|
8
|
+
(click)="valueChange.emit(option.value)"
|
|
9
|
+
>
|
|
10
|
+
{{ option.label }}
|
|
11
|
+
@if (option.count !== null && option.count !== undefined) {
|
|
12
|
+
<span [ngClass]="countClass(option)" style="font-family: var(--og-font-figure)">{{ option.count }}</span>
|
|
13
|
+
}
|
|
14
|
+
</button>
|
|
15
|
+
}
|
|
16
|
+
</div>
|
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.kanban-column {
|
|
13
|
-
@apply flex flex-col min-w-[300px] bg-
|
|
13
|
+
@apply flex flex-col min-w-[300px] bg-surface-sunken rounded-lg;
|
|
14
14
|
flex-shrink: 0;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.kanban-column-header {
|
|
18
|
-
@apply flex items-center justify-between p-4 border-b border-
|
|
18
|
+
@apply flex items-center justify-between p-4 border-b border-border;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.kanban-column-title {
|
|
22
|
-
@apply text-lg font-semibold text-
|
|
22
|
+
@apply text-lg font-semibold text-strong m-0;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.kanban-column-count {
|
|
26
|
-
@apply px-2 py-1 text-sm font-medium bg-
|
|
26
|
+
@apply px-2 py-1 text-sm font-medium bg-neutral-soft text-neutral-soft-fg rounded-full;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.kanban-column-content {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.kanban-item {
|
|
35
|
-
@apply bg-
|
|
35
|
+
@apply bg-surface-raised rounded-lg shadow-sm border border-border;
|
|
36
36
|
@apply transition-shadow duration-200;
|
|
37
37
|
cursor: move;
|
|
38
38
|
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
.kanban-item-default {
|
|
45
|
-
@apply p-4 text-
|
|
45
|
+
@apply p-4 text-strong;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
.kanban-item-placeholder {
|
|
49
|
-
@apply bg-
|
|
49
|
+
@apply bg-neutral-soft rounded-lg border-2 border-dashed border-border-strong;
|
|
50
50
|
@apply opacity-50;
|
|
51
51
|
min-height: 60px;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
.kanban-column-empty {
|
|
55
|
-
@apply flex items-center justify-center h-32 text-
|
|
56
|
-
@apply border-2 border-dashed border-
|
|
55
|
+
@apply flex items-center justify-center h-32 text-faint text-sm;
|
|
56
|
+
@apply border-2 border-dashed border-border rounded-lg;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// CDK Drag and Drop Styles
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<div class="flex items-center gap-normal min-w-0">
|
|
2
|
+
@if (dotTone() !== undefined) {
|
|
3
|
+
<fx-ui-status-dot [tone]="dotTone() ?? null" [pulse]="dotPulse()" />
|
|
4
|
+
}
|
|
5
|
+
<span class="txt-body-medium-01 truncate flex-1">{{ title() }}</span>
|
|
6
|
+
@for (badge of badges(); track badge.label) {
|
|
7
|
+
<span
|
|
8
|
+
class="txt-tag-label px-normal py-[1px] rounded-pill whitespace-nowrap"
|
|
9
|
+
[ngClass]="badgeClass(badge)"
|
|
10
|
+
>
|
|
11
|
+
{{ badge.label }}
|
|
12
|
+
</span>
|
|
13
|
+
}
|
|
14
|
+
</div>
|
|
15
|
+
@if (meta()) {
|
|
16
|
+
<div class="txt-utility-description mt-xs truncate" [class.ml-large]="dotTone() !== undefined">
|
|
17
|
+
{{ meta() }}
|
|
18
|
+
</div>
|
|
19
|
+
}
|
|
20
|
+
<ng-content></ng-content>
|
|
@@ -9,3 +9,25 @@
|
|
|
9
9
|
flex-shrink: 0;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
/* Facets rail: full-width when stacked; fixed narrow column on lg+. */
|
|
14
|
+
.fx-md-facets {
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@media (min-width: 1080px) {
|
|
19
|
+
.fx-md-facets {
|
|
20
|
+
width: 230px;
|
|
21
|
+
flex-shrink: 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* prevnext style: the Material paginator stays as the paging engine but is
|
|
26
|
+
visually removed (display:none would break its measurements on re-show). */
|
|
27
|
+
.fx-md-paginator-hidden {
|
|
28
|
+
position: absolute !important;
|
|
29
|
+
width: 1px;
|
|
30
|
+
height: 1px;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
clip-path: inset(50%);
|
|
33
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
<div class="flex flex-col lg:flex-row items-start gap-xl" [style.--fx-md-list-width]="listWidth()">
|
|
2
|
+
<!-- Facets rail (V2 3-column lookup) — wrapper always rendered so ng-content
|
|
3
|
+
stays unconditional; hidden when the host projects nothing. -->
|
|
4
|
+
<div class="fx-md-facets card-common bg-surface" [class.hidden]="!hasFacets">
|
|
5
|
+
<ng-content select="[mdFacets]"></ng-content>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
2
8
|
<!-- Master: list pane -->
|
|
3
9
|
<div class="fx-md-list card-common">
|
|
4
10
|
<ng-content select="[mdHeader]"></ng-content>
|
|
@@ -24,7 +30,7 @@
|
|
|
24
30
|
class="text-left rounded-lg border p-semi transition-colors"
|
|
25
31
|
[ngClass]="
|
|
26
32
|
isSelected(row)
|
|
27
|
-
? 'border-
|
|
33
|
+
? 'border-accent bg-accent-soft/60'
|
|
28
34
|
: 'border-border-default hover:border-border-interactive bg-bg-primary'
|
|
29
35
|
"
|
|
30
36
|
>
|
|
@@ -44,10 +50,36 @@
|
|
|
44
50
|
wires page events — a binding here would double-fetch every change. -->
|
|
45
51
|
<mat-paginator
|
|
46
52
|
class="mt-normal"
|
|
53
|
+
[class.fx-md-paginator-hidden]="paginationStyle() === 'prevnext'"
|
|
47
54
|
[length]="table.total"
|
|
48
55
|
[pageSize]="table.pageSize"
|
|
49
56
|
[pageSizeOptions]="pageSizeOptions()"
|
|
50
57
|
></mat-paginator>
|
|
58
|
+
@if (paginationStyle() === 'prevnext') {
|
|
59
|
+
<div class="flex items-center justify-between mt-normal">
|
|
60
|
+
<span class="txt-utility-description" style="font-family: var(--og-font-figure)">
|
|
61
|
+
{{ rangeText() }}
|
|
62
|
+
</span>
|
|
63
|
+
<div class="flex gap-small">
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
class="btn-alternative !h-8 !px-semi text-sm"
|
|
67
|
+
[disabled]="!paginator().hasPreviousPage()"
|
|
68
|
+
(click)="paginator().previousPage()"
|
|
69
|
+
>
|
|
70
|
+
{{ prevLabel() }}
|
|
71
|
+
</button>
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
class="btn-alternative !h-8 !px-semi text-sm"
|
|
75
|
+
[disabled]="!paginator().hasNextPage()"
|
|
76
|
+
(click)="paginator().nextPage()"
|
|
77
|
+
>
|
|
78
|
+
{{ nextLabel() }}
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
}
|
|
51
83
|
</div>
|
|
52
84
|
|
|
53
85
|
<!-- Detail pane -->
|