@hotelfriendag/design-tokens 0.3.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/LICENSE +21 -0
- package/README.md +558 -0
- package/README.uk.md +377 -0
- package/RFC-0001-cross-project-design-system.md +273 -0
- package/RFC-0002-semantic-tier-naming.md +296 -0
- package/UI_DESIGN.md +608 -0
- package/ai-rules/CLAUDE.md +80 -0
- package/ai-rules/cursorrules.template +39 -0
- package/ai-rules/github-copilot-instructions.md +45 -0
- package/ai-rules/system-prompt-compact.md +43 -0
- package/components.html +3018 -0
- package/generate-tokens.cjs +665 -0
- package/package.json +98 -0
- package/portal-audit.html +2306 -0
- package/pre-built/_tokens.scss +138 -0
- package/pre-built/components.css +515 -0
- package/pre-built/shadcn-tokens.css +67 -0
- package/pre-built/status.css +51 -0
- package/pre-built/stylelint-design-system.cjs +69 -0
- package/pre-built/tailwind.additive.css +158 -0
- package/pre-built/tailwind.css +158 -0
- package/pre-built/tailwind.preset.js +207 -0
- package/pre-built/tokens.css +185 -0
- package/pre-built/tokens.d.ts +240 -0
- package/pre-built/tokens.js +243 -0
- package/pre-built/tokens.ts +240 -0
- package/scripts/integration-smoke.sh +91 -0
- package/scripts/pre-commit.sh +55 -0
- package/scripts/validate-tokens.cjs +113 -0
- package/states-canonical.json +240 -0
- package/states.json +2950 -0
- package/status-map.json +47 -0
- package/tokens.figma.json +230 -0
|
@@ -0,0 +1,2306 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>HotelFriend Portal Audit (Archival) — Legacy Reference</title>
|
|
7
|
+
<!-- Tailwind CSS for documentation layout -->
|
|
8
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
9
|
+
<!-- Core Font -->
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600&display=swap" rel="stylesheet">
|
|
11
|
+
|
|
12
|
+
<style>
|
|
13
|
+
/* ==========================================================================
|
|
14
|
+
1. Core Design Tokens (CSS Variables)
|
|
15
|
+
========================================================================== */
|
|
16
|
+
:root {
|
|
17
|
+
--primary: #24AFE8; /* canonical primary */
|
|
18
|
+
--primary-live: #24AFE8; /* CSS custom prop currently in legacy code (2-pt-off duplicate) */
|
|
19
|
+
--primary-hover: #149AD1;
|
|
20
|
+
--light-primary: #E9F6FC;
|
|
21
|
+
--primary-tint-bg: #EFF6FF; /* live "Reset Filters" bg */
|
|
22
|
+
--primary-tint-border: rgba(27, 132, 255, 0.2);
|
|
23
|
+
|
|
24
|
+
--white: #ffffff;
|
|
25
|
+
--bg-page: #FBFBFC;
|
|
26
|
+
--bg-accent: #F6F7FB;
|
|
27
|
+
--bg-muted: #F1F3F6;
|
|
28
|
+
--border-light: #E4E8EF;
|
|
29
|
+
--border: #D1D6DD;
|
|
30
|
+
--border-hover: #B2BAC4;
|
|
31
|
+
--neutral-btn-border: #AEBCCF; /* live outline-default border */
|
|
32
|
+
|
|
33
|
+
--text-primary: #2B2B2B;
|
|
34
|
+
--text-secondary: #4B5675;
|
|
35
|
+
--text-tertiary: #4A5565;
|
|
36
|
+
--text-steel: #485B78;
|
|
37
|
+
--text-useful: #7E8EA6;
|
|
38
|
+
--placeholder: #99A1B7;
|
|
39
|
+
|
|
40
|
+
--success: #59B59D;
|
|
41
|
+
--warning: #FFBD5A;
|
|
42
|
+
--warning-strong: #FFC900; /* frontDesk out-of-order */
|
|
43
|
+
--error: #EA6565;
|
|
44
|
+
--coral: #F87921;
|
|
45
|
+
--violet: #5761D8;
|
|
46
|
+
--canceled-gray: #7F8FA4;
|
|
47
|
+
--check-in-olive: #5B7A02;
|
|
48
|
+
--due-out-brown: #A55505;
|
|
49
|
+
|
|
50
|
+
--shadow-card: 0 12px 24px rgba(26,26,30,.06); /* canonical, but absent from live CSS */
|
|
51
|
+
--shadow-wrapper: 0 3px 4px rgba(0,0,0,.03);
|
|
52
|
+
--shadow-hover: 0 2px 3px rgba(0,0,0,.06);
|
|
53
|
+
--shadow-default: 0 1px 8px rgba(0,0,0,.1);
|
|
54
|
+
--shadow-tooltip: 0 6px 18px 0 rgba(0,0,0,.1); /* live --tooltip-shadow */
|
|
55
|
+
|
|
56
|
+
/* Status badge tokens (booking) */
|
|
57
|
+
--status-booking-new-color: rgb(255, 189, 90);
|
|
58
|
+
--status-booking-new-bg: rgba(255, 189, 90, 0.15);
|
|
59
|
+
--status-booking-offer-color: rgb(87, 97, 216);
|
|
60
|
+
--status-booking-offer-bg: rgba(87, 97, 216, 0.15);
|
|
61
|
+
--status-booking-confirmed-color: rgb(38, 173, 228);
|
|
62
|
+
--status-booking-confirmed-bg: rgba(38, 173, 228, 0.15);
|
|
63
|
+
--status-booking-check-in-color: rgb(91, 122, 2);
|
|
64
|
+
--status-booking-check-in-bg: rgba(91, 122, 2, 0.15);
|
|
65
|
+
--status-booking-check-out-color: rgb(248, 121, 33);
|
|
66
|
+
--status-booking-check-out-bg: rgba(248, 121, 33, 0.15);
|
|
67
|
+
--status-booking-no-show-color: rgb(234, 101, 101);
|
|
68
|
+
--status-booking-no-show-bg: rgba(234, 101, 101, 0.15);
|
|
69
|
+
--status-booking-due-in-color: rgb(89, 181, 157);
|
|
70
|
+
--status-booking-due-in-bg: rgba(89, 181, 157, 0.15);
|
|
71
|
+
--status-booking-due-out-color: rgb(165, 85, 5);
|
|
72
|
+
--status-booking-due-out-bg: rgba(165, 85, 5, 0.15);
|
|
73
|
+
--status-booking-canceled-color: rgb(127, 143, 164);
|
|
74
|
+
--status-booking-canceled-bg: rgba(127, 143, 164, 0.15);
|
|
75
|
+
/* Order */
|
|
76
|
+
--status-order-waiting-color: rgb(255, 189, 90);
|
|
77
|
+
--status-order-waiting-bg: rgba(255, 189, 90, 0.15);
|
|
78
|
+
--status-order-confirmed-color: rgb(38, 173, 228);
|
|
79
|
+
--status-order-confirmed-bg: rgba(38, 173, 228, 0.15);
|
|
80
|
+
--status-order-completed-color: rgb(89, 181, 157);
|
|
81
|
+
--status-order-completed-bg: rgba(89, 181, 157, 0.15);
|
|
82
|
+
--status-order-action-required-color: rgb(234, 101, 101);
|
|
83
|
+
--status-order-action-required-bg: rgba(234, 101, 101, 0.15);
|
|
84
|
+
/* Front-desk */
|
|
85
|
+
--status-frontDesk-quota-free-color: rgb(89, 181, 157);
|
|
86
|
+
--status-frontDesk-quota-free-bg: rgba(89, 181, 157, 0.15);
|
|
87
|
+
--status-frontDesk-quota-busy-color: rgb(234, 101, 101);
|
|
88
|
+
--status-frontDesk-quota-busy-bg: rgba(234, 101, 101, 0.15);
|
|
89
|
+
--status-frontDesk-out-of-order-color: rgb(255, 201, 0);
|
|
90
|
+
--status-frontDesk-out-of-order-bg: rgba(255, 201, 0, 0.15);
|
|
91
|
+
/* Cleaning */
|
|
92
|
+
--status-cleaning-clean-color: rgb(89, 181, 157);
|
|
93
|
+
--status-cleaning-clean-bg: rgba(89, 181, 157, 0.15);
|
|
94
|
+
--status-cleaning-cleaning-color: rgb(38, 173, 228);
|
|
95
|
+
--status-cleaning-cleaning-bg: rgba(38, 173, 228, 0.15);
|
|
96
|
+
--status-cleaning-dirty-color: rgb(234, 101, 101);
|
|
97
|
+
--status-cleaning-dirty-bg: rgba(234, 101, 101, 0.15);
|
|
98
|
+
--status-cleaning-out-of-service-color: rgb(174, 188, 207);
|
|
99
|
+
--status-cleaning-out-of-service-bg: rgba(174, 188, 207, 0.15);
|
|
100
|
+
--status-cleaning-inspected-color: rgb(87, 97, 216);
|
|
101
|
+
--status-cleaning-inspected-bg: rgba(87, 97, 216, 0.15);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ==========================================================================
|
|
105
|
+
2. Component Classes (Framework Agnostic)
|
|
106
|
+
========================================================================== */
|
|
107
|
+
body {
|
|
108
|
+
font-family: 'Roboto', sans-serif;
|
|
109
|
+
background-color: var(--white);
|
|
110
|
+
color: var(--text-primary);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Typography Utilities */
|
|
114
|
+
.hf-text-pagetitle { font-size: 26px; line-height: 1.2; font-weight: 600; }
|
|
115
|
+
.hf-text-general { font-size: 14px; line-height: 1.5; font-weight: 400; }
|
|
116
|
+
.hf-text-medium { font-size: 14px; line-height: 1.5; font-weight: 500; }
|
|
117
|
+
.hf-text-gridhead { font-size: 13px; line-height: 1.5; font-weight: 500; }
|
|
118
|
+
.hf-text-label { font-size: 11px; line-height: 1.2; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; }
|
|
119
|
+
|
|
120
|
+
/* Buttons */
|
|
121
|
+
.btn {
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
height: 40px;
|
|
126
|
+
padding: 0 20px;
|
|
127
|
+
border-radius: 6px;
|
|
128
|
+
font-size: 15px;
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
transition: all 200ms ease-in-out;
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
border: 1px solid transparent;
|
|
133
|
+
}
|
|
134
|
+
.btn-primary {
|
|
135
|
+
background-color: var(--primary);
|
|
136
|
+
color: var(--white);
|
|
137
|
+
}
|
|
138
|
+
.btn-primary:hover {
|
|
139
|
+
background-color: var(--primary-hover);
|
|
140
|
+
box-shadow: var(--shadow-hover);
|
|
141
|
+
}
|
|
142
|
+
.btn-outline {
|
|
143
|
+
background-color: var(--white);
|
|
144
|
+
color: var(--text-primary);
|
|
145
|
+
border-color: var(--border);
|
|
146
|
+
}
|
|
147
|
+
.btn-outline:hover {
|
|
148
|
+
border-color: var(--primary);
|
|
149
|
+
color: var(--primary);
|
|
150
|
+
}
|
|
151
|
+
.btn-cancel {
|
|
152
|
+
background-color: var(--bg-muted);
|
|
153
|
+
color: var(--text-secondary);
|
|
154
|
+
}
|
|
155
|
+
.btn-cancel:hover {
|
|
156
|
+
background-color: var(--border-light);
|
|
157
|
+
}
|
|
158
|
+
.btn-delete {
|
|
159
|
+
background-color: var(--error);
|
|
160
|
+
color: var(--white);
|
|
161
|
+
}
|
|
162
|
+
/* Live additional variants */
|
|
163
|
+
.btn-reset-filters {
|
|
164
|
+
background-color: var(--primary-tint-bg);
|
|
165
|
+
color: var(--primary);
|
|
166
|
+
border-color: var(--primary-tint-border);
|
|
167
|
+
height: 38px;
|
|
168
|
+
padding: 9px 10px 9px 32px;
|
|
169
|
+
font-size: 14px;
|
|
170
|
+
font-weight: 500;
|
|
171
|
+
position: relative;
|
|
172
|
+
}
|
|
173
|
+
.btn-reset-filters:hover { background-color: #DDEEFE; }
|
|
174
|
+
.btn-neutral-outline {
|
|
175
|
+
background-color: var(--white);
|
|
176
|
+
color: var(--text-steel);
|
|
177
|
+
border-color: var(--neutral-btn-border);
|
|
178
|
+
height: 38px;
|
|
179
|
+
padding: 8px 16px;
|
|
180
|
+
}
|
|
181
|
+
.btn-text-link {
|
|
182
|
+
background: transparent;
|
|
183
|
+
color: var(--primary);
|
|
184
|
+
border: none;
|
|
185
|
+
height: auto;
|
|
186
|
+
padding: 0;
|
|
187
|
+
font-weight: 400;
|
|
188
|
+
text-decoration: none;
|
|
189
|
+
}
|
|
190
|
+
.btn-text-link:hover { text-decoration: underline; }
|
|
191
|
+
.btn-icon-only {
|
|
192
|
+
width: 32px; height: 32px;
|
|
193
|
+
padding: 0;
|
|
194
|
+
background: var(--white);
|
|
195
|
+
color: var(--text-steel);
|
|
196
|
+
border: 1px solid transparent;
|
|
197
|
+
font-size: 14px;
|
|
198
|
+
}
|
|
199
|
+
.btn-icon-only:hover { background: var(--bg-muted); }
|
|
200
|
+
|
|
201
|
+
/* Status pill (universal) */
|
|
202
|
+
.hf-pill {
|
|
203
|
+
display: inline-flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
padding: 6px 20px;
|
|
206
|
+
border-radius: 6px;
|
|
207
|
+
font-size: 14px;
|
|
208
|
+
font-weight: 500;
|
|
209
|
+
line-height: 1;
|
|
210
|
+
white-space: nowrap;
|
|
211
|
+
}
|
|
212
|
+
/* Booking */
|
|
213
|
+
.status-booking-new { color: var(--status-booking-new-color); background: var(--status-booking-new-bg); }
|
|
214
|
+
.status-booking-offer { color: var(--status-booking-offer-color); background: var(--status-booking-offer-bg); }
|
|
215
|
+
.status-booking-confirmed { color: var(--status-booking-confirmed-color); background: var(--status-booking-confirmed-bg); }
|
|
216
|
+
.status-booking-check-in { color: var(--status-booking-check-in-color); background: var(--status-booking-check-in-bg); }
|
|
217
|
+
.status-booking-check-out { color: var(--status-booking-check-out-color); background: var(--status-booking-check-out-bg); }
|
|
218
|
+
.status-booking-no-show { color: var(--status-booking-no-show-color); background: var(--status-booking-no-show-bg); }
|
|
219
|
+
.status-booking-due-in { color: var(--status-booking-due-in-color); background: var(--status-booking-due-in-bg); }
|
|
220
|
+
.status-booking-due-out { color: var(--status-booking-due-out-color); background: var(--status-booking-due-out-bg); }
|
|
221
|
+
.status-booking-canceled { color: var(--status-booking-canceled-color); background: var(--status-booking-canceled-bg); }
|
|
222
|
+
/* Order */
|
|
223
|
+
.status-order-waiting { color: var(--status-order-waiting-color); background: var(--status-order-waiting-bg); }
|
|
224
|
+
.status-order-confirmed { color: var(--status-order-confirmed-color); background: var(--status-order-confirmed-bg); }
|
|
225
|
+
.status-order-completed { color: var(--status-order-completed-color); background: var(--status-order-completed-bg); }
|
|
226
|
+
.status-order-action-required { color: var(--status-order-action-required-color); background: var(--status-order-action-required-bg); }
|
|
227
|
+
/* Cleaning */
|
|
228
|
+
.status-cleaning-clean { color: var(--status-cleaning-clean-color); background: var(--status-cleaning-clean-bg); }
|
|
229
|
+
.status-cleaning-cleaning { color: var(--status-cleaning-cleaning-color); background: var(--status-cleaning-cleaning-bg); }
|
|
230
|
+
.status-cleaning-dirty { color: var(--status-cleaning-dirty-color); background: var(--status-cleaning-dirty-bg); }
|
|
231
|
+
.status-cleaning-out-of-service{ color: var(--status-cleaning-out-of-service-color);background: var(--status-cleaning-out-of-service-bg); }
|
|
232
|
+
.status-cleaning-inspected { color: var(--status-cleaning-inspected-color); background: var(--status-cleaning-inspected-bg); }
|
|
233
|
+
/* FrontDesk */
|
|
234
|
+
.status-fd-free { color: var(--status-frontDesk-quota-free-color); background: var(--status-frontDesk-quota-free-bg); }
|
|
235
|
+
.status-fd-busy { color: var(--status-frontDesk-quota-busy-color); background: var(--status-frontDesk-quota-busy-bg); }
|
|
236
|
+
.status-fd-out-of-order { color: var(--status-frontDesk-out-of-order-color); background: var(--status-frontDesk-out-of-order-bg); }
|
|
237
|
+
|
|
238
|
+
/* Bootstrap-switch mock (visual only) */
|
|
239
|
+
.hf-switch {
|
|
240
|
+
display: inline-flex;
|
|
241
|
+
width: 68px; height: 32px;
|
|
242
|
+
border-radius: 16px;
|
|
243
|
+
background: var(--bg-muted);
|
|
244
|
+
position: relative;
|
|
245
|
+
cursor: pointer;
|
|
246
|
+
transition: background 0.2s ease-in-out;
|
|
247
|
+
border: 1px solid var(--border-light);
|
|
248
|
+
}
|
|
249
|
+
.hf-switch.is-on { background: var(--primary); border-color: var(--primary); }
|
|
250
|
+
.hf-switch::after {
|
|
251
|
+
content: "";
|
|
252
|
+
width: 24px; height: 24px;
|
|
253
|
+
border-radius: 50%;
|
|
254
|
+
background: white;
|
|
255
|
+
position: absolute;
|
|
256
|
+
top: 3px; left: 3px;
|
|
257
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
258
|
+
transition: left 0.2s ease-in-out;
|
|
259
|
+
}
|
|
260
|
+
.hf-switch.is-on::after { left: 39px; }
|
|
261
|
+
|
|
262
|
+
/* Summernote-like toolbar */
|
|
263
|
+
.hf-rte-toolbar {
|
|
264
|
+
display: flex;
|
|
265
|
+
flex-wrap: wrap;
|
|
266
|
+
gap: 1px;
|
|
267
|
+
padding: 6px;
|
|
268
|
+
background: var(--bg-page);
|
|
269
|
+
border: 1px solid var(--border-light);
|
|
270
|
+
border-bottom: 0;
|
|
271
|
+
border-radius: 6px 6px 0 0;
|
|
272
|
+
}
|
|
273
|
+
.hf-rte-group {
|
|
274
|
+
display: flex;
|
|
275
|
+
border-radius: 6px;
|
|
276
|
+
overflow: hidden;
|
|
277
|
+
background: var(--white);
|
|
278
|
+
border: 1px solid var(--border-light);
|
|
279
|
+
margin-right: 4px;
|
|
280
|
+
}
|
|
281
|
+
.hf-rte-btn {
|
|
282
|
+
width: 32px; height: 32px;
|
|
283
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
284
|
+
color: var(--text-primary);
|
|
285
|
+
background: var(--white);
|
|
286
|
+
border: 0; cursor: pointer;
|
|
287
|
+
font-size: 13px;
|
|
288
|
+
transition: background 0.15s;
|
|
289
|
+
}
|
|
290
|
+
.hf-rte-btn:hover { background: var(--bg-muted); }
|
|
291
|
+
.hf-rte-editable {
|
|
292
|
+
border: 1px solid var(--border-light);
|
|
293
|
+
border-radius: 0 0 6px 6px;
|
|
294
|
+
padding: 14px;
|
|
295
|
+
min-height: 120px;
|
|
296
|
+
background: white;
|
|
297
|
+
color: var(--text-primary);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Krajee FileInput */
|
|
301
|
+
.hf-fileinput {
|
|
302
|
+
display: flex;
|
|
303
|
+
align-items: center;
|
|
304
|
+
border: 1px solid var(--border);
|
|
305
|
+
border-radius: 6px;
|
|
306
|
+
background: white;
|
|
307
|
+
overflow: hidden;
|
|
308
|
+
max-width: 480px;
|
|
309
|
+
height: 38px;
|
|
310
|
+
}
|
|
311
|
+
.hf-fileinput-caption {
|
|
312
|
+
flex: 1;
|
|
313
|
+
display: flex;
|
|
314
|
+
align-items: center;
|
|
315
|
+
gap: 6px;
|
|
316
|
+
padding: 0 12px;
|
|
317
|
+
color: var(--placeholder);
|
|
318
|
+
font-size: 14px;
|
|
319
|
+
border-right: 1px solid var(--border-light);
|
|
320
|
+
}
|
|
321
|
+
.hf-fileinput-actions { display: flex; }
|
|
322
|
+
.hf-fileinput-actions button {
|
|
323
|
+
height: 38px;
|
|
324
|
+
border: 0;
|
|
325
|
+
padding: 0 14px;
|
|
326
|
+
background: var(--bg-muted);
|
|
327
|
+
color: var(--text-secondary);
|
|
328
|
+
font-size: 14px;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
}
|
|
331
|
+
.hf-fileinput-actions button.browse {
|
|
332
|
+
background: var(--primary);
|
|
333
|
+
color: white;
|
|
334
|
+
}
|
|
335
|
+
.hf-fileinput-preview {
|
|
336
|
+
margin-top: 12px;
|
|
337
|
+
border: 1px dashed var(--border);
|
|
338
|
+
border-radius: 6px;
|
|
339
|
+
background: var(--bg-page);
|
|
340
|
+
padding: 16px;
|
|
341
|
+
color: var(--placeholder);
|
|
342
|
+
font-size: 13px;
|
|
343
|
+
text-align: center;
|
|
344
|
+
min-height: 100px;
|
|
345
|
+
display: flex;
|
|
346
|
+
align-items: center;
|
|
347
|
+
justify-content: center;
|
|
348
|
+
}
|
|
349
|
+
.btn-delete:hover {
|
|
350
|
+
filter: brightness(0.9);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* Forms */
|
|
354
|
+
.form-control {
|
|
355
|
+
height: 39px;
|
|
356
|
+
padding: 6px 12px;
|
|
357
|
+
border: 1px solid var(--border);
|
|
358
|
+
border-radius: 6px;
|
|
359
|
+
font-size: 14px;
|
|
360
|
+
color: var(--text-primary);
|
|
361
|
+
width: 100%;
|
|
362
|
+
transition: all 200ms ease-in-out;
|
|
363
|
+
outline: none;
|
|
364
|
+
background: var(--white);
|
|
365
|
+
}
|
|
366
|
+
.form-control::placeholder { color: var(--placeholder); }
|
|
367
|
+
.form-control:focus {
|
|
368
|
+
border-color: var(--primary);
|
|
369
|
+
box-shadow: 0 0 0 2px rgba(38, 173, 228, 0.2);
|
|
370
|
+
}
|
|
371
|
+
.hf-checkbox {
|
|
372
|
+
width: 16px;
|
|
373
|
+
height: 16px;
|
|
374
|
+
border-radius: 6px;
|
|
375
|
+
border: 1px solid var(--border);
|
|
376
|
+
cursor: pointer;
|
|
377
|
+
accent-color: var(--primary);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* Badges */
|
|
381
|
+
.badge {
|
|
382
|
+
display: inline-flex;
|
|
383
|
+
align-items: center;
|
|
384
|
+
padding: 4px 8px;
|
|
385
|
+
border-radius: 99px;
|
|
386
|
+
font-size: 11px;
|
|
387
|
+
font-weight: 500;
|
|
388
|
+
text-transform: uppercase;
|
|
389
|
+
letter-spacing: 0.05em;
|
|
390
|
+
}
|
|
391
|
+
.badge-soft-success { background-color: #EAF7F4; color: var(--success); }
|
|
392
|
+
.badge-soft-warning { background-color: #FFF4E5; color: var(--warning); }
|
|
393
|
+
.badge-soft-error { background-color: #FCE8E8; color: var(--error); }
|
|
394
|
+
|
|
395
|
+
/* Structural Blocks */
|
|
396
|
+
.hf-card {
|
|
397
|
+
background: var(--white);
|
|
398
|
+
border: 1px solid var(--border-light);
|
|
399
|
+
border-radius: 12px;
|
|
400
|
+
box-shadow: var(--shadow-wrapper);
|
|
401
|
+
padding: 20px;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.hf-info-block {
|
|
405
|
+
background: var(--bg-accent);
|
|
406
|
+
border: 1px solid var(--border-light);
|
|
407
|
+
border-radius: 6px;
|
|
408
|
+
padding: 16px;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* ==========================================================================
|
|
412
|
+
States simulators (force visual state without JS)
|
|
413
|
+
========================================================================== */
|
|
414
|
+
.btn[data-state="hover"].btn-primary { background-color: var(--primary-hover); box-shadow: var(--shadow-hover); }
|
|
415
|
+
.btn[data-state="focus"].btn-primary { background-color: var(--primary-hover); outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
416
|
+
.btn[data-state="active"].btn-primary { background-color: var(--primary-hover); transform: scale(0.98); }
|
|
417
|
+
.btn[data-state="disabled"] { opacity: 0.6; cursor: not-allowed; pointer-events: none; }
|
|
418
|
+
.btn[data-state="loading"] { color: transparent; pointer-events: none; position: relative; }
|
|
419
|
+
.btn[data-state="loading"]::after {
|
|
420
|
+
content: ""; position: absolute; left: 50%; top: 50%;
|
|
421
|
+
width: 14px; height: 14px;
|
|
422
|
+
margin: -7px 0 0 -7px;
|
|
423
|
+
border: 2px solid currentColor;
|
|
424
|
+
border-top-color: transparent;
|
|
425
|
+
border-radius: 50%;
|
|
426
|
+
animation: hf-spin 0.6s linear infinite;
|
|
427
|
+
color: var(--white);
|
|
428
|
+
}
|
|
429
|
+
.btn[data-state="hover"].btn-outline { border-color: var(--primary); color: var(--primary); }
|
|
430
|
+
.btn[data-state="focus"].btn-outline { border-color: var(--primary); outline: 2px solid var(--primary); outline-offset: 2px; }
|
|
431
|
+
.btn[data-state="hover"].btn-cancel { background-color: var(--border-light); }
|
|
432
|
+
.btn[data-state="hover"].btn-delete { filter: brightness(0.9); }
|
|
433
|
+
.btn[data-state="focus"].btn-delete { outline: 2px solid var(--error); outline-offset: 2px; }
|
|
434
|
+
|
|
435
|
+
@keyframes hf-spin { to { transform: rotate(360deg); } }
|
|
436
|
+
@keyframes hf-shimmer { 0% { background-position: -400px 0; } 100% { background-position: 400px 0; } }
|
|
437
|
+
|
|
438
|
+
/* ==========================================================================
|
|
439
|
+
Form Controls — states + types
|
|
440
|
+
========================================================================== */
|
|
441
|
+
.form-control[data-state="hover"] { border-color: var(--border-hover); }
|
|
442
|
+
.form-control[data-state="focus"] { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(38, 173, 228, 0.2); }
|
|
443
|
+
.form-control[data-state="disabled"] { background: #F7F9FA; color: #7E8CA0; cursor: not-allowed; }
|
|
444
|
+
.form-control--error { border-color: var(--error) !important; }
|
|
445
|
+
.form-control--success { border-color: var(--success) !important; }
|
|
446
|
+
.form-helper { font-size: 12px; color: var(--text-secondary); margin-top: 4px; }
|
|
447
|
+
.form-helper--error { color: var(--error); }
|
|
448
|
+
.form-helper--success { color: var(--success); }
|
|
449
|
+
.form-required::after { content: " *"; color: var(--error); }
|
|
450
|
+
|
|
451
|
+
/* ==========================================================================
|
|
452
|
+
Tabs (.hf-tabs)
|
|
453
|
+
========================================================================== */
|
|
454
|
+
.hf-tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); }
|
|
455
|
+
.hf-tabs__item {
|
|
456
|
+
position: relative;
|
|
457
|
+
padding: 22px 15px;
|
|
458
|
+
font-size: 15px;
|
|
459
|
+
font-weight: 500;
|
|
460
|
+
color: #50627E;
|
|
461
|
+
cursor: pointer;
|
|
462
|
+
transition: color 200ms ease-in-out;
|
|
463
|
+
}
|
|
464
|
+
.hf-tabs__item:hover { color: var(--text-primary); }
|
|
465
|
+
.hf-tabs__item.is-active { color: var(--primary); }
|
|
466
|
+
.hf-tabs__item.is-active::after {
|
|
467
|
+
content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
|
|
468
|
+
height: 3px; background: var(--primary);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* ==========================================================================
|
|
472
|
+
Modal — full anatomy
|
|
473
|
+
========================================================================== */
|
|
474
|
+
.hf-modal-shell {
|
|
475
|
+
position: relative;
|
|
476
|
+
background: rgba(0,0,0,0.4);
|
|
477
|
+
border-radius: 12px;
|
|
478
|
+
padding: 40px;
|
|
479
|
+
min-height: 420px;
|
|
480
|
+
display: flex;
|
|
481
|
+
justify-content: center;
|
|
482
|
+
align-items: flex-start;
|
|
483
|
+
}
|
|
484
|
+
.hf-modal {
|
|
485
|
+
background: var(--white);
|
|
486
|
+
border-radius: 12px;
|
|
487
|
+
box-shadow: var(--shadow-tooltip);
|
|
488
|
+
max-width: 500px;
|
|
489
|
+
width: 100%;
|
|
490
|
+
overflow: hidden;
|
|
491
|
+
}
|
|
492
|
+
.hf-modal--lg { max-width: 800px; }
|
|
493
|
+
.hf-modal__header,
|
|
494
|
+
.hf-modal__footer { padding: 20px; }
|
|
495
|
+
.hf-modal__header { border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
|
|
496
|
+
.hf-modal__title { font-size: 18px; font-weight: 600; color: var(--text-primary); }
|
|
497
|
+
.hf-modal__close {
|
|
498
|
+
width: 32px; height: 32px; border-radius: 6px; border: 0;
|
|
499
|
+
background: transparent; color: var(--text-secondary);
|
|
500
|
+
cursor: pointer; font-size: 20px;
|
|
501
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
502
|
+
}
|
|
503
|
+
.hf-modal__close:hover { background: var(--bg-muted); color: var(--text-primary); }
|
|
504
|
+
.hf-modal__body { padding: 20px; }
|
|
505
|
+
.hf-modal__footer { border-top: 1px solid var(--border-light); display: flex; justify-content: flex-end; gap: 12px; }
|
|
506
|
+
|
|
507
|
+
/* ==========================================================================
|
|
508
|
+
Dropdown
|
|
509
|
+
========================================================================== */
|
|
510
|
+
.hf-dropdown {
|
|
511
|
+
position: relative;
|
|
512
|
+
display: inline-block;
|
|
513
|
+
}
|
|
514
|
+
.hf-dropdown__menu {
|
|
515
|
+
background: var(--white);
|
|
516
|
+
border-radius: 9px;
|
|
517
|
+
box-shadow: var(--shadow-tooltip);
|
|
518
|
+
min-width: 180px;
|
|
519
|
+
padding: 6px 0;
|
|
520
|
+
border: 1px solid var(--border-light);
|
|
521
|
+
}
|
|
522
|
+
.hf-dropdown__item {
|
|
523
|
+
display: flex; align-items: center; gap: 8px;
|
|
524
|
+
padding: 8px 16px;
|
|
525
|
+
font-size: 14px;
|
|
526
|
+
color: var(--text-secondary);
|
|
527
|
+
cursor: pointer;
|
|
528
|
+
transition: background 150ms;
|
|
529
|
+
}
|
|
530
|
+
.hf-dropdown__item:hover { background: var(--bg-muted); color: var(--text-primary); }
|
|
531
|
+
.hf-dropdown__item--danger { color: var(--error); }
|
|
532
|
+
.hf-dropdown__item--danger:hover { background: rgba(234, 101, 101, 0.08); color: var(--error); }
|
|
533
|
+
.hf-dropdown__divider { height: 1px; background: var(--border-light); margin: 4px 0; }
|
|
534
|
+
|
|
535
|
+
/* ==========================================================================
|
|
536
|
+
Tooltip / Popover
|
|
537
|
+
========================================================================== */
|
|
538
|
+
.hf-tooltip {
|
|
539
|
+
position: relative;
|
|
540
|
+
background: var(--text-primary);
|
|
541
|
+
color: var(--white);
|
|
542
|
+
font-size: 12px;
|
|
543
|
+
padding: 6px 10px;
|
|
544
|
+
border-radius: 4px;
|
|
545
|
+
display: inline-block;
|
|
546
|
+
box-shadow: var(--shadow-hover);
|
|
547
|
+
}
|
|
548
|
+
.hf-tooltip--up::after, .hf-tooltip--down::after {
|
|
549
|
+
content: ""; position: absolute; left: 50%; transform: translateX(-50%);
|
|
550
|
+
border: 4px solid transparent;
|
|
551
|
+
}
|
|
552
|
+
.hf-tooltip--up::after { bottom: -8px; border-top-color: var(--text-primary); }
|
|
553
|
+
.hf-tooltip--down::after { top: -8px; border-bottom-color: var(--text-primary); }
|
|
554
|
+
|
|
555
|
+
.hf-popover {
|
|
556
|
+
background: var(--white);
|
|
557
|
+
border: 1px solid var(--border-light);
|
|
558
|
+
border-radius: 9px;
|
|
559
|
+
padding: 16px;
|
|
560
|
+
box-shadow: var(--shadow-tooltip);
|
|
561
|
+
max-width: 280px;
|
|
562
|
+
font-size: 13px;
|
|
563
|
+
color: var(--text-secondary);
|
|
564
|
+
}
|
|
565
|
+
.hf-popover__title { font-size: 14px; font-weight: 600; color: var(--text-primary); margin-bottom: 6px; }
|
|
566
|
+
|
|
567
|
+
/* ==========================================================================
|
|
568
|
+
Alerts (4 types)
|
|
569
|
+
========================================================================== */
|
|
570
|
+
.hf-alert {
|
|
571
|
+
border-radius: 9px;
|
|
572
|
+
padding: 14px 16px;
|
|
573
|
+
display: flex;
|
|
574
|
+
align-items: flex-start;
|
|
575
|
+
gap: 10px;
|
|
576
|
+
font-size: 14px;
|
|
577
|
+
border-left: 4px solid transparent;
|
|
578
|
+
}
|
|
579
|
+
.hf-alert__title { font-weight: 600; }
|
|
580
|
+
.hf-alert--success { background: rgba(89, 181, 157, 0.1); border-left-color: var(--success); color: #2A6B57; }
|
|
581
|
+
.hf-alert--warning { background: rgba(255, 189, 90, 0.15); border-left-color: var(--warning); color: #8A6300; }
|
|
582
|
+
.hf-alert--error { background: rgba(234, 101, 101, 0.1); border-left-color: var(--error); color: #8A2C2C; }
|
|
583
|
+
.hf-alert--info { background: var(--light-primary); border-left-color: var(--primary); color: #1A5F80; }
|
|
584
|
+
|
|
585
|
+
/* ==========================================================================
|
|
586
|
+
Toast
|
|
587
|
+
========================================================================== */
|
|
588
|
+
.hf-toast {
|
|
589
|
+
background: var(--white);
|
|
590
|
+
box-shadow: var(--shadow-tooltip);
|
|
591
|
+
border-radius: 9px;
|
|
592
|
+
padding: 16px;
|
|
593
|
+
display: flex;
|
|
594
|
+
align-items: flex-start;
|
|
595
|
+
gap: 12px;
|
|
596
|
+
min-width: 320px;
|
|
597
|
+
max-width: 420px;
|
|
598
|
+
border-left: 4px solid var(--primary);
|
|
599
|
+
}
|
|
600
|
+
.hf-toast--success { border-left-color: var(--success); }
|
|
601
|
+
.hf-toast--warning { border-left-color: var(--warning); }
|
|
602
|
+
.hf-toast--error { border-left-color: var(--error); }
|
|
603
|
+
|
|
604
|
+
/* ==========================================================================
|
|
605
|
+
Pagination
|
|
606
|
+
========================================================================== */
|
|
607
|
+
.hf-pagination { display: inline-flex; gap: 4px; }
|
|
608
|
+
.hf-pagination__page {
|
|
609
|
+
width: 32px; height: 32px;
|
|
610
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
611
|
+
border-radius: 6px;
|
|
612
|
+
font-size: 13px;
|
|
613
|
+
color: var(--text-secondary);
|
|
614
|
+
cursor: pointer;
|
|
615
|
+
background: transparent;
|
|
616
|
+
border: 0;
|
|
617
|
+
transition: all 200ms ease-in-out;
|
|
618
|
+
}
|
|
619
|
+
.hf-pagination__page:hover { background: var(--bg-muted); color: var(--text-primary); }
|
|
620
|
+
.hf-pagination__page.is-active { background: var(--primary); color: var(--white); box-shadow: var(--shadow-hover); }
|
|
621
|
+
.hf-pagination__page.is-disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
|
622
|
+
|
|
623
|
+
/* ==========================================================================
|
|
624
|
+
Breadcrumbs
|
|
625
|
+
========================================================================== */
|
|
626
|
+
.hf-breadcrumb { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-secondary); }
|
|
627
|
+
.hf-breadcrumb__item { color: var(--text-secondary); cursor: pointer; }
|
|
628
|
+
.hf-breadcrumb__item:hover { color: var(--primary); }
|
|
629
|
+
.hf-breadcrumb__item.is-current { color: var(--text-primary); font-weight: 500; cursor: default; }
|
|
630
|
+
.hf-breadcrumb__sep { color: var(--placeholder); margin: 0 6px; user-select: none; }
|
|
631
|
+
|
|
632
|
+
/* ==========================================================================
|
|
633
|
+
Empty state + Skeleton
|
|
634
|
+
========================================================================== */
|
|
635
|
+
.hf-empty {
|
|
636
|
+
text-align: center;
|
|
637
|
+
padding: 48px 20px;
|
|
638
|
+
color: var(--text-secondary);
|
|
639
|
+
}
|
|
640
|
+
.hf-empty__icon { color: var(--placeholder); width: 48px; height: 48px; margin: 0 auto 16px; }
|
|
641
|
+
.hf-empty__title { font-size: 16px; font-weight: 600; color: var(--text-primary); margin-bottom: 6px; }
|
|
642
|
+
.hf-empty__desc { font-size: 14px; max-width: 360px; margin: 0 auto 16px; }
|
|
643
|
+
|
|
644
|
+
.hf-skel {
|
|
645
|
+
background: linear-gradient(90deg, var(--border-light) 0%, #F7F9FB 50%, var(--border-light) 100%);
|
|
646
|
+
background-size: 800px 100%;
|
|
647
|
+
border-radius: 6px;
|
|
648
|
+
height: 14px;
|
|
649
|
+
animation: hf-shimmer 1.4s linear infinite;
|
|
650
|
+
}
|
|
651
|
+
.hf-skel--lg { height: 22px; }
|
|
652
|
+
.hf-skel--circle { border-radius: 50%; height: 40px; width: 40px; }
|
|
653
|
+
|
|
654
|
+
/* ==========================================================================
|
|
655
|
+
Datepicker / Timepicker preview
|
|
656
|
+
========================================================================== */
|
|
657
|
+
.hf-datepicker {
|
|
658
|
+
background: var(--white);
|
|
659
|
+
border: 1px solid var(--border-light);
|
|
660
|
+
border-radius: 9px;
|
|
661
|
+
box-shadow: var(--shadow-tooltip);
|
|
662
|
+
padding: 12px;
|
|
663
|
+
width: 280px;
|
|
664
|
+
font-size: 13px;
|
|
665
|
+
}
|
|
666
|
+
.hf-datepicker__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 4px; }
|
|
667
|
+
.hf-datepicker__title { font-weight: 600; color: var(--text-primary); }
|
|
668
|
+
.hf-datepicker__nav { background: var(--bg-muted); border: 0; border-radius: 4px; width: 24px; height: 24px; cursor: pointer; }
|
|
669
|
+
.hf-datepicker__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
|
|
670
|
+
.hf-datepicker__cell {
|
|
671
|
+
text-align: center; padding: 6px 0; border-radius: 6px; cursor: pointer;
|
|
672
|
+
color: var(--text-primary);
|
|
673
|
+
}
|
|
674
|
+
.hf-datepicker__cell:hover { background: var(--bg-muted); }
|
|
675
|
+
.hf-datepicker__cell.is-other-month { color: var(--placeholder); }
|
|
676
|
+
.hf-datepicker__cell.is-today { font-weight: 600; color: var(--primary); }
|
|
677
|
+
.hf-datepicker__cell.is-selected { background: var(--primary); color: var(--white); }
|
|
678
|
+
.hf-datepicker__weekday { color: var(--placeholder); font-size: 11px; font-weight: 500; text-align: center; padding: 4px 0; }
|
|
679
|
+
|
|
680
|
+
.hf-timepicker {
|
|
681
|
+
background: var(--white);
|
|
682
|
+
border: 1px solid var(--border-light);
|
|
683
|
+
border-radius: 9px;
|
|
684
|
+
box-shadow: var(--shadow-tooltip);
|
|
685
|
+
padding: 12px;
|
|
686
|
+
display: inline-flex;
|
|
687
|
+
gap: 8px;
|
|
688
|
+
align-items: center;
|
|
689
|
+
font-size: 14px;
|
|
690
|
+
}
|
|
691
|
+
.hf-timepicker__col {
|
|
692
|
+
display: flex; flex-direction: column; align-items: center;
|
|
693
|
+
color: var(--text-primary);
|
|
694
|
+
border: 1px solid var(--border-light);
|
|
695
|
+
border-radius: 6px;
|
|
696
|
+
min-width: 48px;
|
|
697
|
+
}
|
|
698
|
+
.hf-timepicker__btn { background: transparent; border: 0; cursor: pointer; padding: 2px 0; color: var(--text-secondary); }
|
|
699
|
+
.hf-timepicker__btn:hover { color: var(--primary); }
|
|
700
|
+
.hf-timepicker__val { padding: 4px 8px; font-weight: 600; }
|
|
701
|
+
|
|
702
|
+
/* ==========================================================================
|
|
703
|
+
Cards (3 variants)
|
|
704
|
+
========================================================================== */
|
|
705
|
+
.hf-card-elev {
|
|
706
|
+
background: var(--white);
|
|
707
|
+
border-radius: 12px;
|
|
708
|
+
box-shadow: var(--shadow-default);
|
|
709
|
+
padding: 20px;
|
|
710
|
+
}
|
|
711
|
+
.hf-card-flat {
|
|
712
|
+
background: var(--bg-page);
|
|
713
|
+
border: 1px solid var(--border-light);
|
|
714
|
+
border-radius: 12px;
|
|
715
|
+
padding: 20px;
|
|
716
|
+
}
|
|
717
|
+
.hf-card-stat {
|
|
718
|
+
background: var(--white);
|
|
719
|
+
border: 1px solid var(--border-light);
|
|
720
|
+
border-radius: 12px;
|
|
721
|
+
padding: 20px;
|
|
722
|
+
display: flex;
|
|
723
|
+
align-items: flex-start;
|
|
724
|
+
gap: 16px;
|
|
725
|
+
}
|
|
726
|
+
.hf-card-stat__icon {
|
|
727
|
+
width: 48px; height: 48px; border-radius: 12px;
|
|
728
|
+
background: var(--light-primary);
|
|
729
|
+
color: var(--primary);
|
|
730
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/* ==========================================================================
|
|
734
|
+
Code snippets
|
|
735
|
+
========================================================================== */
|
|
736
|
+
.hf-snippet {
|
|
737
|
+
position: relative;
|
|
738
|
+
margin-top: 16px;
|
|
739
|
+
border: 1px solid var(--border-light);
|
|
740
|
+
border-radius: 9px;
|
|
741
|
+
background: #FAFBFC;
|
|
742
|
+
overflow: hidden;
|
|
743
|
+
}
|
|
744
|
+
.hf-snippet pre {
|
|
745
|
+
padding: 12px 16px;
|
|
746
|
+
font-size: 12.5px;
|
|
747
|
+
line-height: 1.5;
|
|
748
|
+
color: #2B2B2B;
|
|
749
|
+
font-family: ui-monospace, "SF Mono", "Roboto Mono", Menlo, monospace;
|
|
750
|
+
margin: 0;
|
|
751
|
+
overflow-x: auto;
|
|
752
|
+
}
|
|
753
|
+
.hf-snippet button.copy {
|
|
754
|
+
position: absolute; top: 6px; right: 6px;
|
|
755
|
+
background: var(--white); border: 1px solid var(--border-light);
|
|
756
|
+
border-radius: 6px; padding: 4px 8px; font-size: 11px;
|
|
757
|
+
cursor: pointer; color: var(--text-secondary); font-weight: 500;
|
|
758
|
+
}
|
|
759
|
+
.hf-snippet button.copy:hover { color: var(--primary); border-color: var(--primary); }
|
|
760
|
+
.hf-snippet button.copy.copied { color: var(--success); border-color: var(--success); }
|
|
761
|
+
|
|
762
|
+
/* Spacing scale */
|
|
763
|
+
.hf-spacing-row {
|
|
764
|
+
display: flex; align-items: center; gap: 16px;
|
|
765
|
+
font-family: ui-monospace, "SF Mono", "Roboto Mono", Menlo, monospace;
|
|
766
|
+
font-size: 12px;
|
|
767
|
+
}
|
|
768
|
+
.hf-spacing-bar {
|
|
769
|
+
background: var(--primary);
|
|
770
|
+
height: 12px;
|
|
771
|
+
border-radius: 2px;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/* Icon grid */
|
|
775
|
+
.hf-icon-cell {
|
|
776
|
+
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
|
777
|
+
padding: 14px 6px;
|
|
778
|
+
border: 1px solid var(--border-light);
|
|
779
|
+
border-radius: 8px;
|
|
780
|
+
font-size: 11px;
|
|
781
|
+
color: var(--text-secondary);
|
|
782
|
+
background: var(--white);
|
|
783
|
+
}
|
|
784
|
+
.hf-icon-cell svg { color: var(--text-primary); }
|
|
785
|
+
|
|
786
|
+
/* States legend */
|
|
787
|
+
.states-grid {
|
|
788
|
+
display: grid;
|
|
789
|
+
grid-template-columns: 130px repeat(6, 1fr);
|
|
790
|
+
gap: 12px 16px;
|
|
791
|
+
align-items: center;
|
|
792
|
+
font-size: 12px;
|
|
793
|
+
}
|
|
794
|
+
.states-grid > .label {
|
|
795
|
+
font-family: ui-monospace, "SF Mono", "Roboto Mono", Menlo, monospace;
|
|
796
|
+
font-size: 11px;
|
|
797
|
+
font-weight: 600;
|
|
798
|
+
color: var(--text-secondary);
|
|
799
|
+
text-transform: uppercase;
|
|
800
|
+
letter-spacing: 0.05em;
|
|
801
|
+
}
|
|
802
|
+
.states-grid > .head {
|
|
803
|
+
font-weight: 600; color: var(--placeholder);
|
|
804
|
+
text-align: center;
|
|
805
|
+
padding-bottom: 8px;
|
|
806
|
+
border-bottom: 1px solid var(--border-light);
|
|
807
|
+
font-size: 11px;
|
|
808
|
+
text-transform: uppercase;
|
|
809
|
+
letter-spacing: 0.05em;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/* Documentation UI Specifics */
|
|
813
|
+
.sg-section-title { font-size: 24px; font-weight: 600; margin-bottom: 8px; color: var(--text-primary); border-bottom: 2px solid var(--border-light); padding-bottom: 12px; }
|
|
814
|
+
.sg-section-desc { font-size: 15px; color: var(--text-secondary); margin-bottom: 32px; }
|
|
815
|
+
.sg-swatch { width: 100%; height: 64px; border-radius: 8px 8px 0 0; }
|
|
816
|
+
.sg-box { border: 1px solid var(--border-light); border-radius: 8px; overflow: hidden; background: var(--white); }
|
|
817
|
+
.sg-h3 { font-size: 16px; font-weight: 600; margin: 32px 0 12px; color: var(--text-primary); }
|
|
818
|
+
html { scroll-behavior: smooth; }
|
|
819
|
+
</style>
|
|
820
|
+
</head>
|
|
821
|
+
<body class="flex flex-col h-screen overflow-hidden">
|
|
822
|
+
|
|
823
|
+
<!-- ════════════════════════════════════════════════════════════════
|
|
824
|
+
ARCHIVAL BANNER — do not remove. Marks this file as legacy.
|
|
825
|
+
For new code, use components.html instead.
|
|
826
|
+
════════════════════════════════════════════════════════════════ -->
|
|
827
|
+
<div style="
|
|
828
|
+
flex-shrink: 0;
|
|
829
|
+
background: #FFBD5A;
|
|
830
|
+
color: #2B2B2B;
|
|
831
|
+
padding: 10px 20px;
|
|
832
|
+
font-family: 'Roboto', sans-serif;
|
|
833
|
+
font-size: 13px;
|
|
834
|
+
line-height: 1.4;
|
|
835
|
+
border-bottom: 1px solid rgba(0,0,0,0.1);
|
|
836
|
+
display: flex;
|
|
837
|
+
align-items: center;
|
|
838
|
+
gap: 12px;
|
|
839
|
+
">
|
|
840
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink: 0">
|
|
841
|
+
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
|
842
|
+
<line x1="12" y1="9" x2="12" y2="13"/>
|
|
843
|
+
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
|
844
|
+
</svg>
|
|
845
|
+
<div style="flex: 1">
|
|
846
|
+
<strong>Archival snapshot — legacy portal audit.</strong>
|
|
847
|
+
This file documents what the HotelFriend portal CURRENTLY ships (drift detection & migration tracking). It is NOT the canonical design system for new code.
|
|
848
|
+
<br>
|
|
849
|
+
<span style="opacity: .85">
|
|
850
|
+
→ Canonical visual reference for new projects: <a href="components.html" style="color: #2B2B2B; font-weight: 600; text-decoration: underline">components.html</a>
|
|
851
|
+
·
|
|
852
|
+
→ Narrative SSOT: <a href="UI_DESIGN.md" style="color: #2B2B2B; font-weight: 600; text-decoration: underline">UI_DESIGN.md</a>
|
|
853
|
+
</span>
|
|
854
|
+
</div>
|
|
855
|
+
</div>
|
|
856
|
+
|
|
857
|
+
<!-- Main wrapper (preserves original layout) -->
|
|
858
|
+
<div class="flex flex-1 overflow-hidden">
|
|
859
|
+
|
|
860
|
+
<!-- Sidebar Navigation -->
|
|
861
|
+
<aside class="w-[260px] flex-shrink-0 bg-[#FBFBFC] border-r border-[#E4E8EF] h-full flex flex-col z-10 relative">
|
|
862
|
+
<div class="p-6 border-b border-[#E4E8EF]">
|
|
863
|
+
<div class="font-semibold text-[18px] text-[#24AFE8] flex items-center gap-2">
|
|
864
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
|
|
865
|
+
HotelFriend
|
|
866
|
+
</div>
|
|
867
|
+
<div class="text-[13px] text-[#99A1B7] mt-1 font-medium">Enterprise UI Design System</div>
|
|
868
|
+
</div>
|
|
869
|
+
<nav class="p-4 space-y-1 overflow-y-auto">
|
|
870
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-4 px-3">Foundations</div>
|
|
871
|
+
<a href="#colors" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Colors</a>
|
|
872
|
+
<a href="#typography" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Typography</a>
|
|
873
|
+
<a href="#spacing-scale" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Spacing scale</a>
|
|
874
|
+
<a href="#spacing-radius" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Shadows & Radius</a>
|
|
875
|
+
<a href="#icons" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Icons</a>
|
|
876
|
+
|
|
877
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Actions</div>
|
|
878
|
+
<a href="#buttons" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Buttons (states)</a>
|
|
879
|
+
<a href="#status-pills" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Badges & Pills</a>
|
|
880
|
+
|
|
881
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Forms</div>
|
|
882
|
+
<a href="#forms" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Inputs (states)</a>
|
|
883
|
+
<a href="#advanced-form" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Advanced (Switch, RTE, FileInput)</a>
|
|
884
|
+
<a href="#datepickers" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Date / Time pickers</a>
|
|
885
|
+
|
|
886
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Containers</div>
|
|
887
|
+
<a href="#cards" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Cards</a>
|
|
888
|
+
<a href="#modals" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Modals</a>
|
|
889
|
+
<a href="#tabs" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Tabs</a>
|
|
890
|
+
|
|
891
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Overlays</div>
|
|
892
|
+
<a href="#dropdowns" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Dropdowns</a>
|
|
893
|
+
<a href="#tooltips" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Tooltips & Popovers</a>
|
|
894
|
+
<a href="#alerts-toasts" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Alerts & Toasts</a>
|
|
895
|
+
|
|
896
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Navigation & State</div>
|
|
897
|
+
<a href="#pagination" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Pagination & Breadcrumbs</a>
|
|
898
|
+
<a href="#empty-skeleton" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Empty & Skeleton</a>
|
|
899
|
+
|
|
900
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Patterns</div>
|
|
901
|
+
<a href="#page-layout" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Canonical Page Layout</a>
|
|
902
|
+
|
|
903
|
+
<div class="text-[11px] font-semibold text-[#99A1B7] uppercase tracking-wider mb-2 mt-6 px-3">Live extracted</div>
|
|
904
|
+
<a href="#drift-dashboard" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Drift dashboard</a>
|
|
905
|
+
<a href="#live-states" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Live state declarations</a>
|
|
906
|
+
<a href="#live-modal-anatomy" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Modal anatomy (live)</a>
|
|
907
|
+
<a href="#extracted-summary" class="block px-3 py-2 text-[14px] text-[#4B5675] hover:bg-[#E9F6FC] hover:text-[#24AFE8] rounded-[6px] font-medium transition-colors">Catalog summary</a>
|
|
908
|
+
</nav>
|
|
909
|
+
</aside>
|
|
910
|
+
|
|
911
|
+
<!-- Main Content Area -->
|
|
912
|
+
<main class="flex-1 h-full overflow-y-auto bg-white">
|
|
913
|
+
<div class="max-w-[1100px] mx-auto p-12 space-y-24">
|
|
914
|
+
|
|
915
|
+
<!-- Header -->
|
|
916
|
+
<div>
|
|
917
|
+
<h1 class="text-[36px] font-semibold text-[#2B2B2B] leading-tight mb-4">UI Kit Reference</h1>
|
|
918
|
+
<p class="text-[16px] text-[#4B5675] max-w-[800px] leading-relaxed">
|
|
919
|
+
Welcome to the HotelFriend Single Source of Truth (SSOT). This document defines the exact CSS variables, typography rules, component anatomies, and spacing guidelines for all enterprise projects. It is completely framework-agnostic.
|
|
920
|
+
</p>
|
|
921
|
+
<div class="mt-6 max-w-[800px] p-4 rounded-[12px] border border-[#24AFE8] bg-[#E9F6FC]">
|
|
922
|
+
<div class="text-[14px] font-semibold text-[#2B2B2B] mb-1">📡 Live tokens audit (auto-refreshed)</div>
|
|
923
|
+
<p class="text-[13px] text-[#4B5675] leading-relaxed">
|
|
924
|
+
Tokens shown here are reconciled against compiled CSS via <code class="bg-white px-1 rounded">scratch/extract-all-pages.js</code>. Companion artefacts:
|
|
925
|
+
</p>
|
|
926
|
+
<ul class="list-disc pl-5 mt-2 text-[13px] text-[#4B5675] space-y-0.5">
|
|
927
|
+
<li><code class="bg-white px-1 rounded">docs/design-tokens.json</code> — every observed token + occurrence count</li>
|
|
928
|
+
<li><code class="bg-white px-1 rounded">docs/design-tokens-audit.md</code> — drift report (canonical vs live)</li>
|
|
929
|
+
<li><code class="bg-white px-1 rounded">docs/ui-elements-catalog.json</code> / <code class="bg-white px-1 rounded">.md</code> — full inventory across 13 sidebar pages + sub-tabs + edit forms</li>
|
|
930
|
+
<li><code class="bg-white px-1 rounded">docs/tokens.figma.json</code> — Tokens Studio import for Figma</li>
|
|
931
|
+
</ul>
|
|
932
|
+
</div>
|
|
933
|
+
</div>
|
|
934
|
+
|
|
935
|
+
<!-- 1. Colors -->
|
|
936
|
+
<section id="colors">
|
|
937
|
+
<h2 class="sg-section-title">Colors</h2>
|
|
938
|
+
<p class="sg-section-desc">Semantic color palette focusing on clean, readable interfaces.</p>
|
|
939
|
+
|
|
940
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-8">Primary & Accent</h3>
|
|
941
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
|
942
|
+
<div class="sg-box"><div class="sg-swatch bg-[#24AFE8]"></div><div class="p-3"><div class="font-medium text-[14px]">Primary</div><div class="text-[12px] text-[#99A1B7]">#24AFE8</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--primary</div></div></div>
|
|
943
|
+
<div class="sg-box ring-2 ring-amber-300"><div class="sg-swatch bg-[#26ADE4]"></div><div class="p-3"><div class="font-medium text-[14px]">Portal legacy <span class="text-amber-500">⚠ A1</span></div><div class="text-[12px] text-[#99A1B7]">#26ADE4</div><div class="text-[11px] mt-2 font-mono bg-amber-100 px-1 rounded inline-block">$primary (pending A1)</div></div></div>
|
|
944
|
+
<div class="sg-box"><div class="sg-swatch bg-[#149AD1]"></div><div class="p-3"><div class="font-medium text-[14px]">Primary Hover</div><div class="text-[12px] text-[#99A1B7]">#149AD1</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--primary-hover</div></div></div>
|
|
945
|
+
<div class="sg-box"><div class="sg-swatch bg-[#E9F6FC]"></div><div class="p-3"><div class="font-medium text-[14px]">Light Primary</div><div class="text-[12px] text-[#99A1B7]">#E9F6FC</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--light-primary</div></div></div>
|
|
946
|
+
<div class="sg-box"><div class="sg-swatch bg-[#EFF6FF]"></div><div class="p-3"><div class="font-medium text-[14px]">Tint Bg</div><div class="text-[12px] text-[#99A1B7]">#EFF6FF</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--primary-tint-bg</div></div></div>
|
|
947
|
+
</div>
|
|
948
|
+
<p class="text-[13px] text-[#4B5675] mt-3"><strong class="text-amber-600">⚠</strong> Two near-identical primaries co-exist in portal compiled CSS. Canonical is <code class="font-mono bg-gray-100 px-1 rounded">#24AFE8</code> (<code>--color-primary-default</code>). Portal legacy SCSS <code>$primary: #26ADE4</code> is pending consolidation via migration-plan A1.</p>
|
|
949
|
+
|
|
950
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-10">Neutrals & Borders</h3>
|
|
951
|
+
<div class="grid grid-cols-2 md:grid-cols-5 gap-6">
|
|
952
|
+
<div class="sg-box"><div class="sg-swatch bg-[#FBFBFC] border-b border-[#E4E8EF]"></div><div class="p-3"><div class="font-medium text-[14px]">Page BG</div><div class="text-[12px] text-[#99A1B7]">#FBFBFC</div></div></div>
|
|
953
|
+
<div class="sg-box"><div class="sg-swatch bg-[#F6F7FB] border-b border-[#E4E8EF]"></div><div class="p-3"><div class="font-medium text-[14px]">Accent BG</div><div class="text-[12px] text-[#99A1B7]">#F6F7FB</div></div></div>
|
|
954
|
+
<div class="sg-box"><div class="sg-swatch bg-[#F1F3F6] border-b border-[#E4E8EF]"></div><div class="p-3"><div class="font-medium text-[14px]">Muted BG</div><div class="text-[12px] text-[#99A1B7]">#F1F3F6</div></div></div>
|
|
955
|
+
<div class="sg-box"><div class="sg-swatch bg-[#E4E8EF]"></div><div class="p-3"><div class="font-medium text-[14px]">Border Light</div><div class="text-[12px] text-[#99A1B7]">#E4E8EF</div></div></div>
|
|
956
|
+
<div class="sg-box"><div class="sg-swatch bg-[#D1D6DD]"></div><div class="p-3"><div class="font-medium text-[14px]">Border Default</div><div class="text-[12px] text-[#99A1B7]">#D1D6DD</div></div></div>
|
|
957
|
+
</div>
|
|
958
|
+
|
|
959
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-10">Status Colors</h3>
|
|
960
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
|
961
|
+
<div class="sg-box"><div class="sg-swatch bg-[#59B59D]"></div><div class="p-3"><div class="font-medium text-[14px]">Success</div><div class="text-[12px] text-[#99A1B7]">#59B59D</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--success</div></div></div>
|
|
962
|
+
<div class="sg-box"><div class="sg-swatch bg-[#FFBD5A]"></div><div class="p-3"><div class="font-medium text-[14px]">Warning</div><div class="text-[12px] text-[#99A1B7]">#FFBD5A</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--warning</div></div></div>
|
|
963
|
+
<div class="sg-box"><div class="sg-swatch bg-[#FFC900]"></div><div class="p-3"><div class="font-medium text-[14px]">Warning Strong</div><div class="text-[12px] text-[#99A1B7]">#FFC900</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">frontDesk OOO</div></div></div>
|
|
964
|
+
<div class="sg-box"><div class="sg-swatch bg-[#EA6565]"></div><div class="p-3"><div class="font-medium text-[14px]">Error</div><div class="text-[12px] text-[#99A1B7]">#EA6565</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--error</div></div></div>
|
|
965
|
+
<div class="sg-box"><div class="sg-swatch bg-[#F87921]"></div><div class="p-3"><div class="font-medium text-[14px]">Coral</div><div class="text-[12px] text-[#99A1B7]">#F87921</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--coral / check-out</div></div></div>
|
|
966
|
+
<div class="sg-box"><div class="sg-swatch bg-[#5761D8]"></div><div class="p-3"><div class="font-medium text-[14px]">Violet</div><div class="text-[12px] text-[#99A1B7]">#5761D8</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--violet / offer</div></div></div>
|
|
967
|
+
<div class="sg-box"><div class="sg-swatch bg-[#7F8FA4]"></div><div class="p-3"><div class="font-medium text-[14px]">Canceled gray</div><div class="text-[12px] text-[#99A1B7]">#7F8FA4</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--canceled-gray</div></div></div>
|
|
968
|
+
<div class="sg-box"><div class="sg-swatch bg-[#5B7A02]"></div><div class="p-3"><div class="font-medium text-[14px]">Check-in olive</div><div class="text-[12px] text-[#99A1B7]">#5B7A02</div><div class="text-[11px] mt-2 font-mono bg-gray-100 px-1 rounded inline-block">--check-in-olive</div></div></div>
|
|
969
|
+
</div>
|
|
970
|
+
<p class="text-[13px] text-[#4B5675] mt-3">Each domain status (booking, order, frontDesk, roomItem) ships <code>--status-{domain}-{status}-color</code> + <code>--status-{domain}-{status}-bg-color</code> (15% alpha). See <a href="#buttons" class="text-[#24AFE8] underline">Status pills (full token system)</a> below.</p>
|
|
971
|
+
</section>
|
|
972
|
+
|
|
973
|
+
<!-- 2. Typography -->
|
|
974
|
+
<section id="typography">
|
|
975
|
+
<h2 class="sg-section-title">Typography</h2>
|
|
976
|
+
<p class="sg-section-desc">Roboto is the core font. Strict constraints on line-heights are enforced.</p>
|
|
977
|
+
|
|
978
|
+
<div class="bg-[#FBFBFC] border border-[#E4E8EF] rounded-[12px] p-8 space-y-8">
|
|
979
|
+
<div class="flex items-end gap-10 border-b border-[#E4E8EF] pb-4">
|
|
980
|
+
<div class="w-[120px] text-[13px] text-[#99A1B7] font-mono">26px / 600 / 1.2</div>
|
|
981
|
+
<div class="hf-text-pagetitle">Page Title Header</div>
|
|
982
|
+
</div>
|
|
983
|
+
<div class="flex items-end gap-10 border-b border-[#E4E8EF] pb-4">
|
|
984
|
+
<div class="w-[120px] text-[13px] text-[#99A1B7] font-mono">14px / 500 / 1.5</div>
|
|
985
|
+
<div class="hf-text-medium">Medium Text (Tabs, Buttons, Subheadings)</div>
|
|
986
|
+
</div>
|
|
987
|
+
<div class="flex items-end gap-10 border-b border-[#E4E8EF] pb-4">
|
|
988
|
+
<div class="w-[120px] text-[13px] text-[#99A1B7] font-mono">14px / 400 / 1.5</div>
|
|
989
|
+
<div class="hf-text-general text-[#4B5675]">General Body Text. Used for descriptions, table data, and standard reading blocks.</div>
|
|
990
|
+
</div>
|
|
991
|
+
<div class="flex items-end gap-10 border-b border-[#E4E8EF] pb-4">
|
|
992
|
+
<div class="w-[120px] text-[13px] text-[#99A1B7] font-mono">13px / 500 / 1.5</div>
|
|
993
|
+
<div class="hf-text-gridhead text-[#4B5675]">Table Header / Tooltips</div>
|
|
994
|
+
</div>
|
|
995
|
+
<div class="flex items-center gap-10">
|
|
996
|
+
<div class="w-[120px] text-[13px] text-[#99A1B7] font-mono">11px / 500 / 1.2</div>
|
|
997
|
+
<div class="hf-text-label text-[#99A1B7]">UPPERCASE CAPTION</div>
|
|
998
|
+
</div>
|
|
999
|
+
</div>
|
|
1000
|
+
</section>
|
|
1001
|
+
|
|
1002
|
+
<!-- 3. Spacing & Radius -->
|
|
1003
|
+
<section id="spacing-radius">
|
|
1004
|
+
<h2 class="sg-section-title">Shadows & Border Radius</h2>
|
|
1005
|
+
<p class="sg-section-desc">Consistent structural rounding and elevation layers.</p>
|
|
1006
|
+
|
|
1007
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-8">
|
|
1008
|
+
<div>
|
|
1009
|
+
<div class="h-[100px] bg-white border border-[#D1D6DD] rounded-[6px] flex items-center justify-center mb-3">6px</div>
|
|
1010
|
+
<div class="text-[14px] font-medium">sm (6px)</div>
|
|
1011
|
+
<div class="text-[12px] text-[#99A1B7]">Inputs, Buttons</div>
|
|
1012
|
+
</div>
|
|
1013
|
+
<div>
|
|
1014
|
+
<div class="h-[100px] bg-white border border-[#D1D6DD] rounded-[9px] flex items-center justify-center mb-3">9px</div>
|
|
1015
|
+
<div class="text-[14px] font-medium">xl (9px)</div>
|
|
1016
|
+
<div class="text-[12px] text-[#99A1B7]">Dropdowns, Alerts</div>
|
|
1017
|
+
</div>
|
|
1018
|
+
<div>
|
|
1019
|
+
<div class="h-[100px] bg-white border border-[#D1D6DD] rounded-[12px] flex items-center justify-center mb-3">12px</div>
|
|
1020
|
+
<div class="text-[14px] font-medium">xxl (12px)</div>
|
|
1021
|
+
<div class="text-[12px] text-[#99A1B7]">Cards, Modals, Wrappers</div>
|
|
1022
|
+
</div>
|
|
1023
|
+
<div>
|
|
1024
|
+
<div class="h-[100px] bg-white border border-[#D1D6DD] rounded-full flex items-center justify-center mb-3">99px</div>
|
|
1025
|
+
<div class="text-[14px] font-medium">pill (99px)</div>
|
|
1026
|
+
<div class="text-[12px] text-[#99A1B7]">Badges, Avatars</div>
|
|
1027
|
+
</div>
|
|
1028
|
+
</div>
|
|
1029
|
+
|
|
1030
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mt-12">
|
|
1031
|
+
<div class="bg-[#FBFBFC] p-8 rounded-[12px] border border-[#E4E8EF] flex items-center justify-center h-[200px]">
|
|
1032
|
+
<div class="bg-white rounded-[12px] w-[200px] h-[100px] flex items-center justify-center text-[14px] font-medium shadow-[0_3px_4px_rgba(0,0,0,0.03)] border border-[#E4E8EF]">
|
|
1033
|
+
--shadow-wrapper
|
|
1034
|
+
</div>
|
|
1035
|
+
</div>
|
|
1036
|
+
<div class="bg-[#FBFBFC] p-8 rounded-[12px] border border-[#E4E8EF] flex items-center justify-center h-[200px]">
|
|
1037
|
+
<div class="bg-white rounded-[12px] w-[200px] h-[100px] flex items-center justify-center text-[14px] font-medium shadow-[0_12px_24px_rgba(26,26,30,0.06)] border border-[#E4E8EF]">
|
|
1038
|
+
--shadow-card
|
|
1039
|
+
</div>
|
|
1040
|
+
</div>
|
|
1041
|
+
</div>
|
|
1042
|
+
</section>
|
|
1043
|
+
|
|
1044
|
+
<!-- 3.1 Spacing scale -->
|
|
1045
|
+
<section id="spacing-scale">
|
|
1046
|
+
<h2 class="sg-section-title">Spacing scale</h2>
|
|
1047
|
+
<p class="sg-section-desc">Base unit 4px. Default section gap <code class="bg-gray-100 px-1 rounded">20px</code>. The wrapper padding (<code class="bg-gray-100 px-1 rounded">--wrapper-padding</code>) is also 20px. Use these — never arbitrary values like 7px / 13px / 18px.</p>
|
|
1048
|
+
|
|
1049
|
+
<div class="hf-card-elev space-y-3">
|
|
1050
|
+
<div class="hf-spacing-row"><div class="w-12">0</div><div>0px</div></div>
|
|
1051
|
+
<div class="hf-spacing-row"><div class="w-12">1</div><div class="hf-spacing-bar" style="width:4px"></div><div>4px</div></div>
|
|
1052
|
+
<div class="hf-spacing-row"><div class="w-12">2</div><div class="hf-spacing-bar" style="width:8px"></div><div>8px</div></div>
|
|
1053
|
+
<div class="hf-spacing-row"><div class="w-12">3</div><div class="hf-spacing-bar" style="width:12px"></div><div>12px</div></div>
|
|
1054
|
+
<div class="hf-spacing-row"><div class="w-12">4</div><div class="hf-spacing-bar" style="width:16px"></div><div>16px</div></div>
|
|
1055
|
+
<div class="hf-spacing-row"><div class="w-12">5</div><div class="hf-spacing-bar" style="width:20px"></div><div>20px <span class="text-[#99A1B7]">— default section gap</span></div></div>
|
|
1056
|
+
<div class="hf-spacing-row"><div class="w-12">6</div><div class="hf-spacing-bar" style="width:24px"></div><div>24px</div></div>
|
|
1057
|
+
<div class="hf-spacing-row"><div class="w-12">7</div><div class="hf-spacing-bar" style="width:30px"></div><div>30px</div></div>
|
|
1058
|
+
<div class="hf-spacing-row"><div class="w-12">8</div><div class="hf-spacing-bar" style="width:32px"></div><div>32px</div></div>
|
|
1059
|
+
</div>
|
|
1060
|
+
</section>
|
|
1061
|
+
|
|
1062
|
+
<!-- 3.2 Icons -->
|
|
1063
|
+
<section id="icons">
|
|
1064
|
+
<h2 class="sg-section-title">Icons</h2>
|
|
1065
|
+
<p class="sg-section-desc">The portal uses Font Awesome 4 (<code class="bg-gray-100 px-1 rounded">fa fa-*</code> classes) plus custom SVGs in <code class="bg-gray-100 px-1 rounded">/images/icons/</code>. New code should prefer inline SVG (Lucide / Heroicons) at 16/20/24px sizes for consistency. Do NOT mix sets within a single screen.</p>
|
|
1066
|
+
|
|
1067
|
+
<div class="hf-card-elev grid grid-cols-3 md:grid-cols-6 gap-3">
|
|
1068
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 21l-4.35-4.35"/><circle cx="11" cy="11" r="8"/></svg><div>search</div></div>
|
|
1069
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg><div>plus</div></div>
|
|
1070
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg><div>edit</div></div>
|
|
1071
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></svg><div>trash</div></div>
|
|
1072
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg><div>arrow-right</div></div>
|
|
1073
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg><div>arrow-left</div></div>
|
|
1074
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg><div>chevron-down</div></div>
|
|
1075
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg><div>chevron-right</div></div>
|
|
1076
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg><div>x / close</div></div>
|
|
1077
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg><div>info</div></div>
|
|
1078
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 22h20L12 2z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg><div>warning</div></div>
|
|
1079
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg><div>check</div></div>
|
|
1080
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h0a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg><div>settings</div></div>
|
|
1081
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg><div>calendar</div></div>
|
|
1082
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg><div>clock</div></div>
|
|
1083
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg><div>upload</div></div>
|
|
1084
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg><div>download</div></div>
|
|
1085
|
+
<div class="hf-icon-cell"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg><div>more-vertical</div></div>
|
|
1086
|
+
</div>
|
|
1087
|
+
|
|
1088
|
+
<div class="mt-6 hf-alert hf-alert--info">
|
|
1089
|
+
<div class="font-semibold">Audit needed</div>
|
|
1090
|
+
<div>Live portal mixes Font Awesome 4 (~50 classes), custom SVGs (<code>/images/icons/</code>), Glyphicons (Bootstrap 3 leftover), and inline SVG. Single-icon-set migration is unscheduled tech-debt.</div>
|
|
1091
|
+
</div>
|
|
1092
|
+
</section>
|
|
1093
|
+
|
|
1094
|
+
<!-- 4. Buttons & Badges -->
|
|
1095
|
+
<section id="buttons">
|
|
1096
|
+
<h2 class="sg-section-title">Buttons</h2>
|
|
1097
|
+
<p class="sg-section-desc">Full state matrix: every button variant in 6 states. Default state is what designers spec; hover/focus/active/disabled/loading map directly to Figma component variants.</p>
|
|
1098
|
+
|
|
1099
|
+
<div class="hf-card-elev mb-8">
|
|
1100
|
+
<div class="states-grid">
|
|
1101
|
+
<div></div>
|
|
1102
|
+
<div class="head">Default</div>
|
|
1103
|
+
<div class="head">Hover</div>
|
|
1104
|
+
<div class="head">Focus</div>
|
|
1105
|
+
<div class="head">Active</div>
|
|
1106
|
+
<div class="head">Disabled</div>
|
|
1107
|
+
<div class="head">Loading</div>
|
|
1108
|
+
|
|
1109
|
+
<div class="label">Primary</div>
|
|
1110
|
+
<div><button class="btn btn-primary">Save</button></div>
|
|
1111
|
+
<div><button class="btn btn-primary" data-state="hover">Save</button></div>
|
|
1112
|
+
<div><button class="btn btn-primary" data-state="focus">Save</button></div>
|
|
1113
|
+
<div><button class="btn btn-primary" data-state="active">Save</button></div>
|
|
1114
|
+
<div><button class="btn btn-primary" data-state="disabled">Save</button></div>
|
|
1115
|
+
<div><button class="btn btn-primary" data-state="loading">Save</button></div>
|
|
1116
|
+
|
|
1117
|
+
<div class="label">Outline</div>
|
|
1118
|
+
<div><button class="btn btn-outline">Cancel</button></div>
|
|
1119
|
+
<div><button class="btn btn-outline" data-state="hover">Cancel</button></div>
|
|
1120
|
+
<div><button class="btn btn-outline" data-state="focus">Cancel</button></div>
|
|
1121
|
+
<div><button class="btn btn-outline" data-state="active">Cancel</button></div>
|
|
1122
|
+
<div><button class="btn btn-outline" data-state="disabled">Cancel</button></div>
|
|
1123
|
+
<div><button class="btn btn-outline" data-state="loading">Cancel</button></div>
|
|
1124
|
+
|
|
1125
|
+
<div class="label">Cancel (gray)</div>
|
|
1126
|
+
<div><button class="btn btn-cancel">Discard</button></div>
|
|
1127
|
+
<div><button class="btn btn-cancel" data-state="hover">Discard</button></div>
|
|
1128
|
+
<div><button class="btn btn-cancel" data-state="focus">Discard</button></div>
|
|
1129
|
+
<div><button class="btn btn-cancel" data-state="active">Discard</button></div>
|
|
1130
|
+
<div><button class="btn btn-cancel" data-state="disabled">Discard</button></div>
|
|
1131
|
+
<div><button class="btn btn-cancel" data-state="loading">Discard</button></div>
|
|
1132
|
+
|
|
1133
|
+
<div class="label">Delete</div>
|
|
1134
|
+
<div><button class="btn btn-delete">Delete</button></div>
|
|
1135
|
+
<div><button class="btn btn-delete" data-state="hover">Delete</button></div>
|
|
1136
|
+
<div><button class="btn btn-delete" data-state="focus">Delete</button></div>
|
|
1137
|
+
<div><button class="btn btn-delete" data-state="active">Delete</button></div>
|
|
1138
|
+
<div><button class="btn btn-delete" data-state="disabled">Delete</button></div>
|
|
1139
|
+
<div><button class="btn btn-delete" data-state="loading">Delete</button></div>
|
|
1140
|
+
</div>
|
|
1141
|
+
|
|
1142
|
+
<div class="hf-snippet">
|
|
1143
|
+
<button class="copy" data-copy>Copy</button>
|
|
1144
|
+
<pre><button class="btn btn-primary">Save</button>
|
|
1145
|
+
<button class="btn btn-outline">Cancel</button>
|
|
1146
|
+
<button class="btn btn-cancel">Discard</button>
|
|
1147
|
+
<button class="btn btn-delete">Delete</button></pre>
|
|
1148
|
+
</div>
|
|
1149
|
+
</div>
|
|
1150
|
+
|
|
1151
|
+
<h3 class="sg-h3">Sizes</h3>
|
|
1152
|
+
<div class="hf-card-elev flex items-center flex-wrap gap-6">
|
|
1153
|
+
<button class="btn btn-primary" style="height: 40px; padding: 10px 20px;">Default 40px</button>
|
|
1154
|
+
<button class="btn btn-primary" style="height: 38px; padding: 10px 13px; font-size: 15px;">Search 38px</button>
|
|
1155
|
+
<button class="btn btn-primary" style="height: 32px; padding: 7px 14px; font-size: 12px;">Small 32px</button>
|
|
1156
|
+
<button class="btn btn-icon-only" title="More">⋮</button>
|
|
1157
|
+
</div>
|
|
1158
|
+
<div class="hf-snippet">
|
|
1159
|
+
<button class="copy" data-copy>Copy</button>
|
|
1160
|
+
<pre><!-- 40px default -->
|
|
1161
|
+
<button class="btn btn-primary">Default</button>
|
|
1162
|
+
<!-- 38px inline-search submit -->
|
|
1163
|
+
<button class="btn btn-primary pr13">Search</button>
|
|
1164
|
+
<!-- 32px small -->
|
|
1165
|
+
<button class="btn btn-primary btn-sm">Small</button>
|
|
1166
|
+
<!-- icon-only -->
|
|
1167
|
+
<button class="btn-icon-only">⋮</button></pre>
|
|
1168
|
+
</div>
|
|
1169
|
+
|
|
1170
|
+
<h3 class="sg-h3">Live extra variants (extracted from portal)</h3>
|
|
1171
|
+
<div class="hf-card-elev flex flex-wrap gap-4 items-center">
|
|
1172
|
+
<button class="btn btn-reset-filters">
|
|
1173
|
+
<span class="absolute left-[10px]">⟳</span> Reset Filters
|
|
1174
|
+
</button>
|
|
1175
|
+
<button class="btn btn-neutral-outline">No App</button>
|
|
1176
|
+
<button class="btn btn-neutral-outline" style="border-radius:0 6px 6px 0; margin-left:-1px">With App</button>
|
|
1177
|
+
<button class="btn-text-link">Show details</button>
|
|
1178
|
+
</div>
|
|
1179
|
+
<div class="hf-snippet">
|
|
1180
|
+
<button class="copy" data-copy>Copy</button>
|
|
1181
|
+
<pre><button class="btn btn-reset-filters">⟳ Reset Filters</button>
|
|
1182
|
+
<button class="btn btn-neutral-outline">No App</button>
|
|
1183
|
+
<button class="btn-text-link">Show details</button></pre>
|
|
1184
|
+
</div>
|
|
1185
|
+
</section>
|
|
1186
|
+
|
|
1187
|
+
<!-- 4.1 Status pills + Badges -->
|
|
1188
|
+
<section id="status-pills">
|
|
1189
|
+
<h2 class="sg-section-title">Badges & Status pills</h2>
|
|
1190
|
+
<p class="sg-section-desc">Each domain (booking, order, frontDesk, roomItem cleaning) ships <code class="bg-gray-100 px-1 rounded">--status-{domain}-{status}-color</code> + a 15% alpha bg variant. Soft badges (caption-style) are separate.</p>
|
|
1191
|
+
|
|
1192
|
+
<h3 class="sg-h3">Status pills (full token system)</h3>
|
|
1193
|
+
<div class="hf-card grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
1194
|
+
<div>
|
|
1195
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] mb-2 tracking-wider">Booking</div>
|
|
1196
|
+
<div class="flex flex-wrap gap-2">
|
|
1197
|
+
<span class="hf-pill status-booking-new">New</span>
|
|
1198
|
+
<span class="hf-pill status-booking-offer">Offer</span>
|
|
1199
|
+
<span class="hf-pill status-booking-confirmed">Confirmed</span>
|
|
1200
|
+
<span class="hf-pill status-booking-check-in">Check-in</span>
|
|
1201
|
+
<span class="hf-pill status-booking-check-out">Check-out</span>
|
|
1202
|
+
<span class="hf-pill status-booking-no-show">No-show</span>
|
|
1203
|
+
<span class="hf-pill status-booking-due-in">Due-in</span>
|
|
1204
|
+
<span class="hf-pill status-booking-due-out">Due-out</span>
|
|
1205
|
+
<span class="hf-pill status-booking-canceled">Canceled</span>
|
|
1206
|
+
</div>
|
|
1207
|
+
</div>
|
|
1208
|
+
<div>
|
|
1209
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] mb-2 tracking-wider">Order</div>
|
|
1210
|
+
<div class="flex flex-wrap gap-2">
|
|
1211
|
+
<span class="hf-pill status-order-waiting">Waiting</span>
|
|
1212
|
+
<span class="hf-pill status-order-confirmed">Confirmed</span>
|
|
1213
|
+
<span class="hf-pill status-order-completed">Completed</span>
|
|
1214
|
+
<span class="hf-pill status-order-action-required">Action req.</span>
|
|
1215
|
+
</div>
|
|
1216
|
+
</div>
|
|
1217
|
+
<div>
|
|
1218
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] mb-2 tracking-wider">Cleaning</div>
|
|
1219
|
+
<div class="flex flex-wrap gap-2">
|
|
1220
|
+
<span class="hf-pill status-cleaning-clean">Clean</span>
|
|
1221
|
+
<span class="hf-pill status-cleaning-cleaning">Cleaning</span>
|
|
1222
|
+
<span class="hf-pill status-cleaning-dirty">Dirty</span>
|
|
1223
|
+
<span class="hf-pill status-cleaning-out-of-service">Out of service</span>
|
|
1224
|
+
<span class="hf-pill status-cleaning-inspected">Inspected</span>
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
<div>
|
|
1228
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] mb-2 tracking-wider">FrontDesk</div>
|
|
1229
|
+
<div class="flex flex-wrap gap-2">
|
|
1230
|
+
<span class="hf-pill status-fd-free">Free</span>
|
|
1231
|
+
<span class="hf-pill status-fd-busy">Busy</span>
|
|
1232
|
+
<span class="hf-pill status-fd-out-of-order">Out of order</span>
|
|
1233
|
+
</div>
|
|
1234
|
+
</div>
|
|
1235
|
+
</div>
|
|
1236
|
+
<div class="hf-snippet">
|
|
1237
|
+
<button class="copy" data-copy>Copy</button>
|
|
1238
|
+
<pre><span class="hf-pill status-booking-confirmed">Confirmed</span>
|
|
1239
|
+
<span class="hf-pill status-order-completed">Completed</span>
|
|
1240
|
+
<span class="hf-pill status-cleaning-dirty">Dirty</span></pre>
|
|
1241
|
+
</div>
|
|
1242
|
+
|
|
1243
|
+
<h3 class="sg-h3">Soft badges (small captions, 11px uppercase)</h3>
|
|
1244
|
+
<div class="hf-card flex gap-6">
|
|
1245
|
+
<span class="badge badge-soft-success">Active</span>
|
|
1246
|
+
<span class="badge badge-soft-warning">Waiting</span>
|
|
1247
|
+
<span class="badge badge-soft-error">Canceled</span>
|
|
1248
|
+
</div>
|
|
1249
|
+
<div class="hf-snippet">
|
|
1250
|
+
<button class="copy" data-copy>Copy</button>
|
|
1251
|
+
<pre><span class="badge badge-soft-success">Active</span>
|
|
1252
|
+
<span class="badge badge-soft-warning">Waiting</span>
|
|
1253
|
+
<span class="badge badge-soft-error">Canceled</span></pre>
|
|
1254
|
+
</div>
|
|
1255
|
+
</section>
|
|
1256
|
+
|
|
1257
|
+
<!-- 5. Forms -->
|
|
1258
|
+
<section id="forms">
|
|
1259
|
+
<h2 class="sg-section-title">Form Controls</h2>
|
|
1260
|
+
<p class="sg-section-desc">Inputs, selects, checkboxes, radios, textareas. Each control has 6 states + error / success variants. Standard height 39px (form-control), 38px (filter-bar), 40px (primary action).</p>
|
|
1261
|
+
|
|
1262
|
+
<h3 class="sg-h3">Text input — states</h3>
|
|
1263
|
+
<div class="hf-card-elev space-y-4">
|
|
1264
|
+
<div class="grid md:grid-cols-3 gap-4">
|
|
1265
|
+
<div>
|
|
1266
|
+
<label class="block hf-text-medium mb-2 form-required" for="if-d">Default</label>
|
|
1267
|
+
<input id="if-d" type="text" class="form-control" placeholder="Enter full name">
|
|
1268
|
+
</div>
|
|
1269
|
+
<div>
|
|
1270
|
+
<label class="block hf-text-medium mb-2" for="if-h">Hover</label>
|
|
1271
|
+
<input id="if-h" type="text" class="form-control" data-state="hover" placeholder="Hover">
|
|
1272
|
+
</div>
|
|
1273
|
+
<div>
|
|
1274
|
+
<label class="block hf-text-medium mb-2" for="if-f">Focus</label>
|
|
1275
|
+
<input id="if-f" type="text" class="form-control" data-state="focus" value="John Doe">
|
|
1276
|
+
</div>
|
|
1277
|
+
<div>
|
|
1278
|
+
<label class="block hf-text-medium mb-2" for="if-dis">Disabled</label>
|
|
1279
|
+
<input id="if-dis" type="text" class="form-control" data-state="disabled" value="Locked field" readonly>
|
|
1280
|
+
</div>
|
|
1281
|
+
<div>
|
|
1282
|
+
<label class="block hf-text-medium mb-2" for="if-err">Error</label>
|
|
1283
|
+
<input id="if-err" type="text" class="form-control form-control--error" value="not-an-email">
|
|
1284
|
+
<div class="form-helper form-helper--error">Please enter a valid email address.</div>
|
|
1285
|
+
</div>
|
|
1286
|
+
<div>
|
|
1287
|
+
<label class="block hf-text-medium mb-2" for="if-ok">Success</label>
|
|
1288
|
+
<input id="if-ok" type="text" class="form-control form-control--success" value="alex@hotelfriend.co">
|
|
1289
|
+
<div class="form-helper form-helper--success">Email available.</div>
|
|
1290
|
+
</div>
|
|
1291
|
+
</div>
|
|
1292
|
+
</div>
|
|
1293
|
+
<div class="hf-snippet">
|
|
1294
|
+
<button class="copy" data-copy>Copy</button>
|
|
1295
|
+
<pre><label class="form-label form-required" for="email">Email</label>
|
|
1296
|
+
<input id="email" type="text" class="form-control" placeholder="Enter email">
|
|
1297
|
+
<div class="form-helper">We never share your email.</div>
|
|
1298
|
+
|
|
1299
|
+
<!-- Error state -->
|
|
1300
|
+
<input class="form-control form-control--error" />
|
|
1301
|
+
<div class="form-helper form-helper--error">Required</div></pre>
|
|
1302
|
+
</div>
|
|
1303
|
+
|
|
1304
|
+
<h3 class="sg-h3">Select & textarea</h3>
|
|
1305
|
+
<div class="hf-card-elev grid md:grid-cols-2 gap-6">
|
|
1306
|
+
<div>
|
|
1307
|
+
<label class="block hf-text-medium mb-2" for="if-sel">Native select</label>
|
|
1308
|
+
<select id="if-sel" class="form-control text-[#4B5675]">
|
|
1309
|
+
<option>Please select an option</option>
|
|
1310
|
+
<option>Option A</option>
|
|
1311
|
+
<option>Option B</option>
|
|
1312
|
+
</select>
|
|
1313
|
+
<div class="text-[12px] text-[#99A1B7] mt-1">For multi-select / autocomplete use Select2 (<code>.select2-container</code>) — same 38px height, same 6px radius.</div>
|
|
1314
|
+
</div>
|
|
1315
|
+
<div>
|
|
1316
|
+
<label class="block hf-text-medium mb-2" for="if-ta">Textarea</label>
|
|
1317
|
+
<textarea id="if-ta" class="form-control h-[88px] py-2" placeholder="Notes..."></textarea>
|
|
1318
|
+
</div>
|
|
1319
|
+
</div>
|
|
1320
|
+
|
|
1321
|
+
<h3 class="sg-h3">Checkboxes & radios</h3>
|
|
1322
|
+
<div class="hf-card-elev grid md:grid-cols-2 gap-6">
|
|
1323
|
+
<div class="space-y-2">
|
|
1324
|
+
<label class="flex items-center gap-3 cursor-pointer text-[14px]"><input type="checkbox" class="hf-checkbox"> Unchecked</label>
|
|
1325
|
+
<label class="flex items-center gap-3 cursor-pointer text-[14px]"><input type="checkbox" class="hf-checkbox" checked> Checked</label>
|
|
1326
|
+
<label class="flex items-center gap-3 cursor-not-allowed text-[14px] opacity-60"><input type="checkbox" class="hf-checkbox" disabled> Disabled</label>
|
|
1327
|
+
<label class="flex items-center gap-3 cursor-not-allowed text-[14px] opacity-60"><input type="checkbox" class="hf-checkbox" checked disabled> Disabled checked</label>
|
|
1328
|
+
</div>
|
|
1329
|
+
<div class="space-y-2">
|
|
1330
|
+
<label class="flex items-center gap-3 cursor-pointer text-[14px]"><input type="radio" name="r1" class="hf-checkbox" style="border-radius:50%"> Option A</label>
|
|
1331
|
+
<label class="flex items-center gap-3 cursor-pointer text-[14px]"><input type="radio" name="r1" class="hf-checkbox" style="border-radius:50%" checked> Option B (selected)</label>
|
|
1332
|
+
<label class="flex items-center gap-3 cursor-not-allowed text-[14px] opacity-60"><input type="radio" name="r2" class="hf-checkbox" style="border-radius:50%" disabled> Option C (disabled)</label>
|
|
1333
|
+
</div>
|
|
1334
|
+
</div>
|
|
1335
|
+
<div class="hf-snippet">
|
|
1336
|
+
<button class="copy" data-copy>Copy</button>
|
|
1337
|
+
<pre><label>
|
|
1338
|
+
<input type="checkbox" class="hf-checkbox"> Agree to terms
|
|
1339
|
+
</label>
|
|
1340
|
+
<label>
|
|
1341
|
+
<input type="radio" name="opt" class="hf-checkbox" style="border-radius:50%"> Option A
|
|
1342
|
+
</label></pre>
|
|
1343
|
+
</div>
|
|
1344
|
+
</section>
|
|
1345
|
+
|
|
1346
|
+
<!-- 5.1 Date / Time pickers -->
|
|
1347
|
+
<section id="datepickers">
|
|
1348
|
+
<h2 class="sg-section-title">Date / Time pickers</h2>
|
|
1349
|
+
<p class="sg-section-desc">Krajee datepicker (jQuery wrapper around bootstrap-datepicker) and bootstrap-timepicker. Both render as floating dropdown panels with <code class="bg-gray-100 px-1 rounded">--shadow-tooltip</code>.</p>
|
|
1350
|
+
|
|
1351
|
+
<div class="grid md:grid-cols-2 gap-6">
|
|
1352
|
+
<div>
|
|
1353
|
+
<h3 class="sg-h3">Date picker (calendar)</h3>
|
|
1354
|
+
<div class="hf-datepicker">
|
|
1355
|
+
<div class="hf-datepicker__head">
|
|
1356
|
+
<button class="hf-datepicker__nav">‹</button>
|
|
1357
|
+
<div class="hf-datepicker__title">May 2026</div>
|
|
1358
|
+
<button class="hf-datepicker__nav">›</button>
|
|
1359
|
+
</div>
|
|
1360
|
+
<div class="hf-datepicker__grid">
|
|
1361
|
+
<div class="hf-datepicker__weekday">Mo</div>
|
|
1362
|
+
<div class="hf-datepicker__weekday">Tu</div>
|
|
1363
|
+
<div class="hf-datepicker__weekday">We</div>
|
|
1364
|
+
<div class="hf-datepicker__weekday">Th</div>
|
|
1365
|
+
<div class="hf-datepicker__weekday">Fr</div>
|
|
1366
|
+
<div class="hf-datepicker__weekday">Sa</div>
|
|
1367
|
+
<div class="hf-datepicker__weekday">Su</div>
|
|
1368
|
+
<div class="hf-datepicker__cell is-other-month">28</div>
|
|
1369
|
+
<div class="hf-datepicker__cell is-other-month">29</div>
|
|
1370
|
+
<div class="hf-datepicker__cell is-other-month">30</div>
|
|
1371
|
+
<div class="hf-datepicker__cell">1</div>
|
|
1372
|
+
<div class="hf-datepicker__cell">2</div>
|
|
1373
|
+
<div class="hf-datepicker__cell">3</div>
|
|
1374
|
+
<div class="hf-datepicker__cell">4</div>
|
|
1375
|
+
<div class="hf-datepicker__cell">5</div>
|
|
1376
|
+
<div class="hf-datepicker__cell">6</div>
|
|
1377
|
+
<div class="hf-datepicker__cell is-today">7</div>
|
|
1378
|
+
<div class="hf-datepicker__cell">8</div>
|
|
1379
|
+
<div class="hf-datepicker__cell">9</div>
|
|
1380
|
+
<div class="hf-datepicker__cell">10</div>
|
|
1381
|
+
<div class="hf-datepicker__cell">11</div>
|
|
1382
|
+
<div class="hf-datepicker__cell">12</div>
|
|
1383
|
+
<div class="hf-datepicker__cell">13</div>
|
|
1384
|
+
<div class="hf-datepicker__cell is-selected">14</div>
|
|
1385
|
+
<div class="hf-datepicker__cell">15</div>
|
|
1386
|
+
<div class="hf-datepicker__cell">16</div>
|
|
1387
|
+
<div class="hf-datepicker__cell">17</div>
|
|
1388
|
+
<div class="hf-datepicker__cell">18</div>
|
|
1389
|
+
<div class="hf-datepicker__cell">19</div>
|
|
1390
|
+
<div class="hf-datepicker__cell">20</div>
|
|
1391
|
+
<div class="hf-datepicker__cell">21</div>
|
|
1392
|
+
<div class="hf-datepicker__cell">22</div>
|
|
1393
|
+
<div class="hf-datepicker__cell">23</div>
|
|
1394
|
+
<div class="hf-datepicker__cell">24</div>
|
|
1395
|
+
<div class="hf-datepicker__cell">25</div>
|
|
1396
|
+
<div class="hf-datepicker__cell">26</div>
|
|
1397
|
+
<div class="hf-datepicker__cell">27</div>
|
|
1398
|
+
<div class="hf-datepicker__cell">28</div>
|
|
1399
|
+
<div class="hf-datepicker__cell">29</div>
|
|
1400
|
+
<div class="hf-datepicker__cell">30</div>
|
|
1401
|
+
<div class="hf-datepicker__cell">31</div>
|
|
1402
|
+
<div class="hf-datepicker__cell is-other-month">1</div>
|
|
1403
|
+
<div class="hf-datepicker__cell is-other-month">2</div>
|
|
1404
|
+
<div class="hf-datepicker__cell is-other-month">3</div>
|
|
1405
|
+
<div class="hf-datepicker__cell is-other-month">4</div>
|
|
1406
|
+
<div class="hf-datepicker__cell is-other-month">5</div>
|
|
1407
|
+
<div class="hf-datepicker__cell is-other-month">6</div>
|
|
1408
|
+
<div class="hf-datepicker__cell is-other-month">7</div>
|
|
1409
|
+
</div>
|
|
1410
|
+
</div>
|
|
1411
|
+
</div>
|
|
1412
|
+
|
|
1413
|
+
<div>
|
|
1414
|
+
<h3 class="sg-h3">Time picker (HH : MM)</h3>
|
|
1415
|
+
<div class="hf-timepicker">
|
|
1416
|
+
<div class="hf-timepicker__col">
|
|
1417
|
+
<button class="hf-timepicker__btn">▲</button>
|
|
1418
|
+
<span class="hf-timepicker__val">14</span>
|
|
1419
|
+
<button class="hf-timepicker__btn">▼</button>
|
|
1420
|
+
</div>
|
|
1421
|
+
<span class="text-[20px] text-[#99A1B7]">:</span>
|
|
1422
|
+
<div class="hf-timepicker__col">
|
|
1423
|
+
<button class="hf-timepicker__btn">▲</button>
|
|
1424
|
+
<span class="hf-timepicker__val">30</span>
|
|
1425
|
+
<button class="hf-timepicker__btn">▼</button>
|
|
1426
|
+
</div>
|
|
1427
|
+
</div>
|
|
1428
|
+
|
|
1429
|
+
<h3 class="sg-h3">Date input (trigger)</h3>
|
|
1430
|
+
<input type="text" class="form-control krajee-datepicker" value="2026-05-07" readonly style="max-width:240px;">
|
|
1431
|
+
<div class="text-[12px] text-[#99A1B7] mt-2">Live class: <code>input.form-control.krajee-datepicker</code>. Calendar opens on focus.</div>
|
|
1432
|
+
</div>
|
|
1433
|
+
</div>
|
|
1434
|
+
</section>
|
|
1435
|
+
|
|
1436
|
+
<!-- 6.0 Tabs -->
|
|
1437
|
+
<section id="tabs">
|
|
1438
|
+
<h2 class="sg-section-title">Tabs</h2>
|
|
1439
|
+
<p class="sg-section-desc">Default container <code class="bg-gray-100 px-1 rounded">.hf-tabs</code> sits on a 1px <code class="bg-gray-100 px-1 rounded">#D1D6DD</code> bottom border. Active item gets a 3px primary underline.</p>
|
|
1440
|
+
|
|
1441
|
+
<div class="hf-card-elev">
|
|
1442
|
+
<div class="hf-tabs">
|
|
1443
|
+
<div class="hf-tabs__item is-active">All bookings</div>
|
|
1444
|
+
<div class="hf-tabs__item">Upcoming</div>
|
|
1445
|
+
<div class="hf-tabs__item">Past</div>
|
|
1446
|
+
<div class="hf-tabs__item">Canceled</div>
|
|
1447
|
+
</div>
|
|
1448
|
+
<div class="text-[14px] text-[#4B5675] mt-6">Tab content area renders here.</div>
|
|
1449
|
+
</div>
|
|
1450
|
+
<div class="hf-snippet">
|
|
1451
|
+
<button class="copy" data-copy>Copy</button>
|
|
1452
|
+
<pre><div class="hf-tabs">
|
|
1453
|
+
<div class="hf-tabs__item is-active">All bookings</div>
|
|
1454
|
+
<div class="hf-tabs__item">Upcoming</div>
|
|
1455
|
+
<div class="hf-tabs__item">Past</div>
|
|
1456
|
+
<div class="hf-tabs__item">Canceled</div>
|
|
1457
|
+
</div></pre>
|
|
1458
|
+
</div>
|
|
1459
|
+
</section>
|
|
1460
|
+
|
|
1461
|
+
<!-- 6.1 Cards -->
|
|
1462
|
+
<section id="cards">
|
|
1463
|
+
<h2 class="sg-section-title">Cards</h2>
|
|
1464
|
+
<p class="sg-section-desc">Three canonical card variants. Use elevated for primary content, flat for secondary/page-section, stat for dashboard metrics.</p>
|
|
1465
|
+
|
|
1466
|
+
<div class="grid md:grid-cols-3 gap-6">
|
|
1467
|
+
<div class="hf-card-elev">
|
|
1468
|
+
<div class="hf-text-medium mb-2">Elevated card</div>
|
|
1469
|
+
<p class="text-[13px] text-[#4B5675]">12px radius, 1px <code>#E4E8EF</code> border, soft <code>0 3px 4px rgba(0,0,0,.03)</code> shadow + <code>0 1px 8px rgba(0,0,0,.1)</code>. Default for content blocks.</p>
|
|
1470
|
+
</div>
|
|
1471
|
+
<div class="hf-card-flat">
|
|
1472
|
+
<div class="hf-text-medium mb-2">Flat card</div>
|
|
1473
|
+
<p class="text-[13px] text-[#4B5675]"><code>#FBFBFC</code> bg, no shadow. Use as wrapper / aside / read-only summary.</p>
|
|
1474
|
+
</div>
|
|
1475
|
+
<div class="hf-card-stat">
|
|
1476
|
+
<div class="hf-card-stat__icon">
|
|
1477
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3h18v18H3zM3 9h18M9 21V9"/></svg>
|
|
1478
|
+
</div>
|
|
1479
|
+
<div>
|
|
1480
|
+
<div class="text-[13px] text-[#4B5675] mb-1">Active rooms</div>
|
|
1481
|
+
<div class="text-[26px] font-semibold leading-none text-[#2B2B2B]">128</div>
|
|
1482
|
+
<div class="text-[12px] text-[#59B59D] mt-1">+12 this week</div>
|
|
1483
|
+
</div>
|
|
1484
|
+
</div>
|
|
1485
|
+
</div>
|
|
1486
|
+
<div class="hf-snippet">
|
|
1487
|
+
<button class="copy" data-copy>Copy</button>
|
|
1488
|
+
<pre><div class="hf-card-elev">...content...</div>
|
|
1489
|
+
<div class="hf-card-flat">...content...</div>
|
|
1490
|
+
<div class="hf-card-stat">
|
|
1491
|
+
<div class="hf-card-stat__icon"><svg .../></div>
|
|
1492
|
+
<div>
|
|
1493
|
+
<div class="text-secondary">Active rooms</div>
|
|
1494
|
+
<div class="text-page">128</div>
|
|
1495
|
+
</div>
|
|
1496
|
+
</div></pre>
|
|
1497
|
+
</div>
|
|
1498
|
+
</section>
|
|
1499
|
+
|
|
1500
|
+
<!-- 6.2 Modals -->
|
|
1501
|
+
<section id="modals">
|
|
1502
|
+
<h2 class="sg-section-title">Modals</h2>
|
|
1503
|
+
<p class="sg-section-desc">Backdrop <code class="bg-gray-100 px-1 rounded">rgba(0,0,0,0.4)</code>. Container 12px radius, max-width 500px (sm) or 800px (lg). Header / Body / Footer have 20px padding and 1px <code class="bg-gray-100 px-1 rounded">#E4E8EF</code> dividers.</p>
|
|
1504
|
+
|
|
1505
|
+
<h3 class="sg-h3">Standard (sm)</h3>
|
|
1506
|
+
<div class="hf-modal-shell">
|
|
1507
|
+
<div class="hf-modal">
|
|
1508
|
+
<div class="hf-modal__header">
|
|
1509
|
+
<div class="hf-modal__title">Cancel subscription?</div>
|
|
1510
|
+
<button class="hf-modal__close" aria-label="Close">×</button>
|
|
1511
|
+
</div>
|
|
1512
|
+
<div class="hf-modal__body">
|
|
1513
|
+
<p class="text-[14px] text-[#4B5675] leading-relaxed">Your subscription will remain active until the end of the current billing period. After that, all integrations will be disabled.</p>
|
|
1514
|
+
</div>
|
|
1515
|
+
<div class="hf-modal__footer">
|
|
1516
|
+
<button class="btn btn-cancel">Keep subscription</button>
|
|
1517
|
+
<button class="btn btn-delete">Cancel anyway</button>
|
|
1518
|
+
</div>
|
|
1519
|
+
</div>
|
|
1520
|
+
</div>
|
|
1521
|
+
|
|
1522
|
+
<h3 class="sg-h3">Large (form-style)</h3>
|
|
1523
|
+
<div class="hf-modal-shell">
|
|
1524
|
+
<div class="hf-modal hf-modal--lg">
|
|
1525
|
+
<div class="hf-modal__header">
|
|
1526
|
+
<div class="hf-modal__title">Add new contact</div>
|
|
1527
|
+
<button class="hf-modal__close" aria-label="Close">×</button>
|
|
1528
|
+
</div>
|
|
1529
|
+
<div class="hf-modal__body grid grid-cols-2 gap-4">
|
|
1530
|
+
<div>
|
|
1531
|
+
<label class="block hf-text-medium mb-2 form-required" for="m-fn">First name</label>
|
|
1532
|
+
<input id="m-fn" class="form-control" type="text" placeholder="John">
|
|
1533
|
+
</div>
|
|
1534
|
+
<div>
|
|
1535
|
+
<label class="block hf-text-medium mb-2 form-required" for="m-ln">Last name</label>
|
|
1536
|
+
<input id="m-ln" class="form-control" type="text" placeholder="Doe">
|
|
1537
|
+
</div>
|
|
1538
|
+
<div class="col-span-2">
|
|
1539
|
+
<label class="block hf-text-medium mb-2" for="m-em">Email</label>
|
|
1540
|
+
<input id="m-em" class="form-control" type="email" placeholder="john@example.com">
|
|
1541
|
+
</div>
|
|
1542
|
+
</div>
|
|
1543
|
+
<div class="hf-modal__footer">
|
|
1544
|
+
<button class="btn btn-cancel">Cancel</button>
|
|
1545
|
+
<button class="btn btn-primary">Save contact</button>
|
|
1546
|
+
</div>
|
|
1547
|
+
</div>
|
|
1548
|
+
</div>
|
|
1549
|
+
|
|
1550
|
+
<div class="hf-snippet">
|
|
1551
|
+
<button class="copy" data-copy>Copy</button>
|
|
1552
|
+
<pre><div class="hf-modal-shell"> <!-- backdrop -->
|
|
1553
|
+
<div class="hf-modal"> <!-- or hf-modal hf-modal--lg -->
|
|
1554
|
+
<div class="hf-modal__header">
|
|
1555
|
+
<div class="hf-modal__title">Title</div>
|
|
1556
|
+
<button class="hf-modal__close">×</button>
|
|
1557
|
+
</div>
|
|
1558
|
+
<div class="hf-modal__body">...</div>
|
|
1559
|
+
<div class="hf-modal__footer">
|
|
1560
|
+
<button class="btn btn-cancel">Cancel</button>
|
|
1561
|
+
<button class="btn btn-primary">Save</button>
|
|
1562
|
+
</div>
|
|
1563
|
+
</div>
|
|
1564
|
+
</div></pre>
|
|
1565
|
+
</div>
|
|
1566
|
+
</section>
|
|
1567
|
+
|
|
1568
|
+
<!-- 6.3 Dropdowns -->
|
|
1569
|
+
<section id="dropdowns">
|
|
1570
|
+
<h2 class="sg-section-title">Dropdowns</h2>
|
|
1571
|
+
<p class="sg-section-desc">Action menus, select-style triggers, and action lists. Default 9px radius, <code class="bg-gray-100 px-1 rounded">--shadow-tooltip</code>, items 14/regular text on white with <code class="bg-gray-100 px-1 rounded">#F1F3F6</code> hover.</p>
|
|
1572
|
+
|
|
1573
|
+
<div class="grid md:grid-cols-3 gap-8">
|
|
1574
|
+
<div class="hf-card-elev">
|
|
1575
|
+
<div class="hf-text-medium mb-3">Plain action menu</div>
|
|
1576
|
+
<div class="hf-dropdown">
|
|
1577
|
+
<div class="hf-dropdown__menu">
|
|
1578
|
+
<div class="hf-dropdown__item">Edit</div>
|
|
1579
|
+
<div class="hf-dropdown__item">Duplicate</div>
|
|
1580
|
+
<div class="hf-dropdown__item">Archive</div>
|
|
1581
|
+
<div class="hf-dropdown__divider"></div>
|
|
1582
|
+
<div class="hf-dropdown__item hf-dropdown__item--danger">Delete</div>
|
|
1583
|
+
</div>
|
|
1584
|
+
</div>
|
|
1585
|
+
</div>
|
|
1586
|
+
|
|
1587
|
+
<div class="hf-card-elev">
|
|
1588
|
+
<div class="hf-text-medium mb-3">With icons</div>
|
|
1589
|
+
<div class="hf-dropdown">
|
|
1590
|
+
<div class="hf-dropdown__menu">
|
|
1591
|
+
<div class="hf-dropdown__item">
|
|
1592
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
|
1593
|
+
Edit
|
|
1594
|
+
</div>
|
|
1595
|
+
<div class="hf-dropdown__item">
|
|
1596
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
|
1597
|
+
Download
|
|
1598
|
+
</div>
|
|
1599
|
+
<div class="hf-dropdown__divider"></div>
|
|
1600
|
+
<div class="hf-dropdown__item hf-dropdown__item--danger">
|
|
1601
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-2 14a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2L5 6"/></svg>
|
|
1602
|
+
Delete
|
|
1603
|
+
</div>
|
|
1604
|
+
</div>
|
|
1605
|
+
</div>
|
|
1606
|
+
</div>
|
|
1607
|
+
|
|
1608
|
+
<div class="hf-card-elev">
|
|
1609
|
+
<div class="hf-text-medium mb-3">Trigger button</div>
|
|
1610
|
+
<button class="btn btn-outline gap-2">
|
|
1611
|
+
More
|
|
1612
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
|
|
1613
|
+
</button>
|
|
1614
|
+
<p class="text-[12px] text-[#99A1B7] mt-3">Click opens menu (uses Bootstrap dropdown JS).</p>
|
|
1615
|
+
</div>
|
|
1616
|
+
</div>
|
|
1617
|
+
<div class="hf-snippet">
|
|
1618
|
+
<button class="copy" data-copy>Copy</button>
|
|
1619
|
+
<pre><div class="hf-dropdown">
|
|
1620
|
+
<button class="btn btn-outline" data-toggle="dropdown">More</button>
|
|
1621
|
+
<div class="hf-dropdown__menu">
|
|
1622
|
+
<div class="hf-dropdown__item">Edit</div>
|
|
1623
|
+
<div class="hf-dropdown__item">Duplicate</div>
|
|
1624
|
+
<div class="hf-dropdown__divider"></div>
|
|
1625
|
+
<div class="hf-dropdown__item hf-dropdown__item--danger">Delete</div>
|
|
1626
|
+
</div>
|
|
1627
|
+
</div></pre>
|
|
1628
|
+
</div>
|
|
1629
|
+
</section>
|
|
1630
|
+
|
|
1631
|
+
<!-- 6.4 Tooltips & Popovers -->
|
|
1632
|
+
<section id="tooltips">
|
|
1633
|
+
<h2 class="sg-section-title">Tooltips & Popovers</h2>
|
|
1634
|
+
<p class="sg-section-desc">Tooltip — small dark label triggered on hover. Popover — richer floating panel with title + body. Both have 200ms appearance delay to avoid flicker.</p>
|
|
1635
|
+
|
|
1636
|
+
<div class="grid md:grid-cols-2 gap-6">
|
|
1637
|
+
<div class="hf-card-elev">
|
|
1638
|
+
<div class="hf-text-medium mb-4">Tooltips</div>
|
|
1639
|
+
<div class="flex flex-col gap-8 items-center py-6">
|
|
1640
|
+
<div class="hf-tooltip hf-tooltip--down">Tooltip pointing up</div>
|
|
1641
|
+
<div class="hf-tooltip hf-tooltip--up">Tooltip pointing down</div>
|
|
1642
|
+
</div>
|
|
1643
|
+
</div>
|
|
1644
|
+
<div class="hf-card-elev">
|
|
1645
|
+
<div class="hf-text-medium mb-4">Popover</div>
|
|
1646
|
+
<div class="hf-popover">
|
|
1647
|
+
<div class="hf-popover__title">Refund policy</div>
|
|
1648
|
+
<p>Refunds are processed within 3-5 business days. The amount returns to the original payment method.</p>
|
|
1649
|
+
</div>
|
|
1650
|
+
</div>
|
|
1651
|
+
</div>
|
|
1652
|
+
<div class="hf-snippet">
|
|
1653
|
+
<button class="copy" data-copy>Copy</button>
|
|
1654
|
+
<pre><div class="hf-tooltip hf-tooltip--up">Click to copy</div>
|
|
1655
|
+
|
|
1656
|
+
<div class="hf-popover">
|
|
1657
|
+
<div class="hf-popover__title">Refund policy</div>
|
|
1658
|
+
<p>Refunds are processed within 3-5 business days.</p>
|
|
1659
|
+
</div></pre>
|
|
1660
|
+
</div>
|
|
1661
|
+
</section>
|
|
1662
|
+
|
|
1663
|
+
<!-- 6.5 Alerts & Toasts -->
|
|
1664
|
+
<section id="alerts-toasts">
|
|
1665
|
+
<h2 class="sg-section-title">Alerts & Toasts</h2>
|
|
1666
|
+
<p class="sg-section-desc">Alerts are inline (within page flow). Toasts are floating notifications, typically top-right with 20px offset.</p>
|
|
1667
|
+
|
|
1668
|
+
<h3 class="sg-h3">Alerts (4 semantic types)</h3>
|
|
1669
|
+
<div class="space-y-3">
|
|
1670
|
+
<div class="hf-alert hf-alert--success">
|
|
1671
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
|
1672
|
+
<div><div class="hf-alert__title">Payment confirmed</div>The booking is now active and the guest has been notified.</div>
|
|
1673
|
+
</div>
|
|
1674
|
+
<div class="hf-alert hf-alert--warning">
|
|
1675
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
|
1676
|
+
<div><div class="hf-alert__title">Subscription expires soon</div>Renew within 7 days to avoid service interruption.</div>
|
|
1677
|
+
</div>
|
|
1678
|
+
<div class="hf-alert hf-alert--error">
|
|
1679
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
1680
|
+
<div><div class="hf-alert__title">Could not save changes</div>The server returned a 500 error. Please retry in a moment.</div>
|
|
1681
|
+
</div>
|
|
1682
|
+
<div class="hf-alert hf-alert--info">
|
|
1683
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
|
|
1684
|
+
<div><div class="hf-alert__title">Heads up</div>2-factor authentication is now mandatory for all admin users.</div>
|
|
1685
|
+
</div>
|
|
1686
|
+
</div>
|
|
1687
|
+
|
|
1688
|
+
<h3 class="sg-h3">Toasts (top-right floating)</h3>
|
|
1689
|
+
<div class="space-y-3">
|
|
1690
|
+
<div class="hf-toast hf-toast--success">
|
|
1691
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#59B59D" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
|
|
1692
|
+
<div>
|
|
1693
|
+
<div class="hf-text-medium">Saved</div>
|
|
1694
|
+
<div class="text-[13px] text-[#4B5675]">Hotel settings updated.</div>
|
|
1695
|
+
</div>
|
|
1696
|
+
</div>
|
|
1697
|
+
<div class="hf-toast hf-toast--error">
|
|
1698
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#EA6565" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
|
|
1699
|
+
<div>
|
|
1700
|
+
<div class="hf-text-medium">Upload failed</div>
|
|
1701
|
+
<div class="text-[13px] text-[#4B5675]">file_too_large.zip — 14 MB limit.</div>
|
|
1702
|
+
</div>
|
|
1703
|
+
</div>
|
|
1704
|
+
</div>
|
|
1705
|
+
|
|
1706
|
+
<div class="hf-snippet">
|
|
1707
|
+
<button class="copy" data-copy>Copy</button>
|
|
1708
|
+
<pre><div class="hf-alert hf-alert--success">
|
|
1709
|
+
<svg /> <div><b>Saved</b> — settings updated.</div>
|
|
1710
|
+
</div>
|
|
1711
|
+
|
|
1712
|
+
<!-- Floating toast -->
|
|
1713
|
+
<div class="hf-toast hf-toast--success">
|
|
1714
|
+
<svg /> <div><div class="hf-text-medium">Saved</div>Settings updated.</div>
|
|
1715
|
+
</div></pre>
|
|
1716
|
+
</div>
|
|
1717
|
+
</section>
|
|
1718
|
+
|
|
1719
|
+
<!-- 6.6 Pagination & Breadcrumbs -->
|
|
1720
|
+
<section id="pagination">
|
|
1721
|
+
<h2 class="sg-section-title">Pagination & Breadcrumbs</h2>
|
|
1722
|
+
<p class="sg-section-desc">Pagination — 32×32 page tiles with 6px radius, primary bg for active. Breadcrumbs — 12px secondary text with separator chevrons.</p>
|
|
1723
|
+
|
|
1724
|
+
<h3 class="sg-h3">Pagination</h3>
|
|
1725
|
+
<div class="hf-card-elev flex justify-between items-center text-[13px] text-[#4B5675]">
|
|
1726
|
+
<span>Showing 1–10 of 42 items</span>
|
|
1727
|
+
<div class="hf-pagination">
|
|
1728
|
+
<button class="hf-pagination__page is-disabled">‹</button>
|
|
1729
|
+
<button class="hf-pagination__page is-active">1</button>
|
|
1730
|
+
<button class="hf-pagination__page">2</button>
|
|
1731
|
+
<button class="hf-pagination__page">3</button>
|
|
1732
|
+
<button class="hf-pagination__page">4</button>
|
|
1733
|
+
<button class="hf-pagination__page">5</button>
|
|
1734
|
+
<button class="hf-pagination__page">›</button>
|
|
1735
|
+
</div>
|
|
1736
|
+
</div>
|
|
1737
|
+
|
|
1738
|
+
<h3 class="sg-h3">Breadcrumbs</h3>
|
|
1739
|
+
<div class="hf-card-elev">
|
|
1740
|
+
<nav aria-label="breadcrumb" class="hf-breadcrumb">
|
|
1741
|
+
<span class="hf-breadcrumb__item">Hotels</span>
|
|
1742
|
+
<span class="hf-breadcrumb__sep">/</span>
|
|
1743
|
+
<span class="hf-breadcrumb__item">Grand Plaza</span>
|
|
1744
|
+
<span class="hf-breadcrumb__sep">/</span>
|
|
1745
|
+
<span class="hf-breadcrumb__item is-current">Edit</span>
|
|
1746
|
+
</nav>
|
|
1747
|
+
</div>
|
|
1748
|
+
<div class="hf-snippet">
|
|
1749
|
+
<button class="copy" data-copy>Copy</button>
|
|
1750
|
+
<pre><div class="hf-pagination">
|
|
1751
|
+
<button class="hf-pagination__page is-active">1</button>
|
|
1752
|
+
<button class="hf-pagination__page">2</button>
|
|
1753
|
+
</div>
|
|
1754
|
+
|
|
1755
|
+
<nav class="hf-breadcrumb">
|
|
1756
|
+
<span class="hf-breadcrumb__item">Hotels</span>
|
|
1757
|
+
<span class="hf-breadcrumb__sep">/</span>
|
|
1758
|
+
<span class="hf-breadcrumb__item is-current">Edit</span>
|
|
1759
|
+
</nav></pre>
|
|
1760
|
+
</div>
|
|
1761
|
+
</section>
|
|
1762
|
+
|
|
1763
|
+
<!-- 6.7 Empty state & Skeleton -->
|
|
1764
|
+
<section id="empty-skeleton">
|
|
1765
|
+
<h2 class="sg-section-title">Empty states & Skeletons</h2>
|
|
1766
|
+
<p class="sg-section-desc">Empty state — when there's no data to show. Skeleton — loading placeholder with shimmer animation, replaces content while data is in flight.</p>
|
|
1767
|
+
|
|
1768
|
+
<div class="grid md:grid-cols-2 gap-6">
|
|
1769
|
+
<div class="hf-card-elev">
|
|
1770
|
+
<div class="hf-empty">
|
|
1771
|
+
<svg class="hf-empty__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
|
1772
|
+
<div class="hf-empty__title">No bookings yet</div>
|
|
1773
|
+
<div class="hf-empty__desc">When guests book through your website, their reservations will show up here.</div>
|
|
1774
|
+
<button class="btn btn-primary">+ Create manually</button>
|
|
1775
|
+
</div>
|
|
1776
|
+
</div>
|
|
1777
|
+
|
|
1778
|
+
<div class="hf-card-elev">
|
|
1779
|
+
<div class="hf-text-medium mb-4">Skeleton (loading)</div>
|
|
1780
|
+
<div class="flex items-center gap-3 mb-4">
|
|
1781
|
+
<div class="hf-skel hf-skel--circle"></div>
|
|
1782
|
+
<div class="flex-1 space-y-2">
|
|
1783
|
+
<div class="hf-skel hf-skel--lg" style="width:60%"></div>
|
|
1784
|
+
<div class="hf-skel" style="width:40%"></div>
|
|
1785
|
+
</div>
|
|
1786
|
+
</div>
|
|
1787
|
+
<div class="space-y-2">
|
|
1788
|
+
<div class="hf-skel" style="width:100%"></div>
|
|
1789
|
+
<div class="hf-skel" style="width:90%"></div>
|
|
1790
|
+
<div class="hf-skel" style="width:75%"></div>
|
|
1791
|
+
</div>
|
|
1792
|
+
</div>
|
|
1793
|
+
</div>
|
|
1794
|
+
<div class="hf-snippet">
|
|
1795
|
+
<button class="copy" data-copy>Copy</button>
|
|
1796
|
+
<pre><div class="hf-empty">
|
|
1797
|
+
<svg class="hf-empty__icon" />
|
|
1798
|
+
<div class="hf-empty__title">No bookings yet</div>
|
|
1799
|
+
<div class="hf-empty__desc">When guests book ...</div>
|
|
1800
|
+
<button class="btn btn-primary">+ Create manually</button>
|
|
1801
|
+
</div>
|
|
1802
|
+
|
|
1803
|
+
<!-- Skeleton -->
|
|
1804
|
+
<div class="hf-skel hf-skel--lg" style="width:60%"></div>
|
|
1805
|
+
<div class="hf-skel" style="width:90%"></div></pre>
|
|
1806
|
+
</div>
|
|
1807
|
+
</section>
|
|
1808
|
+
|
|
1809
|
+
<!-- 7. Advanced (renamed) -->
|
|
1810
|
+
<section id="advanced-form">
|
|
1811
|
+
<h2 class="sg-section-title">Advanced UI Elements</h2>
|
|
1812
|
+
<p class="sg-section-desc">Specialized widgets extracted directly from the system.</p>
|
|
1813
|
+
|
|
1814
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
1815
|
+
<!-- Progress Bar -->
|
|
1816
|
+
<div class="hf-card">
|
|
1817
|
+
<h3 class="hf-text-medium mb-4">Progress Bar</h3>
|
|
1818
|
+
<div class="h-[8px] rounded-full bg-[#E4E8EF] overflow-hidden mb-2">
|
|
1819
|
+
<div class="h-full bg-[#59B59D]" style="width: 75%"></div>
|
|
1820
|
+
</div>
|
|
1821
|
+
<div class="flex justify-between text-[12px] text-[#4B5675]">
|
|
1822
|
+
<span>75% Capacity</span>
|
|
1823
|
+
<span>25 spots remaining</span>
|
|
1824
|
+
</div>
|
|
1825
|
+
</div>
|
|
1826
|
+
|
|
1827
|
+
<!-- Switch Toggle (Bootstrap-switch live) -->
|
|
1828
|
+
<div class="hf-card">
|
|
1829
|
+
<h3 class="hf-text-medium mb-4">Switch (Bootstrap-Switch live)</h3>
|
|
1830
|
+
<div class="flex flex-col gap-3">
|
|
1831
|
+
<div class="flex items-center gap-3">
|
|
1832
|
+
<div class="hf-switch is-on" role="switch" aria-checked="true"></div>
|
|
1833
|
+
<span class="text-[14px] text-[#4B5675]">Integration Enabled</span>
|
|
1834
|
+
</div>
|
|
1835
|
+
<div class="flex items-center gap-3">
|
|
1836
|
+
<div class="hf-switch" role="switch" aria-checked="false"></div>
|
|
1837
|
+
<span class="text-[14px] text-[#4B5675]">Auto-confirm bookings</span>
|
|
1838
|
+
</div>
|
|
1839
|
+
<div class="text-[12px] text-[#99A1B7] mt-1">Live sizes: <code>68×32</code> (lists), <code>72×32</code> (SEO pages), <code>83×32</code> (forms).</div>
|
|
1840
|
+
</div>
|
|
1841
|
+
</div>
|
|
1842
|
+
|
|
1843
|
+
<!-- Quantity Input -->
|
|
1844
|
+
<div class="hf-card">
|
|
1845
|
+
<h3 class="hf-text-medium mb-4">Quantity Input</h3>
|
|
1846
|
+
<div class="flex items-center border border-[#d1d6dd] rounded-[6px] w-max overflow-hidden bg-white">
|
|
1847
|
+
<button class="px-3 py-1 bg-[#F1F3F6] hover:bg-[#E4E8EF] text-[#4B5675] font-medium">-</button>
|
|
1848
|
+
<input min="0" value="2" type="number" class="w-[50px] text-center text-[14px] outline-none border-x border-[#d1d6dd] py-[6px]">
|
|
1849
|
+
<button class="px-3 py-1 bg-[#F1F3F6] hover:bg-[#E4E8EF] text-[#4B5675] font-medium">+</button>
|
|
1850
|
+
</div>
|
|
1851
|
+
</div>
|
|
1852
|
+
|
|
1853
|
+
<!-- Toggle Switcher -->
|
|
1854
|
+
<div class="hf-card">
|
|
1855
|
+
<h3 class="hf-text-medium mb-4">Input with Switcher</h3>
|
|
1856
|
+
<div class="flex items-center w-max border border-[#d1d6dd] rounded-[6px] overflow-hidden bg-white">
|
|
1857
|
+
<input type="number" class="w-[80px] pl-3 py-[6px] text-[14px] outline-none" value="10">
|
|
1858
|
+
<div class="flex bg-[#F1F3F6] text-[#4B5675] text-[13px] border-l border-[#d1d6dd]">
|
|
1859
|
+
<div class="px-3 py-1 bg-white border border-[#d1d6dd] rounded-[4px] m-1 shadow-sm font-medium">%</div>
|
|
1860
|
+
<div class="px-3 py-1 m-1 cursor-pointer hover:text-[#2B2B2B]">UAH</div>
|
|
1861
|
+
</div>
|
|
1862
|
+
</div>
|
|
1863
|
+
</div>
|
|
1864
|
+
|
|
1865
|
+
<!-- Copy Text -->
|
|
1866
|
+
<div class="hf-card">
|
|
1867
|
+
<h3 class="hf-text-medium mb-4">Copy Text Widget</h3>
|
|
1868
|
+
<div class="flex items-center justify-between border border-[#d1d6dd] rounded-[6px] p-2 bg-[#FBFBFC]">
|
|
1869
|
+
<span class="text-[14px] text-[#2B2B2B] font-mono px-2">HF-2026-X9Z</span>
|
|
1870
|
+
<button class="btn-outline !h-[30px] !text-[13px] gap-2 !px-3">
|
|
1871
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
|
1872
|
+
Copy
|
|
1873
|
+
</button>
|
|
1874
|
+
</div>
|
|
1875
|
+
</div>
|
|
1876
|
+
|
|
1877
|
+
<!-- Info Block -->
|
|
1878
|
+
<div class="hf-info-block">
|
|
1879
|
+
<div class="flex items-center gap-2 mb-2">
|
|
1880
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#F87921" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
|
|
1881
|
+
<span class="text-[18px] font-semibold text-[#2B2B2B]">Attention</span>
|
|
1882
|
+
</div>
|
|
1883
|
+
<p class="text-[15px] text-[#4B5675]">
|
|
1884
|
+
When the group is deleted, all related entities will be deleted permanently.
|
|
1885
|
+
</p>
|
|
1886
|
+
</div>
|
|
1887
|
+
</div>
|
|
1888
|
+
|
|
1889
|
+
<!-- Summernote toolbar (live in /portal/seo-pages/edit) -->
|
|
1890
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-12">Rich-text editor (Summernote toolbar)</h3>
|
|
1891
|
+
<div class="hf-card">
|
|
1892
|
+
<div class="hf-rte-toolbar">
|
|
1893
|
+
<div class="hf-rte-group">
|
|
1894
|
+
<button class="hf-rte-btn"><strong>B</strong></button>
|
|
1895
|
+
<button class="hf-rte-btn"><em>I</em></button>
|
|
1896
|
+
<button class="hf-rte-btn"><u>U</u></button>
|
|
1897
|
+
<button class="hf-rte-btn"><s>S</s></button>
|
|
1898
|
+
</div>
|
|
1899
|
+
<div class="hf-rte-group">
|
|
1900
|
+
<button class="hf-rte-btn">H₁</button>
|
|
1901
|
+
<button class="hf-rte-btn">¶</button>
|
|
1902
|
+
</div>
|
|
1903
|
+
<div class="hf-rte-group">
|
|
1904
|
+
<button class="hf-rte-btn">≡</button>
|
|
1905
|
+
<button class="hf-rte-btn">▤</button>
|
|
1906
|
+
<button class="hf-rte-btn">⇲</button>
|
|
1907
|
+
<button class="hf-rte-btn">⇱</button>
|
|
1908
|
+
</div>
|
|
1909
|
+
<div class="hf-rte-group">
|
|
1910
|
+
<button class="hf-rte-btn">🔗</button>
|
|
1911
|
+
<button class="hf-rte-btn">🖼</button>
|
|
1912
|
+
<button class="hf-rte-btn">⊞</button>
|
|
1913
|
+
</div>
|
|
1914
|
+
<div class="hf-rte-group">
|
|
1915
|
+
<button class="hf-rte-btn">↶</button>
|
|
1916
|
+
<button class="hf-rte-btn">↷</button>
|
|
1917
|
+
</div>
|
|
1918
|
+
</div>
|
|
1919
|
+
<div class="hf-rte-editable" contenteditable="true">
|
|
1920
|
+
<p>Editable area. Each toolbar button is a <code>.btn.btn-default.btn-sm.note-btn</code> 32×32, bg <code>#fff</code>, color <code>#333</code>. Hover lightens to <code>--bg-muted</code>.</p>
|
|
1921
|
+
</div>
|
|
1922
|
+
<p class="text-[12px] text-[#99A1B7] mt-2">Live: 13 unique <code>.note-btn</code> variants on <code>/portal/seo-pages/edit</code>. Wraps in <code>.note-toolbar.panel-heading</code>.</p>
|
|
1923
|
+
</div>
|
|
1924
|
+
|
|
1925
|
+
<!-- Krajee FileInput (live) -->
|
|
1926
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-12">File input (Krajee FileInput)</h3>
|
|
1927
|
+
<div class="hf-card">
|
|
1928
|
+
<label class="block hf-text-medium mb-2" for="kvfi">Upload attachment</label>
|
|
1929
|
+
<div class="hf-fileinput" id="kvfi">
|
|
1930
|
+
<span class="hf-fileinput-caption">📎 No file selected</span>
|
|
1931
|
+
<div class="hf-fileinput-actions">
|
|
1932
|
+
<button type="button" title="Remove">×</button>
|
|
1933
|
+
<button type="button" class="browse">Browse...</button>
|
|
1934
|
+
</div>
|
|
1935
|
+
</div>
|
|
1936
|
+
<div class="hf-fileinput-preview">Preview area appears below the input once a file is selected (drag-and-drop also supported).</div>
|
|
1937
|
+
<p class="text-[12px] text-[#99A1B7] mt-2">Live wrapper: <code>.kv-fileinput-caption</code>. Always use Krajee variant — never raw <code><input type="file"></code>.</p>
|
|
1938
|
+
</div>
|
|
1939
|
+
</section>
|
|
1940
|
+
|
|
1941
|
+
<!-- 7. Page Layout -->
|
|
1942
|
+
<section id="page-layout">
|
|
1943
|
+
<h2 class="sg-section-title">Canonical Page Layout</h2>
|
|
1944
|
+
<p class="sg-section-desc">The standard "Portal" architecture: Title Block -> Filters -> Data Grid -> Footer Pagination.</p>
|
|
1945
|
+
|
|
1946
|
+
<div class="bg-[#F1F3F6] p-8 rounded-[12px] border border-[#E4E8EF]">
|
|
1947
|
+
<!-- Mock Portal Canvas -->
|
|
1948
|
+
<div class="bg-[#FBFBFC] rounded-[12px] overflow-hidden shadow-xl border border-[#D1D6DD]">
|
|
1949
|
+
|
|
1950
|
+
<!-- Title Block -->
|
|
1951
|
+
<div class="bg-white px-6 py-5 border-b border-[#E4E8EF] flex justify-between items-center">
|
|
1952
|
+
<div class="flex items-center gap-6">
|
|
1953
|
+
<h1 class="text-[20px] font-semibold">Guests List</h1>
|
|
1954
|
+
<div class="flex gap-4 border-l border-[#E4E8EF] pl-6 text-[14px]">
|
|
1955
|
+
<span class="text-[#24AFE8] font-medium border-b-2 border-[#24AFE8] pb-5 -mb-5">Active</span>
|
|
1956
|
+
<span class="text-[#4B5675] hover:text-[#2B2B2B] cursor-pointer">Archived</span>
|
|
1957
|
+
</div>
|
|
1958
|
+
</div>
|
|
1959
|
+
<button class="btn btn-primary">Add Guest</button>
|
|
1960
|
+
</div>
|
|
1961
|
+
|
|
1962
|
+
<!-- Filters Bar -->
|
|
1963
|
+
<div class="bg-white px-6 py-4 border-b border-[#E4E8EF] flex gap-4 bg-[#FBFBFC]">
|
|
1964
|
+
<input type="text" class="form-control !w-[250px]" placeholder="Search guests...">
|
|
1965
|
+
<select class="form-control !w-[200px] text-[#4B5675]">
|
|
1966
|
+
<option>All Groups</option>
|
|
1967
|
+
</select>
|
|
1968
|
+
<button class="text-[14px] text-[#4B5675] hover:text-[#2B2B2B] font-medium px-4">Reset Filters</button>
|
|
1969
|
+
</div>
|
|
1970
|
+
|
|
1971
|
+
<!-- Data Grid -->
|
|
1972
|
+
<table class="w-full text-left text-[14px] bg-white">
|
|
1973
|
+
<thead class="bg-[#F1F3F6] text-[#4B5675] text-[13px] font-medium border-b border-[#E4E8EF]">
|
|
1974
|
+
<tr>
|
|
1975
|
+
<th class="p-4 w-[48px] text-center"><input type="checkbox" class="hf-checkbox"></th>
|
|
1976
|
+
<th class="p-4">Name</th>
|
|
1977
|
+
<th class="p-4">Status</th>
|
|
1978
|
+
<th class="p-4 text-right">Actions</th>
|
|
1979
|
+
</tr>
|
|
1980
|
+
</thead>
|
|
1981
|
+
<tbody>
|
|
1982
|
+
<tr class="border-b border-[#E4E8EF] hover:bg-[#FBFBFC]">
|
|
1983
|
+
<td class="p-4 text-center"><input type="checkbox" class="hf-checkbox"></td>
|
|
1984
|
+
<td class="p-4 text-[#2B2B2B] font-medium">Michael Scott</td>
|
|
1985
|
+
<td class="p-4"><span class="badge badge-soft-success">Active</span></td>
|
|
1986
|
+
<td class="p-4 text-right text-[#24AFE8] font-medium cursor-pointer">Edit</td>
|
|
1987
|
+
</tr>
|
|
1988
|
+
<tr class="hover:bg-[#FBFBFC]">
|
|
1989
|
+
<td class="p-4 text-center"><input type="checkbox" class="hf-checkbox"></td>
|
|
1990
|
+
<td class="p-4 text-[#2B2B2B] font-medium">Dwight Schrute</td>
|
|
1991
|
+
<td class="p-4"><span class="badge badge-soft-warning">Waiting</span></td>
|
|
1992
|
+
<td class="p-4 text-right text-[#24AFE8] font-medium cursor-pointer">Edit</td>
|
|
1993
|
+
</tr>
|
|
1994
|
+
</tbody>
|
|
1995
|
+
</table>
|
|
1996
|
+
|
|
1997
|
+
<!-- Footer Pagination -->
|
|
1998
|
+
<div class="bg-white px-6 py-4 border-t border-[#E4E8EF] flex justify-between items-center text-[13px] text-[#4B5675]">
|
|
1999
|
+
<div class="flex items-center gap-3">
|
|
2000
|
+
<span>Show</span>
|
|
2001
|
+
<select class="border border-[#D1D6DD] rounded-[4px] px-2 py-1 outline-none">
|
|
2002
|
+
<option>10</option>
|
|
2003
|
+
<option>25</option>
|
|
2004
|
+
</select>
|
|
2005
|
+
<span>per page</span>
|
|
2006
|
+
</div>
|
|
2007
|
+
<div class="flex items-center gap-4">
|
|
2008
|
+
<span>Showing 1-2 of 42 items.</span>
|
|
2009
|
+
<div class="flex gap-1">
|
|
2010
|
+
<div class="w-[30px] h-[30px] flex items-center justify-center rounded-[4px] border border-[#E4E8EF] opacity-50"><</div>
|
|
2011
|
+
<div class="w-[30px] h-[30px] flex items-center justify-center rounded-[4px] bg-[#24AFE8] text-white">1</div>
|
|
2012
|
+
<div class="w-[30px] h-[30px] flex items-center justify-center rounded-[4px] hover:bg-[#F1F3F6] cursor-pointer">2</div>
|
|
2013
|
+
<div class="w-[30px] h-[30px] flex items-center justify-center rounded-[4px] border border-[#E4E8EF] hover:bg-[#F1F3F6] cursor-pointer">></div>
|
|
2014
|
+
</div>
|
|
2015
|
+
</div>
|
|
2016
|
+
</div>
|
|
2017
|
+
|
|
2018
|
+
</div>
|
|
2019
|
+
</div>
|
|
2020
|
+
</section>
|
|
2021
|
+
|
|
2022
|
+
<!-- 7.5 Drift dashboard -->
|
|
2023
|
+
<section id="drift-dashboard">
|
|
2024
|
+
<h2 class="sg-section-title">Drift dashboard</h2>
|
|
2025
|
+
<p class="sg-section-desc">Where compiled CSS diverges from the canonical design narrative in <code class="bg-gray-100 px-1 rounded">UI_DESIGN.md</code>. Rows are <strong>planned</strong> migrations; they are not yet applied to source. See <code class="bg-gray-100 px-1 rounded">docs/migration-plan.md</code> for execution queue.</p>
|
|
2026
|
+
|
|
2027
|
+
<div class="hf-card-elev space-y-4">
|
|
2028
|
+
<div class="grid grid-cols-12 gap-4 items-center pb-3 border-b border-[#E4E8EF]">
|
|
2029
|
+
<div class="col-span-3 text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider">Token / Element</div>
|
|
2030
|
+
<div class="col-span-3 text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider">Canonical</div>
|
|
2031
|
+
<div class="col-span-3 text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider">⚠ Live</div>
|
|
2032
|
+
<div class="col-span-3 text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider">Migration row</div>
|
|
2033
|
+
</div>
|
|
2034
|
+
|
|
2035
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2036
|
+
<div class="col-span-3"><code class="bg-gray-100 px-1 rounded">--primary-color</code></div>
|
|
2037
|
+
<div class="col-span-3 flex items-center gap-2"><span class="inline-block w-4 h-4 rounded" style="background:#26ADE4"></span> <code>#26ADE4</code> <span class="text-[11px] text-amber-500">legacy portal $primary</span></div>
|
|
2038
|
+
<div class="col-span-3 flex items-center gap-2"><span class="inline-block w-4 h-4 rounded" style="background:#24AFE8"></span> <code>#24AFE8</code> <span class="text-[11px] text-[#99A1B7]">(161×)</span></div>
|
|
2039
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">A1 — one-line in <code class="bg-gray-100 px-1 rounded">_variables.scss:220</code></div>
|
|
2040
|
+
</div>
|
|
2041
|
+
|
|
2042
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2043
|
+
<div class="col-span-3"><code class="bg-gray-100 px-1 rounded">$btn_size</code></div>
|
|
2044
|
+
<div class="col-span-3"><code>15px</code> (matches narrative)</div>
|
|
2045
|
+
<div class="col-span-3"><code>16px</code> in SCSS, but only 4 callers; most buttons hard-code <code>15px</code></div>
|
|
2046
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">A2 — `<code>$btn_size: 15px</code>`</div>
|
|
2047
|
+
</div>
|
|
2048
|
+
|
|
2049
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2050
|
+
<div class="col-span-3"><code class="bg-gray-100 px-1 rounded">$card_shadow</code></div>
|
|
2051
|
+
<div class="col-span-3"><code>0 12px 24px rgba(26,26,30,.06)</code></div>
|
|
2052
|
+
<div class="col-span-3 text-[#EA6565]">0 occurrences — token defined but never compiled</div>
|
|
2053
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">G1 — apply to modal-content + dropdown overrides</div>
|
|
2054
|
+
</div>
|
|
2055
|
+
|
|
2056
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2057
|
+
<div class="col-span-3">Modal radius</div>
|
|
2058
|
+
<div class="col-span-3"><code>12px</code></div>
|
|
2059
|
+
<div class="col-span-3"><code>6px</code> (Bootstrap 3 default)</div>
|
|
2060
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">G1 — patch <code>_modal.scss</code></div>
|
|
2061
|
+
</div>
|
|
2062
|
+
|
|
2063
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2064
|
+
<div class="col-span-3">Modal padding</div>
|
|
2065
|
+
<div class="col-span-3"><code>20px</code></div>
|
|
2066
|
+
<div class="col-span-3"><code>15px</code> on header / body / footer</div>
|
|
2067
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">G1</div>
|
|
2068
|
+
</div>
|
|
2069
|
+
|
|
2070
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2071
|
+
<div class="col-span-3">Default transition</div>
|
|
2072
|
+
<div class="col-span-3"><code>0.2s ease-in-out</code> (4×)</div>
|
|
2073
|
+
<div class="col-span-3"><code>0.3s</code> (35×) and <code>0.2s</code> (15×) dominate</div>
|
|
2074
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">tech-debt — unscheduled</div>
|
|
2075
|
+
</div>
|
|
2076
|
+
|
|
2077
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2078
|
+
<div class="col-span-3">Font size scale</div>
|
|
2079
|
+
<div class="col-span-3"><code>11 / 13 / 14 / 15 / 26</code></div>
|
|
2080
|
+
<div class="col-span-3">Live also has 12, 16, 17, 18, 20, 22, 24, 25, 30 px</div>
|
|
2081
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">doc extension — added in §2</div>
|
|
2082
|
+
</div>
|
|
2083
|
+
|
|
2084
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2085
|
+
<div class="col-span-3">Border radius</div>
|
|
2086
|
+
<div class="col-span-3"><code>6 / 9 / 12 / 99 px</code></div>
|
|
2087
|
+
<div class="col-span-3"><code>3</code> (47×) and <code>4</code> (96×) still ship via Bootstrap 3 with <code>!important</code></div>
|
|
2088
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">D2 — Bootstrap 3 purge</div>
|
|
2089
|
+
</div>
|
|
2090
|
+
|
|
2091
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2 border-b border-[#F1F3F6]">
|
|
2092
|
+
<div class="col-span-3">Iconography</div>
|
|
2093
|
+
<div class="col-span-3">Single set (Lucide) — proposed</div>
|
|
2094
|
+
<div class="col-span-3">FA4 (41 classes) + Glyphicons (10) + 134 custom SVG</div>
|
|
2095
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">F1–F3 — see <code>icon-audit.md</code></div>
|
|
2096
|
+
</div>
|
|
2097
|
+
|
|
2098
|
+
<div class="grid grid-cols-12 gap-4 items-center text-[13px] py-2">
|
|
2099
|
+
<div class="col-span-3">Metronic palette</div>
|
|
2100
|
+
<div class="col-span-3">Not in design system</div>
|
|
2101
|
+
<div class="col-span-3">10+ colors leak from <code>components.min.css</code> (5030 rules)</div>
|
|
2102
|
+
<div class="col-span-3 text-[12px] text-[#4B5675]">E1–E3 — multi-sprint purge</div>
|
|
2103
|
+
</div>
|
|
2104
|
+
</div>
|
|
2105
|
+
</section>
|
|
2106
|
+
|
|
2107
|
+
<!-- 7.6 Live extracted state declarations -->
|
|
2108
|
+
<section id="live-states">
|
|
2109
|
+
<h2 class="sg-section-title">Live state declarations</h2>
|
|
2110
|
+
<p class="sg-section-desc">Pseudo-class declarations (<code>:hover</code> / <code>:focus</code> / <code>:active</code> / <code>:disabled</code>) for 17 component classes, parsed from compiled CSS by <code class="bg-gray-100 px-1 rounded">scratch/extract-states-and-anatomy.js</code>. These are the actual state values shipping today — what Figma component variants must match. Full data: <code class="bg-gray-100 px-1 rounded">docs/component-states.json</code>.</p>
|
|
2111
|
+
|
|
2112
|
+
<div class="hf-card-elev overflow-x-auto">
|
|
2113
|
+
<table class="w-full text-[13px] text-left">
|
|
2114
|
+
<thead class="text-[11px] uppercase text-[#99A1B7] font-semibold tracking-wider border-b border-[#E4E8EF]">
|
|
2115
|
+
<tr>
|
|
2116
|
+
<th class="py-2 pr-4">Class</th>
|
|
2117
|
+
<th class="py-2 pr-4">:hover</th>
|
|
2118
|
+
<th class="py-2 pr-4">:focus</th>
|
|
2119
|
+
<th class="py-2 pr-4">:active</th>
|
|
2120
|
+
<th class="py-2 pr-4">:disabled / .disabled</th>
|
|
2121
|
+
</tr>
|
|
2122
|
+
</thead>
|
|
2123
|
+
<tbody>
|
|
2124
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2125
|
+
<td class="py-2 pr-4"><code>.btn-primary</code></td>
|
|
2126
|
+
<td class="py-2 pr-4">bg → <code>$primary_hover</code></td>
|
|
2127
|
+
<td class="py-2 pr-4">2px outline ring <code>$primary</code></td>
|
|
2128
|
+
<td class="py-2 pr-4"><code>scale(0.98)</code></td>
|
|
2129
|
+
<td class="py-2 pr-4">opacity 0.6, no events</td>
|
|
2130
|
+
</tr>
|
|
2131
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2132
|
+
<td class="py-2 pr-4"><code>.btn-hf-outline-primary</code></td>
|
|
2133
|
+
<td class="py-2 pr-4">border + text → <code>$primary</code></td>
|
|
2134
|
+
<td class="py-2 pr-4">outline ring</td>
|
|
2135
|
+
<td class="py-2 pr-4">—</td>
|
|
2136
|
+
<td class="py-2 pr-4">opacity 0.6</td>
|
|
2137
|
+
</tr>
|
|
2138
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2139
|
+
<td class="py-2 pr-4"><code>.btn-cancel</code></td>
|
|
2140
|
+
<td class="py-2 pr-4">bg → <code>#E4E8EF</code></td>
|
|
2141
|
+
<td class="py-2 pr-4">outline ring</td>
|
|
2142
|
+
<td class="py-2 pr-4">—</td>
|
|
2143
|
+
<td class="py-2 pr-4">opacity 0.6</td>
|
|
2144
|
+
</tr>
|
|
2145
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2146
|
+
<td class="py-2 pr-4"><code>.btn-delete</code></td>
|
|
2147
|
+
<td class="py-2 pr-4"><code>filter: brightness(0.9)</code></td>
|
|
2148
|
+
<td class="py-2 pr-4">outline ring <code>$error</code></td>
|
|
2149
|
+
<td class="py-2 pr-4">—</td>
|
|
2150
|
+
<td class="py-2 pr-4">opacity 0.6</td>
|
|
2151
|
+
</tr>
|
|
2152
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2153
|
+
<td class="py-2 pr-4"><code>.btn-reset-filters</code></td>
|
|
2154
|
+
<td class="py-2 pr-4">bg → <code>#DDEEFE</code></td>
|
|
2155
|
+
<td class="py-2 pr-4">—</td>
|
|
2156
|
+
<td class="py-2 pr-4">—</td>
|
|
2157
|
+
<td class="py-2 pr-4"><code>.disabled</code> opacity 0.6</td>
|
|
2158
|
+
</tr>
|
|
2159
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2160
|
+
<td class="py-2 pr-4"><code>.form-control</code></td>
|
|
2161
|
+
<td class="py-2 pr-4">border → <code>#B2BAC4</code></td>
|
|
2162
|
+
<td class="py-2 pr-4">border <code>$primary</code> + 2px ring rgba(38,173,228,.2)</td>
|
|
2163
|
+
<td class="py-2 pr-4">—</td>
|
|
2164
|
+
<td class="py-2 pr-4">bg <code>#f7f9fa</code>, color <code>#7E8CA0</code></td>
|
|
2165
|
+
</tr>
|
|
2166
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2167
|
+
<td class="py-2 pr-4"><code>.select2-selection</code></td>
|
|
2168
|
+
<td class="py-2 pr-4">border → <code>#B2BAC4</code></td>
|
|
2169
|
+
<td class="py-2 pr-4">border <code>$primary</code> + ring</td>
|
|
2170
|
+
<td class="py-2 pr-4">—</td>
|
|
2171
|
+
<td class="py-2 pr-4">—</td>
|
|
2172
|
+
</tr>
|
|
2173
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2174
|
+
<td class="py-2 pr-4"><code>.dropdown-menu .dropdown-item</code></td>
|
|
2175
|
+
<td class="py-2 pr-4">bg <code>#F1F3F6</code></td>
|
|
2176
|
+
<td class="py-2 pr-4">—</td>
|
|
2177
|
+
<td class="py-2 pr-4">—</td>
|
|
2178
|
+
<td class="py-2 pr-4"><code>.disabled</code> opacity 0.5, no events</td>
|
|
2179
|
+
</tr>
|
|
2180
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2181
|
+
<td class="py-2 pr-4"><code>.dropdown-toggle</code></td>
|
|
2182
|
+
<td class="py-2 pr-4">primary tint, no underline</td>
|
|
2183
|
+
<td class="py-2 pr-4">outline ring</td>
|
|
2184
|
+
<td class="py-2 pr-4">bg <code>$primary</code>, white text</td>
|
|
2185
|
+
<td class="py-2 pr-4">—</td>
|
|
2186
|
+
</tr>
|
|
2187
|
+
<tr class="border-b border-[#F1F3F6]">
|
|
2188
|
+
<td class="py-2 pr-4"><code>.pagination .page</code></td>
|
|
2189
|
+
<td class="py-2 pr-4">bg <code>#F1F3F6</code></td>
|
|
2190
|
+
<td class="py-2 pr-4">—</td>
|
|
2191
|
+
<td class="py-2 pr-4"><code>.active</code> bg <code>$primary</code>, white text, hover-shadow</td>
|
|
2192
|
+
<td class="py-2 pr-4"><code>.disabled</code> opacity 0.5</td>
|
|
2193
|
+
</tr>
|
|
2194
|
+
<tr>
|
|
2195
|
+
<td class="py-2 pr-4"><code>.status-hf</code></td>
|
|
2196
|
+
<td class="py-2 pr-4">no change</td>
|
|
2197
|
+
<td class="py-2 pr-4">—</td>
|
|
2198
|
+
<td class="py-2 pr-4"><code>.active</code> highlights border</td>
|
|
2199
|
+
<td class="py-2 pr-4">—</td>
|
|
2200
|
+
</tr>
|
|
2201
|
+
</tbody>
|
|
2202
|
+
</table>
|
|
2203
|
+
</div>
|
|
2204
|
+
</section>
|
|
2205
|
+
|
|
2206
|
+
<!-- 7.7 Live modal anatomy -->
|
|
2207
|
+
<section id="live-modal-anatomy">
|
|
2208
|
+
<h2 class="sg-section-title">Live modal anatomy (measured)</h2>
|
|
2209
|
+
<p class="sg-section-desc">Actual dimensions of <code>.modal-content</code> from <code class="bg-gray-100 px-1 rounded">docs/component-anatomy.json</code> (24 modals across 5 pages). Use these when matching Figma frames to the existing portal — but new code should target the canonical values.</p>
|
|
2210
|
+
|
|
2211
|
+
<div class="hf-card-elev grid md:grid-cols-2 gap-6">
|
|
2212
|
+
<div>
|
|
2213
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider mb-3">Live (measured)</div>
|
|
2214
|
+
<table class="w-full text-[13px]">
|
|
2215
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Width (default)</td><td class="py-1.5"><code>600px</code></td></tr>
|
|
2216
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Width <code>.modal-medium</code></td><td class="py-1.5"><code>400px</code></td></tr>
|
|
2217
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Border radius</td><td class="py-1.5"><code>6px</code></td></tr>
|
|
2218
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Border</td><td class="py-1.5"><code>1px solid rgba(72,91,120,0.15)</code></td></tr>
|
|
2219
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Shadow</td><td class="py-1.5 text-[12px]"><code>0 2px 4px rgba(72,91,120,0.18)</code></td></tr>
|
|
2220
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Header padding</td><td class="py-1.5"><code>15px</code></td></tr>
|
|
2221
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Body padding</td><td class="py-1.5"><code>15px</code></td></tr>
|
|
2222
|
+
<tr><td class="py-1.5 text-[#99A1B7]">Close btn</td><td class="py-1.5">17×17, 21px ×, weight 700</td></tr>
|
|
2223
|
+
</table>
|
|
2224
|
+
</div>
|
|
2225
|
+
<div>
|
|
2226
|
+
<div class="text-[11px] uppercase font-semibold text-[#99A1B7] tracking-wider mb-3">Canonical (target)</div>
|
|
2227
|
+
<table class="w-full text-[13px]">
|
|
2228
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Width sm / lg</td><td class="py-1.5"><code>500px</code> / <code>800px</code></td></tr>
|
|
2229
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Border radius</td><td class="py-1.5"><code>12px</code></td></tr>
|
|
2230
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Border</td><td class="py-1.5">none</td></tr>
|
|
2231
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Shadow</td><td class="py-1.5 text-[12px]"><code>$card_shadow</code> (or <code>--shadow-tooltip</code>)</td></tr>
|
|
2232
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Header padding</td><td class="py-1.5"><code>20px</code> + 1px divider</td></tr>
|
|
2233
|
+
<tr class="border-b border-[#F1F3F6]"><td class="py-1.5 text-[#99A1B7]">Body padding</td><td class="py-1.5"><code>20px</code></td></tr>
|
|
2234
|
+
<tr><td class="py-1.5 text-[#99A1B7]">Close btn</td><td class="py-1.5">32×32 with 6px radius hover</td></tr>
|
|
2235
|
+
</table>
|
|
2236
|
+
</div>
|
|
2237
|
+
</div>
|
|
2238
|
+
<p class="text-[12px] text-[#99A1B7] mt-3">Modals demoed in <a href="#modals" class="text-[#24AFE8]">§Modals</a> follow the canonical anatomy. Migration row <code>G1</code> in <code>docs/migration-plan.md</code>.</p>
|
|
2239
|
+
</section>
|
|
2240
|
+
|
|
2241
|
+
<!-- 8. Live extracted summary -->
|
|
2242
|
+
<section id="extracted-summary">
|
|
2243
|
+
<h2 class="sg-section-title">Live extracted catalog (auto-generated)</h2>
|
|
2244
|
+
<p class="sg-section-desc">Snapshot from <code>scratch/extract-all-pages.js</code>. Last walk covered <strong>32 pages</strong> (13 sidebar + 7 form-from-* + sub-tabs).</p>
|
|
2245
|
+
|
|
2246
|
+
<div class="hf-card">
|
|
2247
|
+
<div class="grid grid-cols-3 md:grid-cols-5 gap-4 text-center">
|
|
2248
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">44</div><div class="text-[12px] text-[#4B5675]">Buttons</div></div>
|
|
2249
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">13</div><div class="text-[12px] text-[#4B5675]">Icon buttons</div></div>
|
|
2250
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">27</div><div class="text-[12px] text-[#4B5675]">Inputs</div></div>
|
|
2251
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">7</div><div class="text-[12px] text-[#4B5675]">Selects</div></div>
|
|
2252
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">37</div><div class="text-[12px] text-[#4B5675]">Toggles*</div></div>
|
|
2253
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">5</div><div class="text-[12px] text-[#4B5675]">Dropdowns</div></div>
|
|
2254
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">16</div><div class="text-[12px] text-[#4B5675]">Modals</div></div>
|
|
2255
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">8</div><div class="text-[12px] text-[#4B5675]">Tables</div></div>
|
|
2256
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">9</div><div class="text-[12px] text-[#4B5675]">Cards</div></div>
|
|
2257
|
+
<div class="bg-[#E9F6FC] rounded-[8px] p-3"><div class="text-[24px] font-semibold text-[#24AFE8]">7</div><div class="text-[12px] text-[#4B5675]">File inputs</div></div>
|
|
2258
|
+
</div>
|
|
2259
|
+
<p class="text-[12px] text-[#99A1B7] mt-3">* — toggles count includes raw fingerprint variants; after normalization (id-stripping) ≈ 4 distinct sizes. See <code>docs/ui-elements-catalog.md</code> for the full deduplicated tables.</p>
|
|
2260
|
+
</div>
|
|
2261
|
+
|
|
2262
|
+
<h3 class="text-[16px] font-semibold mb-4 mt-10">How to refresh the catalog</h3>
|
|
2263
|
+
<pre class="bg-[#FBFBFC] border border-[#E4E8EF] rounded-[12px] p-4 text-[13px] text-[#2B2B2B] overflow-x-auto"><code>cd scratch
|
|
2264
|
+
node extract-all-pages.js # walks the portal, writes docs/ui-elements-catalog.json
|
|
2265
|
+
node render-catalog.js # rebuilds docs/ui-elements-catalog.md (human-readable)</code></pre>
|
|
2266
|
+
</section>
|
|
2267
|
+
|
|
2268
|
+
</div>
|
|
2269
|
+
</main>
|
|
2270
|
+
|
|
2271
|
+
</div><!-- /flex flex-1 — closes the wrapper added by the archival banner -->
|
|
2272
|
+
|
|
2273
|
+
<script>
|
|
2274
|
+
// Copy-to-clipboard for code snippets
|
|
2275
|
+
document.addEventListener('click', (e) => {
|
|
2276
|
+
const btn = e.target.closest('button.copy[data-copy]');
|
|
2277
|
+
if (!btn) return;
|
|
2278
|
+
const pre = btn.parentElement.querySelector('pre');
|
|
2279
|
+
if (!pre) return;
|
|
2280
|
+
const text = pre.innerText;
|
|
2281
|
+
const done = () => {
|
|
2282
|
+
const orig = btn.textContent;
|
|
2283
|
+
btn.textContent = 'Copied ✓';
|
|
2284
|
+
btn.classList.add('copied');
|
|
2285
|
+
setTimeout(() => { btn.textContent = orig; btn.classList.remove('copied'); }, 1400);
|
|
2286
|
+
};
|
|
2287
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
2288
|
+
navigator.clipboard.writeText(text).then(done);
|
|
2289
|
+
} else {
|
|
2290
|
+
const ta = document.createElement('textarea');
|
|
2291
|
+
ta.value = text; document.body.appendChild(ta); ta.select();
|
|
2292
|
+
try { document.execCommand('copy'); done(); } catch {}
|
|
2293
|
+
document.body.removeChild(ta);
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2296
|
+
|
|
2297
|
+
// Toggle interactive switches
|
|
2298
|
+
document.addEventListener('click', (e) => {
|
|
2299
|
+
const sw = e.target.closest('.hf-switch');
|
|
2300
|
+
if (!sw) return;
|
|
2301
|
+
sw.classList.toggle('is-on');
|
|
2302
|
+
sw.setAttribute('aria-checked', sw.classList.contains('is-on') ? 'true' : 'false');
|
|
2303
|
+
});
|
|
2304
|
+
</script>
|
|
2305
|
+
</body>
|
|
2306
|
+
</html>
|