ppij-design-system 0.0.0-stage → 0.2.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/dist/banners.d.ts +31 -0
- package/dist/banners.js +18 -0
- package/dist/card-themes.d.ts +14 -0
- package/dist/card-themes.js +325 -0
- package/dist/components/account-menu.d.ts +24 -0
- package/dist/components/account-menu.js +13 -0
- package/dist/components/admin-drawer.d.ts +34 -0
- package/dist/components/admin-drawer.js +30 -0
- package/dist/components/alert-dialog.d.ts +16 -0
- package/dist/components/alert-dialog.js +39 -0
- package/dist/components/alert.d.ts +11 -0
- package/dist/components/alert.js +29 -0
- package/dist/components/avatar.d.ts +11 -0
- package/dist/components/avatar.js +22 -0
- package/dist/components/badge.d.ts +9 -0
- package/dist/components/badge.js +27 -0
- package/dist/components/banner-carousel.d.ts +14 -0
- package/dist/components/banner-carousel.js +90 -0
- package/dist/components/bottom-bar.d.ts +22 -0
- package/dist/components/bottom-bar.js +12 -0
- package/dist/components/button.d.ts +10 -0
- package/dist/components/button.js +37 -0
- package/dist/components/card-upload.d.ts +30 -0
- package/dist/components/card-upload.js +19 -0
- package/dist/components/card.d.ts +9 -0
- package/dist/components/card.js +24 -0
- package/dist/components/checkbox.d.ts +4 -0
- package/dist/components/checkbox.js +9 -0
- package/dist/components/data-table.d.ts +26 -0
- package/dist/components/data-table.js +17 -0
- package/dist/components/dialog.d.ts +17 -0
- package/dist/components/dialog.js +37 -0
- package/dist/components/drawer.d.ts +13 -0
- package/dist/components/drawer.js +34 -0
- package/dist/components/dropdown-menu.d.ts +25 -0
- package/dist/components/dropdown-menu.js +50 -0
- package/dist/components/editable-panel.d.ts +25 -0
- package/dist/components/editable-panel.js +18 -0
- package/dist/components/empty.d.ts +12 -0
- package/dist/components/empty.js +33 -0
- package/dist/components/file-upload.d.ts +28 -0
- package/dist/components/file-upload.js +21 -0
- package/dist/components/form-panel.d.ts +15 -0
- package/dist/components/form-panel.js +9 -0
- package/dist/components/funding-picker.d.ts +20 -0
- package/dist/components/funding-picker.js +16 -0
- package/dist/components/input.d.ts +3 -0
- package/dist/components/input.js +6 -0
- package/dist/components/invitation-card.d.ts +14 -0
- package/dist/components/invitation-card.js +13 -0
- package/dist/components/label.d.ts +4 -0
- package/dist/components/label.js +7 -0
- package/dist/components/member-card-block.d.ts +47 -0
- package/dist/components/member-card-block.js +329 -0
- package/dist/components/member-card.css +92 -0
- package/dist/components/member-card.d.ts +29 -0
- package/dist/components/member-card.js +22 -0
- package/dist/components/month-picker.d.ts +16 -0
- package/dist/components/month-picker.js +19 -0
- package/dist/components/offline-banner.d.ts +14 -0
- package/dist/components/offline-banner.js +14 -0
- package/dist/components/page-header.d.ts +14 -0
- package/dist/components/page-header.js +10 -0
- package/dist/components/phone-field.d.ts +25 -0
- package/dist/components/phone-field.js +64 -0
- package/dist/components/pill-radio.d.ts +21 -0
- package/dist/components/pill-radio.js +15 -0
- package/dist/components/portal-shell.d.ts +53 -0
- package/dist/components/portal-shell.js +19 -0
- package/dist/components/postcode-field.d.ts +26 -0
- package/dist/components/postcode-field.js +14 -0
- package/dist/components/progress.d.ts +4 -0
- package/dist/components/progress.js +8 -0
- package/dist/components/radio-group.d.ts +5 -0
- package/dist/components/radio-group.js +11 -0
- package/dist/components/review-panel.d.ts +20 -0
- package/dist/components/review-panel.js +14 -0
- package/dist/components/saving-indicator.d.ts +15 -0
- package/dist/components/saving-indicator.js +19 -0
- package/dist/components/scroll-area.d.ts +5 -0
- package/dist/components/scroll-area.js +13 -0
- package/dist/components/search-filter.d.ts +39 -0
- package/dist/components/search-filter.js +19 -0
- package/dist/components/segmented-progress.d.ts +16 -0
- package/dist/components/segmented-progress.js +12 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.js +38 -0
- package/dist/components/separator.d.ts +4 -0
- package/dist/components/separator.js +7 -0
- package/dist/components/service-tiles.d.ts +26 -0
- package/dist/components/service-tiles.js +17 -0
- package/dist/components/sheet.d.ts +14 -0
- package/dist/components/sheet.js +40 -0
- package/dist/components/sidebar.d.ts +69 -0
- package/dist/components/sidebar.js +210 -0
- package/dist/components/skeleton.d.ts +11 -0
- package/dist/components/skeleton.js +11 -0
- package/dist/components/sonner.d.ts +9 -0
- package/dist/components/sonner.js +25 -0
- package/dist/components/spinner.d.ts +14 -0
- package/dist/components/spinner.js +22 -0
- package/dist/components/stat-card.d.ts +22 -0
- package/dist/components/stat-card.js +12 -0
- package/dist/components/status-card.d.ts +24 -0
- package/dist/components/status-card.js +26 -0
- package/dist/components/stepper.d.ts +25 -0
- package/dist/components/stepper.js +23 -0
- package/dist/components/submit-overlay.d.ts +16 -0
- package/dist/components/submit-overlay.js +15 -0
- package/dist/components/suggestion-sheet.d.ts +20 -0
- package/dist/components/suggestion-sheet.js +36 -0
- package/dist/components/switch.d.ts +6 -0
- package/dist/components/switch.js +8 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/table.js +28 -0
- package/dist/components/tabs.d.ts +11 -0
- package/dist/components/tabs.js +28 -0
- package/dist/components/tag-input.d.ts +15 -0
- package/dist/components/tag-input.js +31 -0
- package/dist/components/textarea.d.ts +3 -0
- package/dist/components/textarea.js +6 -0
- package/dist/components/timeline.d.ts +18 -0
- package/dist/components/timeline.js +11 -0
- package/dist/components/todo-strip.d.ts +14 -0
- package/dist/components/todo-strip.js +11 -0
- package/dist/components/tooltip.d.ts +7 -0
- package/dist/components/tooltip.js +16 -0
- package/dist/components/top-bar.d.ts +23 -0
- package/dist/components/top-bar.js +14 -0
- package/dist/components/type-ahead.d.ts +20 -0
- package/dist/components/type-ahead.js +22 -0
- package/dist/components/unit-card.d.ts +26 -0
- package/dist/components/unit-card.js +18 -0
- package/dist/components/view-toggle.d.ts +20 -0
- package/dist/components/view-toggle.js +15 -0
- package/dist/components/wizard-footer.d.ts +24 -0
- package/dist/components/wizard-footer.js +17 -0
- package/dist/components/wizard-header.d.ts +29 -0
- package/dist/components/wizard-header.js +18 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-mobile.js +11 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +70 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/sample-banners.d.ts +8 -0
- package/dist/sample-banners.js +28 -0
- package/dist/tokens.css +119 -0
- package/dist/tokens.json +50 -0
- package/package.json +60 -4
- package/README.md +0 -3
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promo banner data contract, ported from ppij-identity-sso
|
|
3
|
+
* web/src/lib/banners.ts. The build-time validator (validateBanners /
|
|
4
|
+
* loadPromoBanners) stays in the app; the browser-side selection
|
|
5
|
+
* (activeBanners, jstToday) ships here so consumers render exactly
|
|
6
|
+
* what the portal renders.
|
|
7
|
+
*/
|
|
8
|
+
export interface PromoBanner {
|
|
9
|
+
id: string;
|
|
10
|
+
/** Public paths: desktop 970 x 250 (shown from 768 px), mobile 320 x 100. Both shipped at 2x. */
|
|
11
|
+
image: {
|
|
12
|
+
desktop: string;
|
|
13
|
+
mobile: string;
|
|
14
|
+
};
|
|
15
|
+
alt: {
|
|
16
|
+
id: string;
|
|
17
|
+
en: string;
|
|
18
|
+
};
|
|
19
|
+
href: string;
|
|
20
|
+
/** JST calendar dates, YYYY-MM-DD. Both optional. */
|
|
21
|
+
start?: string;
|
|
22
|
+
end?: string;
|
|
23
|
+
order: number;
|
|
24
|
+
/** false keeps an entry in the file but out of the site (placeholders until the real link and dates are known). */
|
|
25
|
+
active?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const MAX_ACTIVE = 5;
|
|
28
|
+
/** Entries active on `today`, in `order`, at most MAX_ACTIVE. Used in the browser, so an expired promotion drops out without a deploy. */
|
|
29
|
+
export declare function activeBanners(all: PromoBanner[], today: string): PromoBanner[];
|
|
30
|
+
/** Today's JST calendar date, YYYY-MM-DD. */
|
|
31
|
+
export declare function jstToday(now?: Date): string;
|
package/dist/banners.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const MAX_ACTIVE = 5;
|
|
2
|
+
function isActive(b) {
|
|
3
|
+
return b.active !== false;
|
|
4
|
+
}
|
|
5
|
+
function coversDay(b, day) {
|
|
6
|
+
return (!b.start || b.start <= day) && (!b.end || day <= b.end);
|
|
7
|
+
}
|
|
8
|
+
/** Entries active on `today`, in `order`, at most MAX_ACTIVE. Used in the browser, so an expired promotion drops out without a deploy. */
|
|
9
|
+
export function activeBanners(all, today) {
|
|
10
|
+
return all
|
|
11
|
+
.filter((b) => isActive(b) && coversDay(b, today))
|
|
12
|
+
.sort((a, b) => a.order - b.order)
|
|
13
|
+
.slice(0, MAX_ACTIVE);
|
|
14
|
+
}
|
|
15
|
+
/** Today's JST calendar date, YYYY-MM-DD. */
|
|
16
|
+
export function jstToday(now = new Date()) {
|
|
17
|
+
return new Date(now.getTime() + 9 * 3_600_000).toISOString().slice(0, 10);
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Decorative catalog; membership state and affiliation never derive from these IDs. */
|
|
2
|
+
export interface CardTheme {
|
|
3
|
+
id: string;
|
|
4
|
+
group: "korda" | "nusantara" | "seasons" | "ppij";
|
|
5
|
+
labelId: string;
|
|
6
|
+
labelEn: string;
|
|
7
|
+
base: string;
|
|
8
|
+
asset: string;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
viewBox: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const cardThemes: readonly CardTheme[];
|
|
14
|
+
export declare function resolveCardTheme(korda: string | null | undefined, saved: string | null): CardTheme;
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
export const cardThemes = [
|
|
2
|
+
{
|
|
3
|
+
"id": "korda-hokkaido",
|
|
4
|
+
"group": "korda",
|
|
5
|
+
"labelId": "Hokkaido",
|
|
6
|
+
"labelEn": "Hokkaido",
|
|
7
|
+
"base": "#FAFAFA",
|
|
8
|
+
"asset": "/card-themes/korda-hokkaido.png",
|
|
9
|
+
"width": 1581,
|
|
10
|
+
"height": 995,
|
|
11
|
+
"viewBox": "790.5 139.3 774.7 646.8"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "korda-tohoku",
|
|
15
|
+
"group": "korda",
|
|
16
|
+
"labelId": "Tohoku",
|
|
17
|
+
"labelEn": "Tohoku",
|
|
18
|
+
"base": "#FAFAFA",
|
|
19
|
+
"asset": "/card-themes/korda-tohoku.png",
|
|
20
|
+
"width": 1579,
|
|
21
|
+
"height": 996,
|
|
22
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "korda-kanto",
|
|
26
|
+
"group": "korda",
|
|
27
|
+
"labelId": "Kanto",
|
|
28
|
+
"labelEn": "Kanto",
|
|
29
|
+
"base": "#FAFAFA",
|
|
30
|
+
"asset": "/card-themes/korda-kanto.png",
|
|
31
|
+
"width": 1580,
|
|
32
|
+
"height": 995,
|
|
33
|
+
"viewBox": "790.0 139.3 774.2 646.8"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "korda-hokuriku",
|
|
37
|
+
"group": "korda",
|
|
38
|
+
"labelId": "Hokuriku",
|
|
39
|
+
"labelEn": "Hokuriku",
|
|
40
|
+
"base": "#FAFAFA",
|
|
41
|
+
"asset": "/card-themes/korda-hokuriku.png",
|
|
42
|
+
"width": 1579,
|
|
43
|
+
"height": 996,
|
|
44
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "korda-chubu",
|
|
48
|
+
"group": "korda",
|
|
49
|
+
"labelId": "Chubu",
|
|
50
|
+
"labelEn": "Chubu",
|
|
51
|
+
"base": "#FAFAFA",
|
|
52
|
+
"asset": "/card-themes/korda-chubu.png",
|
|
53
|
+
"width": 1579,
|
|
54
|
+
"height": 996,
|
|
55
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "korda-kansai",
|
|
59
|
+
"group": "korda",
|
|
60
|
+
"labelId": "Kansai",
|
|
61
|
+
"labelEn": "Kansai",
|
|
62
|
+
"base": "#FAFAFA",
|
|
63
|
+
"asset": "/card-themes/korda-kansai.png",
|
|
64
|
+
"width": 1580,
|
|
65
|
+
"height": 996,
|
|
66
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "korda-shikoku",
|
|
70
|
+
"group": "korda",
|
|
71
|
+
"labelId": "Shikoku",
|
|
72
|
+
"labelEn": "Shikoku",
|
|
73
|
+
"base": "#FAFAFA",
|
|
74
|
+
"asset": "/card-themes/korda-shikoku.png",
|
|
75
|
+
"width": 1579,
|
|
76
|
+
"height": 996,
|
|
77
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "korda-chugoku",
|
|
81
|
+
"group": "korda",
|
|
82
|
+
"labelId": "Chugoku",
|
|
83
|
+
"labelEn": "Chugoku",
|
|
84
|
+
"base": "#FAFAFA",
|
|
85
|
+
"asset": "/card-themes/korda-chugoku.png",
|
|
86
|
+
"width": 1580,
|
|
87
|
+
"height": 995,
|
|
88
|
+
"viewBox": "790.0 139.3 774.2 646.8"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "korda-kitakyushu-okinawa",
|
|
92
|
+
"group": "korda",
|
|
93
|
+
"labelId": "Kitakyushu–Okinawa",
|
|
94
|
+
"labelEn": "Kitakyushu–Okinawa",
|
|
95
|
+
"base": "#FAFAFA",
|
|
96
|
+
"asset": "/card-themes/korda-kitakyushu-okinawa.png",
|
|
97
|
+
"width": 1579,
|
|
98
|
+
"height": 996,
|
|
99
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "nusantara-sumatera-barat-rumah-gadang",
|
|
103
|
+
"group": "nusantara",
|
|
104
|
+
"labelId": "Sumatera Barat · Rumah Gadang",
|
|
105
|
+
"labelEn": "Sumatera Barat · Rumah Gadang",
|
|
106
|
+
"base": "#F3F7FC",
|
|
107
|
+
"asset": "/card-themes/nusantara-sumatera-barat-rumah-gadang.png",
|
|
108
|
+
"width": 1579,
|
|
109
|
+
"height": 996,
|
|
110
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "nusantara-sumatera-utara-rumah-bolon",
|
|
114
|
+
"group": "nusantara",
|
|
115
|
+
"labelId": "Sumatera Utara · Rumah Bolon",
|
|
116
|
+
"labelEn": "Sumatera Utara · Rumah Bolon",
|
|
117
|
+
"base": "#F3F7F1",
|
|
118
|
+
"asset": "/card-themes/nusantara-sumatera-utara-rumah-bolon.png",
|
|
119
|
+
"width": 1580,
|
|
120
|
+
"height": 996,
|
|
121
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "nusantara-jakarta-monas",
|
|
125
|
+
"group": "nusantara",
|
|
126
|
+
"labelId": "Jakarta · Monas",
|
|
127
|
+
"labelEn": "Jakarta · Monas",
|
|
128
|
+
"base": "#F3F7FC",
|
|
129
|
+
"asset": "/card-themes/nusantara-jakarta-monas.png",
|
|
130
|
+
"width": 1580,
|
|
131
|
+
"height": 996,
|
|
132
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "nusantara-jawa-barat-angklung",
|
|
136
|
+
"group": "nusantara",
|
|
137
|
+
"labelId": "Jawa Barat · Angklung",
|
|
138
|
+
"labelEn": "Jawa Barat · Angklung",
|
|
139
|
+
"base": "#F3F7F1",
|
|
140
|
+
"asset": "/card-themes/nusantara-jawa-barat-angklung.png",
|
|
141
|
+
"width": 1579,
|
|
142
|
+
"height": 996,
|
|
143
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "nusantara-jawa-tengah-borobudur",
|
|
147
|
+
"group": "nusantara",
|
|
148
|
+
"labelId": "Jawa Tengah · Borobudur",
|
|
149
|
+
"labelEn": "Jawa Tengah · Borobudur",
|
|
150
|
+
"base": "#FBF6ED",
|
|
151
|
+
"asset": "/card-themes/nusantara-jawa-tengah-borobudur.png",
|
|
152
|
+
"width": 1580,
|
|
153
|
+
"height": 996,
|
|
154
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"id": "nusantara-yogyakarta-tugu",
|
|
158
|
+
"group": "nusantara",
|
|
159
|
+
"labelId": "Yogyakarta · Tugu",
|
|
160
|
+
"labelEn": "Yogyakarta · Tugu",
|
|
161
|
+
"base": "#F3F7FC",
|
|
162
|
+
"asset": "/card-themes/nusantara-yogyakarta-tugu.png",
|
|
163
|
+
"width": 1580,
|
|
164
|
+
"height": 996,
|
|
165
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"id": "nusantara-jawa-timur-tugu-pahlawan",
|
|
169
|
+
"group": "nusantara",
|
|
170
|
+
"labelId": "Jawa Timur · Tugu Pahlawan",
|
|
171
|
+
"labelEn": "Jawa Timur · Tugu Pahlawan",
|
|
172
|
+
"base": "#FBF6ED",
|
|
173
|
+
"asset": "/card-themes/nusantara-jawa-timur-tugu-pahlawan.png",
|
|
174
|
+
"width": 1580,
|
|
175
|
+
"height": 995,
|
|
176
|
+
"viewBox": "790.0 139.3 774.2 646.8"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"id": "nusantara-bali-ulun-danu",
|
|
180
|
+
"group": "nusantara",
|
|
181
|
+
"labelId": "Bali · Ulun Danu Beratan",
|
|
182
|
+
"labelEn": "Bali · Ulun Danu Beratan",
|
|
183
|
+
"base": "#F3F7FC",
|
|
184
|
+
"asset": "/card-themes/nusantara-bali-ulun-danu.png",
|
|
185
|
+
"width": 1579,
|
|
186
|
+
"height": 996,
|
|
187
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"id": "nusantara-ntb-lumbung",
|
|
191
|
+
"group": "nusantara",
|
|
192
|
+
"labelId": "NTB · Lumbung Sasak",
|
|
193
|
+
"labelEn": "NTB · Lumbung Sasak",
|
|
194
|
+
"base": "#F3F7F1",
|
|
195
|
+
"asset": "/card-themes/nusantara-ntb-lumbung.png",
|
|
196
|
+
"width": 1580,
|
|
197
|
+
"height": 996,
|
|
198
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"id": "nusantara-ntt-sumba-house",
|
|
202
|
+
"group": "nusantara",
|
|
203
|
+
"labelId": "NTT · Rumah Sumba",
|
|
204
|
+
"labelEn": "NTT · Rumah Sumba",
|
|
205
|
+
"base": "#FBF6ED",
|
|
206
|
+
"asset": "/card-themes/nusantara-ntt-sumba-house.png",
|
|
207
|
+
"width": 1579,
|
|
208
|
+
"height": 996,
|
|
209
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": "nusantara-kalimantan-tengah-betang",
|
|
213
|
+
"group": "nusantara",
|
|
214
|
+
"labelId": "Kalimantan Tengah · Huma Betang",
|
|
215
|
+
"labelEn": "Kalimantan Tengah · Huma Betang",
|
|
216
|
+
"base": "#F3F7F1",
|
|
217
|
+
"asset": "/card-themes/nusantara-kalimantan-tengah-betang.png",
|
|
218
|
+
"width": 1579,
|
|
219
|
+
"height": 996,
|
|
220
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"id": "nusantara-sulawesi-selatan-tongkonan",
|
|
224
|
+
"group": "nusantara",
|
|
225
|
+
"labelId": "Sulawesi Selatan · Tongkonan",
|
|
226
|
+
"labelEn": "Sulawesi Selatan · Tongkonan",
|
|
227
|
+
"base": "#FBF6ED",
|
|
228
|
+
"asset": "/card-themes/nusantara-sulawesi-selatan-tongkonan.png",
|
|
229
|
+
"width": 1579,
|
|
230
|
+
"height": 996,
|
|
231
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"id": "nusantara-maluku-baileo",
|
|
235
|
+
"group": "nusantara",
|
|
236
|
+
"labelId": "Maluku · Baileo",
|
|
237
|
+
"labelEn": "Maluku · Baileo",
|
|
238
|
+
"base": "#F3F7FC",
|
|
239
|
+
"asset": "/card-themes/nusantara-maluku-baileo.png",
|
|
240
|
+
"width": 1580,
|
|
241
|
+
"height": 996,
|
|
242
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"id": "nusantara-papua-pegunungan-honai",
|
|
246
|
+
"group": "nusantara",
|
|
247
|
+
"labelId": "Papua Pegunungan · Honai",
|
|
248
|
+
"labelEn": "Papua Pegunungan · Honai",
|
|
249
|
+
"base": "#F3F7F1",
|
|
250
|
+
"asset": "/card-themes/nusantara-papua-pegunungan-honai.png",
|
|
251
|
+
"width": 1579,
|
|
252
|
+
"height": 996,
|
|
253
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"id": "ppij-national",
|
|
257
|
+
"group": "ppij",
|
|
258
|
+
"labelId": "PPI Jepang",
|
|
259
|
+
"labelEn": "PPI Japan",
|
|
260
|
+
"base": "#FAFAFA",
|
|
261
|
+
"asset": "/card-themes/ppij-national.svg",
|
|
262
|
+
"width": 1000,
|
|
263
|
+
"height": 1000,
|
|
264
|
+
"viewBox": "0 0 1000 1000"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": "season-spring",
|
|
268
|
+
"group": "seasons",
|
|
269
|
+
"labelId": "Musim semi · Sakura",
|
|
270
|
+
"labelEn": "Spring · Sakura",
|
|
271
|
+
"base": "#F3F7FC",
|
|
272
|
+
"asset": "/card-themes/season-spring.png",
|
|
273
|
+
"width": 1580,
|
|
274
|
+
"height": 996,
|
|
275
|
+
"viewBox": "790.0 139.4 774.2 647.4"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"id": "season-summer",
|
|
279
|
+
"group": "seasons",
|
|
280
|
+
"labelId": "Musim panas · Matsuri",
|
|
281
|
+
"labelEn": "Summer · Matsuri",
|
|
282
|
+
"base": "#F3F7F1",
|
|
283
|
+
"asset": "/card-themes/season-summer.png",
|
|
284
|
+
"width": 1579,
|
|
285
|
+
"height": 996,
|
|
286
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"id": "season-autumn",
|
|
290
|
+
"group": "seasons",
|
|
291
|
+
"labelId": "Musim gugur · Momiji",
|
|
292
|
+
"labelEn": "Autumn · Momiji",
|
|
293
|
+
"base": "#FBF6ED",
|
|
294
|
+
"asset": "/card-themes/season-autumn.png",
|
|
295
|
+
"width": 1579,
|
|
296
|
+
"height": 996,
|
|
297
|
+
"viewBox": "789.5 139.4 773.7 647.4"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"id": "season-winter",
|
|
301
|
+
"group": "seasons",
|
|
302
|
+
"labelId": "Musim dingin · Salju",
|
|
303
|
+
"labelEn": "Winter · Snow",
|
|
304
|
+
"base": "#F3F7FC",
|
|
305
|
+
"asset": "/card-themes/season-winter.svg",
|
|
306
|
+
"width": 1000,
|
|
307
|
+
"height": 1000,
|
|
308
|
+
"viewBox": "0 0 1000 1000"
|
|
309
|
+
}
|
|
310
|
+
];
|
|
311
|
+
const byId = new Map(cardThemes.map(theme => [theme.id, theme]));
|
|
312
|
+
// The theme id for Kyushu-Okinawa keeps the catalogue's older "kitakyushu" spelling.
|
|
313
|
+
const kordaThemeAliases = { "kyushu-okinawa": "kitakyushu-okinawa" };
|
|
314
|
+
// The saved value comes from the member preference API (server-side, per member_id), so it
|
|
315
|
+
// loads on every device. An id the current catalogue no longer publishes falls back to the
|
|
316
|
+
// korda default — catalogue changes never strand a stored preference.
|
|
317
|
+
export function resolveCardTheme(korda, saved) {
|
|
318
|
+
// /v1/me carries the korda unit's display name as the seed spells it ("PPI Kanto"; one slug
|
|
319
|
+
// is "korda-hokkaido"), so the lookup drops those prefixes before matching the catalogue.
|
|
320
|
+
// A body without membership.korda (older payloads, test stubs) falls back to the national
|
|
321
|
+
// theme; the decorative card must never crash the home page.
|
|
322
|
+
const bare = (korda ?? "").trim().toLowerCase().replace(/[–—]/g, "-").replace(/\s+/g, "-").replace(/^(?:ppi-)?(?:korda-)?/, "");
|
|
323
|
+
const slug = kordaThemeAliases[bare] ?? bare;
|
|
324
|
+
return (saved && byId.get(saved)) || byId.get(`korda-${slug}`) || byId.get("ppij-national");
|
|
325
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface AccountMenuItem {
|
|
3
|
+
label: string;
|
|
4
|
+
href: string;
|
|
5
|
+
icon?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export interface AccountMenuProps {
|
|
8
|
+
/** The signed-in person's name. */
|
|
9
|
+
name: string;
|
|
10
|
+
/** One quiet line under the name, for example the komsat. */
|
|
11
|
+
detail?: string;
|
|
12
|
+
/** Initials for the avatar fallback. */
|
|
13
|
+
initials: string;
|
|
14
|
+
items: AccountMenuItem[];
|
|
15
|
+
signOutLabel?: string;
|
|
16
|
+
onSignOut?: () => void;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The profile navbar piece: avatar and name in the top bar, opening the
|
|
21
|
+
* one account menu (profile, account, sign out). Logout lives here and
|
|
22
|
+
* nowhere else, matching the portal shell rule.
|
|
23
|
+
*/
|
|
24
|
+
export declare function AccountMenu({ name, detail, initials, items, signOutLabel, onSignOut, className }: AccountMenuProps): React.JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconChevronDown, IconLogout } from "@tabler/icons-react";
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
import { Avatar, AvatarFallback } from "./avatar";
|
|
5
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "./dropdown-menu";
|
|
6
|
+
/**
|
|
7
|
+
* The profile navbar piece: avatar and name in the top bar, opening the
|
|
8
|
+
* one account menu (profile, account, sign out). Logout lives here and
|
|
9
|
+
* nowhere else, matching the portal shell rule.
|
|
10
|
+
*/
|
|
11
|
+
export function AccountMenu({ name, detail, initials, items, signOutLabel = "Keluar", onSignOut, className }) {
|
|
12
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex items-center gap-2 rounded-full py-1 pr-2 pl-1 outline-none transition-colors hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring", className), "aria-label": "Menu akun " + name, children: [_jsx(Avatar, { className: "size-8", children: _jsx(AvatarFallback, { children: initials }) }), _jsxs("span", { className: "hidden text-left leading-tight md:grid", children: [_jsx("span", { className: "max-w-44 truncate text-sm font-semibold text-brand-ink", children: name }), detail && _jsx("span", { className: "max-w-44 truncate text-xs text-muted-foreground", children: detail })] }), _jsx(IconChevronDown, { className: "size-4 text-muted-foreground" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsx(DropdownMenuLabel, { children: _jsxs("span", { className: "grid", children: [_jsx("span", { className: "truncate", children: name }), detail && _jsx("span", { className: "truncate text-xs font-normal text-muted-foreground", children: detail })] }) }), _jsx(DropdownMenuSeparator, {}), items.map((item) => (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs("a", { href: item.href, children: [item.icon, item.label] }) }, item.label))), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => onSignOut?.(), variant: "destructive", children: [_jsx(IconLogout, {}), signOutLabel] })] })] }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/** Screens at or above this width open the drawer from the right; narrower screens from the bottom. */
|
|
3
|
+
export type Locale = "id" | "en";
|
|
4
|
+
/** One matchMedia subscription; the only viewport check in the admin drawer. Server render assumes a phone. */
|
|
5
|
+
export declare function useIsDesktop(): boolean;
|
|
6
|
+
export type AdminDrawerProps = {
|
|
7
|
+
open: boolean;
|
|
8
|
+
onOpenChange: (open: boolean) => void;
|
|
9
|
+
/** Accessible name of the dialog; shown in the fixed header. */
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
locale: Locale;
|
|
13
|
+
/** Overrides the built-in close label for this locale. */
|
|
14
|
+
closeLabel?: string;
|
|
15
|
+
/** Overrides the built-in back label for this locale. */
|
|
16
|
+
backLabel?: string;
|
|
17
|
+
/** Two-step body: 1 is the first step (default), 2 is the confirmation step. */
|
|
18
|
+
step?: 1 | 2;
|
|
19
|
+
/** Shown as the "Kembali" button when step is 2. Going back never submits. */
|
|
20
|
+
onBack?: () => void;
|
|
21
|
+
/** Scrolling body of the current step. */
|
|
22
|
+
children: React.ReactNode;
|
|
23
|
+
/** Sticky footer actions of the current step. */
|
|
24
|
+
footer?: React.ReactNode;
|
|
25
|
+
/** Overrides Radix's focus return on close; the caller decides which control gets focus back. */
|
|
26
|
+
onCloseAutoFocus?: (event: Event) => void;
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Admin form or detail in a drawer: right from 900 px, bottom below.
|
|
31
|
+
* Escape, the backdrop and the close button dismiss it without submitting; Radix returns
|
|
32
|
+
* focus to the element that was focused before the drawer opened.
|
|
33
|
+
*/
|
|
34
|
+
export declare function AdminDrawer({ open, onOpenChange, title, description, locale, closeLabel, backLabel, step, onBack, children, footer, onCloseAutoFocus, className, }: AdminDrawerProps): React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { IconX } from "@tabler/icons-react";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
import { Button } from "./button";
|
|
6
|
+
import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, } from "./drawer";
|
|
7
|
+
const labels = {
|
|
8
|
+
id: { close: "Tutup", back: "Kembali" },
|
|
9
|
+
en: { close: "Close", back: "Back" },
|
|
10
|
+
};
|
|
11
|
+
const DESKTOP_QUERY = "(min-width: 900px)";
|
|
12
|
+
function subscribeDesktop(onChange) {
|
|
13
|
+
const media = window.matchMedia(DESKTOP_QUERY);
|
|
14
|
+
media.addEventListener("change", onChange);
|
|
15
|
+
return () => media.removeEventListener("change", onChange);
|
|
16
|
+
}
|
|
17
|
+
/** One matchMedia subscription; the only viewport check in the admin drawer. Server render assumes a phone. */
|
|
18
|
+
export function useIsDesktop() {
|
|
19
|
+
return React.useSyncExternalStore(subscribeDesktop, () => window.matchMedia(DESKTOP_QUERY).matches, () => false);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Admin form or detail in a drawer: right from 900 px, bottom below.
|
|
23
|
+
* Escape, the backdrop and the close button dismiss it without submitting; Radix returns
|
|
24
|
+
* focus to the element that was focused before the drawer opened.
|
|
25
|
+
*/
|
|
26
|
+
export function AdminDrawer({ open, onOpenChange, title, description, locale, closeLabel, backLabel, step = 1, onBack, children, footer, onCloseAutoFocus, className, }) {
|
|
27
|
+
const isDesktop = useIsDesktop();
|
|
28
|
+
const showBack = step === 2 && onBack !== undefined;
|
|
29
|
+
return (_jsx(Drawer, { open: open, onOpenChange: onOpenChange, direction: isDesktop ? "right" : "bottom", children: _jsxs(DrawerContent, { "data-admin-drawer": "", onCloseAutoFocus: onCloseAutoFocus, "data-step": step, className: cn("min-h-0 gap-0 p-0 text-foreground", "data-[vaul-drawer-direction=bottom]:max-h-[85vh]", "data-[vaul-drawer-direction=right]:w-[440px] data-[vaul-drawer-direction=right]:sm:max-w-[440px]", className), children: [_jsxs(DrawerHeader, { "data-vaul-no-drag": "", className: "shrink-0 flex-row items-start justify-between gap-3 border-b border-border p-4 text-left", children: [_jsxs("div", { className: "min-w-0", children: [_jsx(DrawerTitle, { className: "text-base leading-6", children: title }), description ? _jsx(DrawerDescription, { children: description }) : null] }), _jsx(DrawerClose, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": (closeLabel ?? labels[locale].close), className: "shrink-0", children: _jsx(IconX, { className: "size-4" }) }) })] }), _jsx("div", { "data-admin-drawer-body": "", className: "min-h-0 flex-1 overflow-y-auto p-4", children: children }), showBack || footer ? (_jsxs(DrawerFooter, { "data-vaul-no-drag": "", "data-admin-drawer-footer": "", className: "shrink-0 flex-row flex-wrap items-center justify-end gap-2 border-t border-border bg-card p-4", children: [showBack ? (_jsx(Button, { type: "button", variant: "outline", onClick: onBack, className: "mr-auto", children: (backLabel ?? labels[locale].back) })) : null, footer] })) : null] }) }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
|
3
|
+
declare function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>): React.JSX.Element;
|
|
4
|
+
declare function AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>): React.JSX.Element;
|
|
5
|
+
declare function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>): React.JSX.Element;
|
|
6
|
+
declare function AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>): React.JSX.Element;
|
|
7
|
+
declare function AlertDialogContent({ className, size, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
|
|
8
|
+
size?: "default" | "sm";
|
|
9
|
+
}): React.JSX.Element;
|
|
10
|
+
declare function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
11
|
+
declare function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
12
|
+
declare function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>): React.JSX.Element;
|
|
13
|
+
declare function AlertDialogDescription({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>): React.JSX.Element;
|
|
14
|
+
declare function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action>): React.JSX.Element;
|
|
15
|
+
declare function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>): React.JSX.Element;
|
|
16
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
import { buttonVariants } from "./button";
|
|
6
|
+
function AlertDialog({ ...props }) {
|
|
7
|
+
return _jsx(AlertDialogPrimitive.Root, { "data-slot": "alert-dialog", ...props });
|
|
8
|
+
}
|
|
9
|
+
function AlertDialogTrigger({ ...props }) {
|
|
10
|
+
return _jsx(AlertDialogPrimitive.Trigger, { "data-slot": "alert-dialog-trigger", ...props });
|
|
11
|
+
}
|
|
12
|
+
function AlertDialogPortal({ ...props }) {
|
|
13
|
+
return _jsx(AlertDialogPrimitive.Portal, { "data-slot": "alert-dialog-portal", ...props });
|
|
14
|
+
}
|
|
15
|
+
function AlertDialogOverlay({ className, ...props }) {
|
|
16
|
+
return (_jsx(AlertDialogPrimitive.Overlay, { "data-slot": "alert-dialog-overlay", className: cn("fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", className), ...props }));
|
|
17
|
+
}
|
|
18
|
+
function AlertDialogContent({ className, size = "default", ...props }) {
|
|
19
|
+
return (_jsxs(AlertDialogPortal, { children: [_jsx(AlertDialogOverlay, {}), _jsx(AlertDialogPrimitive.Content, { "data-slot": "alert-dialog-content", "data-size": size, className: cn("group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 outline-none data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg", className), ...props })] }));
|
|
20
|
+
}
|
|
21
|
+
function AlertDialogHeader({ className, ...props }) {
|
|
22
|
+
return _jsx("div", { "data-slot": "alert-dialog-header", className: cn("flex flex-col gap-2 text-center sm:text-left", className), ...props });
|
|
23
|
+
}
|
|
24
|
+
function AlertDialogFooter({ className, ...props }) {
|
|
25
|
+
return _jsx("div", { "data-slot": "alert-dialog-footer", className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className), ...props });
|
|
26
|
+
}
|
|
27
|
+
function AlertDialogTitle({ className, ...props }) {
|
|
28
|
+
return _jsx(AlertDialogPrimitive.Title, { "data-slot": "alert-dialog-title", className: cn("text-lg font-semibold", className), ...props });
|
|
29
|
+
}
|
|
30
|
+
function AlertDialogDescription({ className, ...props }) {
|
|
31
|
+
return _jsx(AlertDialogPrimitive.Description, { "data-slot": "alert-dialog-description", className: cn("text-sm text-muted-foreground", className), ...props });
|
|
32
|
+
}
|
|
33
|
+
function AlertDialogAction({ className, ...props }) {
|
|
34
|
+
return _jsx(AlertDialogPrimitive.Action, { className: cn(buttonVariants(), className), ...props });
|
|
35
|
+
}
|
|
36
|
+
function AlertDialogCancel({ className, ...props }) {
|
|
37
|
+
return _jsx(AlertDialogPrimitive.Cancel, { className: cn(buttonVariants({ variant: "outline" }), className), ...props });
|
|
38
|
+
}
|
|
39
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const alertVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "success" | "warning" | "info" | null | undefined;
|
|
5
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
+
declare function Alert({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>): React.JSX.Element;
|
|
7
|
+
declare function AlertTitle({ className, asChild, ...props }: React.ComponentProps<"div"> & {
|
|
8
|
+
asChild?: boolean;
|
|
9
|
+
}): React.JSX.Element;
|
|
10
|
+
declare function AlertDescription({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
11
|
+
export { Alert, AlertTitle, AlertDescription };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
|
+
import { Slot } from "radix-ui";
|
|
5
|
+
const alertVariants = cva("relative grid w-full grid-cols-[auto_1fr] items-start gap-x-3 gap-y-0.5 rounded-lg border px-4 py-3 text-sm [&>svg]:size-5 [&>svg]:translate-y-0.5 [&>svg]:text-current", {
|
|
6
|
+
variants: {
|
|
7
|
+
variant: {
|
|
8
|
+
default: "bg-card text-card-foreground",
|
|
9
|
+
success: "border-success/50 bg-card text-card-foreground [&>svg]:text-success",
|
|
10
|
+
warning: "border-warning/50 bg-card text-card-foreground [&>svg]:text-warning",
|
|
11
|
+
info: "border-info/50 bg-card text-card-foreground [&>svg]:text-info",
|
|
12
|
+
destructive: "bg-card text-destructive",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
variant: "default",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
function Alert({ className, variant, ...props }) {
|
|
20
|
+
return (_jsx("div", { "data-slot": "alert", role: "alert", className: cn(alertVariants({ variant }), className), ...props }));
|
|
21
|
+
}
|
|
22
|
+
function AlertTitle({ className, asChild = false, ...props }) {
|
|
23
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
24
|
+
return (_jsx(Comp, { "data-slot": "alert-title", className: cn("col-start-2 min-w-0 font-medium leading-snug", className), ...props }));
|
|
25
|
+
}
|
|
26
|
+
function AlertDescription({ className, ...props }) {
|
|
27
|
+
return (_jsx("div", { "data-slot": "alert-description", className: cn("col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground", className), ...props }));
|
|
28
|
+
}
|
|
29
|
+
export { Alert, AlertTitle, AlertDescription };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
3
|
+
declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
|
|
4
|
+
size?: "default" | "sm" | "lg";
|
|
5
|
+
}): React.JSX.Element;
|
|
6
|
+
declare function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>): React.JSX.Element;
|
|
7
|
+
declare function AvatarFallback({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback>): React.JSX.Element;
|
|
8
|
+
declare function AvatarBadge({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
9
|
+
declare function AvatarGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
10
|
+
declare function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
11
|
+
export { Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount, };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils";
|
|
3
|
+
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
4
|
+
function Avatar({ className, size = "default", ...props }) {
|
|
5
|
+
return (_jsx(AvatarPrimitive.Root, { "data-slot": "avatar", "data-size": size, className: cn("group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6", className), ...props }));
|
|
6
|
+
}
|
|
7
|
+
function AvatarImage({ className, ...props }) {
|
|
8
|
+
return (_jsx(AvatarPrimitive.Image, { "data-slot": "avatar-image", className: cn("aspect-square size-full rounded-full object-cover", className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
function AvatarFallback({ className, ...props }) {
|
|
11
|
+
return (_jsx(AvatarPrimitive.Fallback, { "data-slot": "avatar-fallback", className: cn("flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs", className), ...props }));
|
|
12
|
+
}
|
|
13
|
+
function AvatarBadge({ className, ...props }) {
|
|
14
|
+
return (_jsx("span", { "data-slot": "avatar-badge", className: cn("absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className), ...props }));
|
|
15
|
+
}
|
|
16
|
+
function AvatarGroup({ className, ...props }) {
|
|
17
|
+
return (_jsx("div", { "data-slot": "avatar-group", className: cn("group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", className), ...props }));
|
|
18
|
+
}
|
|
19
|
+
function AvatarGroupCount({ className, ...props }) {
|
|
20
|
+
return (_jsx("div", { "data-slot": "avatar-group-count", className: cn("relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className), ...props }));
|
|
21
|
+
}
|
|
22
|
+
export { Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount, };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const badgeVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "success" | "warning" | "info" | null | undefined;
|
|
5
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
+
declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
7
|
+
asChild?: boolean;
|
|
8
|
+
}): React.JSX.Element;
|
|
9
|
+
export { Badge, badgeVariants };
|