@dryui/theme-wizard 4.0.0 → 5.0.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/package.json +3 -3
- package/dist/actions.d.ts +0 -4
- package/dist/actions.js +0 -9
- package/dist/components/AlphaSlider.svelte +0 -13
- package/dist/components/AlphaSlider.svelte.d.ts +0 -9
- package/dist/components/ContrastBadge.svelte +0 -22
- package/dist/components/ContrastBadge.svelte.d.ts +0 -8
- package/dist/components/HsbPicker.svelte +0 -304
- package/dist/components/HsbPicker.svelte.d.ts +0 -9
- package/dist/components/StepIndicator.svelte +0 -87
- package/dist/components/StepIndicator.svelte.d.ts +0 -7
- package/dist/components/TokenPreview.svelte +0 -55
- package/dist/components/TokenPreview.svelte.d.ts +0 -8
- package/dist/components/WizardShell.svelte +0 -140
- package/dist/components/WizardShell.svelte.d.ts +0 -15
- package/dist/engine/derivation.d.ts +0 -282
- package/dist/engine/derivation.js +0 -1445
- package/dist/engine/derivation.test.d.ts +0 -1
- package/dist/engine/derivation.test.js +0 -956
- package/dist/engine/export-css.d.ts +0 -32
- package/dist/engine/export-css.js +0 -90
- package/dist/engine/export-css.test.d.ts +0 -1
- package/dist/engine/export-css.test.js +0 -78
- package/dist/engine/index.d.ts +0 -10
- package/dist/engine/index.js +0 -6
- package/dist/engine/palette.d.ts +0 -16
- package/dist/engine/palette.js +0 -44
- package/dist/engine/presets.d.ts +0 -13
- package/dist/engine/presets.js +0 -124
- package/dist/engine/url-codec.d.ts +0 -53
- package/dist/engine/url-codec.js +0 -243
- package/dist/engine/url-codec.test.d.ts +0 -1
- package/dist/engine/url-codec.test.js +0 -137
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -19
- package/dist/state.svelte.d.ts +0 -104
- package/dist/state.svelte.js +0 -574
- package/dist/steps/BrandColor.svelte +0 -216
- package/dist/steps/BrandColor.svelte.d.ts +0 -6
- package/dist/steps/Personality.svelte +0 -319
- package/dist/steps/Personality.svelte.d.ts +0 -3
- package/dist/steps/PreviewExport.svelte +0 -115
- package/dist/steps/PreviewExport.svelte.d.ts +0 -9
- package/dist/steps/Shape.svelte +0 -121
- package/dist/steps/Shape.svelte.d.ts +0 -18
- package/dist/steps/Typography.svelte +0 -115
- package/dist/steps/Typography.svelte.d.ts +0 -18
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Button } from '@dryui/ui';
|
|
3
|
-
import { ColorPicker } from '@dryui/ui/color-picker';
|
|
4
|
-
import { Text } from '@dryui/ui/text';
|
|
5
|
-
import { setBrandHsb, getDerivedTheme, wizardState } from '../state.svelte.js';
|
|
6
|
-
import {
|
|
7
|
-
PRESETS,
|
|
8
|
-
generateTheme,
|
|
9
|
-
hexToHsl,
|
|
10
|
-
hslToHsb,
|
|
11
|
-
hsbToHsl,
|
|
12
|
-
hslToHex
|
|
13
|
-
} from '../engine/index.js';
|
|
14
|
-
import { bg } from '../actions';
|
|
15
|
-
|
|
16
|
-
let { mode = 'light' }: { mode?: 'light' | 'dark' } = $props();
|
|
17
|
-
|
|
18
|
-
let isDark = $derived(mode === 'dark');
|
|
19
|
-
|
|
20
|
-
const SWATCH_TOKENS = [
|
|
21
|
-
{ key: '--dry-color-fill', label: 'Fill' },
|
|
22
|
-
{ key: '--dry-color-stroke-strong', label: 'Stroke' },
|
|
23
|
-
{ key: '--dry-color-fill-brand', label: 'Brand' },
|
|
24
|
-
{ key: '--dry-color-text-strong', label: 'Text' }
|
|
25
|
-
] as const;
|
|
26
|
-
|
|
27
|
-
const PRESET_THEMES = PRESETS.map((p) => generateTheme(p.brandInput));
|
|
28
|
-
|
|
29
|
-
let activeTokens = $derived.by(() => {
|
|
30
|
-
const t = getDerivedTheme();
|
|
31
|
-
return isDark ? t.dark : t.light;
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
let themeSwatches = $derived(
|
|
35
|
-
SWATCH_TOKENS.map(({ key, label }) => ({
|
|
36
|
-
color: activeTokens[key] ?? '',
|
|
37
|
-
label
|
|
38
|
-
}))
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
let pickerColor = $derived.by(() => {
|
|
42
|
-
const hsl = hsbToHsl(
|
|
43
|
-
wizardState.brandHsb.h,
|
|
44
|
-
wizardState.brandHsb.s / 100,
|
|
45
|
-
wizardState.brandHsb.b / 100
|
|
46
|
-
);
|
|
47
|
-
return hslToHex(hsl.h, hsl.s, hsl.l);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const pickerModel = {
|
|
51
|
-
get hex() {
|
|
52
|
-
return pickerColor;
|
|
53
|
-
},
|
|
54
|
-
set hex(value: string) {
|
|
55
|
-
if (!value || value === pickerColor) return;
|
|
56
|
-
const hsl = hexToHsl(value);
|
|
57
|
-
const hsb = hslToHsb(hsl.h, hsl.s, hsl.l);
|
|
58
|
-
setBrandHsb(hsb.h, Math.round(hsb.s * 100), Math.round(hsb.b * 100));
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
function selectPreset(preset: (typeof PRESETS)[number]) {
|
|
63
|
-
setBrandHsb(preset.brandInput.h, preset.brandInput.s, preset.brandInput.b);
|
|
64
|
-
}
|
|
65
|
-
</script>
|
|
66
|
-
|
|
67
|
-
<section class="brand-section">
|
|
68
|
-
<div class="picker-wrap">
|
|
69
|
-
<ColorPicker.Root bind:value={pickerModel.hex} areaHeight={160}>
|
|
70
|
-
<ColorPicker.Area />
|
|
71
|
-
<ColorPicker.HueSlider />
|
|
72
|
-
<ColorPicker.Input format="hex" />
|
|
73
|
-
</ColorPicker.Root>
|
|
74
|
-
</div>
|
|
75
|
-
|
|
76
|
-
<div class="swatch-and-presets">
|
|
77
|
-
<div class="swatch-strip" use:bg={activeTokens['--dry-color-bg-base'] ?? '#ffffff'}>
|
|
78
|
-
{#each themeSwatches as swatch (swatch.label)}
|
|
79
|
-
<div class="swatch-col">
|
|
80
|
-
<div class="swatch" use:bg={swatch.color}></div>
|
|
81
|
-
<span class="swatch-label">{swatch.label}</span>
|
|
82
|
-
</div>
|
|
83
|
-
{/each}
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<div class="presets">
|
|
87
|
-
{#each PRESETS as preset, i (preset.name)}
|
|
88
|
-
{@const presetTheme = PRESET_THEMES[i] ?? PRESET_THEMES[0]!}
|
|
89
|
-
{@const presetTokens = isDark ? presetTheme.dark : presetTheme.light}
|
|
90
|
-
<Button type="button" variant="bare" onclick={() => selectPreset(preset)}>
|
|
91
|
-
<div
|
|
92
|
-
class="preset-btn"
|
|
93
|
-
data-selected={wizardState.brandHsb.h === preset.brandInput.h &&
|
|
94
|
-
wizardState.brandHsb.s === preset.brandInput.s &&
|
|
95
|
-
wizardState.brandHsb.b === preset.brandInput.b
|
|
96
|
-
? ''
|
|
97
|
-
: undefined}
|
|
98
|
-
>
|
|
99
|
-
<div class="preset-thumb">
|
|
100
|
-
{#each SWATCH_TOKENS as { key } (key)}
|
|
101
|
-
<div class="preset-swatch" use:bg={presetTokens[key] ?? ''}></div>
|
|
102
|
-
{/each}
|
|
103
|
-
</div>
|
|
104
|
-
<Text as="span" size="xs" color="muted">{preset.name.toLowerCase()}</Text>
|
|
105
|
-
</div>
|
|
106
|
-
</Button>
|
|
107
|
-
{/each}
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</section>
|
|
111
|
-
|
|
112
|
-
<style>
|
|
113
|
-
.brand-section {
|
|
114
|
-
display: grid;
|
|
115
|
-
gap: var(--dry-space-5);
|
|
116
|
-
container-type: inline-size;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.swatch-and-presets {
|
|
120
|
-
display: grid;
|
|
121
|
-
gap: var(--dry-space-4);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.swatch-strip {
|
|
125
|
-
display: grid;
|
|
126
|
-
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
127
|
-
gap: 0;
|
|
128
|
-
overflow: hidden;
|
|
129
|
-
border-radius: var(--dry-radius-md);
|
|
130
|
-
align-self: end;
|
|
131
|
-
border: 1px solid var(--dry-color-stroke-weak);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.swatch-col {
|
|
135
|
-
display: grid;
|
|
136
|
-
gap: var(--dry-space-1);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.swatch {
|
|
140
|
-
min-height: 3.5rem;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.swatch-label {
|
|
144
|
-
text-align: center;
|
|
145
|
-
font-family: var(--dry-font-mono);
|
|
146
|
-
font-size: var(--dry-type-xs-size, 0.7rem);
|
|
147
|
-
color: var(--dry-color-text-weak);
|
|
148
|
-
text-transform: uppercase;
|
|
149
|
-
letter-spacing: 0.06em;
|
|
150
|
-
padding-block: var(--dry-space-1);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.presets {
|
|
154
|
-
display: grid;
|
|
155
|
-
grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
|
|
156
|
-
gap: var(--dry-space-3);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.preset-btn {
|
|
160
|
-
display: grid;
|
|
161
|
-
gap: var(--dry-space-2);
|
|
162
|
-
padding: var(--dry-space-2);
|
|
163
|
-
border-radius: var(--dry-radius-md);
|
|
164
|
-
border: 1px solid transparent;
|
|
165
|
-
background: none;
|
|
166
|
-
cursor: pointer;
|
|
167
|
-
transition: border-color 0.15s;
|
|
168
|
-
appearance: none;
|
|
169
|
-
text-align: center;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.preset-btn:hover {
|
|
173
|
-
border-color: var(--dry-color-stroke-weak);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.preset-btn[data-selected] {
|
|
177
|
-
border-color: var(--dry-color-stroke-brand);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.preset-thumb {
|
|
181
|
-
display: grid;
|
|
182
|
-
grid-template-columns: repeat(4, 1fr);
|
|
183
|
-
height: 2rem;
|
|
184
|
-
overflow: hidden;
|
|
185
|
-
border-radius: var(--dry-radius-sm);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.preset-swatch {
|
|
189
|
-
height: 100%;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
@container (min-width: 40rem) {
|
|
193
|
-
.brand-section {
|
|
194
|
-
grid-template-columns: auto minmax(0, 1fr);
|
|
195
|
-
align-items: end;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
.swatch {
|
|
199
|
-
min-height: 5rem;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
@container (max-width: 30rem) {
|
|
204
|
-
.swatch {
|
|
205
|
-
min-height: 2rem;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.swatch-strip {
|
|
209
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.presets {
|
|
213
|
-
grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr));
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
</style>
|
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Card } from '@dryui/ui/card';
|
|
3
|
-
import { Text } from '@dryui/ui/text';
|
|
4
|
-
import { wizardState, setPersonality } from '../state.svelte.js';
|
|
5
|
-
import type { Personality as PersonalityPreset } from '../state.svelte.js';
|
|
6
|
-
|
|
7
|
-
const OPTIONS: {
|
|
8
|
-
value: PersonalityPreset;
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
}[] = [
|
|
12
|
-
{
|
|
13
|
-
value: 'minimal',
|
|
14
|
-
name: 'Minimal',
|
|
15
|
-
description: 'Flat, transparent, content-forward'
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
value: 'clean',
|
|
19
|
-
name: 'Clean',
|
|
20
|
-
description: 'Subtle separation, gentle edges'
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
value: 'structured',
|
|
24
|
-
name: 'Structured',
|
|
25
|
-
description: 'Clear regions, visible cards'
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
value: 'rich',
|
|
29
|
-
name: 'Rich',
|
|
30
|
-
description: 'Elevated surfaces, deep layering'
|
|
31
|
-
}
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
let selected = $derived(wizardState.personality);
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<section class="personality-step" aria-label="Personality presets">
|
|
38
|
-
<div class="options-grid">
|
|
39
|
-
{#each OPTIONS as option (option.value)}
|
|
40
|
-
<Card.Root
|
|
41
|
-
as="button"
|
|
42
|
-
variant="interactive"
|
|
43
|
-
size="sm"
|
|
44
|
-
selected={selected === option.value}
|
|
45
|
-
onclick={() => setPersonality(option.value)}
|
|
46
|
-
>
|
|
47
|
-
<Card.Content noPadding>
|
|
48
|
-
<div class="preview-frame" data-personality={option.value}>
|
|
49
|
-
<div class="preview-toolbar">
|
|
50
|
-
<div class="preview-dot"></div>
|
|
51
|
-
<div class="preview-pills">
|
|
52
|
-
<div class="preview-pill"></div>
|
|
53
|
-
<div class="preview-pill short"></div>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
<div class="preview-body">
|
|
58
|
-
<div class="preview-sidebar">
|
|
59
|
-
<div class="preview-nav-line"></div>
|
|
60
|
-
<div class="preview-nav-line"></div>
|
|
61
|
-
<div class="preview-nav-line short"></div>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<div class="preview-main">
|
|
65
|
-
<div class="preview-card primary">
|
|
66
|
-
<div class="preview-line"></div>
|
|
67
|
-
<div class="preview-line short"></div>
|
|
68
|
-
</div>
|
|
69
|
-
<div class="preview-card-grid">
|
|
70
|
-
<div class="preview-card secondary">
|
|
71
|
-
<div class="preview-line"></div>
|
|
72
|
-
<div class="preview-line shorter"></div>
|
|
73
|
-
</div>
|
|
74
|
-
<div class="preview-card secondary">
|
|
75
|
-
<div class="preview-line"></div>
|
|
76
|
-
<div class="preview-line short"></div>
|
|
77
|
-
</div>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
</Card.Content>
|
|
83
|
-
|
|
84
|
-
<Card.Footer>
|
|
85
|
-
<div class="option-stack">
|
|
86
|
-
<div class="title-row">
|
|
87
|
-
<Text as="span" size="sm" weight="semibold">{option.name}</Text>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<Text as="p" size="sm" color="muted">{option.description}</Text>
|
|
91
|
-
</div>
|
|
92
|
-
</Card.Footer>
|
|
93
|
-
</Card.Root>
|
|
94
|
-
{/each}
|
|
95
|
-
</div>
|
|
96
|
-
</section>
|
|
97
|
-
|
|
98
|
-
<style>
|
|
99
|
-
.personality-step {
|
|
100
|
-
container-type: inline-size;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.options-grid {
|
|
104
|
-
display: grid;
|
|
105
|
-
grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr));
|
|
106
|
-
gap: var(--dry-space-4);
|
|
107
|
-
align-items: start;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.option-stack,
|
|
111
|
-
.preview-body,
|
|
112
|
-
.preview-sidebar,
|
|
113
|
-
.preview-main,
|
|
114
|
-
.preview-card,
|
|
115
|
-
.preview-card-grid {
|
|
116
|
-
display: grid;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.option-stack {
|
|
120
|
-
gap: var(--dry-space-2);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.title-row {
|
|
124
|
-
display: grid;
|
|
125
|
-
grid-template-columns: minmax(0, 1fr) max-content;
|
|
126
|
-
align-items: center;
|
|
127
|
-
gap: var(--dry-space-2);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.preview-frame {
|
|
131
|
-
display: grid;
|
|
132
|
-
grid-template-rows: auto 1fr;
|
|
133
|
-
min-block-size: 10.5rem;
|
|
134
|
-
border-radius: var(--dry-radius-lg) var(--dry-radius-lg) 0 0;
|
|
135
|
-
overflow: clip;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.preview-toolbar {
|
|
139
|
-
display: grid;
|
|
140
|
-
grid-template-columns: max-content minmax(0, 1fr);
|
|
141
|
-
align-items: center;
|
|
142
|
-
gap: var(--dry-space-2);
|
|
143
|
-
padding: var(--dry-space-3);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.preview-dot {
|
|
147
|
-
block-size: 0.375rem;
|
|
148
|
-
aspect-ratio: 1;
|
|
149
|
-
border-radius: 999px;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.preview-pills {
|
|
153
|
-
display: grid;
|
|
154
|
-
grid-template-columns: 2rem 1rem;
|
|
155
|
-
gap: var(--dry-space-1);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.preview-pill {
|
|
159
|
-
block-size: 0.25rem;
|
|
160
|
-
border-radius: 999px;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.preview-body {
|
|
164
|
-
grid-template-columns: 2.75rem minmax(0, 1fr);
|
|
165
|
-
min-block-size: 0;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
.preview-sidebar {
|
|
169
|
-
align-content: start;
|
|
170
|
-
gap: 0.375rem;
|
|
171
|
-
padding: var(--dry-space-3);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.preview-nav-line,
|
|
175
|
-
.preview-line {
|
|
176
|
-
block-size: 0.25rem;
|
|
177
|
-
border-radius: 999px;
|
|
178
|
-
background-size: var(--_line-fill, 100%) 100%;
|
|
179
|
-
background-repeat: no-repeat;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.preview-nav-line.short,
|
|
183
|
-
.preview-line.short {
|
|
184
|
-
--_line-fill: 66%;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
.preview-line.shorter {
|
|
188
|
-
--_line-fill: 48%;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.preview-main {
|
|
192
|
-
align-content: start;
|
|
193
|
-
gap: var(--dry-space-2);
|
|
194
|
-
padding: var(--dry-space-3);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.preview-card {
|
|
198
|
-
align-content: start;
|
|
199
|
-
gap: 0.375rem;
|
|
200
|
-
padding: var(--dry-space-3);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.preview-card-grid {
|
|
204
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
205
|
-
gap: var(--dry-space-2);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* Preview colors use currentColor so they stay neutral regardless of
|
|
209
|
-
wizard theme overrides applied to :root. */
|
|
210
|
-
|
|
211
|
-
.preview-frame[data-personality='minimal'] {
|
|
212
|
-
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
[data-personality='minimal'] .preview-dot,
|
|
216
|
-
[data-personality='minimal'] .preview-pill,
|
|
217
|
-
[data-personality='minimal'] .preview-nav-line,
|
|
218
|
-
[data-personality='minimal'] .preview-line {
|
|
219
|
-
background: color-mix(in srgb, currentColor 14%, transparent);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
[data-personality='minimal'] .preview-card {
|
|
223
|
-
background: transparent;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.preview-frame[data-personality='clean'] {
|
|
227
|
-
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
[data-personality='clean'] .preview-toolbar {
|
|
231
|
-
border-bottom: 1px solid color-mix(in srgb, currentColor 8%, transparent);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
[data-personality='clean'] .preview-sidebar {
|
|
235
|
-
border-right: 1px solid color-mix(in srgb, currentColor 8%, transparent);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
[data-personality='clean'] .preview-dot,
|
|
239
|
-
[data-personality='clean'] .preview-pill,
|
|
240
|
-
[data-personality='clean'] .preview-nav-line,
|
|
241
|
-
[data-personality='clean'] .preview-line {
|
|
242
|
-
background: color-mix(in srgb, currentColor 18%, transparent);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
[data-personality='clean'] .preview-card {
|
|
246
|
-
background: color-mix(in srgb, currentColor 6%, transparent);
|
|
247
|
-
border-radius: var(--dry-radius-md);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.preview-frame[data-personality='structured'] {
|
|
251
|
-
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
252
|
-
border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
[data-personality='structured'] .preview-toolbar,
|
|
256
|
-
[data-personality='structured'] .preview-sidebar {
|
|
257
|
-
background: color-mix(in srgb, currentColor 6%, transparent);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
[data-personality='structured'] .preview-toolbar {
|
|
261
|
-
border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
[data-personality='structured'] .preview-sidebar {
|
|
265
|
-
border-right: 1px solid color-mix(in srgb, currentColor 10%, transparent);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
[data-personality='structured'] .preview-dot,
|
|
269
|
-
[data-personality='structured'] .preview-pill,
|
|
270
|
-
[data-personality='structured'] .preview-nav-line,
|
|
271
|
-
[data-personality='structured'] .preview-line {
|
|
272
|
-
background: color-mix(in srgb, currentColor 22%, transparent);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
[data-personality='structured'] .preview-card {
|
|
276
|
-
background: color-mix(in srgb, currentColor 6%, transparent);
|
|
277
|
-
border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
|
|
278
|
-
border-radius: var(--dry-radius-md);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.preview-frame[data-personality='rich'] {
|
|
282
|
-
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
283
|
-
border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
|
284
|
-
box-shadow: 0 1.25rem 2.5rem color-mix(in srgb, currentColor 12%, transparent);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
[data-personality='rich'] .preview-toolbar,
|
|
288
|
-
[data-personality='rich'] .preview-sidebar {
|
|
289
|
-
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
[data-personality='rich'] .preview-toolbar {
|
|
293
|
-
border-bottom: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
[data-personality='rich'] .preview-sidebar {
|
|
297
|
-
border-right: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
[data-personality='rich'] .preview-dot,
|
|
301
|
-
[data-personality='rich'] .preview-pill,
|
|
302
|
-
[data-personality='rich'] .preview-nav-line,
|
|
303
|
-
[data-personality='rich'] .preview-line {
|
|
304
|
-
background: color-mix(in srgb, currentColor 26%, transparent);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
[data-personality='rich'] .preview-card {
|
|
308
|
-
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
309
|
-
border: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
|
310
|
-
border-radius: var(--dry-radius-lg);
|
|
311
|
-
box-shadow: 0 0.75rem 1.5rem color-mix(in srgb, currentColor 10%, transparent);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
@container (max-width: 40rem) {
|
|
315
|
-
.options-grid {
|
|
316
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
</style>
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import { SegmentedControl } from '@dryui/ui/segmented-control';
|
|
4
|
-
import { Button } from '@dryui/ui/button';
|
|
5
|
-
import { Text } from '@dryui/ui/text';
|
|
6
|
-
import { getDerivedTheme, getAllTokens } from '../state.svelte';
|
|
7
|
-
import { downloadCss, copyCss } from '../engine/export-css.js';
|
|
8
|
-
|
|
9
|
-
let {
|
|
10
|
-
preview,
|
|
11
|
-
mode = 'light',
|
|
12
|
-
onmodechange
|
|
13
|
-
}: {
|
|
14
|
-
preview?: Snippet;
|
|
15
|
-
mode?: 'light' | 'dark';
|
|
16
|
-
onmodechange?: (mode: 'light' | 'dark') => void;
|
|
17
|
-
} = $props();
|
|
18
|
-
|
|
19
|
-
let copyFeedback = $state('');
|
|
20
|
-
const tokens = $derived(getAllTokens(mode));
|
|
21
|
-
|
|
22
|
-
function attachThemeTokens(tokens: Record<string, string>) {
|
|
23
|
-
return (node: HTMLElement) => {
|
|
24
|
-
for (const [name, value] of Object.entries(tokens)) {
|
|
25
|
-
node.style.setProperty(name, value);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return () => {
|
|
29
|
-
for (const name of Object.keys(tokens)) {
|
|
30
|
-
node.style.removeProperty(name);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function handleDownload() {
|
|
37
|
-
downloadCss(getDerivedTheme());
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function handleCopyCss() {
|
|
41
|
-
await copyCss(getDerivedTheme());
|
|
42
|
-
copyFeedback = 'Copied!';
|
|
43
|
-
setTimeout(() => (copyFeedback = ''), 2000);
|
|
44
|
-
}
|
|
45
|
-
</script>
|
|
46
|
-
|
|
47
|
-
<section class="preview-section">
|
|
48
|
-
<div class="preview-header">
|
|
49
|
-
<SegmentedControl.Root value={mode}>
|
|
50
|
-
<SegmentedControl.Item value="light" onclick={() => onmodechange?.('light')}>
|
|
51
|
-
Light
|
|
52
|
-
</SegmentedControl.Item>
|
|
53
|
-
<SegmentedControl.Item value="dark" onclick={() => onmodechange?.('dark')}>
|
|
54
|
-
Dark
|
|
55
|
-
</SegmentedControl.Item>
|
|
56
|
-
</SegmentedControl.Root>
|
|
57
|
-
|
|
58
|
-
<div class="export-actions">
|
|
59
|
-
<Button variant="solid" size="sm" onclick={handleDownload}>Download CSS</Button>
|
|
60
|
-
<Button variant="outline" size="sm" onclick={handleCopyCss}>
|
|
61
|
-
{copyFeedback || 'Copy CSS'}
|
|
62
|
-
</Button>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<div class="preview-scene" data-mode={mode} {@attach attachThemeTokens(tokens)}>
|
|
67
|
-
{#if preview}
|
|
68
|
-
{@render preview()}
|
|
69
|
-
{:else}
|
|
70
|
-
<Text as="p" size="sm" color="muted">No preview available.</Text>
|
|
71
|
-
{/if}
|
|
72
|
-
</div>
|
|
73
|
-
</section>
|
|
74
|
-
|
|
75
|
-
<style>
|
|
76
|
-
.preview-section {
|
|
77
|
-
display: grid;
|
|
78
|
-
gap: var(--dry-space-5);
|
|
79
|
-
container-type: inline-size;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.preview-header {
|
|
83
|
-
display: grid;
|
|
84
|
-
grid-template-columns: auto 1fr;
|
|
85
|
-
align-items: center;
|
|
86
|
-
gap: var(--dry-space-4);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.export-actions {
|
|
90
|
-
display: grid;
|
|
91
|
-
grid-auto-flow: column;
|
|
92
|
-
grid-auto-columns: max-content;
|
|
93
|
-
gap: var(--dry-space-2);
|
|
94
|
-
justify-self: end;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.preview-scene {
|
|
98
|
-
padding: var(--dry-space-6);
|
|
99
|
-
border-radius: var(--dry-radius-lg);
|
|
100
|
-
border: 1px solid var(--dry-color-stroke-weak);
|
|
101
|
-
background: var(--dry-color-bg-base);
|
|
102
|
-
color: var(--dry-color-text-strong);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
@container (max-width: 36rem) {
|
|
106
|
-
.preview-header {
|
|
107
|
-
grid-template-columns: 1fr;
|
|
108
|
-
gap: var(--dry-space-3);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.export-actions {
|
|
112
|
-
justify-self: start;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
</style>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from 'svelte';
|
|
2
|
-
type $$ComponentProps = {
|
|
3
|
-
preview?: Snippet;
|
|
4
|
-
mode?: 'light' | 'dark';
|
|
5
|
-
onmodechange?: (mode: 'light' | 'dark') => void;
|
|
6
|
-
};
|
|
7
|
-
declare const PreviewExport: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
-
type PreviewExport = ReturnType<typeof PreviewExport>;
|
|
9
|
-
export default PreviewExport;
|