astro-tractstack 2.0.0-rc.62 → 2.0.0-rc.63
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
CHANGED
|
@@ -481,23 +481,41 @@ function processStoryfragmentUpdate(update) {
|
|
|
481
481
|
log(`📊 Refresh summary: ${refreshedCount} successful, ${errorCount} failed`);
|
|
482
482
|
|
|
483
483
|
if (update.gotoPaneId) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
484
|
+
// Wait a brief moment for the DOM to update and the element to become visible.
|
|
485
|
+
setTimeout(() => {
|
|
486
|
+
const targetElement = document.getElementById(
|
|
487
|
+
`pane-${update.gotoPaneId}`
|
|
488
|
+
);
|
|
489
|
+
if (targetElement) {
|
|
490
|
+
log(`🔍 Smart scrolling to target pane: ${update.gotoPaneId}`);
|
|
491
|
+
try {
|
|
492
|
+
const elementRect = targetElement.getBoundingClientRect();
|
|
493
|
+
const viewportHeight = window.innerHeight;
|
|
494
|
+
|
|
495
|
+
// If the element is taller than the viewport, just scroll to the top of it.
|
|
496
|
+
if (elementRect.height > viewportHeight) {
|
|
497
|
+
targetElement.scrollIntoView({
|
|
498
|
+
behavior: 'smooth',
|
|
499
|
+
block: 'start',
|
|
500
|
+
});
|
|
501
|
+
log('✅ Scroll completed (long element - align to top).');
|
|
502
|
+
} else {
|
|
503
|
+
// Otherwise, center it in the viewport.
|
|
504
|
+
targetElement.scrollIntoView({
|
|
505
|
+
behavior: 'smooth',
|
|
506
|
+
block: 'center',
|
|
507
|
+
});
|
|
508
|
+
log('✅ Scroll completed (short element - align to center).');
|
|
509
|
+
}
|
|
510
|
+
} catch (error) {
|
|
511
|
+
log('❌ Smart scroll failed:', error);
|
|
512
|
+
}
|
|
513
|
+
} else {
|
|
514
|
+
log(
|
|
515
|
+
`⚠️ Target pane element not found after delay: pane-${update.gotoPaneId}`
|
|
516
|
+
);
|
|
492
517
|
}
|
|
493
|
-
}
|
|
494
|
-
log(`⚠️ Target pane element not found: pane-${update.gotoPaneId}`, {
|
|
495
|
-
expectedId: `pane-${update.gotoPaneId}`,
|
|
496
|
-
availablePaneElements: Array.from(
|
|
497
|
-
document.querySelectorAll('[id^="pane-"]')
|
|
498
|
-
).map((el) => el.id),
|
|
499
|
-
});
|
|
500
|
-
}
|
|
518
|
+
}, 100);
|
|
501
519
|
}
|
|
502
520
|
|
|
503
521
|
log('🔄 === UPDATE PROCESSING COMPLETE ===');
|
|
@@ -18,22 +18,30 @@ import ArrowUturnLeftIcon from '@heroicons/react/24/outline/ArrowUturnLeftIcon';
|
|
|
18
18
|
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
|
19
19
|
import CheckIcon from '@heroicons/react/24/outline/CheckIcon';
|
|
20
20
|
import ChevronUpDownIcon from '@heroicons/react/24/outline/ChevronUpDownIcon';
|
|
21
|
+
import PlusIcon from '@heroicons/react/24/outline/PlusIcon';
|
|
22
|
+
import ArrowUpIcon from '@heroicons/react/24/outline/ArrowUpIcon';
|
|
23
|
+
import ArrowDownIcon from '@heroicons/react/24/outline/ArrowDownIcon';
|
|
21
24
|
|
|
22
25
|
interface DisclosureItem {
|
|
23
26
|
id: string;
|
|
24
27
|
beliefValue: string;
|
|
28
|
+
isCustom: boolean;
|
|
25
29
|
title: string;
|
|
26
30
|
description?: string;
|
|
27
31
|
icon: string;
|
|
28
32
|
actionLisp: string;
|
|
29
33
|
isDisabled?: boolean;
|
|
30
34
|
}
|
|
35
|
+
|
|
31
36
|
interface WidgetStyles {
|
|
32
37
|
textColor: string;
|
|
33
38
|
bgColor: string;
|
|
34
39
|
bgOpacity: number;
|
|
35
40
|
}
|
|
36
|
-
type StoredDisclosureItem = Omit<
|
|
41
|
+
type StoredDisclosureItem = Omit<
|
|
42
|
+
DisclosureItem,
|
|
43
|
+
'id' | 'isDisabled' | 'isCustom'
|
|
44
|
+
>;
|
|
37
45
|
interface InteractiveDisclosureWidgetProps {
|
|
38
46
|
node: FlatNode;
|
|
39
47
|
onUpdate: (params: string[]) => void;
|
|
@@ -61,12 +69,7 @@ const IconSelector = ({
|
|
|
61
69
|
() => createListCollection({ items: filteredIcons }),
|
|
62
70
|
[filteredIcons]
|
|
63
71
|
);
|
|
64
|
-
|
|
65
|
-
const iconSelectorStyles = `
|
|
66
|
-
.icon-item .icon-indicator { display: none; }
|
|
67
|
-
.icon-item[data-state="checked"] .icon-indicator { display: flex; }
|
|
68
|
-
`;
|
|
69
|
-
|
|
72
|
+
const iconSelectorStyles = `.icon-item .icon-indicator { display: none; } .icon-item[data-state="checked"] .icon-indicator { display: flex; }`;
|
|
70
73
|
return (
|
|
71
74
|
<div>
|
|
72
75
|
<style>{iconSelectorStyles}</style>
|
|
@@ -88,8 +91,8 @@ const IconSelector = ({
|
|
|
88
91
|
</Combobox.Trigger>
|
|
89
92
|
</Combobox.Control>
|
|
90
93
|
<Portal>
|
|
91
|
-
<Combobox.Positioner style={{ zIndex: 9010 }}>
|
|
92
|
-
<Combobox.Content className="max-h-60 w-
|
|
94
|
+
<Combobox.Positioner style={{ zIndex: 9010, minWidth: '250px' }}>
|
|
95
|
+
<Combobox.Content className="max-h-60 w-full overflow-y-auto rounded-md bg-white shadow-lg">
|
|
93
96
|
{filteredIcons.map((icon) => (
|
|
94
97
|
<Combobox.Item
|
|
95
98
|
key={icon}
|
|
@@ -117,23 +120,51 @@ const DisclosureItemEditor = ({
|
|
|
117
120
|
onUpdate,
|
|
118
121
|
onToggle,
|
|
119
122
|
config,
|
|
123
|
+
onMoveUp,
|
|
124
|
+
onMoveDown,
|
|
125
|
+
isFirst,
|
|
126
|
+
isLast,
|
|
120
127
|
}: {
|
|
121
128
|
item: DisclosureItem;
|
|
122
129
|
onUpdate: (updates: Partial<DisclosureItem>) => void;
|
|
123
130
|
onToggle: () => void;
|
|
124
131
|
config: BrandConfig;
|
|
132
|
+
onMoveUp: () => void;
|
|
133
|
+
onMoveDown: () => void;
|
|
134
|
+
isFirst: boolean;
|
|
135
|
+
isLast: boolean;
|
|
125
136
|
}) => {
|
|
126
137
|
return (
|
|
127
138
|
<div
|
|
128
139
|
className={`space-y-4 rounded-lg border bg-white p-4 shadow-sm transition-opacity ${item.isDisabled ? 'border-gray-100 opacity-40' : 'border-gray-200'}`}
|
|
129
140
|
>
|
|
130
141
|
<div className="flex items-center justify-between">
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
<div className="flex items-center gap-2">
|
|
143
|
+
<div className="flex flex-col">
|
|
144
|
+
<button
|
|
145
|
+
type="button"
|
|
146
|
+
onClick={onMoveUp}
|
|
147
|
+
disabled={isFirst}
|
|
148
|
+
className="rounded p-0.5 text-gray-500 hover:bg-gray-100 disabled:opacity-25"
|
|
149
|
+
>
|
|
150
|
+
<ArrowUpIcon className="h-4 w-4" />
|
|
151
|
+
</button>
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
onClick={onMoveDown}
|
|
155
|
+
disabled={isLast}
|
|
156
|
+
className="rounded p-0.5 text-gray-500 hover:bg-gray-100 disabled:opacity-25"
|
|
157
|
+
>
|
|
158
|
+
<ArrowDownIcon className="h-4 w-4" />
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
<h4 className="font-bold text-gray-800">
|
|
162
|
+
{item.title}{' '}
|
|
163
|
+
<span className="text-xs font-normal text-gray-500">
|
|
164
|
+
(Key: {item.beliefValue})
|
|
165
|
+
</span>
|
|
166
|
+
</h4>
|
|
167
|
+
</div>
|
|
137
168
|
<button
|
|
138
169
|
type="button"
|
|
139
170
|
onClick={onToggle}
|
|
@@ -147,6 +178,13 @@ const DisclosureItemEditor = ({
|
|
|
147
178
|
</button>
|
|
148
179
|
</div>
|
|
149
180
|
<fieldset disabled={item.isDisabled} className="space-y-4">
|
|
181
|
+
{item.isCustom && (
|
|
182
|
+
<SingleParam
|
|
183
|
+
label="Key / Value"
|
|
184
|
+
value={item.beliefValue}
|
|
185
|
+
onChange={(value) => onUpdate({ beliefValue: value })}
|
|
186
|
+
/>
|
|
187
|
+
)}
|
|
150
188
|
<SingleParam
|
|
151
189
|
label="Display Title"
|
|
152
190
|
value={item.title}
|
|
@@ -161,13 +199,25 @@ const DisclosureItemEditor = ({
|
|
|
161
199
|
value={item.icon}
|
|
162
200
|
onChange={(value) => onUpdate({ icon: value })}
|
|
163
201
|
/>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
202
|
+
|
|
203
|
+
{item.isCustom ? (
|
|
204
|
+
<div className="relative rounded-md border p-3">
|
|
205
|
+
<ActionBuilderField
|
|
206
|
+
value={item.actionLisp}
|
|
207
|
+
onChange={(value) => onUpdate({ actionLisp: value })}
|
|
208
|
+
contentMap={fullContentMapStore.get()}
|
|
209
|
+
/>
|
|
210
|
+
</div>
|
|
211
|
+
) : (
|
|
212
|
+
<div>
|
|
213
|
+
<label className="block text-xs font-bold text-gray-600">
|
|
214
|
+
Action (Locked)
|
|
215
|
+
</label>
|
|
216
|
+
<div className="mt-1 rounded-md border border-gray-200 bg-gray-50 p-2 font-mono text-xs text-gray-500">
|
|
217
|
+
{item.actionLisp}
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
)}
|
|
171
221
|
</fieldset>
|
|
172
222
|
</div>
|
|
173
223
|
);
|
|
@@ -187,6 +237,7 @@ export default function InteractiveDisclosureWidget({
|
|
|
187
237
|
bgOpacity: 100,
|
|
188
238
|
});
|
|
189
239
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
240
|
+
const [isDataLoaded, setIsDataLoaded] = useState(false);
|
|
190
241
|
|
|
191
242
|
const selectedBelief = beliefs.find((b) => b.slug === selectedBeliefTag);
|
|
192
243
|
const hasRealSelection = !!selectedBelief;
|
|
@@ -194,8 +245,12 @@ export default function InteractiveDisclosureWidget({
|
|
|
194
245
|
useEffect(() => {
|
|
195
246
|
const beliefTag = String(node.codeHookParams?.[0] || '');
|
|
196
247
|
const payloadJson = String(node.codeHookParams?.[1] || '');
|
|
197
|
-
setSelectedBeliefTag(beliefTag && beliefTag !== 'BELIEF' ? beliefTag : '');
|
|
198
248
|
|
|
249
|
+
if (beliefs.length === 0 && beliefTag && beliefTag !== 'BELIEF') {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
setSelectedBeliefTag(beliefTag && beliefTag !== 'BELIEF' ? beliefTag : '');
|
|
199
254
|
const currentBelief = beliefs.find((b) => b.slug === beliefTag);
|
|
200
255
|
|
|
201
256
|
if (payloadJson && currentBelief) {
|
|
@@ -204,9 +259,10 @@ export default function InteractiveDisclosureWidget({
|
|
|
204
259
|
setWidgetStyles(
|
|
205
260
|
parsed.styles || { textColor: '', bgColor: '', bgOpacity: 100 }
|
|
206
261
|
);
|
|
207
|
-
const loadedDisclosures =
|
|
262
|
+
const loadedDisclosures =
|
|
263
|
+
(parsed.disclosures as StoredDisclosureItem[]) || [];
|
|
208
264
|
|
|
209
|
-
const
|
|
265
|
+
const scaleKeys =
|
|
210
266
|
currentBelief.scale === 'custom'
|
|
211
267
|
? (currentBelief.customValues || []).map((v) => ({
|
|
212
268
|
slug: v,
|
|
@@ -216,34 +272,50 @@ export default function InteractiveDisclosureWidget({
|
|
|
216
272
|
currentBelief.scale as keyof typeof heldBeliefsScales
|
|
217
273
|
] || [];
|
|
218
274
|
|
|
219
|
-
const
|
|
220
|
-
|
|
275
|
+
const actionCommand =
|
|
276
|
+
currentBelief.scale === 'custom' ? 'identifyAs' : 'declare';
|
|
277
|
+
|
|
278
|
+
const finalDisclosures: DisclosureItem[] = loadedDisclosures.map(
|
|
279
|
+
(loadedItem) => {
|
|
280
|
+
const isFromScale = scaleKeys.some(
|
|
281
|
+
(sk) => sk.slug === loadedItem.beliefValue
|
|
282
|
+
);
|
|
221
283
|
return {
|
|
222
|
-
...
|
|
284
|
+
...loadedItem,
|
|
223
285
|
id: generateId(),
|
|
224
|
-
|
|
286
|
+
isCustom: !isFromScale,
|
|
287
|
+
actionLisp: isFromScale
|
|
288
|
+
? `(${actionCommand} ${beliefTag} ${loadedItem.beliefValue})`
|
|
289
|
+
: loadedItem.actionLisp,
|
|
225
290
|
isDisabled: false,
|
|
226
291
|
};
|
|
227
292
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
scaleKeys.forEach(({ slug, name }) => {
|
|
296
|
+
if (!finalDisclosures.some((d) => d.beliefValue === slug)) {
|
|
297
|
+
finalDisclosures.push({
|
|
298
|
+
id: generateId(),
|
|
299
|
+
beliefValue: slug,
|
|
300
|
+
title: name,
|
|
301
|
+
description: '',
|
|
302
|
+
icon: 'app',
|
|
303
|
+
actionLisp: `(${actionCommand} ${beliefTag} ${slug})`,
|
|
304
|
+
isCustom: false,
|
|
305
|
+
isDisabled: true,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
237
308
|
});
|
|
238
|
-
|
|
309
|
+
|
|
310
|
+
setDisclosures(finalDisclosures);
|
|
239
311
|
} catch (e) {
|
|
240
|
-
|
|
241
|
-
setWidgetStyles({ textColor: '', bgColor: '', bgOpacity: 100 });
|
|
312
|
+
console.error('Error parsing disclosure payload:', e);
|
|
242
313
|
}
|
|
243
314
|
} else {
|
|
244
315
|
setDisclosures([]);
|
|
245
316
|
setWidgetStyles({ textColor: '', bgColor: '', bgOpacity: 100 });
|
|
246
317
|
}
|
|
318
|
+
setIsDataLoaded(true);
|
|
247
319
|
}, [node, beliefs]);
|
|
248
320
|
|
|
249
321
|
useEffect(() => {
|
|
@@ -253,30 +325,27 @@ export default function InteractiveDisclosureWidget({
|
|
|
253
325
|
const {
|
|
254
326
|
data: { beliefIds },
|
|
255
327
|
} = await api.get('/api/v1/nodes/beliefs');
|
|
256
|
-
if (!beliefIds?.length)
|
|
328
|
+
if (!beliefIds?.length) {
|
|
329
|
+
setBeliefs([]);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
257
332
|
const {
|
|
258
333
|
data: { beliefs },
|
|
259
334
|
} = await api.post('/api/v1/nodes/beliefs', { beliefIds });
|
|
260
335
|
setBeliefs(beliefs || []);
|
|
261
336
|
} catch (error) {
|
|
262
337
|
console.error('Error fetching beliefs:', error);
|
|
338
|
+
setBeliefs([]);
|
|
263
339
|
}
|
|
264
340
|
};
|
|
265
341
|
fetchData();
|
|
266
|
-
}, []);
|
|
342
|
+
}, [node]);
|
|
267
343
|
|
|
268
344
|
const handleUpdate = () => {
|
|
269
|
-
const disclosuresToStore:
|
|
270
|
-
string,
|
|
271
|
-
Omit<StoredDisclosureItem, 'beliefValue'>
|
|
272
|
-
> = {};
|
|
273
|
-
disclosures
|
|
345
|
+
const disclosuresToStore: StoredDisclosureItem[] = disclosures
|
|
274
346
|
.filter((d) => !d.isDisabled)
|
|
275
|
-
.
|
|
276
|
-
|
|
277
|
-
disclosuresToStore[beliefValue] = rest;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
347
|
+
.map(({ id, isCustom, isDisabled, ...rest }) => rest);
|
|
348
|
+
|
|
280
349
|
const payload = { styles: widgetStyles, disclosures: disclosuresToStore };
|
|
281
350
|
onUpdate([selectedBeliefTag, JSON.stringify(payload)]);
|
|
282
351
|
};
|
|
@@ -286,24 +355,54 @@ export default function InteractiveDisclosureWidget({
|
|
|
286
355
|
const belief = beliefs.find((b) => b.slug === tag);
|
|
287
356
|
let newDisclosures: DisclosureItem[] = [];
|
|
288
357
|
if (belief) {
|
|
358
|
+
const actionCommand =
|
|
359
|
+
belief.scale === 'custom' ? 'identifyAs' : 'declare';
|
|
289
360
|
const keys =
|
|
290
361
|
belief.scale === 'custom'
|
|
291
362
|
? (belief.customValues || []).map((v) => ({ slug: v, name: v }))
|
|
292
363
|
: heldBeliefsScales[belief.scale as keyof typeof heldBeliefsScales] ||
|
|
293
364
|
[];
|
|
365
|
+
|
|
294
366
|
newDisclosures = keys.map(({ slug, name }) => ({
|
|
295
367
|
id: generateId(),
|
|
296
368
|
beliefValue: slug,
|
|
297
369
|
title: name,
|
|
298
370
|
description: '',
|
|
299
371
|
icon: 'app',
|
|
300
|
-
actionLisp:
|
|
372
|
+
actionLisp: `(${actionCommand} ${tag} ${slug})`,
|
|
373
|
+
isCustom: false,
|
|
301
374
|
isDisabled: false,
|
|
302
375
|
}));
|
|
303
376
|
}
|
|
304
377
|
setDisclosures(newDisclosures);
|
|
305
378
|
};
|
|
306
379
|
|
|
380
|
+
const moveDisclosure = (id: string, direction: 'up' | 'down') => {
|
|
381
|
+
const index = disclosures.findIndex((d) => d.id === id);
|
|
382
|
+
if (index === -1) return;
|
|
383
|
+
const newIndex = direction === 'up' ? index - 1 : index + 1;
|
|
384
|
+
if (newIndex < 0 || newIndex >= disclosures.length) return;
|
|
385
|
+
|
|
386
|
+
const newDisclosures = [...disclosures];
|
|
387
|
+
const [movedItem] = newDisclosures.splice(index, 1);
|
|
388
|
+
newDisclosures.splice(newIndex, 0, movedItem);
|
|
389
|
+
setDisclosures(newDisclosures);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const addCustomDisclosure = () => {
|
|
393
|
+
const newItem: DisclosureItem = {
|
|
394
|
+
id: generateId(),
|
|
395
|
+
beliefValue: `custom-key-${disclosures.length + 1}`,
|
|
396
|
+
title: 'New Custom Item',
|
|
397
|
+
description: '',
|
|
398
|
+
icon: 'plus-circle',
|
|
399
|
+
actionLisp: '',
|
|
400
|
+
isCustom: true,
|
|
401
|
+
isDisabled: false,
|
|
402
|
+
};
|
|
403
|
+
setDisclosures([...disclosures, newItem]);
|
|
404
|
+
};
|
|
405
|
+
|
|
307
406
|
const updateDisclosure = (id: string, updates: Partial<DisclosureItem>) =>
|
|
308
407
|
setDisclosures(
|
|
309
408
|
disclosures.map((d) => (d.id === id ? { ...d, ...updates } : d))
|
|
@@ -317,6 +416,13 @@ export default function InteractiveDisclosureWidget({
|
|
|
317
416
|
)
|
|
318
417
|
);
|
|
319
418
|
|
|
419
|
+
const handleColorChange = (
|
|
420
|
+
key: 'textColor' | 'bgColor',
|
|
421
|
+
hex: string | null
|
|
422
|
+
) => {
|
|
423
|
+
updateWidgetStyles({ [key]: hex || '' });
|
|
424
|
+
};
|
|
425
|
+
|
|
320
426
|
return (
|
|
321
427
|
<div className="space-y-4">
|
|
322
428
|
<div className="flex items-center gap-2">
|
|
@@ -347,7 +453,6 @@ export default function InteractiveDisclosureWidget({
|
|
|
347
453
|
</button>
|
|
348
454
|
)}
|
|
349
455
|
</div>
|
|
350
|
-
|
|
351
456
|
{hasRealSelection && (
|
|
352
457
|
<div className="mt-4 border-t border-gray-200 pt-4">
|
|
353
458
|
<button
|
|
@@ -393,64 +498,94 @@ export default function InteractiveDisclosureWidget({
|
|
|
393
498
|
</Dialog.Title>
|
|
394
499
|
</div>
|
|
395
500
|
<div className="flex-1 space-y-6 overflow-y-auto p-4">
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
501
|
+
{isDataLoaded ? (
|
|
502
|
+
<>
|
|
503
|
+
<div className="space-y-4 rounded-lg border border-gray-200 bg-white p-4 shadow-sm">
|
|
504
|
+
<h3 className="font-bold text-gray-800">
|
|
505
|
+
Widget Styles
|
|
506
|
+
</h3>
|
|
507
|
+
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
|
508
|
+
<div>
|
|
509
|
+
<ColorPickerCombo
|
|
510
|
+
title="Background Color"
|
|
511
|
+
defaultColor={widgetStyles.bgColor}
|
|
512
|
+
onColorChange={(hex) =>
|
|
513
|
+
handleColorChange('bgColor', hex)
|
|
514
|
+
}
|
|
515
|
+
config={config}
|
|
516
|
+
allowNull={true}
|
|
517
|
+
skipTailwind={false}
|
|
518
|
+
/>
|
|
519
|
+
</div>
|
|
520
|
+
<div>
|
|
521
|
+
<ColorPickerCombo
|
|
522
|
+
title="Text Color"
|
|
523
|
+
defaultColor={widgetStyles.textColor}
|
|
524
|
+
onColorChange={(hex) =>
|
|
525
|
+
handleColorChange('textColor', hex)
|
|
526
|
+
}
|
|
527
|
+
config={config}
|
|
528
|
+
allowNull={true}
|
|
529
|
+
skipTailwind={false}
|
|
530
|
+
/>
|
|
531
|
+
</div>
|
|
532
|
+
<div>
|
|
533
|
+
<label className="block text-xs font-bold text-gray-600">
|
|
534
|
+
BG Opacity (%)
|
|
535
|
+
</label>
|
|
536
|
+
<div className="mt-1 flex items-center gap-2">
|
|
537
|
+
<input
|
|
538
|
+
type="range"
|
|
539
|
+
min="0"
|
|
540
|
+
max="100"
|
|
541
|
+
value={widgetStyles.bgOpacity}
|
|
542
|
+
onChange={(e) =>
|
|
543
|
+
updateWidgetStyles({
|
|
544
|
+
bgOpacity: parseInt(e.target.value),
|
|
545
|
+
})
|
|
546
|
+
}
|
|
547
|
+
className="w-full"
|
|
548
|
+
/>
|
|
549
|
+
<span className="w-12 text-center font-mono text-sm">
|
|
550
|
+
{widgetStyles.bgOpacity}%
|
|
551
|
+
</span>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
409
555
|
</div>
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
556
|
+
|
|
557
|
+
{disclosures.map((item, index) => (
|
|
558
|
+
<DisclosureItemEditor
|
|
559
|
+
key={item.id}
|
|
560
|
+
item={item}
|
|
561
|
+
onUpdate={(updates) =>
|
|
562
|
+
updateDisclosure(item.id, updates)
|
|
416
563
|
}
|
|
564
|
+
onToggle={() => toggleDisclosure(item.id)}
|
|
417
565
|
config={config}
|
|
418
|
-
|
|
566
|
+
onMoveUp={() => moveDisclosure(item.id, 'up')}
|
|
567
|
+
onMoveDown={() => moveDisclosure(item.id, 'down')}
|
|
568
|
+
isFirst={index === 0}
|
|
569
|
+
isLast={index === disclosures.length - 1}
|
|
419
570
|
/>
|
|
571
|
+
))}
|
|
572
|
+
|
|
573
|
+
<div className="pt-4">
|
|
574
|
+
<button
|
|
575
|
+
type="button"
|
|
576
|
+
onClick={addCustomDisclosure}
|
|
577
|
+
className="flex w-full items-center justify-center rounded-md border-2 border-dashed border-gray-300 bg-white px-3 py-2 text-sm font-bold text-gray-500 hover:border-cyan-600 hover:text-cyan-600"
|
|
578
|
+
>
|
|
579
|
+
<PlusIcon className="mr-2 h-5 w-5" />
|
|
580
|
+
Add Custom Disclosure
|
|
581
|
+
</button>
|
|
420
582
|
</div>
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<div className="mt-1 flex items-center gap-2">
|
|
426
|
-
<input
|
|
427
|
-
type="range"
|
|
428
|
-
min="0"
|
|
429
|
-
max="100"
|
|
430
|
-
value={widgetStyles.bgOpacity}
|
|
431
|
-
onChange={(e) =>
|
|
432
|
-
updateWidgetStyles({
|
|
433
|
-
bgOpacity: parseInt(e.target.value),
|
|
434
|
-
})
|
|
435
|
-
}
|
|
436
|
-
className="w-full"
|
|
437
|
-
/>
|
|
438
|
-
<span className="w-12 text-center font-mono text-sm">
|
|
439
|
-
{widgetStyles.bgOpacity}%
|
|
440
|
-
</span>
|
|
441
|
-
</div>
|
|
442
|
-
</div>
|
|
583
|
+
</>
|
|
584
|
+
) : (
|
|
585
|
+
<div className="p-8 text-center">
|
|
586
|
+
Loading configuration...
|
|
443
587
|
</div>
|
|
444
|
-
|
|
445
|
-
{disclosures.map((item) => (
|
|
446
|
-
<DisclosureItemEditor
|
|
447
|
-
key={item.id}
|
|
448
|
-
item={item}
|
|
449
|
-
onUpdate={(updates) => updateDisclosure(item.id, updates)}
|
|
450
|
-
onToggle={() => toggleDisclosure(item.id)}
|
|
451
|
-
config={config}
|
|
452
|
-
/>
|
|
453
|
-
))}
|
|
588
|
+
)}
|
|
454
589
|
</div>
|
|
455
590
|
<div className="flex-shrink-0 justify-end border-t border-gray-200 bg-white px-6 py-3">
|
|
456
591
|
<Dialog.CloseTrigger asChild>
|