@widgetic/creator 0.3.71 → 0.3.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CreatorApp.svelte +882 -78
- package/dist/components/BrandKitPanel.svelte +556 -0
- package/dist/components/BrandKitPanel.svelte.d.ts +32 -0
- package/dist/components/DesignQuickEdit.svelte +218 -0
- package/dist/components/DesignQuickEdit.svelte.d.ts +33 -0
- package/dist/components/FileUrlSourceControl.svelte +69 -0
- package/dist/components/FileUrlSourceControl.svelte.d.ts +15 -0
- package/dist/components/VersionDropdownRow.svelte +86 -1
- package/dist/components/VersionDropdownRow.svelte.d.ts +10 -0
- package/dist/components/WidgetDetails.svelte +19 -2
- package/dist/components/WidgetShapeLivePreviews.svelte +8 -3
- package/dist/retiredSurface.test.d.ts +1 -0
- package/dist/retiredSurface.test.js +113 -0
- package/dist/stores/websocketStore.d.ts +3 -0
- package/dist/stores/websocketStore.js +4 -0
- package/dist/utils/canvasShapeSnapClient.d.ts +27 -0
- package/dist/utils/canvasShapeSnapClient.js +67 -0
- package/dist/utils/designIntentJevClient.d.ts +32 -0
- package/dist/utils/designIntentJevClient.js +51 -0
- package/dist/utils/designIntentResolver.d.ts +107 -0
- package/dist/utils/designIntentResolver.js +509 -0
- package/dist/utils/designIntentResolver.test.d.ts +1 -0
- package/dist/utils/designIntentResolver.test.js +246 -0
- package/dist/utils/designIntentTelemetry.d.ts +176 -0
- package/dist/utils/designIntentTelemetry.js +474 -0
- package/dist/utils/designIntentTelemetry.test.d.ts +1 -0
- package/dist/utils/designIntentTelemetry.test.js +385 -0
- package/dist/utils/designQuickEditValues.d.ts +51 -0
- package/dist/utils/designQuickEditValues.js +77 -0
- package/dist/utils/designQuickEditValues.test.d.ts +1 -0
- package/dist/utils/designQuickEditValues.test.js +100 -0
- package/dist/utils/pinScrollToBottom.js +9 -2
- package/package.json +2 -2
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { writable } from 'svelte/store';
|
|
3
|
+
import { DropdownMenu, Portal } from '@widgetic/design-system';
|
|
4
|
+
import { FontInputController } from '@widgetic/editor';
|
|
5
|
+
import FileUrlSourceControl from './FileUrlSourceControl.svelte';
|
|
6
|
+
import HoverTooltip from './HoverTooltip.svelte';
|
|
7
|
+
|
|
8
|
+
interface FontModel {
|
|
9
|
+
family: string;
|
|
10
|
+
weight: string;
|
|
11
|
+
category: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
class?: string;
|
|
16
|
+
style?: string;
|
|
17
|
+
part?: 'checks' | 'panel';
|
|
18
|
+
brandKitEnabled?: boolean;
|
|
19
|
+
librariesEnabled?: boolean;
|
|
20
|
+
showPresetLibraries?: boolean;
|
|
21
|
+
suspendPickers?: boolean;
|
|
22
|
+
primary?: string;
|
|
23
|
+
secondary?: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
sub?: string;
|
|
26
|
+
fonts?: string[];
|
|
27
|
+
libraries?: string[];
|
|
28
|
+
libraryGitUrl?: string;
|
|
29
|
+
libraryFileName?: string;
|
|
30
|
+
libraryUploads?: { name: string; content: string; encoding: string }[];
|
|
31
|
+
fontUploads?: { name: string; content: string; encoding: string }[];
|
|
32
|
+
showLanguage?: boolean;
|
|
33
|
+
language?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const maxFonts = 3;
|
|
37
|
+
|
|
38
|
+
let {
|
|
39
|
+
class: className = '',
|
|
40
|
+
style = '',
|
|
41
|
+
part = 'checks',
|
|
42
|
+
brandKitEnabled = $bindable(false),
|
|
43
|
+
librariesEnabled = $bindable(false),
|
|
44
|
+
showPresetLibraries = false,
|
|
45
|
+
suspendPickers = false,
|
|
46
|
+
primary = $bindable('#314F2F'),
|
|
47
|
+
secondary = $bindable('#7BA668'),
|
|
48
|
+
title = $bindable('#0F2010'),
|
|
49
|
+
sub = $bindable('#5C6B58'),
|
|
50
|
+
fonts = $bindable(['Inter']),
|
|
51
|
+
libraries = $bindable([] as string[]),
|
|
52
|
+
libraryGitUrl = $bindable(''),
|
|
53
|
+
libraryFileName = $bindable(''),
|
|
54
|
+
libraryUploads = $bindable([] as { name: string; content: string; encoding: string }[]),
|
|
55
|
+
fontUploads = $bindable([] as { name: string; content: string; encoding: string }[]),
|
|
56
|
+
showLanguage = false,
|
|
57
|
+
language = $bindable('svelte'),
|
|
58
|
+
}: Props = $props();
|
|
59
|
+
|
|
60
|
+
const libraryChoices = [
|
|
61
|
+
{ id: 'chart.js/auto', label: 'Chart.js' },
|
|
62
|
+
{ id: 'd3', label: 'D3' },
|
|
63
|
+
{ id: 'gsap', label: 'GSAP' },
|
|
64
|
+
{ id: 'three', label: 'Three.js' },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
// FontInputController requires a store for its open-dropdown contract.
|
|
68
|
+
const openDropdowns = writable(new Set<string>());
|
|
69
|
+
|
|
70
|
+
let fontModels = $state<FontModel[]>(
|
|
71
|
+
(fonts.length ? fonts : ['Inter']).slice(0, maxFonts).map((family) => ({
|
|
72
|
+
family,
|
|
73
|
+
weight: '400',
|
|
74
|
+
category: 'sans-serif',
|
|
75
|
+
})),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
function publishFonts() {
|
|
79
|
+
fonts = fontModels.map((model) => model.family);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function toggleDropdown(id: string) {
|
|
83
|
+
openDropdowns.update((current) => {
|
|
84
|
+
const next = new Set(current);
|
|
85
|
+
if (next.has(id)) next.delete(id);
|
|
86
|
+
else {
|
|
87
|
+
next.clear();
|
|
88
|
+
next.add(id);
|
|
89
|
+
}
|
|
90
|
+
return next;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function updateFont(index: number, next: { family?: string } | null) {
|
|
95
|
+
const family = next?.family?.trim() || 'Inter';
|
|
96
|
+
if (fontModels[index]?.family === family) return;
|
|
97
|
+
fontModels[index] = { family, weight: '400', category: 'sans-serif' };
|
|
98
|
+
publishFonts();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function addFont() {
|
|
102
|
+
if (fontModels.length >= maxFonts) return;
|
|
103
|
+
fontModels = [...fontModels, { family: 'Inter', weight: '400', category: 'sans-serif' }];
|
|
104
|
+
publishFonts();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function removeFont(index: number) {
|
|
108
|
+
if (fontModels.length <= 1) return;
|
|
109
|
+
fontModels = fontModels.filter((_, entryIndex) => entryIndex !== index);
|
|
110
|
+
publishFonts();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function toggleLibrary(id: string) {
|
|
114
|
+
const next = libraries.includes(id)
|
|
115
|
+
? libraries.filter((entry) => entry !== id)
|
|
116
|
+
: [...libraries, id];
|
|
117
|
+
libraries = next;
|
|
118
|
+
if (next.length > 0) librariesEnabled = true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let iconFileName = $state('');
|
|
122
|
+
let iconUrl = $state('');
|
|
123
|
+
|
|
124
|
+
type SourceRow = { id: string; fileName: string; url: string; content: string; encoding: string };
|
|
125
|
+
const emptySource = (): SourceRow => ({
|
|
126
|
+
id: crypto.randomUUID(),
|
|
127
|
+
fileName: '',
|
|
128
|
+
url: '',
|
|
129
|
+
content: '',
|
|
130
|
+
encoding: 'utf8',
|
|
131
|
+
});
|
|
132
|
+
let libraryRows = $state<SourceRow[]>([emptySource()]);
|
|
133
|
+
let iconRows = $state<SourceRow[]>([emptySource()]);
|
|
134
|
+
|
|
135
|
+
function addSourceRow(kind: 'library' | 'icon') {
|
|
136
|
+
const rows = kind === 'library' ? libraryRows : iconRows;
|
|
137
|
+
if (rows.length >= 4) return;
|
|
138
|
+
const next = [emptySource(), ...rows];
|
|
139
|
+
if (kind === 'library') libraryRows = next;
|
|
140
|
+
else iconRows = next;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function removeSourceRow(kind: 'library' | 'icon', id: string) {
|
|
144
|
+
const rows = kind === 'library' ? libraryRows : iconRows;
|
|
145
|
+
const next = rows.filter((row) => row.id !== id);
|
|
146
|
+
const kept = next.length > 0 ? next : [emptySource()];
|
|
147
|
+
if (kind === 'library') libraryRows = kept;
|
|
148
|
+
else iconRows = kept;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let fontFileName = $state('');
|
|
152
|
+
let fontFileContent = $state('');
|
|
153
|
+
let fontFileEncoding = $state('base64');
|
|
154
|
+
let fontFileUrl = $state('');
|
|
155
|
+
|
|
156
|
+
function clearFontUpload() {
|
|
157
|
+
fontFileName = '';
|
|
158
|
+
fontFileContent = '';
|
|
159
|
+
fontFileEncoding = 'base64';
|
|
160
|
+
fontFileUrl = '';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
$effect(() => {
|
|
164
|
+
libraryFileName = libraryRows[0]?.fileName || '';
|
|
165
|
+
libraryGitUrl = libraryRows[0]?.url || '';
|
|
166
|
+
iconFileName = iconRows[0]?.fileName || '';
|
|
167
|
+
iconUrl = iconRows[0]?.url || '';
|
|
168
|
+
libraryUploads = [...libraryRows, ...iconRows]
|
|
169
|
+
.filter((row) => row.fileName && row.content)
|
|
170
|
+
.map((row) => ({ name: row.fileName, content: row.content, encoding: row.encoding }));
|
|
171
|
+
fontUploads = fontFileName && fontFileContent
|
|
172
|
+
? [{ name: fontFileName, content: fontFileContent, encoding: fontFileEncoding || 'base64' }]
|
|
173
|
+
: [];
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
let brandPanelOpen = $state(false);
|
|
177
|
+
let brandPanelMaxHeight = $state(0);
|
|
178
|
+
let brandButtonEl = $state<HTMLLabelElement | null>(null);
|
|
179
|
+
let brandPopoverEl = $state<HTMLDivElement | null>(null);
|
|
180
|
+
let brandPanelTop = $state(0);
|
|
181
|
+
let brandPanelLeft = $state(0);
|
|
182
|
+
|
|
183
|
+
function placePopover(anchor: HTMLElement | null, panel: HTMLElement | null, width: number) {
|
|
184
|
+
if (!anchor) return { top: 0, left: 8 };
|
|
185
|
+
const rect = anchor.getBoundingClientRect();
|
|
186
|
+
const height = panel?.offsetHeight || 320;
|
|
187
|
+
const left = Math.max(8, Math.min(rect.left, window.innerWidth - width - 8));
|
|
188
|
+
const below = rect.bottom + 6;
|
|
189
|
+
const fitsBelow = below + height <= window.innerHeight - 8;
|
|
190
|
+
const top = fitsBelow ? below : Math.max(8, rect.top - height - 6);
|
|
191
|
+
return { top, left };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function closeFontPickers() {
|
|
195
|
+
openDropdowns.set(new Set());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function onBrandKitChange(event: Event) {
|
|
199
|
+
brandKitEnabled = (event.currentTarget as HTMLInputElement).checked;
|
|
200
|
+
closeFontPickers();
|
|
201
|
+
brandPanelOpen = brandKitEnabled;
|
|
202
|
+
if (!brandKitEnabled) brandPanelMaxHeight = 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function onLibrariesChange(event: Event) {
|
|
206
|
+
librariesEnabled = (event.currentTarget as HTMLInputElement).checked;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function componentExtension() {
|
|
210
|
+
return language === 'react' ? '.jsx' : '.svelte';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function sourceAccept(includeSvg: boolean) {
|
|
214
|
+
const extensions = ['.js', '.ts', componentExtension(), '.zip', '.tar', '.tgz', '.gz'];
|
|
215
|
+
if (includeSvg) extensions.unshift('.svg');
|
|
216
|
+
return extensions.join(',');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function uploadTooltip(includeSvg: boolean) {
|
|
220
|
+
return includeSvg ? 'Upload your icon library.' : 'Upload your custom library.';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function urlPlaceholder(includeSvg: boolean) {
|
|
224
|
+
const component = componentExtension();
|
|
225
|
+
return includeSvg
|
|
226
|
+
? `URL (git, archive, .svg, ${component})`
|
|
227
|
+
: `URL (git, archive, .js, .ts, ${component})`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
$effect(() => {
|
|
231
|
+
if (!brandPanelOpen) return;
|
|
232
|
+
|
|
233
|
+
function place() {
|
|
234
|
+
const brandPlace = placePopover(brandButtonEl, brandPopoverEl, 320);
|
|
235
|
+
brandPanelTop = brandPlace.top;
|
|
236
|
+
brandPanelLeft = brandPlace.left;
|
|
237
|
+
const openHeight = brandPopoverEl?.offsetHeight || 0;
|
|
238
|
+
if (openHeight > 0 && brandPanelMaxHeight === 0) brandPanelMaxHeight = openHeight;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function onPointerDown(event: PointerEvent) {
|
|
242
|
+
const target = event.target as HTMLElement | null;
|
|
243
|
+
if (!target) return;
|
|
244
|
+
if (brandButtonEl?.contains(target)) return;
|
|
245
|
+
if (target.closest('.generation-brand-kit-popover')) return;
|
|
246
|
+
if (target.closest('.font-input-popover')) return;
|
|
247
|
+
if (target.closest('#widgetic-font-picker-portal')) return;
|
|
248
|
+
closeFontPickers();
|
|
249
|
+
brandPanelOpen = false;
|
|
250
|
+
brandPanelMaxHeight = 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
place();
|
|
254
|
+
const frame = requestAnimationFrame(place);
|
|
255
|
+
window.addEventListener('pointerdown', onPointerDown, true);
|
|
256
|
+
window.addEventListener('resize', place);
|
|
257
|
+
window.addEventListener('scroll', place, true);
|
|
258
|
+
return () => {
|
|
259
|
+
cancelAnimationFrame(frame);
|
|
260
|
+
window.removeEventListener('pointerdown', onPointerDown, true);
|
|
261
|
+
window.removeEventListener('resize', place);
|
|
262
|
+
window.removeEventListener('scroll', place, true);
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
</script>
|
|
266
|
+
|
|
267
|
+
{#if part === 'checks'}
|
|
268
|
+
<div class="generation-options-checks contents {className}" {style}>
|
|
269
|
+
<label
|
|
270
|
+
class="generation-brand-kit-toggle ml-auto flex h-10 shrink-0 cursor-pointer items-center gap-1.5 rounded-lg border px-2 text-sm {brandKitEnabled ? 'border-[#314F2F] bg-[#314F2F] text-white' : 'border-gray-300 bg-white text-gray-800'}"
|
|
271
|
+
bind:this={brandButtonEl}
|
|
272
|
+
>
|
|
273
|
+
<input
|
|
274
|
+
class="generation-option-check cursor-pointer"
|
|
275
|
+
type="checkbox"
|
|
276
|
+
checked={brandKitEnabled}
|
|
277
|
+
onchange={onBrandKitChange}
|
|
278
|
+
/>
|
|
279
|
+
Brand kit
|
|
280
|
+
</label>
|
|
281
|
+
<div class="generation-libraries-row flex w-full flex-col gap-2">
|
|
282
|
+
<div class="generation-libraries-checks flex flex-nowrap items-center gap-1">
|
|
283
|
+
{#if showLanguage}
|
|
284
|
+
<HoverTooltip class="inline-flex shrink-0" text="Select language">
|
|
285
|
+
<DropdownMenu.Root>
|
|
286
|
+
<DropdownMenu.Trigger
|
|
287
|
+
class="generation-language-select flex h-10 w-[4.75rem] shrink-0 cursor-pointer items-center justify-between gap-0.5 rounded-lg border border-gray-300 bg-white px-1.5 text-sm text-gray-900"
|
|
288
|
+
>
|
|
289
|
+
<span class="truncate">{language === 'react' ? 'React' : 'Svelte'}</span>
|
|
290
|
+
<svg class="h-3 w-3 shrink-0 text-gray-500" viewBox="0 0 12 12" fill="none" aria-hidden="true">
|
|
291
|
+
<path d="M3 4.5 6 7.5 9 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
|
292
|
+
</svg>
|
|
293
|
+
</DropdownMenu.Trigger>
|
|
294
|
+
<DropdownMenu.Content class="w-[4.75rem] min-w-0">
|
|
295
|
+
<DropdownMenu.Item
|
|
296
|
+
class="cursor-pointer {language === 'svelte' ? 'bg-[#314F2F]/15 text-[#314F2F]' : ''}"
|
|
297
|
+
onSelect={() => (language = 'svelte')}
|
|
298
|
+
>Svelte</DropdownMenu.Item>
|
|
299
|
+
<DropdownMenu.Item
|
|
300
|
+
class="cursor-pointer {language === 'react' ? 'bg-[#314F2F]/15 text-[#314F2F]' : ''}"
|
|
301
|
+
onSelect={() => (language = 'react')}
|
|
302
|
+
>React</DropdownMenu.Item>
|
|
303
|
+
</DropdownMenu.Content>
|
|
304
|
+
</DropdownMenu.Root>
|
|
305
|
+
</HoverTooltip>
|
|
306
|
+
{/if}
|
|
307
|
+
<label class="generation-option-toggle flex h-10 shrink-0 cursor-pointer items-center gap-1.5 rounded-lg border px-2 text-sm {librariesEnabled ? 'border-[#314F2F] bg-[#314F2F] text-white' : 'border-gray-300 bg-white text-gray-800'}">
|
|
308
|
+
<input class="generation-option-check cursor-pointer" type="checkbox" checked={librariesEnabled} onchange={onLibrariesChange} />
|
|
309
|
+
Libraries
|
|
310
|
+
</label>
|
|
311
|
+
{#if librariesEnabled && showPresetLibraries}
|
|
312
|
+
{#each libraryChoices as choice (choice.id)}
|
|
313
|
+
<label class="generation-library flex items-center gap-1 text-xs text-gray-700">
|
|
314
|
+
<input
|
|
315
|
+
class="generation-library-check cursor-pointer"
|
|
316
|
+
type="checkbox"
|
|
317
|
+
checked={libraries.includes(choice.id)}
|
|
318
|
+
onchange={() => toggleLibrary(choice.id)}
|
|
319
|
+
/>
|
|
320
|
+
{choice.label}
|
|
321
|
+
</label>
|
|
322
|
+
{/each}
|
|
323
|
+
{/if}
|
|
324
|
+
{#if librariesEnabled}
|
|
325
|
+
<HoverTooltip class="inline-flex shrink-0" text="Add Library">
|
|
326
|
+
<button
|
|
327
|
+
type="button"
|
|
328
|
+
class="generation-library-add flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-gray-300 bg-white text-sm text-gray-800"
|
|
329
|
+
aria-label="Add Library"
|
|
330
|
+
onclick={() => addSourceRow('library')}
|
|
331
|
+
>+</button>
|
|
332
|
+
</HoverTooltip>
|
|
333
|
+
{/if}
|
|
334
|
+
</div>
|
|
335
|
+
{#if librariesEnabled}
|
|
336
|
+
{#each libraryRows as row (row.id)}
|
|
337
|
+
<div class="generation-source-row flex items-center gap-1">
|
|
338
|
+
<FileUrlSourceControl
|
|
339
|
+
class="min-w-0 flex-1"
|
|
340
|
+
bind:fileName={row.fileName}
|
|
341
|
+
bind:fileContent={row.content}
|
|
342
|
+
bind:fileEncoding={row.encoding}
|
|
343
|
+
bind:url={row.url}
|
|
344
|
+
fileLabel="Upload library"
|
|
345
|
+
fileTitle={uploadTooltip(false)}
|
|
346
|
+
urlPlaceholder={urlPlaceholder(false)}
|
|
347
|
+
accept={sourceAccept(false)}
|
|
348
|
+
/>
|
|
349
|
+
{#if libraryRows.length > 1}
|
|
350
|
+
<button
|
|
351
|
+
type="button"
|
|
352
|
+
class="generation-source-remove flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-gray-300 text-gray-500"
|
|
353
|
+
aria-label="Remove library"
|
|
354
|
+
onclick={() => removeSourceRow('library', row.id)}
|
|
355
|
+
>
|
|
356
|
+
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
357
|
+
<path d="M4 7h16" />
|
|
358
|
+
<path d="M9 7V5h6v2" />
|
|
359
|
+
<path d="M8 7l1 13h6l1-13" />
|
|
360
|
+
</svg>
|
|
361
|
+
</button>
|
|
362
|
+
{/if}
|
|
363
|
+
</div>
|
|
364
|
+
{/each}
|
|
365
|
+
{/if}
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
{#if brandPanelOpen}
|
|
369
|
+
<Portal
|
|
370
|
+
target="generation-brand-kit-portal"
|
|
371
|
+
class="generation-brand-kit-portal-root"
|
|
372
|
+
style="position: fixed; top: {brandPanelTop}px; left: {brandPanelLeft}px; width: 320px; height: auto;"
|
|
373
|
+
>
|
|
374
|
+
<div
|
|
375
|
+
class="generation-brand-kit-popover flex flex-col gap-3 overflow-y-auto rounded-lg border border-gray-200 bg-white p-3 shadow-lg"
|
|
376
|
+
style={brandPanelMaxHeight > 0 ? `max-height: ${brandPanelMaxHeight}px;` : ''}
|
|
377
|
+
bind:this={brandPopoverEl}
|
|
378
|
+
>
|
|
379
|
+
<p class="generation-options-note text-xs text-gray-500">Replaces the Widgetic palette for this generation.</p>
|
|
380
|
+
<section class="generation-color-palette flex flex-col gap-2">
|
|
381
|
+
<h3 class="generation-section-title text-xs font-semibold text-gray-800">Color palette</h3>
|
|
382
|
+
<div class="generation-brand-colors flex flex-wrap items-end gap-3">
|
|
383
|
+
<label class="generation-brand-color flex flex-col gap-1 text-xs text-gray-600">
|
|
384
|
+
Primary
|
|
385
|
+
<input class="generation-brand-color-input h-8 w-14 cursor-pointer border border-gray-200 bg-white" type="color" bind:value={primary} />
|
|
386
|
+
</label>
|
|
387
|
+
<label class="generation-brand-color flex flex-col gap-1 text-xs text-gray-600">
|
|
388
|
+
Secondary
|
|
389
|
+
<input class="generation-brand-color-input h-8 w-14 cursor-pointer border border-gray-200 bg-white" type="color" bind:value={secondary} />
|
|
390
|
+
</label>
|
|
391
|
+
<label class="generation-brand-color flex flex-col gap-1 text-xs text-gray-600">
|
|
392
|
+
Title
|
|
393
|
+
<input class="generation-brand-color-input h-8 w-14 cursor-pointer border border-gray-200 bg-white" type="color" bind:value={title} />
|
|
394
|
+
</label>
|
|
395
|
+
<label class="generation-brand-color flex flex-col gap-1 text-xs text-gray-600">
|
|
396
|
+
Sub
|
|
397
|
+
<input class="generation-brand-color-input h-8 w-14 cursor-pointer border border-gray-200 bg-white" type="color" bind:value={sub} />
|
|
398
|
+
</label>
|
|
399
|
+
</div>
|
|
400
|
+
</section>
|
|
401
|
+
<div class="generation-section-separator border-t border-gray-200"></div>
|
|
402
|
+
<section class="generation-brand-fonts flex flex-col gap-2">
|
|
403
|
+
<div class="generation-fonts-header flex items-center justify-between gap-2">
|
|
404
|
+
<h3 class="generation-section-title text-xs font-semibold text-gray-800">Fonts</h3>
|
|
405
|
+
{#if fontModels.length < maxFonts && !suspendPickers}
|
|
406
|
+
<button
|
|
407
|
+
type="button"
|
|
408
|
+
class="generation-brand-font-add h-7 cursor-pointer rounded-md border border-gray-300 px-2 text-xs text-gray-700"
|
|
409
|
+
onclick={addFont}
|
|
410
|
+
>
|
|
411
|
+
+ Font
|
|
412
|
+
</button>
|
|
413
|
+
{/if}
|
|
414
|
+
</div>
|
|
415
|
+
{#each fontModels as model, index (index)}
|
|
416
|
+
<div class="generation-brand-font-row flex items-start gap-2">
|
|
417
|
+
{#if suspendPickers}
|
|
418
|
+
<p class="generation-brand-font-name min-w-0 flex-1 py-2 text-sm text-gray-800">{model.family}</p>
|
|
419
|
+
{:else}
|
|
420
|
+
<div class="generation-brand-font-picker min-w-0 flex-1">
|
|
421
|
+
<FontInputController
|
|
422
|
+
label={index === 0 ? 'Font' : `Font ${index + 1}`}
|
|
423
|
+
controllerId="generation-brand-font-{index}"
|
|
424
|
+
value={model}
|
|
425
|
+
{openDropdowns}
|
|
426
|
+
{toggleDropdown}
|
|
427
|
+
hideTrashIcon={true}
|
|
428
|
+
hideRecentFromList={true}
|
|
429
|
+
onChange={(next) => updateFont(index, next)}
|
|
430
|
+
/>
|
|
431
|
+
</div>
|
|
432
|
+
{/if}
|
|
433
|
+
{#if fontModels.length > 1}
|
|
434
|
+
<button
|
|
435
|
+
type="button"
|
|
436
|
+
class="generation-brand-font-remove mt-1 flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-gray-300 text-gray-500"
|
|
437
|
+
aria-label="Remove font"
|
|
438
|
+
onclick={() => removeFont(index)}
|
|
439
|
+
>
|
|
440
|
+
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
441
|
+
<path d="M4 7h16" />
|
|
442
|
+
<path d="M9 7V5h6v2" />
|
|
443
|
+
<path d="M8 7l1 13h6l1-13" />
|
|
444
|
+
</svg>
|
|
445
|
+
</button>
|
|
446
|
+
{/if}
|
|
447
|
+
</div>
|
|
448
|
+
{/each}
|
|
449
|
+
<div class="generation-font-upload flex items-center gap-1">
|
|
450
|
+
<FileUrlSourceControl
|
|
451
|
+
class="min-w-0 flex-1"
|
|
452
|
+
bind:fileName={fontFileName}
|
|
453
|
+
bind:fileContent={fontFileContent}
|
|
454
|
+
bind:fileEncoding={fontFileEncoding}
|
|
455
|
+
bind:url={fontFileUrl}
|
|
456
|
+
fileLabel="Upload Fonts"
|
|
457
|
+
fileTitle="Upload a font file or an archive."
|
|
458
|
+
urlPlaceholder="URL (archive, .woff2, .ttf, .otf)"
|
|
459
|
+
accept=".woff,.woff2,.ttf,.otf,.eot,.zip,.tar,.tgz,.gz"
|
|
460
|
+
/>
|
|
461
|
+
{#if fontFileName || fontFileUrl}
|
|
462
|
+
<button
|
|
463
|
+
type="button"
|
|
464
|
+
class="generation-source-remove flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-gray-300 text-gray-500"
|
|
465
|
+
aria-label="Remove uploaded font"
|
|
466
|
+
onclick={clearFontUpload}
|
|
467
|
+
>
|
|
468
|
+
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
469
|
+
<path d="M4 7h16" />
|
|
470
|
+
<path d="M9 7V5h6v2" />
|
|
471
|
+
<path d="M8 7l1 13h6l1-13" />
|
|
472
|
+
</svg>
|
|
473
|
+
</button>
|
|
474
|
+
{/if}
|
|
475
|
+
</div>
|
|
476
|
+
</section>
|
|
477
|
+
<div class="generation-section-separator border-t border-gray-200"></div>
|
|
478
|
+
<section class="generation-brand-icons flex flex-col gap-2">
|
|
479
|
+
<div class="generation-icons-header flex items-center justify-between gap-2">
|
|
480
|
+
<h3 class="generation-section-title text-xs font-semibold text-gray-800">Icons</h3>
|
|
481
|
+
<HoverTooltip text="Add icon library">
|
|
482
|
+
<button
|
|
483
|
+
type="button"
|
|
484
|
+
class="generation-icon-add flex h-7 w-7 cursor-pointer items-center justify-center rounded-md border border-gray-300 text-sm text-gray-700"
|
|
485
|
+
aria-label="Add icon library"
|
|
486
|
+
onclick={() => addSourceRow('icon')}
|
|
487
|
+
>+</button>
|
|
488
|
+
</HoverTooltip>
|
|
489
|
+
</div>
|
|
490
|
+
{#each iconRows as row (row.id)}
|
|
491
|
+
<div class="generation-source-row flex items-center gap-1">
|
|
492
|
+
<FileUrlSourceControl
|
|
493
|
+
class="min-w-0 flex-1"
|
|
494
|
+
bind:fileName={row.fileName}
|
|
495
|
+
bind:fileContent={row.content}
|
|
496
|
+
bind:fileEncoding={row.encoding}
|
|
497
|
+
bind:url={row.url}
|
|
498
|
+
fileLabel="Upload library"
|
|
499
|
+
fileTitle={uploadTooltip(true)}
|
|
500
|
+
urlPlaceholder={urlPlaceholder(true)}
|
|
501
|
+
accept={sourceAccept(true)}
|
|
502
|
+
/>
|
|
503
|
+
{#if iconRows.length > 1}
|
|
504
|
+
<button
|
|
505
|
+
type="button"
|
|
506
|
+
class="generation-source-remove flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-gray-300 text-gray-500"
|
|
507
|
+
aria-label="Remove icon library"
|
|
508
|
+
onclick={() => removeSourceRow('icon', row.id)}
|
|
509
|
+
>
|
|
510
|
+
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
511
|
+
<path d="M4 7h16" />
|
|
512
|
+
<path d="M9 7V5h6v2" />
|
|
513
|
+
<path d="M8 7l1 13h6l1-13" />
|
|
514
|
+
</svg>
|
|
515
|
+
</button>
|
|
516
|
+
{/if}
|
|
517
|
+
</div>
|
|
518
|
+
{/each}
|
|
519
|
+
</section>
|
|
520
|
+
</div>
|
|
521
|
+
</Portal>
|
|
522
|
+
{/if}
|
|
523
|
+
{/if}
|
|
524
|
+
|
|
525
|
+
<style>
|
|
526
|
+
.generation-options-checks input:focus,
|
|
527
|
+
.generation-options-checks input:focus-visible,
|
|
528
|
+
.generation-brand-kit-popover button:focus,
|
|
529
|
+
.generation-brand-kit-popover button:focus-visible,
|
|
530
|
+
.generation-brand-kit-popover input:focus,
|
|
531
|
+
.generation-brand-kit-popover input:focus-visible,
|
|
532
|
+
.generation-language-select:focus,
|
|
533
|
+
.generation-language-select:focus-visible {
|
|
534
|
+
outline: none;
|
|
535
|
+
box-shadow: none;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.generation-brand-kit-popover {
|
|
539
|
+
scrollbar-width: thin;
|
|
540
|
+
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.generation-brand-kit-popover::-webkit-scrollbar {
|
|
544
|
+
width: 8px;
|
|
545
|
+
background: transparent;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.generation-brand-kit-popover::-webkit-scrollbar-track {
|
|
549
|
+
background: transparent;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.generation-brand-kit-popover::-webkit-scrollbar-thumb {
|
|
553
|
+
background: rgba(0, 0, 0, 0.2);
|
|
554
|
+
border-radius: 4px;
|
|
555
|
+
}
|
|
556
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
class?: string;
|
|
3
|
+
style?: string;
|
|
4
|
+
part?: 'checks' | 'panel';
|
|
5
|
+
brandKitEnabled?: boolean;
|
|
6
|
+
librariesEnabled?: boolean;
|
|
7
|
+
showPresetLibraries?: boolean;
|
|
8
|
+
suspendPickers?: boolean;
|
|
9
|
+
primary?: string;
|
|
10
|
+
secondary?: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
sub?: string;
|
|
13
|
+
fonts?: string[];
|
|
14
|
+
libraries?: string[];
|
|
15
|
+
libraryGitUrl?: string;
|
|
16
|
+
libraryFileName?: string;
|
|
17
|
+
libraryUploads?: {
|
|
18
|
+
name: string;
|
|
19
|
+
content: string;
|
|
20
|
+
encoding: string;
|
|
21
|
+
}[];
|
|
22
|
+
fontUploads?: {
|
|
23
|
+
name: string;
|
|
24
|
+
content: string;
|
|
25
|
+
encoding: string;
|
|
26
|
+
}[];
|
|
27
|
+
showLanguage?: boolean;
|
|
28
|
+
language?: string;
|
|
29
|
+
}
|
|
30
|
+
declare const BrandKitPanel: import("svelte").Component<Props, {}, "brandKitEnabled" | "librariesEnabled" | "primary" | "secondary" | "title" | "sub" | "fonts" | "libraries" | "libraryGitUrl" | "libraryFileName" | "libraryUploads" | "fontUploads" | "language">;
|
|
31
|
+
type BrandKitPanel = ReturnType<typeof BrandKitPanel>;
|
|
32
|
+
export default BrandKitPanel;
|