@papu1337/builder 0.0.4 → 1.0.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.
Files changed (124) hide show
  1. package/dist/builder/BuilderView.svelte +158 -0
  2. package/dist/builder/BuilderView.svelte.d.ts +8 -0
  3. package/dist/builder/builder.vanilla.es.js +6514 -0
  4. package/dist/builder/builder.vanilla.umd.js +89 -0
  5. package/dist/builder/canvas/canvas.svelte +92 -0
  6. package/dist/builder/canvas/canvas.svelte.d.ts +17 -0
  7. package/dist/builder/canvas/styles.css +63 -0
  8. package/dist/builder/createBuilder.svelte.d.ts +9 -0
  9. package/dist/builder/createBuilder.svelte.js +17 -0
  10. package/dist/builder/index.d.ts +8 -0
  11. package/dist/builder/index.js +7 -0
  12. package/dist/builder/leftbar/leftBar.svelte +740 -0
  13. package/dist/builder/leftbar/leftBar.svelte.d.ts +8 -0
  14. package/dist/builder/leftbar/styles.css +152 -0
  15. package/dist/builder/pageMeta.svelte.d.ts +13 -0
  16. package/dist/builder/pageMeta.svelte.js +25 -0
  17. package/dist/builder/rightbar/rightBar.svelte +100 -0
  18. package/dist/builder/rightbar/rightBar.svelte.d.ts +10 -0
  19. package/dist/builder/rightbar/styles.css +167 -0
  20. package/dist/builder/topbar/TopBar.svelte +337 -0
  21. package/dist/builder/topbar/TopBar.svelte.d.ts +12 -0
  22. package/dist/builder/topbar/styles.css +123 -0
  23. package/dist/builder/viewport.svelte.d.ts +9 -0
  24. package/dist/builder/viewport.svelte.js +17 -0
  25. package/dist/elements/_shared/Arrow.svelte +58 -0
  26. package/dist/elements/_shared/Arrow.svelte.d.ts +11 -0
  27. package/dist/elements/_shared/GradientBorder.svelte +55 -0
  28. package/dist/elements/_shared/GradientBorder.svelte.d.ts +10 -0
  29. package/dist/elements/banner/bannerElement.svelte +120 -24
  30. package/dist/elements/banner/settings.d.ts +15 -3
  31. package/dist/elements/banner/settings.js +93 -8
  32. package/dist/elements/button/buttonElement.svelte +31 -21
  33. package/dist/elements/button/settings.d.ts +12 -9
  34. package/dist/elements/button/settings.js +21 -38
  35. package/dist/elements/globalSettings.js +5 -4
  36. package/dist/elements/howItWorks/howItWorksElement.svelte +221 -0
  37. package/dist/elements/howItWorks/howItWorksElement.svelte.d.ts +7 -0
  38. package/dist/elements/howItWorks/settings.d.ts +16 -0
  39. package/dist/elements/howItWorks/settings.js +70 -0
  40. package/dist/elements/steps/settings.d.ts +17 -0
  41. package/dist/elements/steps/settings.js +69 -0
  42. package/dist/elements/steps/stepsElement.svelte +220 -0
  43. package/dist/elements/steps/stepsElement.svelte.d.ts +7 -0
  44. package/dist/elements/terms/settings.d.ts +8 -5
  45. package/dist/elements/terms/settings.js +26 -33
  46. package/dist/elements/terms/termsElement.svelte +164 -79
  47. package/dist/elements/text/settings.d.ts +5 -3
  48. package/dist/elements/text/settings.js +22 -8
  49. package/dist/elements/text/textElement.svelte +25 -20
  50. package/dist/hooks/index.d.ts +1 -0
  51. package/dist/hooks/index.js +1 -0
  52. package/dist/hooks/useTranslation.svelte.d.ts +9 -0
  53. package/dist/hooks/useTranslation.svelte.js +10 -0
  54. package/dist/index.d.ts +3 -0
  55. package/dist/index.js +3 -0
  56. package/dist/renderer/BuilderRenderer.svelte +30 -2
  57. package/dist/renderer/registry.js +7 -13
  58. package/dist/renderer/renderer.vanilla.es.js +1395 -1218
  59. package/dist/renderer/renderer.vanilla.umd.js +64 -31
  60. package/dist/renderer/resolve.d.ts +1 -1
  61. package/dist/renderer/resolve.js +28 -14
  62. package/dist/renderer/types.d.ts +2 -0
  63. package/dist/service/element.action.svelte.d.ts +21 -0
  64. package/dist/service/element.action.svelte.js +125 -0
  65. package/dist/service/element.history.svelte.d.ts +8 -0
  66. package/dist/service/element.history.svelte.js +36 -0
  67. package/dist/service/element.io.svelte.d.ts +4 -0
  68. package/dist/service/element.io.svelte.js +232 -0
  69. package/dist/service/element.reader.svelte.d.ts +4 -0
  70. package/dist/service/element.reader.svelte.js +51 -0
  71. package/dist/service/element.translate.svelte.d.ts +12 -0
  72. package/dist/service/element.translate.svelte.js +81 -0
  73. package/dist/service/index.d.ts +5 -0
  74. package/dist/service/index.js +5 -0
  75. package/dist/service/types.d.ts +13 -0
  76. package/dist/service/types.js +1 -0
  77. package/dist/settings/base.svelte.d.ts +6 -1
  78. package/dist/settings/base.svelte.js +64 -22
  79. package/dist/settings/components/ColorSettings.svelte +174 -45
  80. package/dist/settings/components/ColorSettings.svelte.d.ts +3 -2
  81. package/dist/settings/components/ListSettings.svelte +11 -12
  82. package/dist/settings/components/NumberSettings.svelte +121 -24
  83. package/dist/settings/components/RepeaterSettings.svelte +145 -0
  84. package/dist/settings/components/RepeaterSettings.svelte.d.ts +14 -0
  85. package/dist/settings/components/SegmentSettings.svelte +85 -0
  86. package/dist/settings/components/SegmentSettings.svelte.d.ts +5 -0
  87. package/dist/settings/components/SelectSettings.svelte +6 -7
  88. package/dist/settings/components/SettingsGroup.svelte +13 -68
  89. package/dist/settings/components/SettingsRenderer.svelte +76 -0
  90. package/dist/settings/components/SettingsRenderer.svelte.d.ts +8 -0
  91. package/dist/settings/components/TextSettings.svelte +52 -2
  92. package/dist/settings/components/TranslatableSettings.svelte +16 -17
  93. package/dist/settings/components/UploadSettings.svelte +7 -8
  94. package/dist/settings/groups.d.ts +23 -7
  95. package/dist/settings/groups.js +48 -24
  96. package/dist/settings/implementation.svelte.js +4 -0
  97. package/dist/settings/index.d.ts +2 -0
  98. package/dist/settings/index.js +2 -0
  99. package/dist/settings/mode.svelte.d.ts +4 -0
  100. package/dist/settings/mode.svelte.js +4 -0
  101. package/dist/settings/repeater.svelte.d.ts +26 -0
  102. package/dist/settings/repeater.svelte.js +70 -0
  103. package/dist/settings/types.d.ts +28 -2
  104. package/package.json +11 -5
  105. package/dist/elements/auth/authElement.svelte +0 -115
  106. package/dist/elements/auth/authElement.svelte.d.ts +0 -7
  107. package/dist/elements/auth/settings.d.ts +0 -25
  108. package/dist/elements/auth/settings.js +0 -63
  109. package/dist/elements/badge/badgeElement.svelte +0 -48
  110. package/dist/elements/badge/badgeElement.svelte.d.ts +0 -7
  111. package/dist/elements/badge/settings.d.ts +0 -13
  112. package/dist/elements/badge/settings.js +0 -57
  113. package/dist/elements/cards/cardsElement.svelte +0 -136
  114. package/dist/elements/cards/cardsElement.svelte.d.ts +0 -7
  115. package/dist/elements/cards/settings.d.ts +0 -14
  116. package/dist/elements/cards/settings.js +0 -52
  117. package/dist/elements/divider/dividerElement.svelte +0 -34
  118. package/dist/elements/divider/dividerElement.svelte.d.ts +0 -7
  119. package/dist/elements/divider/settings.d.ts +0 -7
  120. package/dist/elements/divider/settings.js +0 -15
  121. package/dist/elements/products/productsElement.svelte +0 -283
  122. package/dist/elements/products/productsElement.svelte.d.ts +0 -7
  123. package/dist/elements/products/settings.d.ts +0 -16
  124. package/dist/elements/products/settings.js +0 -56
@@ -0,0 +1,740 @@
1
+ <script lang="ts">
2
+ import type { ElementEntry } from '../../service';
3
+ import {
4
+ ComponentsInstance,
5
+ GLOBAL_KEY,
6
+ selectComponent,
7
+ getSelectedComponent,
8
+ deleteComponent,
9
+ handleDragAndDrop
10
+ } from '../../service';
11
+ import { pageMeta, setSlug, readPromoImage } from '../pageMeta.svelte';
12
+
13
+ interface LeftBarProps {
14
+ components: ElementEntry[];
15
+ addComponent: (component: ElementEntry) => void;
16
+ }
17
+
18
+ let { components, addComponent }: LeftBarProps = $props();
19
+
20
+ const DISPLAY_NAMES: Record<string, string> = {
21
+ banner: 'Banner',
22
+ text: 'Text',
23
+ button: 'Button',
24
+ howItWorks: 'How It Works',
25
+ steps: 'Steps',
26
+ terms: 'Terms'
27
+ };
28
+
29
+ const label = (name: string): string => DISPLAY_NAMES[name] ?? name;
30
+
31
+ let tab = $state<'layers' | 'setup'>('layers');
32
+
33
+ const placed = $derived(
34
+ [...ComponentsInstance]
35
+ .filter(([id]) => id !== GLOBAL_KEY)
36
+ .map(([id, value]) => ({ id, value }))
37
+ );
38
+
39
+ const selectedId = $derived(getSelectedComponent()?.id ?? null);
40
+
41
+ function layerTitle(entry: ElementEntry): string {
42
+ const values = entry.settings.values as Record<string, unknown>;
43
+ const typography = values.typography as { text?: unknown } | undefined;
44
+ if (typography && typeof typography.text === 'string' && typography.text) {
45
+ return typography.text;
46
+ }
47
+ return label(entry.name);
48
+ }
49
+
50
+ function move(index: number, dir: -1 | 1): void {
51
+ const next = index + dir;
52
+ if (next < 0 || next >= placed.length) return;
53
+ const arr = placed.slice();
54
+ const tmp = arr[index];
55
+ arr[index] = arr[next];
56
+ arr[next] = tmp;
57
+ handleDragAndDrop(arr.map((x) => ({ id: x.id, value: x.value })));
58
+ }
59
+ </script>
60
+
61
+ <aside class="rail">
62
+ <div class="rail__tabs">
63
+ <button
64
+ type="button"
65
+ class="rail__tab"
66
+ class:rail__tab--active={tab === 'layers'}
67
+ onclick={() => (tab = 'layers')}
68
+ >
69
+ Layers
70
+ </button>
71
+ <button
72
+ type="button"
73
+ class="rail__tab"
74
+ class:rail__tab--active={tab === 'setup'}
75
+ onclick={() => (tab = 'setup')}
76
+ >
77
+ Setup
78
+ </button>
79
+ </div>
80
+
81
+ {#if tab === 'layers'}
82
+ <div class="layers">
83
+ <div class="palette">
84
+ <div class="palette__label">Elements</div>
85
+ <div class="elements-list">
86
+ {#each components as entry (entry.name)}
87
+ <button type="button" class="element-btn" onclick={() => addComponent(entry)}>
88
+ <span class="element-icon">&#9642;</span>
89
+ <span class="element-name">{label(entry.name)}</span>
90
+ <span class="element-add">+</span>
91
+ </button>
92
+ {/each}
93
+ </div>
94
+ </div>
95
+
96
+ <div class="layers__section">
97
+ <span class="layers__section-title">Page Layers</span>
98
+ <span class="layers__count">{placed.length}</span>
99
+ </div>
100
+
101
+ <div class="layers__list">
102
+ {#each placed as item, index (item.id)}
103
+ <button
104
+ type="button"
105
+ class="layer"
106
+ class:layer--active={selectedId === item.id}
107
+ onclick={() => selectComponent(item.value)}
108
+ >
109
+ <span class="layer__reorder">
110
+ <span
111
+ class="layer__move"
112
+ class:layer__move--disabled={index === 0}
113
+ role="button"
114
+ tabindex="-1"
115
+ onclick={(e) => {
116
+ e.stopPropagation();
117
+ move(index, -1);
118
+ }}
119
+ >
120
+ &#8593;
121
+ </span>
122
+ <span
123
+ class="layer__move"
124
+ class:layer__move--disabled={index === placed.length - 1}
125
+ role="button"
126
+ tabindex="-1"
127
+ onclick={(e) => {
128
+ e.stopPropagation();
129
+ move(index, 1);
130
+ }}
131
+ >
132
+ &#8595;
133
+ </span>
134
+ </span>
135
+ <span class="layer__icon">{label(item.value.name).charAt(0)}</span>
136
+ <span class="layer__text">
137
+ <span class="layer__name">{layerTitle(item.value)}</span>
138
+ <span class="layer__type">{label(item.value.name)}</span>
139
+ </span>
140
+ <span
141
+ class="layer__remove"
142
+ title="Remove layer"
143
+ role="button"
144
+ tabindex="-1"
145
+ onclick={(e) => {
146
+ e.stopPropagation();
147
+ deleteComponent(item.id);
148
+ }}
149
+ >
150
+ &#10005;
151
+ </span>
152
+ </button>
153
+ {/each}
154
+
155
+ {#if placed.length === 0}
156
+ <div class="layers__empty">No elements yet. Click “Add element”.</div>
157
+ {/if}
158
+ </div>
159
+ </div>
160
+ {:else}
161
+ <div class="setup">
162
+ <div class="setup__section">
163
+ <span class="setup__legend">Release</span>
164
+ <button
165
+ type="button"
166
+ class="setup__check"
167
+ onclick={() => (pageMeta.isActive = !pageMeta.isActive)}
168
+ >
169
+ <span class="setup__box" class:setup__box--on={pageMeta.isActive}>
170
+ {#if pageMeta.isActive}&#10003;{/if}
171
+ </span>
172
+ <span class="setup__check-label">Is active</span>
173
+ </button>
174
+ <button
175
+ type="button"
176
+ class="setup__check"
177
+ onclick={() => (pageMeta.showOnPromotionPages = !pageMeta.showOnPromotionPages)}
178
+ >
179
+ <span class="setup__box" class:setup__box--on={pageMeta.showOnPromotionPages}>
180
+ {#if pageMeta.showOnPromotionPages}&#10003;{/if}
181
+ </span>
182
+ <span class="setup__check-label">Show on promotion pages</span>
183
+ </button>
184
+
185
+ {#if pageMeta.showOnPromotionPages}
186
+ <div class="setup__field">
187
+ <label class="setup__label" for="promo-title">Promotion title</label>
188
+ <input
189
+ id="promo-title"
190
+ class="setup__input"
191
+ bind:value={pageMeta.promoTitle}
192
+ placeholder="Title shown on promotion pages"
193
+ maxlength="120"
194
+ />
195
+ </div>
196
+ <button
197
+ type="button"
198
+ class="setup__check setup__check--sub"
199
+ onclick={() => (pageMeta.promoTitleNoTranslate = !pageMeta.promoTitleNoTranslate)}
200
+ >
201
+ <span class="setup__box" class:setup__box--on={pageMeta.promoTitleNoTranslate}>
202
+ {#if pageMeta.promoTitleNoTranslate}&#10003;{/if}
203
+ </span>
204
+ <span class="setup__check-label">Don't translate title</span>
205
+ </button>
206
+
207
+ <div class="setup__field">
208
+ <label class="setup__label" for="promo-desc">Promotion description</label>
209
+ <textarea
210
+ id="promo-desc"
211
+ class="setup__input setup__input--area"
212
+ bind:value={pageMeta.promoDescription}
213
+ placeholder="Short description shown on promotion pages"
214
+ maxlength="280"
215
+ rows="3"
216
+ ></textarea>
217
+ </div>
218
+ <button
219
+ type="button"
220
+ class="setup__check setup__check--sub"
221
+ onclick={() =>
222
+ (pageMeta.promoDescriptionNoTranslate = !pageMeta.promoDescriptionNoTranslate)}
223
+ >
224
+ <span class="setup__box" class:setup__box--on={pageMeta.promoDescriptionNoTranslate}>
225
+ {#if pageMeta.promoDescriptionNoTranslate}&#10003;{/if}
226
+ </span>
227
+ <span class="setup__check-label">Don't translate description</span>
228
+ </button>
229
+
230
+ <div class="setup__field">
231
+ <span class="setup__label">Promotion image</span>
232
+ {#if pageMeta.promoImage}
233
+ <div class="promo-image">
234
+ <img src={pageMeta.promoImage} alt="Promotion" />
235
+ <button
236
+ type="button"
237
+ class="promo-image__remove"
238
+ title="Remove"
239
+ onclick={() => (pageMeta.promoImage = '')}
240
+ >
241
+ &#10005;
242
+ </button>
243
+ </div>
244
+ {:else}
245
+ <label class="promo-upload">
246
+ <span class="promo-upload__text">Click to upload</span>
247
+ <span class="promo-upload__hint">PNG, JPG, SVG</span>
248
+ <input
249
+ type="file"
250
+ accept="image/*"
251
+ hidden
252
+ onchange={(e) => readPromoImage(e.currentTarget)}
253
+ />
254
+ </label>
255
+ {/if}
256
+ </div>
257
+ {/if}
258
+ </div>
259
+
260
+ <div class="setup__section">
261
+ <span class="setup__legend">Page settings</span>
262
+ <div class="setup__field">
263
+ <label class="setup__label" for="setup-seo">SEO title</label>
264
+ <input
265
+ id="setup-seo"
266
+ class="setup__input"
267
+ bind:value={pageMeta.seoTitle}
268
+ placeholder="UEFA Champions League — Freebet"
269
+ maxlength="160"
270
+ />
271
+ </div>
272
+ <div class="setup__field">
273
+ <label class="setup__label" for="setup-slug">URL slug</label>
274
+ <input
275
+ id="setup-slug"
276
+ class="setup__input setup__input--mono"
277
+ value={pageMeta.slug}
278
+ oninput={(e) => setSlug(e.currentTarget.value)}
279
+ placeholder="/ucl-freebet"
280
+ />
281
+ </div>
282
+ </div>
283
+ </div>
284
+ {/if}
285
+ </aside>
286
+
287
+ <style>
288
+ .rail {
289
+ width: var(--sidebar-width);
290
+ flex-shrink: 0;
291
+ display: flex;
292
+ flex-direction: column;
293
+ background: var(--bg-surface);
294
+ border-right: 1px solid var(--border);
295
+ height: 100%;
296
+ overflow: hidden;
297
+ }
298
+
299
+ .rail__tabs {
300
+ flex: none;
301
+ display: flex;
302
+ gap: 2px;
303
+ padding: 10px 10px 0;
304
+ border-bottom: 1px solid var(--border);
305
+ }
306
+
307
+ .rail__tab {
308
+ flex: 1;
309
+ height: 34px;
310
+ border: none;
311
+ background: transparent;
312
+ border-radius: 8px 8px 0 0;
313
+ cursor: pointer;
314
+ font: inherit;
315
+ font-size: 12.5px;
316
+ font-weight: 600;
317
+ color: var(--text-secondary);
318
+ box-shadow: inset 0 -2px 0 transparent;
319
+ transition: color var(--transition), box-shadow var(--transition);
320
+ }
321
+
322
+ .rail__tab:hover {
323
+ color: var(--text-primary);
324
+ }
325
+
326
+ .rail__tab--active {
327
+ color: var(--accent);
328
+ box-shadow: inset 0 -2px 0 var(--accent);
329
+ }
330
+
331
+ .layers {
332
+ flex: 1;
333
+ display: flex;
334
+ flex-direction: column;
335
+ min-height: 0;
336
+ }
337
+
338
+ .palette {
339
+ flex: none;
340
+ padding: 10px 10px 4px;
341
+ }
342
+
343
+ .palette__label {
344
+ font-size: 10px;
345
+ font-weight: 600;
346
+ letter-spacing: 0.12em;
347
+ text-transform: uppercase;
348
+ color: var(--text-muted);
349
+ padding: 2px 4px 8px;
350
+ }
351
+
352
+ .elements-list {
353
+ display: flex;
354
+ flex-direction: column;
355
+ gap: 4px;
356
+ }
357
+
358
+ .element-btn {
359
+ display: flex;
360
+ align-items: center;
361
+ gap: 10px;
362
+ width: 100%;
363
+ padding: 9px 12px;
364
+ background: transparent;
365
+ border: 1px solid transparent;
366
+ border-radius: var(--radius-md);
367
+ cursor: pointer;
368
+ color: var(--text-secondary);
369
+ font: inherit;
370
+ font-size: 0.85rem;
371
+ font-weight: 500;
372
+ text-align: left;
373
+ transition: background var(--transition), border-color var(--transition), color var(--transition);
374
+ }
375
+
376
+ .element-btn:hover {
377
+ background: var(--accent-subtle);
378
+ border-color: var(--accent);
379
+ color: var(--text-primary);
380
+ }
381
+
382
+ .element-btn:hover .element-add {
383
+ opacity: 1;
384
+ color: var(--accent-hover);
385
+ }
386
+
387
+ .element-icon {
388
+ font-size: 0.55rem;
389
+ color: var(--accent);
390
+ opacity: 0.7;
391
+ flex-shrink: 0;
392
+ }
393
+
394
+ .element-name {
395
+ flex: 1;
396
+ }
397
+
398
+ .element-add {
399
+ font-size: 1rem;
400
+ font-weight: 300;
401
+ color: var(--text-muted);
402
+ opacity: 0;
403
+ transition: opacity var(--transition);
404
+ }
405
+
406
+ .layers__section {
407
+ flex: none;
408
+ display: flex;
409
+ align-items: center;
410
+ justify-content: space-between;
411
+ padding: 6px 14px;
412
+ }
413
+
414
+ .layers__section-title {
415
+ font-size: 10px;
416
+ font-weight: 600;
417
+ letter-spacing: 0.12em;
418
+ text-transform: uppercase;
419
+ color: var(--text-muted);
420
+ }
421
+
422
+ .layers__count {
423
+ font-size: 11px;
424
+ color: var(--text-muted);
425
+ }
426
+
427
+ .layers__list {
428
+ flex: 1;
429
+ overflow-y: auto;
430
+ padding: 0 8px 12px;
431
+ }
432
+
433
+ .layer {
434
+ display: flex;
435
+ align-items: center;
436
+ gap: 8px;
437
+ width: 100%;
438
+ height: 44px;
439
+ padding: 0 8px;
440
+ margin-bottom: 2px;
441
+ border: none;
442
+ border-radius: 9px;
443
+ cursor: pointer;
444
+ background: transparent;
445
+ text-align: left;
446
+ box-shadow: inset 0 0 0 1px transparent;
447
+ transition: background-color var(--transition), box-shadow var(--transition);
448
+ }
449
+
450
+ .layer:hover {
451
+ background: var(--bg-elevated);
452
+ }
453
+
454
+ .layer--active {
455
+ background: var(--accent-subtle);
456
+ box-shadow: inset 0 0 0 1.5px var(--accent);
457
+ }
458
+
459
+ .layer--active .layer__icon {
460
+ background: var(--accent);
461
+ color: #fff;
462
+ }
463
+
464
+ .layer--active .layer__name {
465
+ color: var(--accent);
466
+ }
467
+
468
+ .layer__reorder {
469
+ display: flex;
470
+ flex-direction: column;
471
+ flex: none;
472
+ gap: 1px;
473
+ }
474
+
475
+ .layer__move {
476
+ width: 16px;
477
+ height: 15px;
478
+ display: flex;
479
+ align-items: center;
480
+ justify-content: center;
481
+ font-size: 9px;
482
+ color: var(--text-muted);
483
+ border-radius: 3px;
484
+ cursor: pointer;
485
+ }
486
+
487
+ .layer__move:hover {
488
+ background: var(--bg-hover);
489
+ color: var(--text-primary);
490
+ }
491
+
492
+ .layer__move--disabled {
493
+ opacity: 0.3;
494
+ pointer-events: none;
495
+ }
496
+
497
+ .layer__icon {
498
+ width: 26px;
499
+ height: 26px;
500
+ flex: none;
501
+ border-radius: 7px;
502
+ display: flex;
503
+ align-items: center;
504
+ justify-content: center;
505
+ background: var(--bg-hover);
506
+ color: var(--text-secondary);
507
+ font-weight: 700;
508
+ font-size: 12px;
509
+ }
510
+
511
+ .layer__text {
512
+ flex: 1;
513
+ min-width: 0;
514
+ }
515
+
516
+ .layer__name {
517
+ display: block;
518
+ font-size: 12.5px;
519
+ font-weight: 500;
520
+ color: var(--text-primary);
521
+ white-space: nowrap;
522
+ overflow: hidden;
523
+ text-overflow: ellipsis;
524
+ }
525
+
526
+ .layer__type {
527
+ display: block;
528
+ font-size: 10px;
529
+ font-weight: 600;
530
+ letter-spacing: 0.08em;
531
+ text-transform: uppercase;
532
+ color: var(--text-muted);
533
+ }
534
+
535
+ .layer__remove {
536
+ width: 24px;
537
+ height: 24px;
538
+ flex: none;
539
+ display: none;
540
+ align-items: center;
541
+ justify-content: center;
542
+ border-radius: 6px;
543
+ color: var(--text-muted);
544
+ font-size: 11px;
545
+ }
546
+
547
+ .layer:hover .layer__remove {
548
+ display: flex;
549
+ }
550
+
551
+ .layer__remove:hover {
552
+ background: var(--danger-subtle);
553
+ color: var(--danger);
554
+ }
555
+
556
+ .layers__empty {
557
+ padding: 24px 14px;
558
+ text-align: center;
559
+ font-size: 12px;
560
+ color: var(--text-muted);
561
+ }
562
+
563
+ .setup {
564
+ flex: 1;
565
+ overflow-y: auto;
566
+ min-height: 0;
567
+ }
568
+
569
+ .setup__section {
570
+ padding: 14px;
571
+ border-bottom: 1px solid var(--border-light);
572
+ display: flex;
573
+ flex-direction: column;
574
+ gap: 11px;
575
+ }
576
+
577
+ .setup__legend {
578
+ font-size: 10px;
579
+ font-weight: 600;
580
+ letter-spacing: 0.12em;
581
+ text-transform: uppercase;
582
+ color: var(--text-muted);
583
+ }
584
+
585
+ .setup__check {
586
+ display: flex;
587
+ align-items: center;
588
+ gap: 11px;
589
+ border: none;
590
+ background: transparent;
591
+ padding: 0;
592
+ cursor: pointer;
593
+ text-align: left;
594
+ }
595
+
596
+ .setup__box {
597
+ width: 20px;
598
+ height: 20px;
599
+ flex: none;
600
+ border-radius: 6px;
601
+ display: flex;
602
+ align-items: center;
603
+ justify-content: center;
604
+ background: var(--bg-surface);
605
+ color: #fbf8f3;
606
+ font-size: 12px;
607
+ box-shadow: inset 0 0 0 1.5px var(--border);
608
+ transition: background-color 0.12s ease, box-shadow 0.12s ease;
609
+ }
610
+
611
+ .setup__box--on {
612
+ background: var(--accent);
613
+ box-shadow: inset 0 0 0 1.5px var(--accent);
614
+ }
615
+
616
+ .setup__check-label {
617
+ font-size: 12.5px;
618
+ font-weight: 600;
619
+ color: var(--text-primary);
620
+ }
621
+
622
+ .setup__field {
623
+ display: flex;
624
+ flex-direction: column;
625
+ gap: 6px;
626
+ }
627
+
628
+ .setup__label {
629
+ font-size: 10px;
630
+ font-weight: 600;
631
+ letter-spacing: 0.1em;
632
+ text-transform: uppercase;
633
+ color: var(--text-muted);
634
+ }
635
+
636
+ .setup__input {
637
+ width: 100%;
638
+ height: 38px;
639
+ padding: 0 11px;
640
+ font: inherit;
641
+ font-size: 12.5px;
642
+ color: var(--text-primary);
643
+ background: var(--bg-elevated);
644
+ border: 1px solid var(--border-light);
645
+ border-radius: var(--radius-md);
646
+ outline: none;
647
+ transition: border-color var(--transition);
648
+ }
649
+
650
+ .setup__input:focus {
651
+ border-color: var(--accent);
652
+ }
653
+
654
+ .setup__input--mono {
655
+ font-family: var(--font-mono);
656
+ font-size: 12px;
657
+ }
658
+
659
+ .setup__input--area {
660
+ height: auto;
661
+ min-height: 64px;
662
+ padding: 9px 11px;
663
+ line-height: 1.5;
664
+ resize: vertical;
665
+ }
666
+
667
+ .setup__check--sub {
668
+ margin-top: -4px;
669
+ margin-left: 2px;
670
+ }
671
+
672
+ .setup__check--sub .setup__box {
673
+ width: 18px;
674
+ height: 18px;
675
+ }
676
+
677
+ .setup__check--sub .setup__check-label {
678
+ font-size: 12px;
679
+ font-weight: 500;
680
+ color: var(--text-secondary);
681
+ }
682
+
683
+ .promo-upload {
684
+ display: flex;
685
+ flex-direction: column;
686
+ align-items: center;
687
+ justify-content: center;
688
+ gap: 2px;
689
+ height: 84px;
690
+ border: 1.5px dashed var(--border);
691
+ border-radius: var(--radius-md);
692
+ background: var(--bg-elevated);
693
+ cursor: pointer;
694
+ transition: border-color var(--transition);
695
+ }
696
+
697
+ .promo-upload:hover {
698
+ border-color: var(--accent);
699
+ }
700
+
701
+ .promo-upload__text {
702
+ font-size: 12.5px;
703
+ font-weight: 600;
704
+ color: var(--text-secondary);
705
+ }
706
+
707
+ .promo-upload__hint {
708
+ font-size: 10.5px;
709
+ color: var(--text-muted);
710
+ }
711
+
712
+ .promo-image {
713
+ position: relative;
714
+ border-radius: var(--radius-md);
715
+ overflow: hidden;
716
+ border: 1px solid var(--border-light);
717
+ }
718
+
719
+ .promo-image img {
720
+ display: block;
721
+ width: 100%;
722
+ }
723
+
724
+ .promo-image__remove {
725
+ position: absolute;
726
+ top: 6px;
727
+ right: 6px;
728
+ width: 24px;
729
+ height: 24px;
730
+ display: flex;
731
+ align-items: center;
732
+ justify-content: center;
733
+ border: none;
734
+ border-radius: 6px;
735
+ background: rgba(31, 29, 24, 0.6);
736
+ color: #fff;
737
+ cursor: pointer;
738
+ font-size: 12px;
739
+ }
740
+ </style>