@mrintel/villain-ui 0.8.2 → 0.9.1
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/README.md +52 -3
- package/dist/components/buttons/Button.svelte +1 -1
- package/dist/components/buttons/FloatingActionButton.svelte +1 -1
- package/dist/components/buttons/IconButton.svelte +2 -2
- package/dist/components/buttons/LinkButton.svelte +1 -1
- package/dist/components/buttons/buttonClasses.js +7 -7
- package/dist/components/cards/Card.svelte +43 -11
- package/dist/components/cards/Card.svelte.d.ts +11 -0
- package/dist/components/cards/Panel.svelte +44 -5
- package/dist/components/cards/Panel.svelte.d.ts +7 -0
- package/dist/components/cards/SectionHeader.svelte +2 -2
- package/dist/components/data/Avatar.svelte +1 -1
- package/dist/components/data/Badge.svelte +3 -3
- package/dist/components/data/CalendarGrid.svelte +6 -4
- package/dist/components/data/CalendarGrid.svelte.d.ts +3 -0
- package/dist/components/data/CodeBlock.svelte +1 -1
- package/dist/components/data/List.svelte +1 -1
- package/dist/components/data/Pagination.svelte +3 -3
- package/dist/components/data/Stat.svelte +3 -5
- package/dist/components/data/Table.svelte +12 -14
- package/dist/components/data/Tag.svelte +1 -1
- package/dist/components/data/WeekHeatmap.svelte +2 -2
- package/dist/components/forms/Checkbox.svelte +1 -1
- package/dist/components/forms/DatePicker.svelte +3 -1
- package/dist/components/forms/DateTimePicker.svelte +3 -1
- package/dist/components/forms/FileUpload.svelte +1 -1
- package/dist/components/forms/FormSection.svelte +21 -0
- package/dist/components/forms/FormSection.svelte.d.ts +14 -0
- package/dist/components/forms/InputGroup.svelte +1 -1
- package/dist/components/forms/RadioGroup.svelte +0 -1
- package/dist/components/forms/RangeSlider.svelte +2 -6
- package/dist/components/forms/SelectMenu.svelte +4 -3
- package/dist/components/forms/Switch.svelte +1 -1
- package/dist/components/forms/TimePicker.svelte +1 -1
- package/dist/components/forms/TimePickerGrid.svelte +0 -3
- package/dist/components/forms/formClasses.d.ts +2 -2
- package/dist/components/forms/formClasses.js +2 -2
- package/dist/components/forms/index.d.ts +1 -0
- package/dist/components/forms/index.js +1 -0
- package/dist/components/navigation/Breadcrumbs.svelte +3 -3
- package/dist/components/navigation/ContextMenu.svelte +2 -2
- package/dist/components/navigation/DropdownMenu.svelte +2 -2
- package/dist/components/navigation/Menu.svelte +2 -2
- package/dist/components/navigation/Navbar.svelte +10 -2
- package/dist/components/navigation/Sidebar.svelte +6 -9
- package/dist/components/navigation/Tabs.svelte +2 -2
- package/dist/components/overlays/Alert.svelte +1 -1
- package/dist/components/overlays/CommandPalette.svelte +2 -2
- package/dist/components/overlays/Drawer.svelte +5 -5
- package/dist/components/overlays/Dropdown.svelte +1 -1
- package/dist/components/overlays/Modal.svelte +2 -2
- package/dist/components/overlays/Popover.svelte +1 -1
- package/dist/components/overlays/ProgressBar.svelte +3 -3
- package/dist/components/overlays/SkeletonLoader.svelte +2 -2
- package/dist/components/overlays/Spinner.svelte +1 -1
- package/dist/components/overlays/Toast.svelte +2 -2
- package/dist/components/overlays/Tooltip.svelte +1 -1
- package/dist/components/typography/Code.svelte +1 -1
- package/dist/components/utilities/Carousel.svelte +4 -4
- package/dist/components/utilities/Collapse.svelte +1 -1
- package/dist/components/utilities/Hero.svelte +3 -2
- package/dist/components/utilities/SystemConsole.svelte +1 -1
- package/dist/components/utilities/SystemInterface.svelte +1 -2
- package/dist/components/wizard/StepForm.svelte +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/theme.css +207 -190
- package/package.json +2 -1
|
@@ -256,7 +256,7 @@ const errorClasses = $derived(hasError ? 'error-state' : '');
|
|
|
256
256
|
role="dialog"
|
|
257
257
|
aria-modal="true"
|
|
258
258
|
aria-label="Choose date and time"
|
|
259
|
-
class="datetime-picker-dropdown {variant === 'glass' ? 'glass-panel' : 'panel-floating'} rounded-
|
|
259
|
+
class="datetime-picker-dropdown {variant === 'glass' ? 'glass-panel' : 'panel-floating'} rounded-[var(--radius-sm)] overflow-hidden"
|
|
260
260
|
onclick={(e) => e.stopPropagation()}
|
|
261
261
|
>
|
|
262
262
|
<!-- Tab navigation -->
|
|
@@ -308,6 +308,8 @@ const errorClasses = $derived(hasError ? 'error-state' : '');
|
|
|
308
308
|
selectedDate={selectedDate}
|
|
309
309
|
onDateSelect={handleDateSelect}
|
|
310
310
|
highlightToday={true}
|
|
311
|
+
minDate={minDateStr ? new Date(minDateStr + 'T00:00:00') : undefined}
|
|
312
|
+
maxDate={maxDateStr ? new Date(maxDateStr + 'T00:00:00') : undefined}
|
|
311
313
|
class="calendar-picker"
|
|
312
314
|
/>
|
|
313
315
|
{:else}
|
|
@@ -67,7 +67,7 @@ const fileList = $derived(files ? Array.from(files) : []);
|
|
|
67
67
|
ondrop={handleDrop}
|
|
68
68
|
onclick={handleClick}
|
|
69
69
|
onkeydown={(e) => e.key === 'Enter' && handleClick()}
|
|
70
|
-
class="panel-raised rounded-[var(--radius-
|
|
70
|
+
class="panel-raised rounded-[var(--radius-sm)] p-8 text-center cursor-pointer transition-all duration-300 ease-luxe {isDragging ? 'border-2 border-accent accent-glow bg-base-2' : ''} {hasError && !isDragging ? 'border-2 border-error' : ''} {disabled ? 'opacity-50 cursor-not-allowed pointer-events-none' : ''}"
|
|
71
71
|
>
|
|
72
72
|
<div class="flex flex-col items-center gap-2">
|
|
73
73
|
{#if icon}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">let { legend, description, columns = 1, class: className = '', children, ...restProps } = $props();
|
|
2
|
+
export {};
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<fieldset class="border-0 p-0 m-0 min-w-0 {className}" {...restProps}>
|
|
6
|
+
{#if legend}
|
|
7
|
+
<legend
|
|
8
|
+
class="font-[var(--font-mono)] text-xs uppercase tracking-[0.08em] text-[var(--color-text-soft)] p-0 mb-2 w-full border-b border-[var(--color-border-subtle)] pb-3"
|
|
9
|
+
>
|
|
10
|
+
{legend}
|
|
11
|
+
</legend>
|
|
12
|
+
{/if}
|
|
13
|
+
{#if description}
|
|
14
|
+
<p class="text-sm text-[var(--color-text-soft)] mt-3 mb-6">{description}</p>
|
|
15
|
+
{:else if legend}
|
|
16
|
+
<div class="mt-6"></div>
|
|
17
|
+
{/if}
|
|
18
|
+
<div class="grid gap-5 {columns === 2 ? 'md:grid-cols-2' : ''}">
|
|
19
|
+
{@render children?.()}
|
|
20
|
+
</div>
|
|
21
|
+
</fieldset>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Mono uppercase section label (e.g. "01 / IDENTITY"). */
|
|
4
|
+
legend?: string;
|
|
5
|
+
/** Supporting copy under the legend. */
|
|
6
|
+
description?: string;
|
|
7
|
+
/** Field layout: single column (default) or two columns on md+. */
|
|
8
|
+
columns?: 1 | 2;
|
|
9
|
+
class?: string;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
}
|
|
12
|
+
declare const FormSection: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type FormSection = ReturnType<typeof FormSection>;
|
|
14
|
+
export default FormSection;
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// No props needed for standard slot usage
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
|
-
<div class="flex items-stretch rounded-[var(--radius-
|
|
5
|
+
<div class="flex items-stretch rounded-[var(--radius-sm)] overflow-hidden panel-raised [&>*:not(:first-child)]:ml-[-1px] [&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none">
|
|
6
6
|
<slot />
|
|
7
7
|
</div>
|
|
@@ -47,7 +47,6 @@ const percentage = $derived(max === min ? 0 : ((value - min) / (max - min)) * 10
|
|
|
47
47
|
height: 1.25rem;
|
|
48
48
|
border-radius: var(--radius-pill);
|
|
49
49
|
background: var(--color-accent);
|
|
50
|
-
box-shadow: var(--shadow-accent-glow);
|
|
51
50
|
cursor: pointer;
|
|
52
51
|
transition: transform 0.2s var(--ease-luxe);
|
|
53
52
|
}
|
|
@@ -62,7 +61,6 @@ const percentage = $derived(max === min ? 0 : ((value - min) / (max - min)) * 10
|
|
|
62
61
|
height: 1.25rem;
|
|
63
62
|
border-radius: var(--radius-pill);
|
|
64
63
|
background: var(--color-accent);
|
|
65
|
-
box-shadow: var(--shadow-accent-glow);
|
|
66
64
|
cursor: pointer;
|
|
67
65
|
transition: transform 0.2s var(--ease-luxe);
|
|
68
66
|
border: none;
|
|
@@ -73,15 +71,13 @@ const percentage = $derived(max === min ? 0 : ((value - min) / (max - min)) * 10
|
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
input[type="range"]:focus::-webkit-slider-thumb {
|
|
76
|
-
box-shadow:
|
|
77
|
-
var(--shadow-accent-glow),
|
|
74
|
+
box-shadow:
|
|
78
75
|
0 0 0 3px var(--color-base-1),
|
|
79
76
|
0 0 0 5px var(--color-accent);
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
input[type="range"]:focus::-moz-range-thumb {
|
|
83
|
-
box-shadow:
|
|
84
|
-
var(--shadow-accent-glow),
|
|
80
|
+
box-shadow:
|
|
85
81
|
0 0 0 3px var(--color-base-1),
|
|
86
82
|
0 0 0 5px var(--color-accent);
|
|
87
83
|
}
|
|
@@ -86,16 +86,17 @@ function handleListboxKeyDown(event) {
|
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
function scrollOptionIntoView(index) {
|
|
89
|
+
function scrollOptionIntoView(index, block = 'nearest') {
|
|
90
90
|
requestAnimationFrame(() => {
|
|
91
91
|
const optionEl = listboxElement?.querySelector(`[data-index="${index}"]`);
|
|
92
|
-
optionEl?.scrollIntoView({ block
|
|
92
|
+
optionEl?.scrollIntoView({ block });
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
-
// Set highlighted index and focus listbox when dropdown opens
|
|
95
|
+
// Set highlighted index, scroll it into view, and focus listbox when dropdown opens
|
|
96
96
|
$effect(() => {
|
|
97
97
|
if (open) {
|
|
98
98
|
highlightedIndex = selectedIndex >= 0 ? selectedIndex : 0;
|
|
99
|
+
scrollOptionIntoView(highlightedIndex, 'center');
|
|
99
100
|
if (listboxElement) {
|
|
100
101
|
requestAnimationFrame(() => listboxElement?.focus());
|
|
101
102
|
}
|
|
@@ -14,7 +14,7 @@ const hasError = $derived(error || !!validationMessage);
|
|
|
14
14
|
{disabled}
|
|
15
15
|
bind:checked
|
|
16
16
|
onchange={onchange}
|
|
17
|
-
class="w-14 h-7 rounded-pill bg-base-3 border appearance-none transition-all duration-300 ease-luxe cursor-pointer checked:bg-accent
|
|
17
|
+
class="w-14 h-7 rounded-pill bg-base-3 border appearance-none transition-all duration-300 ease-luxe cursor-pointer checked:bg-accent focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 focus:ring-offset-base-1 relative {hasError ? 'border-error' : 'border-border'} {disabled ? 'cursor-not-allowed' : ''}"
|
|
18
18
|
/>
|
|
19
19
|
{#if iconBefore}
|
|
20
20
|
<span class="inline-flex items-center justify-center text-text-soft">
|
|
@@ -169,7 +169,7 @@ const errorClasses = $derived(hasError ? 'error-state' : '');
|
|
|
169
169
|
role="dialog"
|
|
170
170
|
aria-modal="true"
|
|
171
171
|
aria-label="Choose time"
|
|
172
|
-
class="time-picker-dropdown {variant === 'glass' ? 'glass-panel' : 'panel-floating'} rounded-
|
|
172
|
+
class="time-picker-dropdown {variant === 'glass' ? 'glass-panel' : 'panel-floating'} rounded-[var(--radius-sm)] overflow-hidden"
|
|
173
173
|
>
|
|
174
174
|
<TimePickerGrid
|
|
175
175
|
bind:hours={selectedHours}
|
|
@@ -445,7 +445,6 @@ $effect(() => {
|
|
|
445
445
|
border-color: var(--color-accent);
|
|
446
446
|
color: var(--color-base-0);
|
|
447
447
|
font-weight: 700;
|
|
448
|
-
box-shadow: 0 0 12px var(--color-accent-glow);
|
|
449
448
|
}
|
|
450
449
|
|
|
451
450
|
.time-option.disabled,
|
|
@@ -482,8 +481,6 @@ $effect(() => {
|
|
|
482
481
|
|
|
483
482
|
.confirm-button:hover:not(:disabled) {
|
|
484
483
|
background: var(--color-accent-hover);
|
|
485
|
-
box-shadow: 0 0 20px var(--color-accent-glow);
|
|
486
|
-
transform: translateY(-1px);
|
|
487
484
|
}
|
|
488
485
|
|
|
489
486
|
.confirm-button:active:not(:disabled) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const baseInputClasses = "
|
|
2
|
-
export declare const focusClasses = "focus:outline-none focus:border-accent
|
|
1
|
+
export declare const baseInputClasses = "input-well rounded-[var(--radius-sm)] px-5 py-3.5 font-body text-text placeholder:text-text-muted transition-all duration-150 ease-luxe w-full";
|
|
2
|
+
export declare const focusClasses = "focus:outline-none focus:border-[var(--color-accent)]";
|
|
3
3
|
export declare const disabledClasses = "opacity-50 cursor-not-allowed";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const baseInputClasses = '
|
|
2
|
-
export const focusClasses = 'focus:outline-none focus:border-accent
|
|
1
|
+
export const baseInputClasses = 'input-well rounded-[var(--radius-sm)] px-5 py-3.5 font-body text-text placeholder:text-text-muted transition-all duration-150 ease-luxe w-full';
|
|
2
|
+
export const focusClasses = 'focus:outline-none focus:border-[var(--color-accent)]';
|
|
3
3
|
export const disabledClasses = 'opacity-50 cursor-not-allowed';
|
|
@@ -11,3 +11,4 @@ export { default as DatePicker } from './DatePicker.svelte';
|
|
|
11
11
|
export { default as TimePicker } from './TimePicker.svelte';
|
|
12
12
|
export { default as DateTimePicker } from './DateTimePicker.svelte';
|
|
13
13
|
export { default as SelectMenu } from './SelectMenu.svelte';
|
|
14
|
+
export { default as FormSection } from './FormSection.svelte';
|
|
@@ -11,3 +11,4 @@ export { default as DatePicker } from './DatePicker.svelte';
|
|
|
11
11
|
export { default as TimePicker } from './TimePicker.svelte';
|
|
12
12
|
export { default as DateTimePicker } from './DateTimePicker.svelte';
|
|
13
13
|
export { default as SelectMenu } from './SelectMenu.svelte';
|
|
14
|
+
export { default as FormSection } from './FormSection.svelte';
|
|
@@ -9,7 +9,7 @@ export {};
|
|
|
9
9
|
{#if item.href}
|
|
10
10
|
<a
|
|
11
11
|
href={item.href}
|
|
12
|
-
class="flex items-center gap-2 text-
|
|
12
|
+
class="flex items-center gap-2 text-xs font-[var(--font-mono)] uppercase tracking-[0.08em] text-[var(--color-text-soft)] hover:text-[var(--color-accent)] hover:underline transition-colors duration-200 ease-[var(--ease-luxe)]"
|
|
13
13
|
>
|
|
14
14
|
{#if item.icon}
|
|
15
15
|
<span class="inline-flex items-center justify-center">
|
|
@@ -21,7 +21,7 @@ export {};
|
|
|
21
21
|
{:else if item.onclick}
|
|
22
22
|
<button
|
|
23
23
|
onclick={item.onclick}
|
|
24
|
-
class="flex items-center gap-2 text-
|
|
24
|
+
class="flex items-center gap-2 text-xs font-[var(--font-mono)] uppercase tracking-[0.08em] text-[var(--color-text-soft)] hover:text-[var(--color-accent)] hover:underline transition-colors duration-200 ease-[var(--ease-luxe)] cursor-pointer"
|
|
25
25
|
>
|
|
26
26
|
{#if item.icon}
|
|
27
27
|
<span class="inline-flex items-center justify-center">
|
|
@@ -31,7 +31,7 @@ export {};
|
|
|
31
31
|
{item.label}
|
|
32
32
|
</button>
|
|
33
33
|
{:else}
|
|
34
|
-
<span class="flex items-center gap-2 text-
|
|
34
|
+
<span class="flex items-center gap-2 text-xs font-[var(--font-mono)] uppercase tracking-[0.08em] {index === items.length - 1 ? 'text-[var(--color-text)]' : 'text-[var(--color-text-soft)]'}">
|
|
35
35
|
{#if item.icon}
|
|
36
36
|
<span class="inline-flex items-center justify-center">
|
|
37
37
|
{@render item.icon()}
|
|
@@ -111,7 +111,7 @@ $effect(() => {
|
|
|
111
111
|
role="menu"
|
|
112
112
|
tabindex="-1"
|
|
113
113
|
onkeydown={handleMenuKeyDown}
|
|
114
|
-
class="fixed z-[var(--z-50)] glass-panel rounded-[var(--radius-
|
|
114
|
+
class="fixed z-[var(--z-50)] glass-panel rounded-[var(--radius-sm)] shadow-[var(--shadow-deep)] min-w-[12rem] animate-[fade-in_0.15s_var(--ease-luxe)]"
|
|
115
115
|
style="left: {x}px; top: {y}px;"
|
|
116
116
|
>
|
|
117
117
|
{#each items as item, index}
|
|
@@ -121,7 +121,7 @@ $effect(() => {
|
|
|
121
121
|
tabindex={index === selectedIndex ? 0 : -1}
|
|
122
122
|
onclick={() => handleItemClick(item)}
|
|
123
123
|
disabled={item.disabled}
|
|
124
|
-
class="w-full text-left px-4 py-2 text-
|
|
124
|
+
class="w-full text-left px-4 py-2 font-[var(--font-mono)] text-xs uppercase tracking-[0.08em] text-text hover:bg-base-3 transition-colors duration-200 flex items-center gap-2 {item.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}"
|
|
125
125
|
>
|
|
126
126
|
{#if item.icon}
|
|
127
127
|
{@render item.icon()}
|
|
@@ -117,7 +117,7 @@ $effect(() => {
|
|
|
117
117
|
role="menu"
|
|
118
118
|
tabindex="-1"
|
|
119
119
|
onkeydown={handleMenuKeyDown}
|
|
120
|
-
class="absolute {placementClasses[placement]} z-[var(--z-50)] glass-panel rounded-[var(--radius-
|
|
120
|
+
class="absolute {placementClasses[placement]} z-[var(--z-50)] glass-panel rounded-[var(--radius-sm)] shadow-[var(--shadow-deep)] min-w-[12rem] animate-[scale-in_0.15s_var(--ease-sharp)]"
|
|
121
121
|
>
|
|
122
122
|
{#each items as item, index}
|
|
123
123
|
<button
|
|
@@ -126,7 +126,7 @@ $effect(() => {
|
|
|
126
126
|
tabindex={index === selectedIndex ? 0 : -1}
|
|
127
127
|
onclick={() => handleItemClick(item)}
|
|
128
128
|
disabled={item.disabled}
|
|
129
|
-
class="w-full text-left px-4 py-2 text-
|
|
129
|
+
class="w-full text-left px-4 py-2 font-[var(--font-mono)] text-xs uppercase tracking-[0.08em] text-text hover:bg-base-3 transition-colors duration-200 flex items-center gap-2 {item.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}"
|
|
130
130
|
>
|
|
131
131
|
{#if item.icon}
|
|
132
132
|
{@render item.icon()}
|
|
@@ -49,7 +49,7 @@ $effect(() => {
|
|
|
49
49
|
export {};
|
|
50
50
|
</script>
|
|
51
51
|
|
|
52
|
-
<div bind:this={menuContainer} role="menu" tabindex="-1" onkeydown={handleMenuKeyDown} class="glass-panel rounded-[var(--radius-
|
|
52
|
+
<div bind:this={menuContainer} role="menu" tabindex="-1" onkeydown={handleMenuKeyDown} class="glass-panel rounded-[var(--radius-sm)] p-3 shadow-[var(--shadow-deep)]">
|
|
53
53
|
{#if children}
|
|
54
54
|
{@render children()}
|
|
55
55
|
{:else if items}
|
|
@@ -60,7 +60,7 @@ export {};
|
|
|
60
60
|
tabindex={index === selectedIndex ? 0 : -1}
|
|
61
61
|
onclick={() => handleItemClick(item)}
|
|
62
62
|
disabled={item.disabled}
|
|
63
|
-
class="flex items-center gap-2 w-full px-4 py-3 rounded-[var(--radius-
|
|
63
|
+
class="flex items-center gap-2 w-full px-4 py-3 rounded-[var(--radius-sm)] text-[var(--color-text)] text-xs font-[var(--font-mono)] uppercase tracking-[0.08em] hover:bg-[var(--color-base-3)] hover-lift transition-all duration-200 ease-[var(--ease-luxe)] {item.disabled ? 'opacity-50 pointer-events-none' : 'cursor-pointer'}"
|
|
64
64
|
>
|
|
65
65
|
{#if item.icon}
|
|
66
66
|
{@render item.icon()}
|
|
@@ -80,9 +80,18 @@ export {};
|
|
|
80
80
|
</nav>
|
|
81
81
|
|
|
82
82
|
<style>
|
|
83
|
+
/* System text: navigation is mono, uppercase, tracked */
|
|
84
|
+
nav :global(a),
|
|
85
|
+
nav :global(button) {
|
|
86
|
+
font-family: var(--font-mono);
|
|
87
|
+
font-size: var(--text-xs);
|
|
88
|
+
text-transform: uppercase;
|
|
89
|
+
letter-spacing: 0.08em;
|
|
90
|
+
}
|
|
91
|
+
|
|
83
92
|
nav :global(.navbar-logo) {
|
|
84
93
|
color: var(--color-accent);
|
|
85
|
-
font-weight:
|
|
94
|
+
font-weight: 700;
|
|
86
95
|
font-size: var(--text-lg);
|
|
87
96
|
}
|
|
88
97
|
|
|
@@ -102,7 +111,6 @@ export {};
|
|
|
102
111
|
right: 0;
|
|
103
112
|
height: 2px;
|
|
104
113
|
background: var(--color-accent);
|
|
105
|
-
box-shadow: var(--shadow-accent-glow);
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
nav :global(a:not(.active):hover),
|
|
@@ -171,7 +171,7 @@ export {};
|
|
|
171
171
|
justify-content: center;
|
|
172
172
|
width: 2.5rem;
|
|
173
173
|
height: 2.5rem;
|
|
174
|
-
border-radius: var(--radius-
|
|
174
|
+
border-radius: var(--radius-sm);
|
|
175
175
|
background: var(--color-accent-overlay-20);
|
|
176
176
|
color: var(--color-accent);
|
|
177
177
|
font-weight: 600;
|
|
@@ -204,11 +204,6 @@ export {};
|
|
|
204
204
|
font-weight: 600;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
aside :global(a.active),
|
|
208
|
-
aside :global(button.active) {
|
|
209
|
-
box-shadow: var(--shadow-accent-glow);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
207
|
aside :global(a:not(.active):hover),
|
|
213
208
|
aside :global(button:not(.active):hover) {
|
|
214
209
|
background: var(--color-base-3);
|
|
@@ -222,7 +217,7 @@ export {};
|
|
|
222
217
|
gap: 0.75rem;
|
|
223
218
|
padding: 0.75rem 1rem;
|
|
224
219
|
margin: 0.25rem 0.5rem;
|
|
225
|
-
border-radius:
|
|
220
|
+
border-radius: 0;
|
|
226
221
|
color: var(--color-text-soft);
|
|
227
222
|
text-decoration: none;
|
|
228
223
|
transition: all 0.2s var(--ease-luxe);
|
|
@@ -231,6 +226,8 @@ export {};
|
|
|
231
226
|
background: transparent;
|
|
232
227
|
width: calc(100% - 1rem);
|
|
233
228
|
text-align: left;
|
|
234
|
-
font-family: var(--font-
|
|
235
|
-
font-size:
|
|
229
|
+
font-family: var(--font-mono);
|
|
230
|
+
font-size: var(--text-xs);
|
|
231
|
+
text-transform: uppercase;
|
|
232
|
+
letter-spacing: 0.08em;
|
|
236
233
|
}</style>
|
|
@@ -59,7 +59,7 @@ const orientationClasses = {
|
|
|
59
59
|
horizontal: 'flex flex-row',
|
|
60
60
|
vertical: 'flex flex-col'
|
|
61
61
|
};
|
|
62
|
-
const radiusClass = variant === 'pills' ? 'rounded-pill' : 'rounded-
|
|
62
|
+
const radiusClass = variant === 'pills' ? 'rounded-pill' : 'rounded-none';
|
|
63
63
|
export {};
|
|
64
64
|
</script>
|
|
65
65
|
|
|
@@ -73,7 +73,7 @@ export {};
|
|
|
73
73
|
onclick={() => handleTabClick(tab.id, tab.disabled)}
|
|
74
74
|
onkeydown={(e) => handleKeyDown(e, tab.id)}
|
|
75
75
|
disabled={tab.disabled}
|
|
76
|
-
class="flex items-center gap-2 px-6 py-3 {radiusClass} font-
|
|
76
|
+
class="flex items-center gap-2 px-6 py-3 {radiusClass} font-mono text-xs uppercase tracking-[0.08em] transition-all duration-150 ease-luxe {activeTab === tab.id ? 'bg-accent text-text' : 'text-text-soft hover:bg-base-3'} {tab.disabled ? 'opacity-50 pointer-events-none' : 'cursor-pointer'}"
|
|
77
77
|
>
|
|
78
78
|
{#if tab.iconBefore}
|
|
79
79
|
<span class="inline-flex items-center justify-center">
|
|
@@ -40,7 +40,7 @@ export {};
|
|
|
40
40
|
|
|
41
41
|
{#if visible}
|
|
42
42
|
<div
|
|
43
|
-
class="glass-panel rounded-[var(--radius-
|
|
43
|
+
class="glass-panel rounded-[var(--radius-sm)] p-4 flex gap-3 {variantClasses[variant]} {className} animate-[fade-in_0.2s_var(--ease-sharp)]"
|
|
44
44
|
role={roleMap[variant]}
|
|
45
45
|
aria-live={ariaLiveMap[variant]}
|
|
46
46
|
>
|
|
@@ -103,12 +103,12 @@ $effect(() => {
|
|
|
103
103
|
|
|
104
104
|
{#if open}
|
|
105
105
|
<div
|
|
106
|
-
class="fixed inset-0 z-[var(--z-50)] flex items-start justify-center pt-[20vh] p-4 bg-overlay
|
|
106
|
+
class="fixed inset-0 z-[var(--z-50)] flex items-start justify-center pt-[20vh] p-4 bg-overlay animate-[fade-in_0.2s_var(--ease-luxe)]"
|
|
107
107
|
onclick={handleBackdropClick}
|
|
108
108
|
role="presentation"
|
|
109
109
|
>
|
|
110
110
|
<div
|
|
111
|
-
class="panel-floating rounded-
|
|
111
|
+
class="panel-floating rounded-[var(--radius-md)] shadow-deep w-full max-w-[36rem] animate-[scale-in_0.2s_var(--ease-sharp)]"
|
|
112
112
|
role="combobox"
|
|
113
113
|
aria-expanded="true"
|
|
114
114
|
aria-haspopup="listbox"
|
|
@@ -34,10 +34,10 @@ const positionClasses = {
|
|
|
34
34
|
bottom: 'bottom-0 left-0 w-full'
|
|
35
35
|
};
|
|
36
36
|
const animationClasses = {
|
|
37
|
-
left: 'animate-[slide-in-left_0.
|
|
38
|
-
right: 'animate-[slide-in-right_0.
|
|
39
|
-
top: 'animate-[slide-in-top_0.
|
|
40
|
-
bottom: 'animate-[slide-in-bottom_0.
|
|
37
|
+
left: 'animate-[slide-in-left_0.2s_var(--ease-sharp)]',
|
|
38
|
+
right: 'animate-[slide-in-right_0.2s_var(--ease-sharp)]',
|
|
39
|
+
top: 'animate-[slide-in-top_0.2s_var(--ease-sharp)]',
|
|
40
|
+
bottom: 'animate-[slide-in-bottom_0.2s_var(--ease-sharp)]'
|
|
41
41
|
};
|
|
42
42
|
function handleClose() {
|
|
43
43
|
open = false;
|
|
@@ -106,7 +106,7 @@ $effect(() => {
|
|
|
106
106
|
|
|
107
107
|
{#if open}
|
|
108
108
|
<div
|
|
109
|
-
class="fixed inset-0 z-[var(--z-50)] bg-overlay
|
|
109
|
+
class="fixed inset-0 z-[var(--z-50)] bg-overlay animate-[fade-in_0.2s_var(--ease-luxe)]"
|
|
110
110
|
onclick={handleBackdropClick}
|
|
111
111
|
role="presentation"
|
|
112
112
|
>
|
|
@@ -76,7 +76,7 @@ $effect(() => {
|
|
|
76
76
|
<div
|
|
77
77
|
bind:this={dropdownElement}
|
|
78
78
|
id={dropdownId}
|
|
79
|
-
class="absolute {placementClasses[placement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-
|
|
79
|
+
class="absolute {placementClasses[placement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-sm)] shadow-[var(--shadow-deep)] min-w-[12rem] animate-[scale-in_0.15s_var(--ease-sharp)]"
|
|
80
80
|
style={fullWidth && triggerWidth > 0 ? `width: ${triggerWidth}px` : ''}
|
|
81
81
|
role="menu"
|
|
82
82
|
>
|
|
@@ -77,13 +77,13 @@ $effect(() => {
|
|
|
77
77
|
|
|
78
78
|
{#if open}
|
|
79
79
|
<div
|
|
80
|
-
class="fixed inset-0 z-[var(--z-50)] flex items-center justify-center p-4 bg-overlay
|
|
80
|
+
class="fixed inset-0 z-[var(--z-50)] flex items-center justify-center p-4 bg-overlay animate-[fade-in_0.2s_var(--ease-luxe)]"
|
|
81
81
|
onclick={handleBackdropClick}
|
|
82
82
|
role="presentation"
|
|
83
83
|
>
|
|
84
84
|
<div
|
|
85
85
|
bind:this={modalElement}
|
|
86
|
-
class="panel-floating rounded-[var(--radius-
|
|
86
|
+
class="panel-floating rounded-[var(--radius-md)] shadow-deep w-full {sizeClasses[size]} {className} animate-[scale-in_0.2s_var(--ease-sharp)] flex flex-col max-h-[90vh]"
|
|
87
87
|
role="dialog"
|
|
88
88
|
aria-modal="true"
|
|
89
89
|
aria-labelledby={title ? titleId : undefined}
|
|
@@ -97,7 +97,7 @@ $effect(() => {
|
|
|
97
97
|
<div
|
|
98
98
|
bind:this={popoverElement}
|
|
99
99
|
id={popoverId}
|
|
100
|
-
class="absolute {placementClasses[actualPlacement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-
|
|
100
|
+
class="absolute {placementClasses[actualPlacement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-sm)] shadow-deep p-4 animate-[scale-in_0.15s_var(--ease-sharp)]"
|
|
101
101
|
role="dialog"
|
|
102
102
|
>
|
|
103
103
|
{@render children?.()}
|
|
@@ -9,7 +9,7 @@ const heightClasses = {
|
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
11
|
<div
|
|
12
|
-
class="relative bg-[var(--color-base-3)] border border-[var(--color-border)] rounded-
|
|
12
|
+
class="relative bg-[var(--color-base-3)] border border-[var(--color-border)] rounded-none overflow-hidden shadow-[var(--shadow-deep)] {heightClasses[size]}"
|
|
13
13
|
role="progressbar"
|
|
14
14
|
aria-valuenow={value}
|
|
15
15
|
aria-valuemin="0"
|
|
@@ -17,12 +17,12 @@ const heightClasses = {
|
|
|
17
17
|
aria-label={label || `${percentage.toFixed(0)}% complete`}
|
|
18
18
|
>
|
|
19
19
|
<div
|
|
20
|
-
class="h-full bg-[var(--color-accent)]
|
|
20
|
+
class="h-full bg-[var(--color-accent)] transition-all duration-500 ease-[var(--ease-luxe)]"
|
|
21
21
|
style="width: {percentage}%"
|
|
22
22
|
></div>
|
|
23
23
|
|
|
24
24
|
{#if showLabel}
|
|
25
|
-
<div class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-[var(--color-text)]
|
|
25
|
+
<div class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-[var(--color-text)]">
|
|
26
26
|
{label || `${percentage.toFixed(0)}%`}
|
|
27
27
|
</div>
|
|
28
28
|
{/if}
|
|
@@ -8,7 +8,7 @@ const defaultDimensions = {
|
|
|
8
8
|
const roundingClasses = {
|
|
9
9
|
text: 'rounded-[var(--radius-sm)]',
|
|
10
10
|
circular: 'rounded-[var(--radius-pill)]',
|
|
11
|
-
rectangular: 'rounded-[var(--radius-
|
|
11
|
+
rectangular: 'rounded-[var(--radius-sm)]'
|
|
12
12
|
};
|
|
13
13
|
const finalWidth = width || defaultDimensions[variant].width;
|
|
14
14
|
const finalHeight = height || defaultDimensions[variant].height;
|
|
@@ -53,7 +53,7 @@ const finalHeight = height || defaultDimensions[variant].height;
|
|
|
53
53
|
var(--color-accent-overlay-10),
|
|
54
54
|
transparent
|
|
55
55
|
);
|
|
56
|
-
animation: shimmer
|
|
56
|
+
animation: shimmer 2.8s ease-in-out infinite;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
@keyframes shimmer {
|
|
@@ -14,7 +14,7 @@ const sizeClasses = {
|
|
|
14
14
|
aria-label={label || 'Loading'}
|
|
15
15
|
>
|
|
16
16
|
<div
|
|
17
|
-
class="{sizeClasses[size]} border-[var(--color-base-3)] border-t-[var(--color-accent)] rounded-[var(--radius-pill)]
|
|
17
|
+
class="{sizeClasses[size]} border-[var(--color-base-3)] border-t-[var(--color-accent)] rounded-[var(--radius-pill)] animate-spin"
|
|
18
18
|
></div>
|
|
19
19
|
<span class="sr-only">{label || 'Loading'}</span>
|
|
20
20
|
</div>
|
|
@@ -42,7 +42,7 @@ const ariaLiveMap = {
|
|
|
42
42
|
error: 'assertive'
|
|
43
43
|
};
|
|
44
44
|
const animationClasses = $derived(position.startsWith('bottom')
|
|
45
|
-
? 'animate-[
|
|
45
|
+
? 'animate-[scale-in_0.2s_var(--ease-sharp)]'
|
|
46
46
|
: 'animate-[fade-in_0.3s_var(--ease-luxe)]');
|
|
47
47
|
const stackOffset = $derived(position.startsWith('bottom')
|
|
48
48
|
? `translateY(-${index * 5}rem)`
|
|
@@ -75,7 +75,7 @@ $effect(() => {
|
|
|
75
75
|
style="transform: {stackOffset}"
|
|
76
76
|
>
|
|
77
77
|
<div
|
|
78
|
-
class="panel-floating rounded-[var(--radius-
|
|
78
|
+
class="panel-floating rounded-[var(--radius-sm)] p-4 min-w-[20rem] max-w-md flex gap-3 items-start {variantBorderClasses[variant]}"
|
|
79
79
|
role={roleMap[variant]}
|
|
80
80
|
aria-live={ariaLiveMap[variant]}
|
|
81
81
|
aria-atomic="true"
|
|
@@ -87,7 +87,7 @@ $effect(() => {
|
|
|
87
87
|
id={tooltipId}
|
|
88
88
|
role="tooltip"
|
|
89
89
|
aria-hidden={visible ? 'false' : 'true'}
|
|
90
|
-
class="absolute {placementClasses[actualPlacement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-
|
|
90
|
+
class="absolute {placementClasses[actualPlacement]} z-[var(--z-50)] panel-floating rounded-[var(--radius-sm)] px-4 py-2.5 text-sm text-text whitespace-nowrap pointer-events-none {className} {visible ? 'animate-[fade-in_0.15s_var(--ease-luxe)] opacity-100' : 'opacity-0 invisible'}"
|
|
91
91
|
>
|
|
92
92
|
{content}
|
|
93
93
|
</div>
|
|
@@ -3,7 +3,7 @@ let { children } = $props();
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<code
|
|
6
|
-
class="inline-flex items-center
|
|
6
|
+
class="inline-flex items-center"
|
|
7
7
|
style="background: var(--color-accent-overlay-10); border: 1px solid var(--color-border); padding: 0.125rem 0.375rem; border-radius: var(--radius-sm); font-family: var(--font-mono); color: var(--color-accent-soft); font-size: 0.9em;"
|
|
8
8
|
>
|
|
9
9
|
{@render children?.()}
|
|
@@ -64,7 +64,7 @@ export {};
|
|
|
64
64
|
</script>
|
|
65
65
|
|
|
66
66
|
<div class="relative">
|
|
67
|
-
<div class="panel-raised rounded-
|
|
67
|
+
<div class="panel-raised rounded-none overflow-hidden">
|
|
68
68
|
<div
|
|
69
69
|
class="flex transition-transform duration-300 ease-luxe"
|
|
70
70
|
style="transform: translateX(-{currentIndex * 100}%);"
|
|
@@ -88,7 +88,7 @@ export {};
|
|
|
88
88
|
<button
|
|
89
89
|
type="button"
|
|
90
90
|
onclick={goToPrev}
|
|
91
|
-
class="absolute left-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-
|
|
91
|
+
class="absolute left-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-[var(--radius-sm)] p-2 text-text hover:border-[var(--color-border-strong)] transition-all"
|
|
92
92
|
aria-label="Previous item"
|
|
93
93
|
>
|
|
94
94
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -99,7 +99,7 @@ export {};
|
|
|
99
99
|
<button
|
|
100
100
|
type="button"
|
|
101
101
|
onclick={goToNext}
|
|
102
|
-
class="absolute right-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-
|
|
102
|
+
class="absolute right-2 top-1/2 -translate-y-1/2 obsidian-surface metal-edge rounded-[var(--radius-sm)] p-2 text-text hover:border-[var(--color-border-strong)] transition-all"
|
|
103
103
|
aria-label="Next item"
|
|
104
104
|
>
|
|
105
105
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -114,7 +114,7 @@ export {};
|
|
|
114
114
|
<button
|
|
115
115
|
type="button"
|
|
116
116
|
onclick={() => goToIndex(index)}
|
|
117
|
-
class="w-2 h-2 rounded-full transition-all {index === currentIndex ? '
|
|
117
|
+
class="w-2 h-2 rounded-full transition-all {index === currentIndex ? 'bg-accent w-8' : 'bg-text-muted'}"
|
|
118
118
|
aria-label="Go to item {index + 1}"
|
|
119
119
|
>
|
|
120
120
|
</button>
|
|
@@ -11,7 +11,7 @@ let effectiveOpen = $derived(onToggle ? open : openLocal);
|
|
|
11
11
|
let maxHeight = $derived(effectiveOpen && contentElement ? `${contentElement.scrollHeight}px` : '0px');
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
|
-
<div class="border border-border rounded-
|
|
14
|
+
<div class="border border-border rounded-[var(--radius-sm)] overflow-hidden {effectiveOpen ? 'panel-raised' : ''}">
|
|
15
15
|
<button
|
|
16
16
|
id={headerId}
|
|
17
17
|
type="button"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">let { messages = [], prompt = '>', placeholder = 'Enter command...', height = '500px', maxHeight = '80vh', showTimestamps = false, autoScroll = true, typewriterEffect = false, typewriterSpeed = 50, showScanlines = true, glowEffect =
|
|
1
|
+
<script lang="ts">let { messages = [], prompt = '>', placeholder = 'Enter command...', height = '500px', maxHeight = '80vh', showTimestamps = false, autoScroll = true, typewriterEffect = false, typewriterSpeed = 50, showScanlines = true, glowEffect = false, onSubmit, disabled = false, class: className = '', ...restProps } = $props();
|
|
2
2
|
let inputValue = $state('');
|
|
3
3
|
let consoleContainer = $state();
|
|
4
4
|
let inputElement = $state();
|