@rimelight/ui 0.0.20 → 0.0.22

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.
@@ -0,0 +1,321 @@
1
+ ---
2
+ interface HighlightGroup {
3
+ keys: string[]
4
+ color?: string
5
+ label?: string
6
+ }
7
+
8
+ interface Props {
9
+ highlightedKeys?: string[]
10
+ groups?: HighlightGroup[]
11
+ keyGap?: number
12
+ sectionGap?: number
13
+ keySize?: number
14
+ variant?: 'full' | '60'
15
+ os?: 'windows' | 'mac'
16
+ highlightColor?: string
17
+ backgroundColor?: string
18
+ }
19
+
20
+ const {
21
+ highlightedKeys = [],
22
+ groups = [],
23
+ keyGap = 8,
24
+ sectionGap = 40,
25
+ keySize = 40,
26
+ variant = 'full',
27
+ os = 'windows',
28
+ highlightColor = 'var(--ui-color-primary-500, #00c16a)',
29
+ backgroundColor = 'transparent'
30
+ } = Astro.props
31
+
32
+ interface Key {
33
+ label?: string
34
+ width: number
35
+ height?: number
36
+ code?: string
37
+ type?: 'spacer' | 'key'
38
+ }
39
+
40
+ const mainRows: Key[][] = [
41
+ [
42
+ { label: 'Esc', width: 1, code: 'Escape' },
43
+ { type: 'spacer', width: 1 },
44
+ { label: 'F1', width: 1 }, { label: 'F2', width: 1 }, { label: 'F3', width: 1 }, { label: 'F4', width: 1 },
45
+ { type: 'spacer', width: 0.5 },
46
+ { label: 'F5', width: 1 }, { label: 'F6', width: 1 }, { label: 'F7', width: 1 }, { label: 'F8', width: 1 },
47
+ { type: 'spacer', width: 0.5 },
48
+ { label: 'F9', width: 1 }, { label: 'F10', width: 1 }, { label: 'F11', width: 1 }, { label: 'F12', width: 1 },
49
+ ],
50
+ [
51
+ { label: '`', width: 1 }, { label: '1', width: 1, code: 'Digit1' }, { label: '2', width: 1, code: 'Digit2' }, { label: '3', width: 1, code: 'Digit3' },
52
+ { label: '4', width: 1, code: 'Digit4' }, { label: '5', width: 1, code: 'Digit5' }, { label: '6', width: 1, code: 'Digit6' }, { label: '7', width: 1, code: 'Digit7' },
53
+ { label: '8', width: 1, code: 'Digit8' }, { label: '9', width: 1, code: 'Digit9' }, { label: '0', width: 1, code: 'Digit0' }, { label: '-', width: 1, code: 'Minus' },
54
+ { label: '=', width: 1, code: 'Equal' }, { label: 'Bkspc', width: 2, code: 'Backspace' },
55
+ ],
56
+ [
57
+ { label: 'Tab', width: 1.5 }, { label: 'Q', width: 1 }, { label: 'W', width: 1 }, { label: 'E', width: 1 },
58
+ { label: 'R', width: 1 }, { label: 'T', width: 1 }, { label: 'Y', width: 1 }, { label: 'U', width: 1 },
59
+ { label: 'I', width: 1 }, { label: 'O', width: 1 }, { label: 'P', width: 1 }, { label: '[', width: 1 },
60
+ { label: ']', width: 1 }, { label: '\\', width: 1.5 },
61
+ ],
62
+ [
63
+ { label: 'Caps', width: 1.75, code: 'CapsLock' }, { label: 'A', width: 1 }, { label: 'S', width: 1 }, { label: 'D', width: 1 },
64
+ { label: 'F', width: 1 }, { label: 'G', width: 1 }, { label: 'H', width: 1 }, { label: 'J', width: 1 },
65
+ { label: 'K', width: 1 }, { label: 'L', width: 1 }, { label: ';', width: 1 }, { label: "'", width: 1 },
66
+ { label: 'Enter', width: 2.25, code: 'Enter' },
67
+ ],
68
+ [
69
+ { label: 'Shift', width: 2.5, code: 'ShiftLeft' }, { label: 'Z', width: 1 }, { label: 'X', width: 1 }, { label: 'C', width: 1 },
70
+ { label: 'V', width: 1 }, { label: 'B', width: 1 }, { label: 'N', width: 1 }, { label: 'M', width: 1 },
71
+ { label: ',', width: 1 }, { label: '.', width: 1, code: 'Period' }, { label: '/', width: 1, code: 'Slash' }, { label: 'Shift', width: 2.5, code: 'ShiftRight' },
72
+ ],
73
+ [
74
+ { label: 'Ctrl', width: 1.25, code: 'ControlLeft' }, { label: 'Win', width: 1.25, code: 'MetaLeft' }, { label: 'Alt', width: 1.25, code: 'AltLeft' },
75
+ { label: 'Space', width: 6.25, code: 'Space' },
76
+ { label: 'Alt', width: 1.25, code: 'AltRight' }, { label: 'Fn', width: 1.25 }, { label: 'Menu', width: 1.25, code: 'ContextMenu' }, { label: 'Ctrl', width: 1.25, code: 'ControlRight' },
77
+ ]
78
+ ]
79
+
80
+ const functionRows: Key[][] = [
81
+ [{ label: 'PrtSc', width: 1, code: 'PrintScreen' }, { label: 'ScrLk', width: 1, code: 'ScrollLock' }, { label: 'Pause', width: 1, code: 'Pause' }],
82
+ [{ label: 'Ins', width: 1 }, { label: 'Home', width: 1 }, { label: 'PgUp', width: 1 }],
83
+ [{ label: 'Del', width: 1 }, { label: 'End', width: 1 }, { label: 'PgDn', width: 1 }],
84
+ [{ type: 'spacer', width: 3 }],
85
+ [{ type: 'spacer', width: 1 }, { label: '↑', width: 1, code: 'ArrowUp' }, { type: 'spacer', width: 1 }],
86
+ [{ label: '←', width: 1, code: 'ArrowLeft' }, { label: '↓', width: 1, code: 'ArrowDown' }, { label: '→', width: 1, code: 'ArrowRight' }],
87
+ ]
88
+
89
+ const numpadKeys: Key[] = [
90
+ { label: 'Num', width: 1, code: 'NumLock' }, { label: '/', width: 1, code: 'NumpadDivide' }, { label: '*', width: 1, code: 'NumpadMultiply' }, { label: '-', width: 1, code: 'NumpadSubtract' },
91
+ { label: '7', width: 1, code: 'Numpad7' }, { label: '8', width: 1, code: 'Numpad8' }, { label: '9', width: 1, code: 'Numpad9' }, { label: '+', width: 1, height: 2, code: 'NumpadAdd' },
92
+ { label: '4', width: 1, code: 'Numpad4' }, { label: '5', width: 1, code: 'Numpad5' }, { label: '6', width: 1, code: 'Numpad6' },
93
+ { label: '1', width: 1, code: 'Numpad1' }, { label: '2', width: 1, code: 'Numpad2' }, { label: '3', width: 1, code: 'Numpad3' }, { label: 'Enter', width: 1, height: 2, code: 'NumpadEnter' },
94
+ { label: '0', width: 2, code: 'Numpad0' }, { label: '.', width: 1, code: 'NumpadDecimal' },
95
+ ]
96
+
97
+ function getKeyLabel(key: Key) {
98
+ if (os !== 'mac') return key.label;
99
+
100
+ const macMap: Record<string, string> = {
101
+ 'Ctrl': 'control',
102
+ 'Win': 'option',
103
+ 'Alt': 'command',
104
+ 'Bkspc': 'delete',
105
+ 'Enter': 'return',
106
+ 'Caps': 'caps lock',
107
+ 'Shift': 'shift',
108
+ 'Menu': 'option',
109
+ 'Tab': 'tab',
110
+ 'Esc': 'esc',
111
+ };
112
+
113
+ const label = (key.label && macMap[key.label]) || key.label;
114
+
115
+ if (label === 'command') return 'cmd ⌘';
116
+ if (label === 'option') return 'opt ⌥';
117
+ if (label === 'control') return 'ctrl ⌃';
118
+ if (label === 'shift') return 'shift ⇧';
119
+ if (label === 'return') return 'return ↩';
120
+ if (label === 'delete') return 'delete ⌫';
121
+
122
+ return label;
123
+ }
124
+
125
+ function getKeyHighlight(key: Key) {
126
+ if (!key) return { active: false };
127
+
128
+ const code = key.code || key.label || '';
129
+ const label = key.label || '';
130
+ const macLabel = getKeyLabel(key) || '';
131
+
132
+ const isMatch = (list: string[]) => {
133
+ if (!list || !Array.isArray(list)) return false;
134
+ if (list.includes(code)) return true;
135
+ if (list.includes(label)) {
136
+ if (code.startsWith('Numpad') && /^\d$/.test(label)) return false;
137
+ return true;
138
+ }
139
+ return os === 'mac' && list.includes(macLabel);
140
+ };
141
+
142
+ if (isMatch(highlightedKeys)) {
143
+ return { active: true, color: highlightColor };
144
+ }
145
+
146
+ for (const group of groups) {
147
+ if (isMatch(group.keys)) {
148
+ return { active: true, color: group.color };
149
+ }
150
+ }
151
+
152
+ return { active: false };
153
+ }
154
+
155
+ const displayMainRows = variant === '60'
156
+ ? [
157
+ [{ label: 'Esc', width: 1, code: 'Escape' }, ...(mainRows[1] || []).slice(1)],
158
+ ...mainRows.slice(2)
159
+ ]
160
+ : mainRows;
161
+
162
+
163
+ interface RenderKey extends Key {
164
+ x: number;
165
+ y: number;
166
+ w: number;
167
+ h: number;
168
+ }
169
+
170
+ function processRows(rows: Key[][], startX: number, startY: number): RenderKey[] {
171
+ const result: RenderKey[] = [];
172
+ let currentY = startY;
173
+
174
+ for (const row of rows) {
175
+ let currentX = startX;
176
+ for (const key of row) {
177
+ const w = key.width || 1;
178
+ const h = key.height || 1;
179
+ const widthPx = w * keySize + (w - 1) * keyGap;
180
+ const heightPx = h * keySize + (h - 1) * keyGap;
181
+
182
+ if (key.type !== 'spacer') {
183
+ result.push({
184
+ ...key,
185
+ x: currentX,
186
+ y: currentY,
187
+ w: widthPx,
188
+ h: heightPx
189
+ });
190
+ }
191
+ currentX += widthPx + keyGap;
192
+ }
193
+ currentY += keySize + keyGap;
194
+ }
195
+ return result;
196
+ }
197
+
198
+ const mainRenderKeys = processRows(displayMainRows, 0, 0);
199
+ const mainHeight = displayMainRows.length * (keySize + keyGap);
200
+
201
+ let secondaryKeys: RenderKey[] = [];
202
+ let numpadRenderKeys: RenderKey[] = [];
203
+ let totalWidth = (15 * keySize) + (14 * keyGap);
204
+ let finalHeight = mainHeight;
205
+
206
+ if (variant === 'full') {
207
+ const secondaryY = mainHeight + sectionGap;
208
+ secondaryKeys = processRows(functionRows, 0, secondaryY);
209
+
210
+ const numpadX = (3 * keySize) + (3 * keyGap) + sectionGap;
211
+
212
+ numpadKeys.forEach((key, i) => {
213
+ const k = key as Key;
214
+ const w = k.width || 1;
215
+ const h = k.height || 1;
216
+
217
+ const positions = [
218
+ [0,0], [1,0], [2,0], [3,0],
219
+ [0,1], [1,1], [2,1], [3,1],
220
+ [0,2], [1,2], [2,2],
221
+ [0,3], [1,3], [2,3], [3,3],
222
+ [0,4], [2,4]
223
+ ];
224
+
225
+ const pxOffset = positions[i]?.[0] ?? 0;
226
+ const pyOffset = positions[i]?.[1] ?? 0;
227
+
228
+ const px = numpadX + pxOffset * (keySize + keyGap);
229
+ const py = secondaryY + (pyOffset + 1) * (keySize + keyGap);
230
+
231
+ numpadRenderKeys.push({
232
+ ...k,
233
+ x: px,
234
+ y: py,
235
+ w: w * keySize + (w - 1) * keyGap,
236
+ h: h * keySize + (h - 1) * keyGap
237
+ });
238
+ });
239
+
240
+ totalWidth = Math.max(totalWidth, numpadX + (4 * keySize) + (3 * keyGap));
241
+ finalHeight = secondaryY + (6 * keySize) + (5 * keyGap);
242
+ }
243
+ ---
244
+
245
+ <div class="keyboard-wrapper">
246
+ <div class="keyboard-container">
247
+ <svg
248
+ viewBox={`-16 -16 ${totalWidth + 32} ${finalHeight + 64}`}
249
+ class="keyboard-svg"
250
+ preserveAspectRatio="xMidYMid meet"
251
+ >
252
+ {backgroundColor && backgroundColor !== 'transparent' && (
253
+ <rect
254
+ x="-16" y="-16"
255
+ width={totalWidth + 32}
256
+ height={finalHeight + 64}
257
+ fill={backgroundColor}
258
+ rx="12"
259
+ />
260
+ )}
261
+
262
+ {[...mainRenderKeys, ...secondaryKeys, ...numpadRenderKeys].map((key) => {
263
+ const highlight = getKeyHighlight(key);
264
+ const color = highlight.active ? (highlight.color || highlightColor) : '#2a2a3e';
265
+ const label = getKeyLabel(key);
266
+
267
+ return (
268
+ <g class={`kb-key-group ${highlight.active ? 'highlighted' : ''}`}>
269
+ {/* Key Base / Shadow */}
270
+ <rect
271
+ x={key.x}
272
+ y={key.y + 1}
273
+ width={key.w}
274
+ height={key.h}
275
+ rx="4"
276
+ fill="#1a1a2e"
277
+ />
278
+ {/* Key Face */}
279
+ <rect
280
+ x={key.x}
281
+ y={key.y}
282
+ width={key.w}
283
+ height={key.h}
284
+ rx="4"
285
+ fill={color}
286
+ stroke={highlight.active ? "#ffffff66" : "#3a3a4e"}
287
+ stroke-width="1"
288
+ />
289
+ {label && (
290
+ <text
291
+ x={key.x + key.w / 2}
292
+ y={key.y + key.h / 2}
293
+ text-anchor="middle"
294
+ dominant-baseline="central"
295
+ class="kb-key-label"
296
+ fill={highlight.active ? "#fff" : "#e0e0e0"}
297
+ >
298
+ {label}
299
+ </text>
300
+ )}
301
+ </g>
302
+ );
303
+ })}
304
+
305
+ </svg>
306
+ </div>
307
+
308
+ {groups.some(g => g.label) && (
309
+ <div class="flex flex-wrap justify-center gap-x-6 gap-y-3 mt-6 w-full">
310
+ {groups.filter(g => g.label).map(group => (
311
+ <div class="flex items-center gap-2 m-0 p-0 text-[10px] text-[#a0a0b0] uppercase tracking-[0.05em] font-medium whitespace-nowrap leading-none">
312
+ <svg width="8" height="8" class="flex-shrink-0 block">
313
+ <rect width="8" height="8" rx="2" fill={group.color || '#6366f1'} />
314
+ </svg>
315
+ <span class="m-0 p-0 leading-none inline-block">{group.label}</span>
316
+ </div>
317
+ ))}
318
+ </div>
319
+ )}
320
+ </div>
321
+
@@ -59,13 +59,7 @@ export default function starlightAddons(userConfig?: StarlightAddonsConfig): Sta
59
59
  return {
60
60
  name: "rimelight-ui-starlight-addons",
61
61
  hooks: {
62
- "config:setup"({
63
- addIntegration,
64
- updateConfig,
65
- logger,
66
- command,
67
- config: starlightConfig
68
- }) {
62
+ "config:setup"({ addIntegration, updateConfig, logger, command, config: starlightConfig }) {
69
63
  // --- Sidebar Topics Logic ---
70
64
  if ((command === "dev" || command === "build") && topicsData.length > 0) {
71
65
  if (starlightConfig.sidebar) {
@@ -1,3 +1,156 @@
1
1
  @import "tailwindcss";
2
2
  @import "@nuxt/ui";
3
3
  @import "./prism.css";
4
+
5
+ /* Keyboard Component Styles */
6
+ .keyboard-wrapper {
7
+ display: flex;
8
+ flex-direction: column;
9
+ align-items: center;
10
+ padding: 16px;
11
+ border-radius: 12px;
12
+ width: 100%;
13
+ max-width: 100%;
14
+ margin: 16px 0;
15
+ box-sizing: border-box;
16
+ }
17
+ .keyboard-container {
18
+ width: 100%;
19
+ display: flex;
20
+ justify-content: center;
21
+ }
22
+ .keyboard-svg {
23
+ width: 100%;
24
+ height: auto;
25
+ max-width: 900px;
26
+ }
27
+ .kb-key-label {
28
+ font-family: var(--font-mono, monospace);
29
+ font-size: 10px;
30
+ font-weight: 600;
31
+ pointer-events: none;
32
+ user-select: none;
33
+ }
34
+ .kb-legend {
35
+ display: flex;
36
+ flex-wrap: wrap;
37
+ justify-content: center;
38
+ gap: 12px 24px;
39
+ margin-top: 24px;
40
+ width: 100%;
41
+ }
42
+ .keyboard-wrapper .legend-item {
43
+ display: flex !important;
44
+ align-items: center !important;
45
+ gap: 8px;
46
+ margin: 0 !important;
47
+ padding: 0 !important;
48
+ font-size: 10px;
49
+ color: #a0a0b0;
50
+ text-transform: uppercase;
51
+ letter-spacing: 0.05em;
52
+ font-weight: 500;
53
+ white-space: nowrap;
54
+ line-height: 1 !important;
55
+ }
56
+ .legend-color-svg {
57
+ flex-shrink: 0;
58
+ display: block;
59
+ }
60
+ .keyboard-wrapper .legend-label {
61
+ margin: 0 !important;
62
+ padding: 0 !important;
63
+ line-height: 1 !important;
64
+ display: inline-block !important;
65
+ }
66
+
67
+ /* Gamepad Component Styles */
68
+ .gamepad-wrapper {
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ padding: 48px;
73
+ border-radius: 24px;
74
+ width: 100%;
75
+ max-width: 100%;
76
+ margin: 24px 0;
77
+ box-sizing: border-box;
78
+ container-type: inline-size;
79
+ border: 1px solid #1a1a2e;
80
+ }
81
+ .gamepad-container {
82
+ width: 100%;
83
+ max-width: 440px;
84
+ }
85
+ .gamepad-svg {
86
+ width: 100%;
87
+ height: auto;
88
+ }
89
+ .gp-btn rect,
90
+ .gp-btn circle {
91
+ fill: #1e1e30;
92
+ stroke: #33334d;
93
+ stroke-width: 1;
94
+ transition: all 0.2s ease;
95
+ }
96
+ .btn-label {
97
+ fill: #555570;
98
+ font-size: 10px;
99
+ font-family: var(--font-sans, system-ui);
100
+ font-weight: 800;
101
+ pointer-events: none;
102
+ line-height: 1;
103
+ }
104
+ .gp-btn.active rect,
105
+ .gp-btn.active circle {
106
+ fill: var(--hl-color, #00c16a);
107
+ stroke: #ffffff33;
108
+ stroke-width: 1.5;
109
+ }
110
+ .gp-btn.active .btn-label {
111
+ fill: #fff;
112
+ }
113
+ .gamepad-legend {
114
+ display: flex;
115
+ flex-wrap: wrap;
116
+ justify-content: center;
117
+ gap: 12px 24px;
118
+ margin-top: 40px;
119
+ width: 100%;
120
+ }
121
+ .gamepad-wrapper .legend-item {
122
+ display: flex !important;
123
+ align-items: center !important;
124
+ gap: 8px;
125
+ height: 10px !important;
126
+ font-size: 10px;
127
+ color: #777790;
128
+ text-transform: uppercase;
129
+ letter-spacing: 0.1em;
130
+ font-weight: 700;
131
+ line-height: 10px !important;
132
+ padding: 0 !important;
133
+ margin: 0 !important;
134
+ }
135
+ .gamepad-wrapper .legend-label {
136
+ display: inline-block !important;
137
+ height: 10px !important;
138
+ line-height: 10px !important;
139
+ margin: 0 !important;
140
+ padding: 0 !important;
141
+ }
142
+
143
+ .kb-legend-label {
144
+ font-family: var(--font-sans, system-ui);
145
+ font-size: 10px;
146
+ font-weight: 700;
147
+ text-transform: uppercase;
148
+ letter-spacing: 0.05em;
149
+ }
150
+ .gp-legend-label {
151
+ font-family: var(--font-sans, system-ui);
152
+ font-size: 10px;
153
+ font-weight: 700;
154
+ text-transform: uppercase;
155
+ letter-spacing: 0.1em;
156
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Theme configuration for the Footer component. Defines the slots, base styles, and variants for
3
+ * layout management.
4
+ */
5
+ export const footerTheme = {
6
+ slots: ["root", "container", "left", "center", "right"],
7
+ base: {
8
+ root: "py-8 lg:py-12",
9
+ container:
10
+ "flex flex-col justify-between gap-xl lg:flex-row lg:items-stretch px-4 md:px-6 lg:px-8",
11
+ left: "order-last flex flex-col items-center justify-between gap-xl lg:order-1 lg:flex-none lg:items-start",
12
+ center: "flex flex-col items-center justify-start lg:order-2 lg:flex-1",
13
+ right:
14
+ "order-first flex flex-col items-center justify-between gap-xl lg:order-3 lg:flex-none lg:items-end"
15
+ },
16
+ variants: {
17
+ contain: {
18
+ true: {
19
+ container: "mx-auto max-w-7xl"
20
+ },
21
+ false: {
22
+ container: "w-full"
23
+ }
24
+ }
25
+ },
26
+ defaultVariants: {
27
+ contain: false
28
+ }
29
+ } as const
@@ -1,11 +1,29 @@
1
1
  /**
2
2
  * Theme configuration for the Header component. Defines the slots, base styles, and variants for
3
3
  * layout management.
4
+ *
5
+ * Slots:
6
+ *
7
+ * - `root` — the `<header>` element
8
+ * - `content` — inner wrapper div used for height measurement (fixed/hideOnScroll mode)
9
+ * - `container` — max-width flex row
10
+ * - `left` — left region
11
+ * - `center` — center region
12
+ * - `right` — right region
13
+ *
14
+ * Variants:
15
+ *
16
+ * - `contain` — constrains container to max-w-7xl
17
+ * - `sticky` — sticky positioning (ignored when `fixed` variant is true)
18
+ * - `fixed` — position: fixed with left/right 0 and smooth top/opacity transition; used for stacked
19
+ * header layers. Top offset and z-index are applied via inline style (top prop + stackIndex prop)
20
+ * rather than theme classes.
4
21
  */
5
22
  export const headerTheme = {
6
- slots: ["root", "container", "left", "center", "right"],
23
+ slots: ["root", "content", "container", "left", "center", "right"],
7
24
  base: {
8
25
  root: "w-full",
26
+ content: "w-full",
9
27
  container:
10
28
  "flex flex-row items-center justify-between gap-4xs h-16 md:h-18 px-4 md:px-6 lg:px-8",
11
29
  left: "flex flex-none items-center justify-start",
@@ -28,10 +46,22 @@ export const headerTheme = {
28
46
  false: {
29
47
  root: "relative"
30
48
  }
49
+ },
50
+ /**
51
+ * Fixed-layer mode. When true, overrides sticky/relative positioning with `position: fixed` and
52
+ * enables smooth transitions. `top` and `z-index` are applied via inline `:style` on the
53
+ * component.
54
+ */
55
+ fixed: {
56
+ true: {
57
+ root: "fixed left-0 right-0 transition-[top,opacity] duration-200 ease-in-out"
58
+ },
59
+ false: {}
31
60
  }
32
61
  },
33
62
  defaultVariants: {
34
63
  contain: true,
35
- sticky: true
64
+ sticky: true,
65
+ fixed: false
36
66
  }
37
67
  } as const
@@ -1,13 +1,17 @@
1
- import { buttonTheme } from "./button.theme"
2
1
  import { headerTheme } from "./header.theme"
2
+ import { footerTheme } from "./footer.theme"
3
+ import { scrollToTopTheme } from "./scroll-to-top.theme"
4
+ import { buttonTheme } from "./button.theme"
3
5
 
4
6
  /**
5
7
  * Default UI configuration for all components. This is the baseline that gets merged with
6
8
  * user-provided overrides via the Astro integration options.
7
9
  */
8
10
  export const defaultUIConfig = {
9
- button: buttonTheme,
10
- header: headerTheme
11
+ "header": headerTheme,
12
+ "footer": footerTheme,
13
+ "scroll-to-top": scrollToTopTheme,
14
+ "button": buttonTheme
11
15
  } as const
12
16
 
13
17
  export type DefaultUIConfig = typeof defaultUIConfig
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Theme configuration for the ScrollToTop component. Defines the slots, base styles, and variants
3
+ * for the scroll-to-top button with progress indicator.
4
+ */
5
+ export const scrollToTopTheme = {
6
+ slots: ["root", "button", "progressBase", "svg", "iconContainer", "icon"],
7
+ base: {
8
+ root: "fixed bottom-6 right-6 z-50",
9
+ button: "size-14 lg:size-12 p-0 rounded-full",
10
+ progressBase: "progress-circle-base size-full",
11
+ svg: "size-full",
12
+ iconContainer: "absolute inset-0 flex items-center justify-center text-center",
13
+ icon: "size-6 text-white"
14
+ },
15
+ variants: {
16
+ color: {
17
+ primary: {
18
+ progressBase: "",
19
+ svg: "",
20
+ iconContainer: "",
21
+ icon: ""
22
+ },
23
+ secondary: {
24
+ progressBase: "",
25
+ svg: "",
26
+ iconContainer: "",
27
+ icon: ""
28
+ }
29
+ }
30
+ },
31
+ compoundVariants: [
32
+ {
33
+ color: "primary",
34
+ classNames: {
35
+ icon: "text-primary-foreground"
36
+ }
37
+ },
38
+ {
39
+ color: "secondary",
40
+ classNames: {
41
+ icon: "text-secondary-foreground"
42
+ }
43
+ }
44
+ ],
45
+ defaultVariants: {
46
+ color: "primary"
47
+ }
48
+ } as const