@widgetic/creator 0.3.54 → 0.3.56
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 +1509 -999
- package/dist/components/EditableName.svelte +149 -36
- package/dist/components/EditableName.svelte.d.ts +0 -1
- package/dist/components/HoverTooltip.svelte +60 -0
- package/dist/components/HoverTooltip.svelte.d.ts +31 -0
- package/dist/components/WidgetDetails.svelte +512 -228
- package/dist/components/WidgetDetails.svelte.d.ts +12 -1
- package/dist/creator-types.d.ts +2 -1
- package/dist/pageHelpers.d.ts +2 -0
- package/dist/pageHelpers.js +40 -6
- package/dist/stores/userSession.d.ts +1 -1
- package/dist/stores/userSession.js +19 -4
- package/dist/stores/websocketStore.js +2 -1
- package/dist/syncSiteAuth.js +1 -1
- package/dist/utils/embedCode.d.ts +3 -27
- package/dist/utils/embedCode.js +5 -34
- package/dist/utils/nativeScrollbarPadding.d.ts +5 -0
- package/dist/utils/nativeScrollbarPadding.js +27 -0
- package/dist/utils/persistWidgetThumbnail.d.ts +5 -0
- package/dist/utils/persistWidgetThumbnail.js +28 -0
- package/dist/utils/widgeticChatUpload.js +2 -2
- package/package.json +13 -19
- package/dist/utils/models.d.ts +0 -4
- package/dist/utils/models.js +0 -94
- package/dist/utils/prototypes.d.ts +0 -0
- package/dist/utils/prototypes.js +0 -20
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
import { userSession as userSessionStore } from '../stores/userSession.js';
|
|
33
33
|
|
|
34
34
|
import { WidgetPreview } from '@widgetic/editor';
|
|
35
|
+
import HoverTooltip from './HoverTooltip.svelte';
|
|
36
|
+
import EditableName from './EditableName.svelte';
|
|
37
|
+
|
|
38
|
+
const HEADER_ELEMENTS_GAP_PX = 6;
|
|
39
|
+
const HEADER_PADDING_PX = HEADER_ELEMENTS_GAP_PX + 2;
|
|
40
|
+
const HEADER_NAME_MIN_WIDTH_PX = 22;
|
|
41
|
+
const DETAILS_DRAG_THRESHOLD_PX = 5;
|
|
35
42
|
|
|
36
43
|
const dispatch = createEventDispatcher();
|
|
37
44
|
|
|
@@ -278,6 +285,14 @@
|
|
|
278
285
|
// ═══════════════════════════════════════════════════════════════════════
|
|
279
286
|
type WidgetStep = 'create' | 'edit' | 'embed';
|
|
280
287
|
export let currentStep: WidgetStep = 'create';
|
|
288
|
+
/**
|
|
289
|
+
* Canvas Creator is code-only (chat + preview). Edit/Embed header steps stay
|
|
290
|
+
* off until composition editing lives on /composition. Keep the Edit/Embed
|
|
291
|
+
* panels mounted (CSS-hidden) so we can turn this back on without ripping slots.
|
|
292
|
+
*/
|
|
293
|
+
export let showCompositionSteps: boolean = false;
|
|
294
|
+
/** After Set live, Create preview stays on that published artifact until the next Worker build. */
|
|
295
|
+
let pinnedPublishedPreviewUrl: string | null = null;
|
|
281
296
|
|
|
282
297
|
const STEPS: { id: WidgetStep; label: string; number: number }[] = [
|
|
283
298
|
{ id: 'create', label: 'Create', number: 1 },
|
|
@@ -299,8 +314,15 @@
|
|
|
299
314
|
previewError = null;
|
|
300
315
|
if (!iframeSrc) previewLoading = true;
|
|
301
316
|
}
|
|
302
|
-
$: canEditStep = lastPublishedVersion !== null && !isGeneratingCode;
|
|
303
|
-
$: canEmbedStep = lastPublishedVersion !== null && !isGeneratingCode;
|
|
317
|
+
$: canEditStep = showCompositionSteps && lastPublishedVersion !== null && !isGeneratingCode;
|
|
318
|
+
$: canEmbedStep = showCompositionSteps && lastPublishedVersion !== null && !isGeneratingCode;
|
|
319
|
+
$: activeWorkflowStep = showCompositionSteps ? currentStep : 'create';
|
|
320
|
+
|
|
321
|
+
$: if (!showCompositionSteps && currentStep !== 'create') {
|
|
322
|
+
currentStep = 'create';
|
|
323
|
+
dispatch('stepChange', { step: 'create' });
|
|
324
|
+
switchPreviewUrlForStep('create');
|
|
325
|
+
}
|
|
304
326
|
|
|
305
327
|
// Auto-switch back to Create when code generation starts
|
|
306
328
|
let _justFinishedGenerating = false;
|
|
@@ -314,6 +336,7 @@
|
|
|
314
336
|
previewError = null;
|
|
315
337
|
previewHasRuntimeError = false;
|
|
316
338
|
previewRuntimeErrorStatus = null;
|
|
339
|
+
pinnedPublishedPreviewUrl = null;
|
|
317
340
|
}
|
|
318
341
|
|
|
319
342
|
// Default step on widget switch: always open on Create
|
|
@@ -326,6 +349,7 @@
|
|
|
326
349
|
}
|
|
327
350
|
currentStep = 'create';
|
|
328
351
|
dispatch('stepChange', { step: 'create' });
|
|
352
|
+
pinnedPublishedPreviewUrl = null;
|
|
329
353
|
const createBase = normalizePreviewBaseUrl(
|
|
330
354
|
toPreviewFetchUrl(resolvePreviewUrlForStep('create') ?? '')
|
|
331
355
|
);
|
|
@@ -347,6 +371,7 @@
|
|
|
347
371
|
|
|
348
372
|
function canNavigateToStep(step: WidgetStep): boolean {
|
|
349
373
|
if (step === 'create') return true;
|
|
374
|
+
if (!showCompositionSteps) return false;
|
|
350
375
|
if (step === 'edit') return canEditStep;
|
|
351
376
|
if (step === 'embed') return canEmbedStep;
|
|
352
377
|
return false;
|
|
@@ -399,6 +424,10 @@
|
|
|
399
424
|
dynamicWorkerPreviewUrl = workerUrl;
|
|
400
425
|
syncPreviewDisplayUrlForStep('create');
|
|
401
426
|
void forceReloadPreviewIframe(workerUrl);
|
|
427
|
+
} else if ((step === 'edit' || step === 'embed') && nextResolved) {
|
|
428
|
+
// Always remount Edit/Embed on the published URL — skip-reload left the previous
|
|
429
|
+
// live version in the iframe after auto-publish on Create.
|
|
430
|
+
void forceReloadPreviewIframe(nextResolved);
|
|
402
431
|
} else {
|
|
403
432
|
switchPreviewUrlForStep(step, { forceReload: crossingPreviewFamily });
|
|
404
433
|
}
|
|
@@ -422,7 +451,7 @@
|
|
|
422
451
|
/** Resolve the canonical preview URL for a workflow step (without cache buster). */
|
|
423
452
|
function resolvePreviewUrlForStep(step: WidgetStep): string | null {
|
|
424
453
|
if (step === 'create') {
|
|
425
|
-
return dynamicWorkerPreviewUrl;
|
|
454
|
+
return pinnedPublishedPreviewUrl || dynamicWorkerPreviewUrl;
|
|
426
455
|
}
|
|
427
456
|
// Use published URL unless probe already confirmed it missing.
|
|
428
457
|
// Waiting for publishedArtifactReachable === true left Edit/Embed on the idle
|
|
@@ -454,6 +483,16 @@
|
|
|
454
483
|
}, 3000);
|
|
455
484
|
}
|
|
456
485
|
|
|
486
|
+
/** Load a published CDN artifact (Set live) even on Create — pin until next Worker build. */
|
|
487
|
+
export function showPublishedArtifact(url: string | null): void {
|
|
488
|
+
if (!url) return;
|
|
489
|
+
pinnedPublishedPreviewUrl = url;
|
|
490
|
+
publishedArtifactReachable = true;
|
|
491
|
+
_lastEditPreviewBase = null;
|
|
492
|
+
_lastEmbedPreviewBase = null;
|
|
493
|
+
void forceReloadPreviewIframe(url);
|
|
494
|
+
}
|
|
495
|
+
|
|
457
496
|
export function finishCompositionHydration(): void {
|
|
458
497
|
if (compositionHydrationTimeout) {
|
|
459
498
|
clearTimeout(compositionHydrationTimeout);
|
|
@@ -532,9 +571,12 @@
|
|
|
532
571
|
}
|
|
533
572
|
directPreviewUrl = toPreviewDisplayUrl(fetchUrl);
|
|
534
573
|
let nextFull = fetchUrl;
|
|
574
|
+
const isImmutableCdnUrl = /cdn\.widgetic\.com/i.test(fetchUrl) && /\/v\d+\//i.test(fetchUrl);
|
|
535
575
|
try {
|
|
536
576
|
const parsed = new URL(fetchUrl, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
537
|
-
|
|
577
|
+
if (!isImmutableCdnUrl || cacheBuster !== undefined) {
|
|
578
|
+
parsed.searchParams.set('_t', (cacheBuster ?? Date.now()).toString());
|
|
579
|
+
}
|
|
538
580
|
nextFull = parsed.toString();
|
|
539
581
|
} catch {
|
|
540
582
|
nextFull = fetchUrl;
|
|
@@ -666,8 +708,7 @@
|
|
|
666
708
|
const editBase = editSource ? normalizePreviewBaseUrl(toPreviewFetchUrl(editSource)) : null;
|
|
667
709
|
if (editBase && editBase !== _lastEditPreviewBase) {
|
|
668
710
|
_lastEditPreviewBase = editBase;
|
|
669
|
-
|
|
670
|
-
switchPreviewUrlForStep('edit', { forceReload: !_stepSwitchInProgress });
|
|
711
|
+
void forceReloadPreviewIframe(editSource);
|
|
671
712
|
}
|
|
672
713
|
}
|
|
673
714
|
|
|
@@ -753,7 +794,7 @@
|
|
|
753
794
|
export function markCodegenPreviewFresh(): void {
|
|
754
795
|
codegenPreviewFreshUntil = Date.now() + 30_000;
|
|
755
796
|
widgetNotFoundAutoRebuildAttempts = 1;
|
|
756
|
-
console.log('[WidgetDetails] Codegen preview marked fresh — skipping GitLab rebuilds for 30s');
|
|
797
|
+
// console.log('[WidgetDetails] Codegen preview marked fresh — skipping GitLab rebuilds for 30s');
|
|
757
798
|
}
|
|
758
799
|
|
|
759
800
|
/** True when the iframe is already showing this widget's Worker preview (not about:blank / error). */
|
|
@@ -812,6 +853,8 @@
|
|
|
812
853
|
|
|
813
854
|
function handleWidgetConsoleMessage(event: MessageEvent) {
|
|
814
855
|
if (!event.data || typeof event.data !== 'object') return;
|
|
856
|
+
const activeWin = previewIframe?.contentWindow;
|
|
857
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
815
858
|
const { type, level, message, args } = event.data;
|
|
816
859
|
if (type !== 'widgetic:console') return;
|
|
817
860
|
const entry: ConsoleLogEntry = {
|
|
@@ -869,19 +912,19 @@
|
|
|
869
912
|
$: detailsPanelTopOffset = panelTopOffset ?? legacyTopOffset;
|
|
870
913
|
$: detailsPanelBottomMargin = panelBottomMargin ?? legacyBottomMargin;
|
|
871
914
|
|
|
872
|
-
const DETAILS_PANEL_DEFAULT_WIDTH =
|
|
873
|
-
const DETAILS_PANEL_MAX_WIDTH =
|
|
915
|
+
const DETAILS_PANEL_DEFAULT_WIDTH = 1000;
|
|
916
|
+
const DETAILS_PANEL_MAX_WIDTH = 1200;
|
|
874
917
|
const DETAILS_PANEL_MAX_HEIGHT = 800;
|
|
875
|
-
const DETAILS_PANEL_MIN_WIDTH =
|
|
918
|
+
const DETAILS_PANEL_MIN_WIDTH = 480;
|
|
876
919
|
const DETAILS_PANEL_MIN_HEIGHT = 400;
|
|
877
920
|
const DETAILS_PANEL_FILL_INSET = 16;
|
|
878
921
|
const DETAILS_PANEL_SHAPE_GAP = 12;
|
|
879
|
-
/** Left column share of the two-col layout (chat / PropsEditor). */
|
|
880
|
-
const LEFT_COL_DEFAULT_PERCENT =
|
|
922
|
+
/** Left column share of the two-col layout (chat / PropsEditor). Preview gets the rest. */
|
|
923
|
+
const LEFT_COL_DEFAULT_PERCENT = 50;
|
|
881
924
|
const LEFT_COL_MIN_PERCENT = 32;
|
|
882
|
-
const LEFT_COL_MAX_PERCENT =
|
|
925
|
+
const LEFT_COL_MAX_PERCENT = 62;
|
|
883
926
|
const COL_RESIZER_PX = 10;
|
|
884
|
-
const PREVIEW_COL_MIN_PX =
|
|
927
|
+
const PREVIEW_COL_MIN_PX = 420;
|
|
885
928
|
/** Chat-first layout: preview column starts collapsed and opens on generate. */
|
|
886
929
|
let previewColumnCollapsed = true;
|
|
887
930
|
let lastAutoExpandForGenerating = false;
|
|
@@ -924,36 +967,33 @@
|
|
|
924
967
|
|
|
925
968
|
function collapsePreviewColumn() {
|
|
926
969
|
previewColumnCollapsed = true;
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
}
|
|
932
|
-
console.log('[WidgetDetails] Preview column minimized, restored width', detailsPanelWidth);
|
|
970
|
+
widthBeforePreviewExpand = 0;
|
|
971
|
+
leftColPercent = LEFT_COL_DEFAULT_PERCENT;
|
|
972
|
+
detailsPanelWidth = DETAILS_PANEL_MIN_WIDTH;
|
|
973
|
+
console.log('[WidgetDetails] Close Preview — panel width', detailsPanelWidth);
|
|
933
974
|
}
|
|
934
975
|
|
|
935
976
|
function expandPreviewColumn() {
|
|
936
977
|
if (!previewColumnCollapsed) return;
|
|
937
|
-
widthBeforePreviewExpand = detailsPanelWidth;
|
|
938
978
|
previewColumnCollapsed = false;
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
leftColPercent = clampLeftColPercent((widthBeforePreviewExpand / usable) * 100);
|
|
946
|
-
console.log('[WidgetDetails] Preview column expanded', {
|
|
947
|
-
from: widthBeforePreviewExpand,
|
|
948
|
-
to: detailsPanelWidth,
|
|
949
|
-
leftColPercent,
|
|
950
|
-
});
|
|
979
|
+
leftColPercent = clampLeftColPercent(LEFT_COL_DEFAULT_PERCENT);
|
|
980
|
+
detailsPanelWidth = clampPanelWidth(DETAILS_PANEL_DEFAULT_WIDTH);
|
|
981
|
+
if (typeof window !== 'undefined' && detailsPanelX + detailsPanelWidth > window.innerWidth - 8) {
|
|
982
|
+
detailsPanelX = Math.max(8, window.innerWidth - 8 - detailsPanelWidth);
|
|
983
|
+
}
|
|
984
|
+
console.log('[WidgetDetails] Open Preview — panel width', detailsPanelWidth);
|
|
951
985
|
tick().then(() => requestAnimationFrame(() => fitPreviewToArea()));
|
|
952
986
|
}
|
|
953
987
|
|
|
954
988
|
let detailsPanelX = -1;
|
|
955
989
|
let detailsPanelY = -1;
|
|
956
990
|
let isDraggingDetails = false;
|
|
991
|
+
let pendingDetailsDrag = false;
|
|
992
|
+
let detailsDragBarEl: HTMLElement | null = null;
|
|
993
|
+
let widgetDetailsNameCtEl: HTMLElement | null = null;
|
|
994
|
+
let widgetDetailsStepsRowEl: HTMLElement | null = null;
|
|
995
|
+
let widgetDetailsDebugButtonsEl: HTMLElement | null = null;
|
|
996
|
+
let headerNameMaxWidthPx = 96;
|
|
957
997
|
let detailsDragStartX = 0;
|
|
958
998
|
let detailsDragStartY = 0;
|
|
959
999
|
let detailsInitialX = 0;
|
|
@@ -998,7 +1038,7 @@
|
|
|
998
1038
|
const pageOrigin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
999
1039
|
const isApiProxy = !!(apiBaseUrl && fetchUrl.startsWith(apiBaseUrl));
|
|
1000
1040
|
if (pageOrigin && absolute.origin !== pageOrigin && !isApiProxy) {
|
|
1001
|
-
console.log('[WidgetDetails] Skipping cross-origin HEAD probe (CORS); loading in iframe:', absolute.origin);
|
|
1041
|
+
// console.log('[WidgetDetails] Skipping cross-origin HEAD probe (CORS); loading in iframe:', absolute.origin);
|
|
1002
1042
|
return true;
|
|
1003
1043
|
}
|
|
1004
1044
|
} catch {
|
|
@@ -1057,11 +1097,11 @@
|
|
|
1057
1097
|
if (iframeSrc && previewLoadedForWidgetId === widgetId) {
|
|
1058
1098
|
previewBuildDeferred = false;
|
|
1059
1099
|
previewLoading = false;
|
|
1060
|
-
console.log('[WidgetDetails] Preview already loaded, skipping pipeline:', widgetId.substring(0, 8));
|
|
1100
|
+
// console.log('[WidgetDetails] Preview already loaded, skipping pipeline:', widgetId.substring(0, 8));
|
|
1061
1101
|
return;
|
|
1062
1102
|
}
|
|
1063
1103
|
if (shouldDeferPreviewNetworkWork()) {
|
|
1064
|
-
console.log('[WidgetDetails] Deferring preview load (background panel):', widgetId.substring(0, 8));
|
|
1104
|
+
// console.log('[WidgetDetails] Deferring preview load (background panel):', widgetId.substring(0, 8));
|
|
1065
1105
|
previewBuildDeferred = true;
|
|
1066
1106
|
previewLoading = false;
|
|
1067
1107
|
previewError = null;
|
|
@@ -1092,10 +1132,10 @@
|
|
|
1092
1132
|
}
|
|
1093
1133
|
|
|
1094
1134
|
if (probeResult === 'not-found') {
|
|
1095
|
-
console.log('[WidgetDetails] Widget not on Worker — published artifact or build-from-repo', {
|
|
1096
|
-
widgetId: capturedWidgetId.substring(0, 8),
|
|
1097
|
-
hasJwt: !!getAuthJwt(),
|
|
1098
|
-
});
|
|
1135
|
+
// console.log('[WidgetDetails] Widget not on Worker — published artifact or build-from-repo', {
|
|
1136
|
+
// widgetId: capturedWidgetId.substring(0, 8),
|
|
1137
|
+
// hasJwt: !!getAuthJwt(),
|
|
1138
|
+
// });
|
|
1099
1139
|
if (isGeneratingCode) {
|
|
1100
1140
|
previewLoading = true;
|
|
1101
1141
|
previewError = null;
|
|
@@ -1108,13 +1148,13 @@
|
|
|
1108
1148
|
if (!hasRepo) {
|
|
1109
1149
|
const fallbackUrl = publishedHtmlUrlFromJsPath(widgetJsPath);
|
|
1110
1150
|
if (fallbackUrl) {
|
|
1111
|
-
console.log('[WidgetDetails] No repo yet — loading js_path artifact', fallbackUrl);
|
|
1151
|
+
// console.log('[WidgetDetails] No repo yet — loading js_path artifact', fallbackUrl);
|
|
1112
1152
|
previewError = null;
|
|
1113
1153
|
applyPreviewUrlToIframe(fallbackUrl);
|
|
1114
1154
|
previewLoading = false;
|
|
1115
1155
|
return;
|
|
1116
1156
|
}
|
|
1117
|
-
console.log('[WidgetDetails] No repository yet — skipping build-from-repo');
|
|
1157
|
+
// console.log('[WidgetDetails] No repository yet — skipping build-from-repo');
|
|
1118
1158
|
previewLoading = false;
|
|
1119
1159
|
previewError = 'NO_CODE_YET';
|
|
1120
1160
|
return;
|
|
@@ -1127,7 +1167,7 @@
|
|
|
1127
1167
|
directPreviewUrl = workerPreviewUrl;
|
|
1128
1168
|
previewLoading = true;
|
|
1129
1169
|
switchPreviewUrlForStep(currentStep);
|
|
1130
|
-
console.log('[WidgetDetails] Loading preview iframe:', workerPreviewUrl, 'step:', currentStep);
|
|
1170
|
+
// console.log('[WidgetDetails] Loading preview iframe:', workerPreviewUrl, 'step:', currentStep);
|
|
1131
1171
|
requestAnimationFrame(() => {
|
|
1132
1172
|
setTimeout(fitPreviewToArea, 150);
|
|
1133
1173
|
});
|
|
@@ -1139,7 +1179,7 @@
|
|
|
1139
1179
|
if (!previewBuildDeferred || !selectedWidgetId) return;
|
|
1140
1180
|
if (iframeSrc && previewLoadedForWidgetId === selectedWidgetId) {
|
|
1141
1181
|
previewBuildDeferred = false;
|
|
1142
|
-
console.log('[WidgetDetails] Skip deferred preview — already loaded for', selectedWidgetId.substring(0, 8));
|
|
1182
|
+
// console.log('[WidgetDetails] Skip deferred preview — already loaded for', selectedWidgetId.substring(0, 8));
|
|
1143
1183
|
return;
|
|
1144
1184
|
}
|
|
1145
1185
|
previewBuildDeferred = false;
|
|
@@ -1199,18 +1239,18 @@
|
|
|
1199
1239
|
|
|
1200
1240
|
await tick();
|
|
1201
1241
|
|
|
1202
|
-
console.log('WidgetDetails: loadWidget completed:', {
|
|
1203
|
-
widgetId,
|
|
1204
|
-
name: selectedWidget?.name,
|
|
1205
|
-
currentRepositoryId,
|
|
1206
|
-
});
|
|
1242
|
+
// console.log('WidgetDetails: loadWidget completed:', {
|
|
1243
|
+
// widgetId,
|
|
1244
|
+
// name: selectedWidget?.name,
|
|
1245
|
+
// currentRepositoryId,
|
|
1246
|
+
// });
|
|
1207
1247
|
|
|
1208
1248
|
dispatch('widgetReady', { widgetId: selectedWidgetId });
|
|
1209
1249
|
|
|
1210
1250
|
// If skipBasePreview is set, the caller will handle compiling via triggerBuildFromRepo
|
|
1211
1251
|
// (e.g. duplicates waiting for GitLab fork, or converts waiting for code generation)
|
|
1212
1252
|
if (skipBasePreview) {
|
|
1213
|
-
console.log('[WidgetDetails] skipBasePreview is set — deferring preview load to caller');
|
|
1253
|
+
// console.log('[WidgetDetails] skipBasePreview is set — deferring preview load to caller');
|
|
1214
1254
|
previewLoading = true;
|
|
1215
1255
|
previewError = null;
|
|
1216
1256
|
return;
|
|
@@ -1222,11 +1262,11 @@
|
|
|
1222
1262
|
|
|
1223
1263
|
const hasRepo = !!(normalizeRepositoryId(selectedWidget) || currentRepositoryId);
|
|
1224
1264
|
if (!lastCommitId && lastPublishedVersion === null && !widgetJsPath && !hasRepo) {
|
|
1225
|
-
console.log('[WidgetDetails] No code yet — skipping Worker probe/build-from-repo', {
|
|
1226
|
-
widgetId: widgetId?.substring(0, 8),
|
|
1227
|
-
hasRepo,
|
|
1228
|
-
repositorySetupStatus,
|
|
1229
|
-
});
|
|
1265
|
+
// console.log('[WidgetDetails] No code yet — skipping Worker probe/build-from-repo', {
|
|
1266
|
+
// widgetId: widgetId?.substring(0, 8),
|
|
1267
|
+
// hasRepo,
|
|
1268
|
+
// repositorySetupStatus,
|
|
1269
|
+
// });
|
|
1230
1270
|
previewLoading = false;
|
|
1231
1271
|
previewError = 'NO_CODE_YET';
|
|
1232
1272
|
return;
|
|
@@ -1251,7 +1291,7 @@
|
|
|
1251
1291
|
|
|
1252
1292
|
export async function refreshPreview(opts: { withRetry?: boolean; skipIfAlreadyShowing?: boolean } = {}): Promise<void> {
|
|
1253
1293
|
if (opts.skipIfAlreadyShowing && hasLiveWorkerPreview()) {
|
|
1254
|
-
console.log('[WidgetDetails] refreshPreview skipped — Worker preview already showing');
|
|
1294
|
+
// console.log('[WidgetDetails] refreshPreview skipped — Worker preview already showing');
|
|
1255
1295
|
previewLoading = false;
|
|
1256
1296
|
previewHydrating = false;
|
|
1257
1297
|
return;
|
|
@@ -1275,11 +1315,11 @@
|
|
|
1275
1315
|
middleware: cfg.middleware,
|
|
1276
1316
|
headers: cfg.headers,
|
|
1277
1317
|
});
|
|
1278
|
-
console.log('[WidgetDetails] buildWidgetFromRepo', {
|
|
1279
|
-
widgetId: widgetId.substring(0, 8),
|
|
1280
|
-
builderBasePath,
|
|
1281
|
-
sdkPath: '/v1/agent/widget-builder/build-from-repo/{widgetId}',
|
|
1282
|
-
});
|
|
1318
|
+
// console.log('[WidgetDetails] buildWidgetFromRepo', {
|
|
1319
|
+
// widgetId: widgetId.substring(0, 8),
|
|
1320
|
+
// builderBasePath,
|
|
1321
|
+
// sdkPath: '/v1/agent/widget-builder/build-from-repo/{widgetId}',
|
|
1322
|
+
// });
|
|
1283
1323
|
return builder.buildWidgetFromRepo({ widgetId });
|
|
1284
1324
|
}
|
|
1285
1325
|
|
|
@@ -1287,13 +1327,13 @@
|
|
|
1287
1327
|
const forceRebuild = options?.force === true;
|
|
1288
1328
|
if (!selectedWidgetId) return;
|
|
1289
1329
|
if (shouldDeferPreviewNetworkWork(forceRebuild)) {
|
|
1290
|
-
console.log('[WidgetDetails] triggerBuildFromRepo deferred (background panel)');
|
|
1330
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo deferred (background panel)');
|
|
1291
1331
|
previewBuildDeferred = true;
|
|
1292
1332
|
return;
|
|
1293
1333
|
}
|
|
1294
1334
|
const hasRepo = !!(normalizeRepositoryId(selectedWidget) || currentRepositoryId);
|
|
1295
1335
|
if (!hasRepo) {
|
|
1296
|
-
console.log('[WidgetDetails] triggerBuildFromRepo skipped — widget has no repository yet');
|
|
1336
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo skipped — widget has no repository yet');
|
|
1297
1337
|
previewLoading = false;
|
|
1298
1338
|
previewError = 'NO_CODE_YET';
|
|
1299
1339
|
return;
|
|
@@ -1301,6 +1341,7 @@
|
|
|
1301
1341
|
const capturedWidgetId = selectedWidgetId;
|
|
1302
1342
|
const runId = ++buildFromRepoRunId;
|
|
1303
1343
|
if (forceRebuild) isRebuildingPreview = true;
|
|
1344
|
+
pinnedPublishedPreviewUrl = null;
|
|
1304
1345
|
try {
|
|
1305
1346
|
const workerPreviewUrl = buildWorkerPreviewUrl(capturedWidgetId);
|
|
1306
1347
|
const workerPreviewDisplayUrl = buildWorkerPreviewUrl(capturedWidgetId, { forDisplay: true });
|
|
@@ -1309,7 +1350,7 @@
|
|
|
1309
1350
|
const freshProbe = await probeWorkerReachable(workerPreviewUrl);
|
|
1310
1351
|
if (selectedWidgetId !== capturedWidgetId || runId !== buildFromRepoRunId) return;
|
|
1311
1352
|
if (freshProbe === 'ok') {
|
|
1312
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: skipping GitLab rebuild — codegen preview is fresh');
|
|
1353
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: skipping GitLab rebuild — codegen preview is fresh');
|
|
1313
1354
|
dynamicWorkerPreviewUrl = workerPreviewUrl;
|
|
1314
1355
|
directPreviewUrl = workerPreviewDisplayUrl;
|
|
1315
1356
|
inlinePanelView = 'preview';
|
|
@@ -1349,7 +1390,7 @@
|
|
|
1349
1390
|
const probeResult = await probeWorkerReachable(workerPreviewUrl);
|
|
1350
1391
|
if (isStaleRun()) return;
|
|
1351
1392
|
if (!forceRebuild && probeResult === 'ok') {
|
|
1352
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: Worker already has widget, loading preview directly');
|
|
1393
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: Worker already has widget, loading preview directly');
|
|
1353
1394
|
dispatch('buildFromRepoSuccess', { widgetId: capturedWidgetId });
|
|
1354
1395
|
loadPreviewFromWorker();
|
|
1355
1396
|
return;
|
|
@@ -1363,7 +1404,7 @@
|
|
|
1363
1404
|
|
|
1364
1405
|
// Skip build-from-repo while codegen is running — WS / refreshPreview will load when ready
|
|
1365
1406
|
if (isGeneratingCode) {
|
|
1366
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: codegen in progress — deferring build-from-repo');
|
|
1407
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: codegen in progress — deferring build-from-repo');
|
|
1367
1408
|
previewLoading = true;
|
|
1368
1409
|
previewError = null;
|
|
1369
1410
|
return;
|
|
@@ -1381,7 +1422,7 @@
|
|
|
1381
1422
|
const buildData = await requestBuildFromRepo(capturedWidgetId);
|
|
1382
1423
|
if (isStaleRun()) return;
|
|
1383
1424
|
|
|
1384
|
-
console.log('[WidgetDetails] triggerBuildFromRepo succeeded', { buildTimeMs: buildData?.data?.buildTimeMs ?? buildData?.buildTimeMs, attempt });
|
|
1425
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo succeeded', { buildTimeMs: buildData?.data?.buildTimeMs ?? buildData?.buildTimeMs, attempt });
|
|
1385
1426
|
previewError = null;
|
|
1386
1427
|
previewLoading = false;
|
|
1387
1428
|
dispatch('widgetDataChanged', { widgetId: capturedWidgetId });
|
|
@@ -1409,7 +1450,7 @@
|
|
|
1409
1450
|
lastBuildErrorMsg = sanitizePreviewBuildError(lastBuildErrorMsg);
|
|
1410
1451
|
|
|
1411
1452
|
if (buildErrorCode === 'NO_CODE_YET') {
|
|
1412
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: repo exists but has no code yet — skipping retries');
|
|
1453
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: repo exists but has no code yet — skipping retries');
|
|
1413
1454
|
lastBuildErrorMsg = 'NO_CODE_YET';
|
|
1414
1455
|
break;
|
|
1415
1456
|
}
|
|
@@ -1417,7 +1458,7 @@
|
|
|
1417
1458
|
const status = buildErr?.response?.status ?? buildErr?.status;
|
|
1418
1459
|
const isRetryable = status === 404 || status === 500 || !status;
|
|
1419
1460
|
if (isRetryable && attempt < maxRetries) {
|
|
1420
|
-
console.log(`[WidgetDetails] triggerBuildFromRepo attempt ${attempt}/${maxRetries} failed (${lastBuildErrorMsg}), retrying in ${retryDelayMs}ms...`);
|
|
1461
|
+
// console.log(`[WidgetDetails] triggerBuildFromRepo attempt ${attempt}/${maxRetries} failed (${lastBuildErrorMsg}), retrying in ${retryDelayMs}ms...`);
|
|
1421
1462
|
await new Promise(r => setTimeout(r, retryDelayMs));
|
|
1422
1463
|
continue;
|
|
1423
1464
|
}
|
|
@@ -1439,14 +1480,14 @@
|
|
|
1439
1480
|
|
|
1440
1481
|
// Preview may have loaded via codegen/WS while build-from-repo was in flight
|
|
1441
1482
|
if (allowStalePreviewRecovery && iframeSrc && !previewHasRuntimeError) {
|
|
1442
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: build failed but preview iframe already loaded — keeping preview');
|
|
1483
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: build failed but preview iframe already loaded — keeping preview');
|
|
1443
1484
|
previewError = null;
|
|
1444
1485
|
previewLoading = false;
|
|
1445
1486
|
return;
|
|
1446
1487
|
}
|
|
1447
1488
|
|
|
1448
1489
|
if (allowStalePreviewRecovery && (await tryRecoverPreviewFromWorker())) {
|
|
1449
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: recovered preview from Worker after build-from-repo failure');
|
|
1490
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: recovered preview from Worker after build-from-repo failure');
|
|
1450
1491
|
return;
|
|
1451
1492
|
}
|
|
1452
1493
|
|
|
@@ -1454,7 +1495,7 @@
|
|
|
1454
1495
|
// For published widgets, try loading via API proxy (handles both R2 and CDN)
|
|
1455
1496
|
const sourceArtifactUrl = publishedHtmlUrlFromJsPath(widgetJsPath);
|
|
1456
1497
|
if (sourceArtifactUrl) {
|
|
1457
|
-
console.log('[WidgetDetails] triggerBuildFromRepo: using js_path artifact (not new-id proxy)', sourceArtifactUrl);
|
|
1498
|
+
// console.log('[WidgetDetails] triggerBuildFromRepo: using js_path artifact (not new-id proxy)', sourceArtifactUrl);
|
|
1458
1499
|
const reachable = await probePublishedArtifactUrl(sourceArtifactUrl);
|
|
1459
1500
|
if (reachable) {
|
|
1460
1501
|
previewError = null;
|
|
@@ -1586,7 +1627,7 @@
|
|
|
1586
1627
|
/** Duplicate/fork fallback: keep published iframe if it loaded; otherwise compile from repo. */
|
|
1587
1628
|
export async function retryPreviewIfEmpty(): Promise<void> {
|
|
1588
1629
|
if (iframeSrc && !previewError) {
|
|
1589
|
-
console.log('[WidgetDetails] retryPreviewIfEmpty skipped — preview already loaded');
|
|
1630
|
+
// console.log('[WidgetDetails] retryPreviewIfEmpty skipped — preview already loaded');
|
|
1590
1631
|
return;
|
|
1591
1632
|
}
|
|
1592
1633
|
previewLoading = true;
|
|
@@ -1595,7 +1636,7 @@
|
|
|
1595
1636
|
if (await loadPublishedPreviewForCurrentStep()) return;
|
|
1596
1637
|
const hasRepo = !!(normalizeRepositoryId(selectedWidget) || currentRepositoryId);
|
|
1597
1638
|
if (hasRepo) {
|
|
1598
|
-
console.log('[WidgetDetails] retryPreviewIfEmpty — compiling from repository');
|
|
1639
|
+
// console.log('[WidgetDetails] retryPreviewIfEmpty — compiling from repository');
|
|
1599
1640
|
await triggerBuildFromRepo();
|
|
1600
1641
|
return;
|
|
1601
1642
|
}
|
|
@@ -1664,10 +1705,9 @@
|
|
|
1664
1705
|
// Widget is alive — never keep a runtime-error overlay over a working preview.
|
|
1665
1706
|
clearPendingRuntimeErrorOverlay();
|
|
1666
1707
|
if (previewHasRuntimeError) {
|
|
1667
|
-
console.log('[WidgetDetails] Clearing runtime error overlay — widgetic:ready');
|
|
1668
1708
|
previewHasRuntimeError = false;
|
|
1669
1709
|
previewRuntimeErrorStatus = null;
|
|
1670
|
-
if (previewError && /runtime error|HTTP 500|compilation/i.test(previewError)) {
|
|
1710
|
+
if (previewError && /did not start|runtime error|HTTP 500|compilation/i.test(previewError)) {
|
|
1671
1711
|
previewError = null;
|
|
1672
1712
|
}
|
|
1673
1713
|
notifyPreviewCompileErrorChanged();
|
|
@@ -1684,6 +1724,17 @@
|
|
|
1684
1724
|
return typeof value === 'string' && /<[a-z][\s\S]*>/i.test(value);
|
|
1685
1725
|
}
|
|
1686
1726
|
|
|
1727
|
+
function contentOverlaySelectors(key: string): string {
|
|
1728
|
+
const exact = `[data-content="${CSS.escape(key)}"]`;
|
|
1729
|
+
if (/subtitle/i.test(key)) {
|
|
1730
|
+
return `${exact}, [data-content="widgetSubtitle"], [data-content="gallerySubtitle"], [data-content="subtitle"], .widget-subtitle, .gallery-subtitle`;
|
|
1731
|
+
}
|
|
1732
|
+
if (/^(widgetTitle|galleryTitle|title|heading)$/i.test(key)) {
|
|
1733
|
+
return `${exact}, [data-content="widgetTitle"], [data-content="galleryTitle"], h1, .widget-title`;
|
|
1734
|
+
}
|
|
1735
|
+
return exact;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1687
1738
|
/** Same-origin preview iframes (Vite /__widget_builder__ proxy): restore bold/italic after widgets set textContent. */
|
|
1688
1739
|
function applyRichTextInPreviewIframe(message: Record<string, unknown>): void {
|
|
1689
1740
|
if (message.type !== 'widgetic:update') return;
|
|
@@ -1694,10 +1745,16 @@
|
|
|
1694
1745
|
const content = message.content as Record<string, unknown> | undefined;
|
|
1695
1746
|
if (content) {
|
|
1696
1747
|
for (const [key, value] of Object.entries(content)) {
|
|
1697
|
-
if (
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
el
|
|
1748
|
+
if (typeof value !== 'string') continue;
|
|
1749
|
+
const selectors = contentOverlaySelectors(key);
|
|
1750
|
+
doc.querySelectorAll(selectors).forEach((el) => {
|
|
1751
|
+
if (el instanceof HTMLImageElement) {
|
|
1752
|
+
el.src = value;
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLAnchorElement) return;
|
|
1756
|
+
if (looksLikeHtmlMarkup(value)) el.innerHTML = value;
|
|
1757
|
+
else el.textContent = value;
|
|
1701
1758
|
});
|
|
1702
1759
|
}
|
|
1703
1760
|
}
|
|
@@ -1737,25 +1794,63 @@
|
|
|
1737
1794
|
}
|
|
1738
1795
|
|
|
1739
1796
|
function ensureGoogleFontInPreviewDoc(doc: Document, family: string): void {
|
|
1740
|
-
if (!family || /^(
|
|
1797
|
+
if (!family || /^(system-ui|sans-serif|serif)$/i.test(family)) return;
|
|
1741
1798
|
const id = `widgetic-gf-${family.replace(/[^a-z0-9]+/gi, '-').toLowerCase()}`;
|
|
1742
1799
|
if (doc.getElementById(id)) return;
|
|
1743
1800
|
const link = doc.createElement('link');
|
|
1744
1801
|
link.id = id;
|
|
1745
1802
|
link.rel = 'stylesheet';
|
|
1746
|
-
link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap`;
|
|
1803
|
+
link.href = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap`;
|
|
1747
1804
|
doc.head?.appendChild(link);
|
|
1748
|
-
console.log('[WidgetDetails] Loaded Google Font in preview iframe:', family);
|
|
1805
|
+
// console.log('[WidgetDetails] Loaded Google Font in preview iframe:', family);
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
function parseOverlayFontFace(weight: string | undefined): { cssWeight: string; cssStyle: string } {
|
|
1809
|
+
const raw = String(weight || 'Regular');
|
|
1810
|
+
const cssStyle = /italic|oblique/i.test(raw) ? 'italic' : 'normal';
|
|
1811
|
+
const name = raw.toLowerCase().replace(/italic|oblique/g, '').replace(/[\s_-]/g, '');
|
|
1812
|
+
const table: Record<string, string> = {
|
|
1813
|
+
thin: '100', hairline: '100',
|
|
1814
|
+
extralight: '200', ultralight: '200',
|
|
1815
|
+
light: '300',
|
|
1816
|
+
regular: '400', normal: '400', '': '400',
|
|
1817
|
+
medium: '500',
|
|
1818
|
+
semibold: '600', demibold: '600',
|
|
1819
|
+
bold: '700',
|
|
1820
|
+
extrabold: '800', ultrabold: '800',
|
|
1821
|
+
black: '900', heavy: '900',
|
|
1822
|
+
};
|
|
1823
|
+
if (/^\d{3}$/.test(name)) return { cssWeight: name, cssStyle };
|
|
1824
|
+
return { cssWeight: table[name] || '400', cssStyle };
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
function flattenDesignOverlay(raw: Record<string, unknown> | undefined): Record<string, string> | null {
|
|
1828
|
+
if (!raw) return null;
|
|
1829
|
+
const out: Record<string, string> = {};
|
|
1830
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
1831
|
+
if (value && typeof value === 'object' && 'family' in (value as Record<string, unknown>)) {
|
|
1832
|
+
const font = value as { family?: string; weight?: string };
|
|
1833
|
+
const family = String(font.family || 'Inter');
|
|
1834
|
+
const face = parseOverlayFontFace(font.weight);
|
|
1835
|
+
out[key] = `"${family}", sans-serif`;
|
|
1836
|
+
out[`${key}Family`] = family;
|
|
1837
|
+
out[`${key}Weight`] = face.cssWeight;
|
|
1838
|
+
out[`${key}Style`] = face.cssStyle;
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
if (typeof value === 'string' && value) out[key] = value;
|
|
1842
|
+
}
|
|
1843
|
+
return Object.keys(out).length ? out : null;
|
|
1749
1844
|
}
|
|
1750
1845
|
|
|
1751
1846
|
/** Same-origin preview: apply CSS vars, Google Fonts, title/subtitle, tile aspect-ratio. */
|
|
1752
1847
|
function applyDesignOverlayInPreviewIframe(message: Record<string, unknown>): void {
|
|
1753
1848
|
if (message.type !== 'widgetic:update') return;
|
|
1754
|
-
const design = message.design as Record<string,
|
|
1849
|
+
const design = flattenDesignOverlay(message.design as Record<string, unknown> | undefined);
|
|
1755
1850
|
if (!design) return;
|
|
1756
1851
|
const doc = previewIframe?.contentDocument;
|
|
1757
1852
|
if (!doc?.documentElement) {
|
|
1758
|
-
console.log('[WidgetDetails] Design overlay skipped — preview iframe not same-origin');
|
|
1853
|
+
// console.log('[WidgetDetails] Design overlay skipped — preview iframe not same-origin');
|
|
1759
1854
|
return;
|
|
1760
1855
|
}
|
|
1761
1856
|
const apply = () => {
|
|
@@ -1776,46 +1871,69 @@
|
|
|
1776
1871
|
}
|
|
1777
1872
|
families.forEach((family) => ensureGoogleFontInPreviewDoc(doc, family));
|
|
1778
1873
|
|
|
1779
|
-
const
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
extractCssFontFamily(design.subtitleFont) ||
|
|
1788
|
-
design.descriptionFontFamily ||
|
|
1789
|
-
extractCssFontFamily(design.descriptionFont);
|
|
1790
|
-
const subtitleWeight = design.subtitleFontWeight || design.descriptionFontWeight || '';
|
|
1791
|
-
|
|
1792
|
-
if (titleFamily || titleWeight) {
|
|
1793
|
-
const titleStack = titleFamily ? `"${titleFamily}", sans-serif` : '';
|
|
1794
|
-
doc.querySelectorAll(
|
|
1795
|
-
'h1, h2, h3, .widget-title, [data-content="title"], [data-content="widgetTitle"], [data-content="heading"]'
|
|
1796
|
-
).forEach((el) => {
|
|
1797
|
-
if (!(el instanceof HTMLElement)) return;
|
|
1798
|
-
if (titleStack) el.style.setProperty('font-family', titleStack, 'important');
|
|
1799
|
-
if (titleWeight) el.style.setProperty('font-weight', titleWeight, 'important');
|
|
1874
|
+
const applyFace = (family: string, weight: string, style: string, selectors: string) => {
|
|
1875
|
+
if (!family && !weight && !style) return;
|
|
1876
|
+
const stack = family ? `"${family}", sans-serif` : '';
|
|
1877
|
+
doc.querySelectorAll(selectors).forEach((node) => {
|
|
1878
|
+
if (!(node instanceof HTMLElement)) return;
|
|
1879
|
+
if (stack) node.style.setProperty('font-family', stack, 'important');
|
|
1880
|
+
if (weight) node.style.setProperty('font-weight', weight, 'important');
|
|
1881
|
+
if (style) node.style.setProperty('font-style', style, 'important');
|
|
1800
1882
|
});
|
|
1883
|
+
};
|
|
1884
|
+
|
|
1885
|
+
const cssChunks: string[] = [];
|
|
1886
|
+
const fontPrefixes = new Set<string>();
|
|
1887
|
+
for (const key of Object.keys(design)) {
|
|
1888
|
+
const match = key.match(/^(.*)Font(?:Family|Weight|Style)?$/i);
|
|
1889
|
+
if (match) fontPrefixes.add(match[1] || '');
|
|
1801
1890
|
}
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
const
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1891
|
+
|
|
1892
|
+
for (const prefix of fontPrefixes) {
|
|
1893
|
+
const family =
|
|
1894
|
+
design[`${prefix}FontFamily`] ||
|
|
1895
|
+
extractCssFontFamily(design[`${prefix}Font`]) ||
|
|
1896
|
+
'';
|
|
1897
|
+
const weight = design[`${prefix}FontWeight`] || '';
|
|
1898
|
+
const style = design[`${prefix}FontStyle`] || '';
|
|
1899
|
+
const isTitleLike =
|
|
1900
|
+
/^(title|heading|tite)?$/i.test(prefix) ||
|
|
1901
|
+
/title|heading|tite/i.test(prefix);
|
|
1902
|
+
const isSubtitleLike = /subtitle|description|caption|label/i.test(prefix);
|
|
1903
|
+
const varFamily = `--${prefix}Font`;
|
|
1904
|
+
const varWeight = `--${prefix}FontWeight`;
|
|
1905
|
+
const varStyle = `--${prefix}FontStyle`;
|
|
1906
|
+
if (isSubtitleLike) {
|
|
1907
|
+
cssChunks.push(
|
|
1908
|
+
`[data-content="caption"], [data-content="subtitle"], [data-content="description"], [data-content="widgetSubtitle"], .caption-bottom p, [class*="caption"], [class*="subtitle"] { font-family: var(${varFamily}, inherit) !important; font-weight: var(${varWeight}, inherit) !important; font-style: var(${varStyle}, normal) !important; }`
|
|
1909
|
+
);
|
|
1910
|
+
applyFace(
|
|
1911
|
+
family,
|
|
1912
|
+
weight,
|
|
1913
|
+
style,
|
|
1914
|
+
'.widget-subtitle, .gallery-subtitle, .gallery-caption, .caption-bottom p, [data-content="subtitle"], [data-content="description"], [data-content="widgetSubtitle"], [data-content="caption"], [class*="caption"], [class*="subtitle"]'
|
|
1915
|
+
);
|
|
1916
|
+
} else if (isTitleLike || fontPrefixes.size === 1) {
|
|
1917
|
+
cssChunks.push(
|
|
1918
|
+
`h1, h2, h3, [data-content="widgetTitle"], [data-content="title"], [data-content="heading"], .widget-title, .gallery-title, [class*="title"] { font-family: var(${varFamily}, inherit) !important; font-weight: var(${varWeight}, inherit) !important; font-style: var(${varStyle}, normal) !important; }`
|
|
1919
|
+
);
|
|
1920
|
+
applyFace(
|
|
1921
|
+
family,
|
|
1922
|
+
weight,
|
|
1923
|
+
style,
|
|
1924
|
+
'h1, h2, h3, .widget-title, .gallery-title, [data-content="title"], [data-content="widgetTitle"], [data-content="heading"], [class*="title"]'
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
if (cssChunks.length) {
|
|
1930
|
+
let sheet = doc.getElementById('widgetic-font-overlay') as HTMLStyleElement | null;
|
|
1931
|
+
if (!sheet) {
|
|
1932
|
+
sheet = doc.createElement('style');
|
|
1933
|
+
sheet.id = 'widgetic-font-overlay';
|
|
1934
|
+
doc.head.appendChild(sheet);
|
|
1818
1935
|
}
|
|
1936
|
+
sheet.textContent = cssChunks.join('\n');
|
|
1819
1937
|
}
|
|
1820
1938
|
|
|
1821
1939
|
const aspectEntry = Object.entries(design).find(([key, value]) =>
|
|
@@ -1832,7 +1950,7 @@
|
|
|
1832
1950
|
el.style.height = 'auto';
|
|
1833
1951
|
}
|
|
1834
1952
|
});
|
|
1835
|
-
console.log('[WidgetDetails] Applied tile aspect-ratio overlay:', cssRatio);
|
|
1953
|
+
// console.log('[WidgetDetails] Applied tile aspect-ratio overlay:', cssRatio);
|
|
1836
1954
|
}
|
|
1837
1955
|
} catch (error) {
|
|
1838
1956
|
console.warn('[WidgetDetails] Design overlay skipped:', error);
|
|
@@ -1899,7 +2017,7 @@
|
|
|
1899
2017
|
|
|
1900
2018
|
function startPreviewTokenAutoRefresh() {
|
|
1901
2019
|
stopPreviewTokenAutoRefresh();
|
|
1902
|
-
console.log('[TokenAutoRefresh] Started - checking every', TOKEN_CHECK_INTERVAL_MS / 1000, 'seconds');
|
|
2020
|
+
// console.log('[TokenAutoRefresh] Started - checking every', TOKEN_CHECK_INTERVAL_MS / 1000, 'seconds');
|
|
1903
2021
|
previewTokenRefreshInterval = setInterval(async () => {
|
|
1904
2022
|
const isPreviewVisible = showPreviewModal || (showWidgetDetails && inlinePanelView === 'preview');
|
|
1905
2023
|
if (!isPreviewVisible || !lastPreviewUrlFetchTime || !directPreviewUrl) return;
|
|
@@ -2008,7 +2126,7 @@
|
|
|
2008
2126
|
const retryCount = opts._retryCount || 0;
|
|
2009
2127
|
const withRetry = opts.withRetry || false;
|
|
2010
2128
|
|
|
2011
|
-
console.log('WidgetDetails: Triggering preview refresh via src manipulation', retryCount > 0 ? `(retry ${retryCount})` : '');
|
|
2129
|
+
// console.log('WidgetDetails: Triggering preview refresh via src manipulation', retryCount > 0 ? `(retry ${retryCount})` : '');
|
|
2012
2130
|
const newCacheBuster = Date.now();
|
|
2013
2131
|
previewCacheBuster = newCacheBuster;
|
|
2014
2132
|
|
|
@@ -2018,7 +2136,7 @@
|
|
|
2018
2136
|
const workerPreviewDisplayUrl = buildWorkerPreviewUrl(selectedWidgetId, { forDisplay: true });
|
|
2019
2137
|
dynamicWorkerPreviewUrl = workerPreviewUrl;
|
|
2020
2138
|
directPreviewUrl = workerPreviewDisplayUrl;
|
|
2021
|
-
console.log('[WidgetDetails] refreshPreview: initialized worker preview URL');
|
|
2139
|
+
// console.log('[WidgetDetails] refreshPreview: initialized worker preview URL');
|
|
2022
2140
|
}
|
|
2023
2141
|
|
|
2024
2142
|
// After publish (or any time the CDN artifact may have changed), edit/embed steps must
|
|
@@ -2044,7 +2162,7 @@
|
|
|
2044
2162
|
// If not reachable and we have retry budget, retry after a short delay (CDN propagation).
|
|
2045
2163
|
if (withRetry && retryCount < 3) {
|
|
2046
2164
|
const delay = (retryCount + 1) * 2000;
|
|
2047
|
-
console.log(`[WidgetDetails] Published artifact not reachable yet, retrying in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
|
2165
|
+
// console.log(`[WidgetDetails] Published artifact not reachable yet, retrying in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
|
2048
2166
|
setTimeout(() => refreshPreviewIframe({ withRetry: true, _retryCount: retryCount + 1 }), delay);
|
|
2049
2167
|
return;
|
|
2050
2168
|
}
|
|
@@ -2073,14 +2191,14 @@
|
|
|
2073
2191
|
if (probeResult === 'not-found') {
|
|
2074
2192
|
if (withRetry && retryCount < 3) {
|
|
2075
2193
|
const delay = (retryCount + 1) * 2000;
|
|
2076
|
-
console.log(`[WidgetDetails] Preview not found, retrying in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
|
2194
|
+
// console.log(`[WidgetDetails] Preview not found, retrying in ${delay}ms (attempt ${retryCount + 1}/3)`);
|
|
2077
2195
|
previewLoading = true;
|
|
2078
2196
|
setTimeout(() => refreshPreviewIframe({ withRetry: true, _retryCount: retryCount + 1 }), delay);
|
|
2079
2197
|
return;
|
|
2080
2198
|
}
|
|
2081
2199
|
// Worker cache miss after codegen — compile from GitLab repo
|
|
2082
2200
|
if (lastCommitId && !isGeneratingCode && !shouldDeferPreviewNetworkWork()) {
|
|
2083
|
-
console.log('[WidgetDetails] Preview not on Worker after retries — trying build-from-repo');
|
|
2201
|
+
// console.log('[WidgetDetails] Preview not on Worker after retries — trying build-from-repo');
|
|
2084
2202
|
await triggerBuildFromRepo();
|
|
2085
2203
|
if (iframeSrc) return;
|
|
2086
2204
|
}
|
|
@@ -2196,9 +2314,16 @@
|
|
|
2196
2314
|
if (!previewWidgetReady) {
|
|
2197
2315
|
if (previewReadyFallbackTimeout) clearTimeout(previewReadyFallbackTimeout);
|
|
2198
2316
|
previewReadyFallbackTimeout = setTimeout(() => {
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2317
|
+
if (previewWidgetReady) return;
|
|
2318
|
+
console.warn('[WidgetDetails] Create step: iframe loaded but widget did not signal ready');
|
|
2319
|
+
previewLoading = false;
|
|
2320
|
+
previewHydrating = false;
|
|
2321
|
+
previewHasRuntimeError = true;
|
|
2322
|
+
previewRuntimeErrorStatus = 500;
|
|
2323
|
+
previewError =
|
|
2324
|
+
'Preview loaded but the widget did not start. Open in a new tab or tap Rebuild. If the new tab is also blank, the generated code likely failed at runtime.';
|
|
2325
|
+
notifyPreviewCompileErrorChanged();
|
|
2326
|
+
}, 4000);
|
|
2202
2327
|
}
|
|
2203
2328
|
scheduleFitPreviewToArea();
|
|
2204
2329
|
}
|
|
@@ -2376,8 +2501,13 @@
|
|
|
2376
2501
|
return Math.max(DETAILS_PANEL_MIN_HEIGHT, Math.min(DETAILS_PANEL_MAX_HEIGHT, available));
|
|
2377
2502
|
}
|
|
2378
2503
|
|
|
2504
|
+
function getDetailsPanelMinWidth(): number {
|
|
2505
|
+
if (previewColumnCollapsed) return DETAILS_PANEL_MIN_WIDTH;
|
|
2506
|
+
return DETAILS_PANEL_MIN_WIDTH + COL_RESIZER_PX + 240;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2379
2509
|
function clampPanelWidth(w: number): number {
|
|
2380
|
-
return Math.max(
|
|
2510
|
+
return Math.max(getDetailsPanelMinWidth(), Math.min(w, DETAILS_PANEL_MAX_WIDTH));
|
|
2381
2511
|
}
|
|
2382
2512
|
|
|
2383
2513
|
function clampPanelHeight(h: number): number {
|
|
@@ -2420,7 +2550,14 @@
|
|
|
2420
2550
|
}
|
|
2421
2551
|
const cascade = panelCascadeIndex * 32;
|
|
2422
2552
|
detailsPanelX = Math.max(8, Math.round((window.innerWidth - detailsPanelWidth) / 2) + cascade);
|
|
2423
|
-
|
|
2553
|
+
const availableTop = detailsPanelTopOffset;
|
|
2554
|
+
detailsPanelY = Math.max(
|
|
2555
|
+
availableTop,
|
|
2556
|
+
Math.round(availableTop + (window.innerHeight - availableTop - detailsPanelHeight) / 2) + cascade,
|
|
2557
|
+
);
|
|
2558
|
+
if (detailsPanelY + detailsPanelHeight > window.innerHeight - 8) {
|
|
2559
|
+
detailsPanelY = Math.max(availableTop, window.innerHeight - detailsPanelHeight - 8);
|
|
2560
|
+
}
|
|
2424
2561
|
}
|
|
2425
2562
|
|
|
2426
2563
|
/** Keep the panel on-screen after a browser resize. Does not reset to default 600×800. */
|
|
@@ -2446,8 +2583,7 @@
|
|
|
2446
2583
|
}
|
|
2447
2584
|
|
|
2448
2585
|
/**
|
|
2449
|
-
*
|
|
2450
|
-
* shape Props panel. Can hang halfway outside the viewport.
|
|
2586
|
+
* Center Widget Details in the canvas viewport (X and Y), clamped on-screen.
|
|
2451
2587
|
*/
|
|
2452
2588
|
export function positionBesideShape(shapeRect: {
|
|
2453
2589
|
left: number;
|
|
@@ -2464,24 +2600,28 @@
|
|
|
2464
2600
|
_hasBeenOpenedOnce = true;
|
|
2465
2601
|
if (!shapeRect) {
|
|
2466
2602
|
centerDetailsPanel();
|
|
2467
|
-
console.log('[WidgetDetails] No shape rect — centered floating panel', detailsPanelWidth, detailsPanelHeight);
|
|
2603
|
+
// console.log('[WidgetDetails] No shape rect — centered floating panel', detailsPanelWidth, detailsPanelHeight);
|
|
2468
2604
|
return;
|
|
2469
2605
|
}
|
|
2470
2606
|
|
|
2471
|
-
|
|
2472
|
-
detailsPanelWidth = clampPanelWidth(DETAILS_PANEL_MAX_WIDTH);
|
|
2607
|
+
detailsPanelWidth = clampPanelWidth(DETAILS_PANEL_DEFAULT_WIDTH);
|
|
2473
2608
|
detailsPanelHeight = clampPanelHeight(DETAILS_PANEL_MAX_HEIGHT);
|
|
2474
2609
|
|
|
2475
|
-
const
|
|
2476
|
-
const
|
|
2610
|
+
const viewportLeft = shapeRect.viewportLeft ?? 0;
|
|
2611
|
+
const viewportWidth = shapeRect.viewportWidth || window.innerWidth;
|
|
2612
|
+
const viewportTop = shapeRect.viewportTop ?? detailsPanelTopOffset;
|
|
2613
|
+
const viewportHeight = shapeRect.viewportHeight || (window.innerHeight - viewportTop);
|
|
2614
|
+
|
|
2615
|
+
const x = Math.round(viewportLeft + (viewportWidth - detailsPanelWidth) / 2);
|
|
2616
|
+
const y = Math.round(viewportTop + Math.max(0, (viewportHeight - detailsPanelHeight) / 2));
|
|
2617
|
+
const pos = clampDetailsPanelPosition(x, y);
|
|
2477
2618
|
detailsPanelX = pos.x;
|
|
2478
2619
|
detailsPanelY = pos.y;
|
|
2479
|
-
console.log('[WidgetDetails]
|
|
2620
|
+
console.log('[WidgetDetails] Centered in canvas viewport', {
|
|
2480
2621
|
x: Math.round(detailsPanelX),
|
|
2481
2622
|
y: Math.round(detailsPanelY),
|
|
2482
2623
|
w: detailsPanelWidth,
|
|
2483
2624
|
h: detailsPanelHeight,
|
|
2484
|
-
shapeLeft: Math.round(shapeRect.left),
|
|
2485
2625
|
});
|
|
2486
2626
|
}
|
|
2487
2627
|
|
|
@@ -2546,7 +2686,7 @@
|
|
|
2546
2686
|
|
|
2547
2687
|
if (selectedWidgetId) {
|
|
2548
2688
|
if (iframeSrc && previewLoadedForWidgetId === selectedWidgetId) {
|
|
2549
|
-
console.log('[WidgetDetails] Reopened with existing preview, no reload needed');
|
|
2689
|
+
// console.log('[WidgetDetails] Reopened with existing preview, no reload needed');
|
|
2550
2690
|
return;
|
|
2551
2691
|
}
|
|
2552
2692
|
loadWidget(selectedWidgetId);
|
|
@@ -2570,7 +2710,7 @@
|
|
|
2570
2710
|
function handleCloseButtonClick(e: MouseEvent) {
|
|
2571
2711
|
e.preventDefault();
|
|
2572
2712
|
e.stopPropagation();
|
|
2573
|
-
console.log('[WidgetDetails] Close button clicked');
|
|
2713
|
+
// console.log('[WidgetDetails] Close button clicked');
|
|
2574
2714
|
closeWidgetDetails();
|
|
2575
2715
|
}
|
|
2576
2716
|
|
|
@@ -2620,7 +2760,7 @@
|
|
|
2620
2760
|
if (!isResizingDetails) return;
|
|
2621
2761
|
const deltaX = e.clientX - detailsResizeStartX;
|
|
2622
2762
|
const deltaY = e.clientY - detailsResizeStartY;
|
|
2623
|
-
const minW =
|
|
2763
|
+
const minW = getDetailsPanelMinWidth();
|
|
2624
2764
|
const minH = DETAILS_PANEL_MIN_HEIGHT;
|
|
2625
2765
|
const maxRight = window.innerWidth - 8;
|
|
2626
2766
|
const maxBottom = window.innerHeight - 8;
|
|
@@ -2692,23 +2832,83 @@
|
|
|
2692
2832
|
};
|
|
2693
2833
|
}
|
|
2694
2834
|
|
|
2835
|
+
function updateHeaderNameMaxWidth() {
|
|
2836
|
+
if (!widgetDetailsNameCtEl) return;
|
|
2837
|
+
const nameRect = widgetDetailsNameCtEl.getBoundingClientRect();
|
|
2838
|
+
const rightEl = showCompositionSteps && widgetDetailsStepsRowEl
|
|
2839
|
+
? widgetDetailsStepsRowEl
|
|
2840
|
+
: widgetDetailsDebugButtonsEl;
|
|
2841
|
+
if (!rightEl) return;
|
|
2842
|
+
const rightRect = rightEl.getBoundingClientRect();
|
|
2843
|
+
const available = Math.floor(rightRect.left - nameRect.left - HEADER_ELEMENTS_GAP_PX);
|
|
2844
|
+
const next = Math.max(HEADER_NAME_MIN_WIDTH_PX, available);
|
|
2845
|
+
if (next !== headerNameMaxWidthPx) {
|
|
2846
|
+
headerNameMaxWidthPx = next;
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
function trackHeaderNameMaxWidth(node: HTMLElement) {
|
|
2851
|
+
detailsDragBarEl = node;
|
|
2852
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
2853
|
+
requestAnimationFrame(updateHeaderNameMaxWidth);
|
|
2854
|
+
});
|
|
2855
|
+
resizeObserver.observe(node);
|
|
2856
|
+
requestAnimationFrame(updateHeaderNameMaxWidth);
|
|
2857
|
+
return {
|
|
2858
|
+
destroy() {
|
|
2859
|
+
resizeObserver.disconnect();
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2695
2864
|
function startDetailsDrag(e: PointerEvent) {
|
|
2696
2865
|
const target = e.target as HTMLElement | null;
|
|
2697
2866
|
if (target?.closest('.step-button, .widget-details-close-bt, .widget-details-debug-buttons, button, a, input, select, textarea')) {
|
|
2698
2867
|
return;
|
|
2699
2868
|
}
|
|
2700
|
-
handlePanelFocusRequest();
|
|
2701
|
-
e.preventDefault();
|
|
2702
|
-
e.stopPropagation();
|
|
2703
|
-
isDraggingDetails = true;
|
|
2704
2869
|
detailsDragStartX = e.clientX;
|
|
2705
2870
|
detailsDragStartY = e.clientY;
|
|
2706
2871
|
detailsInitialX = detailsPanelX < 0 ? 0 : detailsPanelX;
|
|
2707
2872
|
detailsInitialY = detailsPanelY < 0 ? detailsPanelTopOffset : detailsPanelY;
|
|
2873
|
+
detailsDragBarEl = e.currentTarget as HTMLElement | null;
|
|
2874
|
+
const fromName = !!target?.closest('.widget-details-name-ct');
|
|
2875
|
+
if (fromName) {
|
|
2876
|
+
pendingDetailsDrag = true;
|
|
2877
|
+
window.addEventListener('pointermove', onPendingDetailsDrag);
|
|
2878
|
+
window.addEventListener('pointerup', cancelPendingDetailsDrag);
|
|
2879
|
+
window.addEventListener('pointercancel', cancelPendingDetailsDrag);
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
beginDetailsDrag(e);
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
function onPendingDetailsDrag(e: PointerEvent) {
|
|
2886
|
+
if (!pendingDetailsDrag) return;
|
|
2887
|
+
const moved = Math.hypot(e.clientX - detailsDragStartX, e.clientY - detailsDragStartY);
|
|
2888
|
+
if (moved < DETAILS_DRAG_THRESHOLD_PX) return;
|
|
2889
|
+
pendingDetailsDrag = false;
|
|
2890
|
+
window.removeEventListener('pointermove', onPendingDetailsDrag);
|
|
2891
|
+
window.removeEventListener('pointerup', cancelPendingDetailsDrag);
|
|
2892
|
+
window.removeEventListener('pointercancel', cancelPendingDetailsDrag);
|
|
2893
|
+
beginDetailsDrag(e);
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
function cancelPendingDetailsDrag() {
|
|
2897
|
+
pendingDetailsDrag = false;
|
|
2898
|
+
window.removeEventListener('pointermove', onPendingDetailsDrag);
|
|
2899
|
+
window.removeEventListener('pointerup', cancelPendingDetailsDrag);
|
|
2900
|
+
window.removeEventListener('pointercancel', cancelPendingDetailsDrag);
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
function beginDetailsDrag(e: PointerEvent) {
|
|
2904
|
+
handlePanelFocusRequest();
|
|
2905
|
+
e.preventDefault();
|
|
2906
|
+
e.stopPropagation();
|
|
2907
|
+
isDraggingDetails = true;
|
|
2708
2908
|
document.body.style.cursor = 'grabbing';
|
|
2709
2909
|
document.body.style.userSelect = 'none';
|
|
2710
2910
|
try {
|
|
2711
|
-
|
|
2911
|
+
detailsDragBarEl?.setPointerCapture?.(e.pointerId);
|
|
2712
2912
|
} catch {
|
|
2713
2913
|
/* ignore capture failures */
|
|
2714
2914
|
}
|
|
@@ -2735,6 +2935,7 @@
|
|
|
2735
2935
|
}
|
|
2736
2936
|
|
|
2737
2937
|
function stopDetailsDrag() {
|
|
2938
|
+
cancelPendingDetailsDrag();
|
|
2738
2939
|
if (!isDraggingDetails) return;
|
|
2739
2940
|
isDraggingDetails = false;
|
|
2740
2941
|
document.body.style.cursor = '';
|
|
@@ -2883,7 +3084,7 @@
|
|
|
2883
3084
|
if (currentToken) setWsAuthToken(currentToken);
|
|
2884
3085
|
const userId = userSession?.user?.id;
|
|
2885
3086
|
if (userId) {
|
|
2886
|
-
console.log('[WidgetDetails] Connecting WebSocket for user events');
|
|
3087
|
+
// console.log('[WidgetDetails] Connecting WebSocket for user events');
|
|
2887
3088
|
connectWebSocket(userId);
|
|
2888
3089
|
}
|
|
2889
3090
|
}
|
|
@@ -2891,17 +3092,18 @@
|
|
|
2891
3092
|
let lastWsPreviewSignature: string | null = null;
|
|
2892
3093
|
|
|
2893
3094
|
async function applyWorkerPreviewFromEvent(workerUrl: string, buildTimeMs?: number | null): Promise<void> {
|
|
3095
|
+
if (pinnedPublishedPreviewUrl) return;
|
|
2894
3096
|
const fetchUrl = toWorkerPreviewFetchUrl(workerUrl);
|
|
2895
3097
|
const signature = `${fetchUrl}:${buildTimeMs ?? 'na'}:${selectedWidgetId ?? ''}`;
|
|
2896
3098
|
if (signature === lastWsPreviewSignature) return;
|
|
2897
3099
|
lastWsPreviewSignature = signature;
|
|
2898
3100
|
|
|
2899
|
-
console.log('[WidgetDetails] Worker preview ready — force reloading iframe', {
|
|
2900
|
-
widgetId: selectedWidgetId,
|
|
2901
|
-
previewUrl: fetchUrl,
|
|
2902
|
-
displayUrl: toWorkerPreviewDisplayUrl(fetchUrl),
|
|
2903
|
-
buildTimeMs,
|
|
2904
|
-
});
|
|
3101
|
+
// console.log('[WidgetDetails] Worker preview ready — force reloading iframe', {
|
|
3102
|
+
// widgetId: selectedWidgetId,
|
|
3103
|
+
// previewUrl: fetchUrl,
|
|
3104
|
+
// displayUrl: toWorkerPreviewDisplayUrl(fetchUrl),
|
|
3105
|
+
// buildTimeMs,
|
|
3106
|
+
// });
|
|
2905
3107
|
|
|
2906
3108
|
dynamicWorkerPreviewUrl = fetchUrl;
|
|
2907
3109
|
directPreviewUrl = toWorkerPreviewDisplayUrl(fetchUrl);
|
|
@@ -2947,25 +3149,29 @@
|
|
|
2947
3149
|
// Worker-built widgets signal readiness via widgetic:ready (not sveltekit-hydration-complete)
|
|
2948
3150
|
const handleWidgeticReady = (event: MessageEvent) => {
|
|
2949
3151
|
if (event.data?.type !== 'widgetic:ready') return;
|
|
2950
|
-
|
|
3152
|
+
const activeWin = previewIframe?.contentWindow;
|
|
3153
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
3154
|
+
// console.log('[WidgetDetails] widgetic:ready received — applying queued composition updates');
|
|
2951
3155
|
markPreviewWidgetReady();
|
|
2952
3156
|
};
|
|
2953
3157
|
window.addEventListener('message', handleWidgeticReady);
|
|
2954
3158
|
|
|
2955
3159
|
// Listen for SvelteKit hydration completion signal (legacy VM / published SvelteKit artifacts)
|
|
2956
3160
|
const handleHydrationSignal = (event: MessageEvent) => {
|
|
2957
|
-
if (event.data?.type
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3161
|
+
if (event.data?.type !== 'sveltekit-hydration-complete') return;
|
|
3162
|
+
const activeWin = previewIframe?.contentWindow;
|
|
3163
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
3164
|
+
previewHydrating = false;
|
|
3165
|
+
if (hydrationSafetyTimeout) { clearTimeout(hydrationSafetyTimeout); hydrationSafetyTimeout = null; }
|
|
3166
|
+
markPreviewWidgetReady();
|
|
2963
3167
|
};
|
|
2964
3168
|
window.addEventListener('message', handleHydrationSignal);
|
|
2965
3169
|
|
|
2966
3170
|
// Listen for runtime error signals from the preview iframe
|
|
2967
3171
|
const handleIframeRuntimeError = (event: MessageEvent) => {
|
|
2968
3172
|
if (event.data?.type !== 'sveltekit-runtime-error') return;
|
|
3173
|
+
const activeWin = previewIframe?.contentWindow;
|
|
3174
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
2969
3175
|
|
|
2970
3176
|
const runtimeMsg = String(event.data?.message || event.data?.error || '').trim();
|
|
2971
3177
|
const runtimeSource = event.data?.source ? String(event.data.source) : '';
|
|
@@ -2976,16 +3182,10 @@
|
|
|
2976
3182
|
console.warn('[WidgetDetails] Ignoring runtime error during code generation:', runtimeMsg);
|
|
2977
3183
|
return;
|
|
2978
3184
|
}
|
|
2979
|
-
if (isCodegenPreviewFresh()) {
|
|
3185
|
+
if (isCodegenPreviewFresh() && !looksLikeHardCompileFailure(runtimeMsg)) {
|
|
2980
3186
|
console.warn('[WidgetDetails] Ignoring runtime error during codegen preview window:', runtimeMsg);
|
|
2981
3187
|
return;
|
|
2982
3188
|
}
|
|
2983
|
-
// Stale iframe (previous build) must not poison the active preview
|
|
2984
|
-
const activeWin = previewIframe?.contentWindow;
|
|
2985
|
-
if (activeWin && event.source && event.source !== activeWin) {
|
|
2986
|
-
console.warn('[WidgetDetails] Ignoring runtime error from inactive iframe');
|
|
2987
|
-
return;
|
|
2988
|
-
}
|
|
2989
3189
|
if (isBenignPreviewRuntimeError(runtimeMsg)) {
|
|
2990
3190
|
console.warn('[WidgetDetails] Ignoring benign preview runtime error:', runtimeMsg);
|
|
2991
3191
|
return;
|
|
@@ -3036,20 +3236,21 @@
|
|
|
3036
3236
|
|
|
3037
3237
|
// Listen for expired preview token signal
|
|
3038
3238
|
const handleTokenExpired = async (event: MessageEvent) => {
|
|
3039
|
-
if (event.data?.type
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3239
|
+
if (event.data?.type !== 'preview-token-expired') return;
|
|
3240
|
+
const activeWin = previewIframe?.contentWindow;
|
|
3241
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
3242
|
+
directPreviewUrl = null;
|
|
3243
|
+
lastPreviewUrlFetchTime = 0;
|
|
3244
|
+
try {
|
|
3245
|
+
const freshUrl = await fetchDirectPreviewUrl();
|
|
3246
|
+
if (freshUrl) {
|
|
3247
|
+
const cacheBuster = Date.now();
|
|
3248
|
+
const url = new URL(freshUrl);
|
|
3249
|
+
url.searchParams.set('_t', cacheBuster.toString());
|
|
3250
|
+
iframeSrc = url.toString();
|
|
3251
|
+
previewCacheBuster = cacheBuster;
|
|
3252
|
+
}
|
|
3253
|
+
} catch (err) { console.error('Error refreshing preview token:', err); }
|
|
3053
3254
|
};
|
|
3054
3255
|
window.addEventListener('message', handleTokenExpired);
|
|
3055
3256
|
|
|
@@ -3059,12 +3260,14 @@
|
|
|
3059
3260
|
// "Rebuild" whenever we lose the L1/L2 cache. (Reset happens on widget switch.)
|
|
3060
3261
|
const handleWidgetNotFound = async (event: MessageEvent) => {
|
|
3061
3262
|
if (event.data?.type !== 'widgetic:widget-not-found') return;
|
|
3263
|
+
const activeWin = previewIframe?.contentWindow;
|
|
3264
|
+
if (!activeWin || event.source !== activeWin) return;
|
|
3062
3265
|
if (isCodegenPreviewFresh()) {
|
|
3063
|
-
console.log('[WidgetDetails] Ignoring widget-not-found during codegen preview window');
|
|
3266
|
+
// console.log('[WidgetDetails] Ignoring widget-not-found during codegen preview window');
|
|
3064
3267
|
return;
|
|
3065
3268
|
}
|
|
3066
3269
|
if (dwLoadTimeoutHandle) { clearTimeout(dwLoadTimeoutHandle); dwLoadTimeoutHandle = null; }
|
|
3067
|
-
console.log('[WidgetDetails] Worker reports widget not found — checking if repo has code');
|
|
3270
|
+
// console.log('[WidgetDetails] Worker reports widget not found — checking if repo has code');
|
|
3068
3271
|
dynamicWorkerPreviewUrl = null;
|
|
3069
3272
|
directPreviewUrl = null;
|
|
3070
3273
|
iframeSrc = null;
|
|
@@ -3075,7 +3278,7 @@
|
|
|
3075
3278
|
const hasRepo = !!currentRepositoryId;
|
|
3076
3279
|
if (hasRepo && capturedWidgetId && widgetNotFoundAutoRebuildAttempts === 0) {
|
|
3077
3280
|
widgetNotFoundAutoRebuildAttempts = 1;
|
|
3078
|
-
console.log('[WidgetDetails] Widget missing from Worker — auto-triggering build-from-repo');
|
|
3281
|
+
// console.log('[WidgetDetails] Widget missing from Worker — auto-triggering build-from-repo');
|
|
3079
3282
|
previewLoading = true;
|
|
3080
3283
|
try {
|
|
3081
3284
|
await triggerBuildFromRepo({ force: true });
|
|
@@ -3105,6 +3308,7 @@
|
|
|
3105
3308
|
if (contentContainerEl) {
|
|
3106
3309
|
hasScrollbar = contentContainerEl.scrollHeight > contentContainerEl.clientHeight;
|
|
3107
3310
|
}
|
|
3311
|
+
updateHeaderNameMaxWidth();
|
|
3108
3312
|
});
|
|
3109
3313
|
|
|
3110
3314
|
onDestroy(() => {
|
|
@@ -3133,13 +3337,13 @@
|
|
|
3133
3337
|
onclick={handleCloseButtonClick}
|
|
3134
3338
|
onmousedown={(e) => e.stopPropagation()}
|
|
3135
3339
|
onpointerdown={(e) => e.stopPropagation()}
|
|
3136
|
-
class="widget-details-close-bt pointer-events-auto absolute -top-
|
|
3340
|
+
class="widget-details-close-bt pointer-events-auto absolute -top-3 -right-3 z-40 w-7 h-7 flex items-center justify-center rounded-full bg-white border border-gray-300 shadow-md hover:bg-red-50 hover:border-red-300 hover:text-red-600 text-gray-500 cursor-pointer transition-colors text-sm"
|
|
3137
3341
|
title="Close widget details"
|
|
3138
3342
|
>
|
|
3139
3343
|
✕
|
|
3140
3344
|
</button>
|
|
3141
3345
|
<div
|
|
3142
|
-
|
|
3346
|
+
class="widget-details-floating-panel pointer-events-auto relative flex flex-col h-full w-full min-w-[480px]
|
|
3143
3347
|
{fillViewport
|
|
3144
3348
|
? 'bg-white rounded-none border-x border-b border-t-0 ring-0 shadow-none overflow-hidden'
|
|
3145
3349
|
: 'bg-white/95 backdrop-blur-sm shadow-2xl rounded-xl border overflow-hidden'}
|
|
@@ -3151,23 +3355,44 @@
|
|
|
3151
3355
|
<!-- Widget Details Top Bar — title, steps, and close on one row -->
|
|
3152
3356
|
<div class="widget-details-header-ct flex flex-col shrink-0 bg-gray-100 border-b border-gray-200">
|
|
3153
3357
|
<div
|
|
3154
|
-
class="widget-details-drag-bar relative flex items-center
|
|
3358
|
+
class="widget-details-drag-bar relative flex items-center py-1.5 cursor-grab active:cursor-grabbing select-none min-h-[40px] touch-none flex-nowrap min-w-0"
|
|
3359
|
+
style="--header-elements-gap: {HEADER_ELEMENTS_GAP_PX}px; gap: {HEADER_ELEMENTS_GAP_PX}px; padding-left: {HEADER_PADDING_PX}px; padding-right: {HEADER_PADDING_PX}px;"
|
|
3360
|
+
bind:this={detailsDragBarEl}
|
|
3361
|
+
use:trackHeaderNameMaxWidth
|
|
3155
3362
|
onpointerdown={startDetailsDrag}
|
|
3156
3363
|
>
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3364
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
3365
|
+
<div
|
|
3366
|
+
class="widget-details-name-ct relative z-[1] min-w-0 w-fit overflow-hidden"
|
|
3367
|
+
bind:this={widgetDetailsNameCtEl}
|
|
3368
|
+
style="min-width: {HEADER_NAME_MIN_WIDTH_PX}px; max-width: {headerNameMaxWidthPx}px;"
|
|
3160
3369
|
>
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3370
|
+
<EditableName
|
|
3371
|
+
class="widget-details-name min-w-0 truncate text-sm font-bold text-gray-800"
|
|
3372
|
+
name={selectedWidget?.name || ''}
|
|
3373
|
+
placeholder={isDraftConvertPanel ? 'Widget Draft' : 'Widget'}
|
|
3374
|
+
tooltipText="Double-click to rename"
|
|
3375
|
+
on:rename={(e) => {
|
|
3376
|
+
if (!selectedWidgetId) return;
|
|
3377
|
+
dispatch('widgetRename', { widgetId: selectedWidgetId, newName: e.detail.newName });
|
|
3378
|
+
}}
|
|
3379
|
+
/>
|
|
3380
|
+
</div>
|
|
3381
|
+
{#if showCompositionSteps}
|
|
3382
|
+
<div
|
|
3383
|
+
class="widget-details-step-indicator-row pointer-events-none absolute left-1/2 top-1/2 z-0 flex -translate-x-1/2 -translate-y-1/2 justify-center"
|
|
3384
|
+
bind:this={widgetDetailsStepsRowEl}
|
|
3385
|
+
>
|
|
3386
|
+
<div
|
|
3387
|
+
class="widget-details-step-indicator pointer-events-auto flex items-center flex-nowrap justify-center whitespace-nowrap"
|
|
3388
|
+
style="gap: {HEADER_ELEMENTS_GAP_PX}px;"
|
|
3389
|
+
>
|
|
3390
|
+
<HoverTooltip text="Create widget code" class="inline-flex shrink-0">
|
|
3166
3391
|
<!-- svelte-ignore a11y_consider_explicit_label -->
|
|
3167
3392
|
<button
|
|
3168
3393
|
type="button"
|
|
3169
3394
|
onclick={() => goToStep('create')}
|
|
3170
|
-
class="step-button step-button-create flex items-center gap-
|
|
3395
|
+
class="step-button step-button-create flex items-center gap-0.5 px-1 py-0.5 rounded-md text-xs font-medium transition-all
|
|
3171
3396
|
{currentStep === 'create'
|
|
3172
3397
|
? 'bg-blue-100 text-blue-700 border border-blue-300 cursor-pointer'
|
|
3173
3398
|
: 'text-gray-600 hover:bg-gray-200 border border-transparent cursor-pointer'}"
|
|
@@ -3175,15 +3400,16 @@
|
|
|
3175
3400
|
<span class="step-number inline-flex items-center justify-center w-5 h-5 rounded-full text-[11px] font-bold leading-none {currentStep === 'create' ? 'bg-blue-600 text-white' : 'bg-gray-300 text-gray-700'}">1</span>
|
|
3176
3401
|
<span class="step-label">Create</span>
|
|
3177
3402
|
</button>
|
|
3178
|
-
|
|
3403
|
+
</HoverTooltip>
|
|
3404
|
+
<span class="step-connector text-sm font-semibold leading-none {canEditStep ? 'text-gray-500' : 'text-gray-300'}" aria-hidden="true">→</span>
|
|
3405
|
+
<HoverTooltip text={canEditStep ? 'Edit composition' : 'Publish the widget to edit composition'} class="inline-flex shrink-0">
|
|
3179
3406
|
<!-- svelte-ignore a11y_consider_explicit_label -->
|
|
3180
3407
|
<button
|
|
3181
3408
|
type="button"
|
|
3182
3409
|
onclick={() => goToStep('edit')}
|
|
3183
3410
|
tabindex={canEditStep ? 0 : -1}
|
|
3184
3411
|
aria-disabled={!canEditStep}
|
|
3185
|
-
|
|
3186
|
-
class="step-button step-button-edit flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium transition-all
|
|
3412
|
+
class="step-button step-button-edit flex items-center gap-0.5 px-1 py-0.5 rounded-md text-xs font-medium transition-all
|
|
3187
3413
|
{currentStep === 'edit'
|
|
3188
3414
|
? 'bg-blue-100 text-blue-700 border border-blue-300 cursor-pointer'
|
|
3189
3415
|
: canEditStep
|
|
@@ -3193,15 +3419,16 @@
|
|
|
3193
3419
|
<span class="step-number inline-flex items-center justify-center w-5 h-5 rounded-full text-[11px] font-bold leading-none {currentStep === 'edit' ? 'bg-blue-600 text-white' : canEditStep ? 'bg-gray-300 text-gray-700' : 'bg-gray-200 text-gray-400'}">2</span>
|
|
3194
3420
|
<span class="step-label">Edit</span>
|
|
3195
3421
|
</button>
|
|
3196
|
-
|
|
3422
|
+
</HoverTooltip>
|
|
3423
|
+
<span class="step-connector text-sm font-semibold leading-none {canEmbedStep ? 'text-gray-500' : 'text-gray-300'}" aria-hidden="true">→</span>
|
|
3424
|
+
<HoverTooltip text={canEmbedStep ? 'Embed the published widget' : 'Publish the widget to get embed code'} class="inline-flex shrink-0">
|
|
3197
3425
|
<!-- svelte-ignore a11y_consider_explicit_label -->
|
|
3198
3426
|
<button
|
|
3199
3427
|
type="button"
|
|
3200
3428
|
onclick={() => goToStep('embed')}
|
|
3201
3429
|
tabindex={canEmbedStep ? 0 : -1}
|
|
3202
3430
|
aria-disabled={!canEmbedStep}
|
|
3203
|
-
|
|
3204
|
-
class="step-button step-button-embed flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium transition-all
|
|
3431
|
+
class="step-button step-button-embed flex items-center gap-0.5 px-1 py-0.5 rounded-md text-xs font-medium transition-all
|
|
3205
3432
|
{currentStep === 'embed'
|
|
3206
3433
|
? 'bg-blue-100 text-blue-700 border border-blue-300 cursor-pointer'
|
|
3207
3434
|
: canEmbedStep
|
|
@@ -3211,41 +3438,61 @@
|
|
|
3211
3438
|
<span class="step-number inline-flex items-center justify-center w-5 h-5 rounded-full text-[11px] font-bold leading-none {currentStep === 'embed' ? 'bg-blue-600 text-white' : canEmbedStep ? 'bg-gray-300 text-gray-700' : 'bg-gray-200 text-gray-400'}">3</span>
|
|
3212
3439
|
<span class="step-label">Embed</span>
|
|
3213
3440
|
</button>
|
|
3441
|
+
</HoverTooltip>
|
|
3214
3442
|
</div>
|
|
3215
3443
|
</div>
|
|
3444
|
+
{/if}
|
|
3216
3445
|
|
|
3217
|
-
<div
|
|
3446
|
+
<div
|
|
3447
|
+
class="widget-details-debug-buttons relative z-[1] ml-auto flex items-center shrink-0"
|
|
3448
|
+
bind:this={widgetDetailsDebugButtonsEl}
|
|
3449
|
+
>
|
|
3450
|
+
<HoverTooltip text={previewColumnCollapsed ? 'Open live preview' : 'Close live preview'}>
|
|
3218
3451
|
<button
|
|
3219
3452
|
type="button"
|
|
3220
3453
|
onclick={() => previewColumnCollapsed ? expandPreviewColumn() : collapsePreviewColumn()}
|
|
3221
3454
|
onmousedown={(e) => e.stopPropagation()}
|
|
3222
3455
|
onpointerdown={(e) => e.stopPropagation()}
|
|
3223
|
-
|
|
3456
|
+
aria-label={previewColumnCollapsed ? 'Open live preview' : 'Close live preview'}
|
|
3457
|
+
class="widget-details-preview-toggle-bt h-6 w-6 flex items-center justify-center rounded-lg cursor-pointer transition-colors
|
|
3224
3458
|
{previewColumnCollapsed
|
|
3225
3459
|
? 'bg-white border border-gray-300 text-gray-600 hover:bg-gray-100'
|
|
3226
3460
|
: 'bg-blue-50 border border-blue-300 text-blue-700 hover:bg-blue-100'}"
|
|
3227
|
-
title={previewColumnCollapsed ? 'Open live preview column' : 'Close live preview column'}
|
|
3228
3461
|
>
|
|
3229
|
-
{previewColumnCollapsed
|
|
3462
|
+
{#if previewColumnCollapsed}
|
|
3463
|
+
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
3464
|
+
<rect x="3" y="4" width="18" height="16" rx="2"/>
|
|
3465
|
+
<path d="M14 4v16"/>
|
|
3466
|
+
<path d="M17 9l3 3-3 3"/>
|
|
3467
|
+
</svg>
|
|
3468
|
+
{:else}
|
|
3469
|
+
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
3470
|
+
<rect x="3" y="4" width="18" height="16" rx="2"/>
|
|
3471
|
+
<path d="M14 4v16"/>
|
|
3472
|
+
<path d="M10 15L7 12l3-3"/>
|
|
3473
|
+
</svg>
|
|
3474
|
+
{/if}
|
|
3230
3475
|
</button>
|
|
3476
|
+
</HoverTooltip>
|
|
3231
3477
|
</div>
|
|
3232
3478
|
</div>
|
|
3233
3479
|
</div>
|
|
3234
3480
|
|
|
3235
3481
|
<!-- Widget Details Content: Two-column layout -->
|
|
3236
|
-
<div class="widget-details-content-wrapper relative m-2.5 min-w-
|
|
3237
|
-
<div class="widget-details-two-col flex h-full min-h-0 min-w-
|
|
3482
|
+
<div class="widget-details-content-wrapper relative m-2.5 min-w-[460px] min-h-0 flex-1 overflow-hidden">
|
|
3483
|
+
<div class="widget-details-two-col flex h-full min-h-0 min-w-[460px] gap-0 overflow-hidden">
|
|
3238
3484
|
|
|
3239
3485
|
<!-- ═══ LEFT COLUMN: Step Content (scrollable) ═══ -->
|
|
3240
3486
|
<div
|
|
3241
|
-
class="widget-details-left-col flex flex-col min-w-
|
|
3487
|
+
class="widget-details-left-col flex flex-col min-w-[460px] min-h-0 overflow-hidden relative"
|
|
3242
3488
|
style="width: {previewColumnCollapsed ? 100 : leftColPercent}%; flex: 0 0 {previewColumnCollapsed ? 100 : leftColPercent}%;"
|
|
3243
3489
|
>
|
|
3244
3490
|
<div class="widget-details-left-border absolute inset-y-0 left-0 right-0 border border-gray-300 rounded-lg pointer-events-none z-10"></div>
|
|
3245
3491
|
|
|
3246
3492
|
{#if selectedWidgetId}
|
|
3493
|
+
<div class="widget-details-left-stack relative z-0 flex flex-col h-full min-h-0 min-w-[460px] overflow-hidden">
|
|
3247
3494
|
<!-- Sticky Widget Info Bar (always visible above scrollable content) -->
|
|
3248
|
-
<div class="widget-info-sticky-bar flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 rounded-t-lg shrink-0 gap-2 min-w-0 z-
|
|
3495
|
+
<div class="widget-info-sticky-bar relative flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 rounded-t-lg shrink-0 gap-2 min-w-0 z-20 overflow-visible">
|
|
3249
3496
|
<div class="widget-info-name flex items-center min-w-0 gap-1 text-sm text-gray-700">
|
|
3250
3497
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
3251
3498
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
@@ -3263,12 +3510,14 @@
|
|
|
3263
3510
|
{:else if saveStatus === 'error'}
|
|
3264
3511
|
<span class="text-[10px] px-1.5 py-0.5 rounded bg-red-100 text-red-700">Save Error</span>
|
|
3265
3512
|
{/if}
|
|
3513
|
+
{#if debugMode}
|
|
3266
3514
|
<span class="text-[10px] text-gray-500">
|
|
3267
3515
|
Commit: <span class="font-mono font-medium text-gray-600" title={lastCommitId || ''}>{lastCommitId ? lastCommitId.substring(0, 8) : '—'}</span>
|
|
3268
3516
|
</span>
|
|
3269
|
-
{#if lastPublishedVersion !== null}
|
|
3270
|
-
<a href="/test-widget?widgetId={selectedWidgetId}&version={lastPublishedVersion}" target="_blank" rel="noopener noreferrer" class="text-[10px] px-1.5 py-0.5 rounded bg-emerald-600 border border-emerald-700 text-white hover:bg-emerald-700 transition-colors whitespace-nowrap cursor-pointer" title="Open published widget v{lastPublishedVersion}">Live: v{lastPublishedVersion} ↗</a>
|
|
3271
3517
|
{/if}
|
|
3518
|
+
<div class="widget-info-version-history-slot relative z-20 shrink-0">
|
|
3519
|
+
<slot name="version-history" />
|
|
3520
|
+
</div>
|
|
3272
3521
|
</div>
|
|
3273
3522
|
</div>
|
|
3274
3523
|
|
|
@@ -3280,23 +3529,34 @@
|
|
|
3280
3529
|
<div class="actions-panel widget-details-actions-panel relative flex flex-col flex-1 min-h-0">
|
|
3281
3530
|
|
|
3282
3531
|
<!-- Keep all steps mounted — switching tabs must not destroy chat / PropsEditor state -->
|
|
3283
|
-
<div class="widget-details-create-step flex flex-col flex-1 min-h-0 overflow-hidden overflow-x-hidden {
|
|
3284
|
-
<div class="widget-details-create-
|
|
3285
|
-
<slot name="code-generation" />
|
|
3532
|
+
<div class="widget-details-create-step flex flex-col flex-1 min-h-0 overflow-hidden overflow-x-hidden {activeWorkflowStep === 'create' ? '' : 'hidden'}">
|
|
3533
|
+
<div class="widget-details-create-models-ct shrink-0 empty:hidden">
|
|
3534
|
+
<slot name="code-generation-models" />
|
|
3535
|
+
</div>
|
|
3536
|
+
<div
|
|
3537
|
+
class="widget-details-create-chat-ct flex flex-col flex-1 min-h-0 overflow-hidden overflow-x-hidden"
|
|
3538
|
+
>
|
|
3539
|
+
<div class="widget-details-create-status-slot shrink-0 empty:hidden">
|
|
3540
|
+
<slot name="code-generation-status" />
|
|
3541
|
+
</div>
|
|
3542
|
+
<div class="widget-details-create-chat-body flex flex-col flex-1 min-h-0 overflow-hidden">
|
|
3543
|
+
<slot name="code-generation" />
|
|
3544
|
+
</div>
|
|
3286
3545
|
</div>
|
|
3287
|
-
<div class="widget-details-create-publish-ct shrink-0
|
|
3546
|
+
<div class="widget-details-create-publish-ct shrink-0 empty:hidden">
|
|
3288
3547
|
<slot name="publish-widget" />
|
|
3289
3548
|
</div>
|
|
3290
3549
|
</div>
|
|
3291
|
-
<div class="widget-details-edit-step flex flex-col
|
|
3550
|
+
<div class="widget-details-edit-step flex flex-col flex-1 min-h-0 overflow-hidden {activeWorkflowStep === 'edit' ? '' : 'hidden'}">
|
|
3292
3551
|
<slot name="composition-editor" />
|
|
3293
3552
|
</div>
|
|
3294
|
-
<div class="widget-details-embed-step flex flex-col gap-2 p-2 {
|
|
3553
|
+
<div class="widget-details-embed-step flex flex-col flex-1 min-h-0 overflow-y-auto overflow-x-hidden scrollbar-thin gap-2 p-2 {activeWorkflowStep === 'embed' ? '' : 'hidden'}">
|
|
3295
3554
|
<slot name="embed-section" />
|
|
3296
3555
|
</div>
|
|
3297
3556
|
|
|
3298
3557
|
</div> <!-- end of actions-panel -->
|
|
3299
3558
|
</div> <!-- end of widget-details-left-content -->
|
|
3559
|
+
</div> <!-- end of widget-details-left-stack -->
|
|
3300
3560
|
{/if}
|
|
3301
3561
|
|
|
3302
3562
|
</div> <!-- end of widget-details-left-col -->
|
|
@@ -3581,14 +3841,38 @@
|
|
|
3581
3841
|
{/if}
|
|
3582
3842
|
|
|
3583
3843
|
<style>
|
|
3584
|
-
.widget-details-
|
|
3585
|
-
|
|
3586
|
-
|
|
3844
|
+
.widget-details-drag-bar button:focus,
|
|
3845
|
+
.widget-details-drag-bar button:focus-visible,
|
|
3846
|
+
.widget-details-drag-bar a:focus,
|
|
3847
|
+
.widget-details-drag-bar a:focus-visible {
|
|
3848
|
+
outline: none;
|
|
3849
|
+
box-shadow: none;
|
|
3850
|
+
}
|
|
3851
|
+
.widget-details-create-models-ct :global(button:focus),
|
|
3852
|
+
.widget-details-create-models-ct :global(button:focus-visible),
|
|
3853
|
+
.widget-details-create-models-ct :global(select:focus),
|
|
3854
|
+
.widget-details-create-models-ct :global(select:focus-visible) {
|
|
3855
|
+
outline: none;
|
|
3856
|
+
box-shadow: none;
|
|
3857
|
+
}
|
|
3858
|
+
.widget-details-create-chat-ct :global(.prompt-chat-messages) {
|
|
3859
|
+
overflow-y: auto;
|
|
3587
3860
|
scrollbar-width: thin;
|
|
3588
|
-
scrollbar-color: rgba(0, 0, 0, 0.
|
|
3861
|
+
scrollbar-color: rgba(0, 0, 0, 0.22) transparent;
|
|
3862
|
+
}
|
|
3863
|
+
.widget-details-create-chat-ct :global(.prompt-chat-messages::-webkit-scrollbar) {
|
|
3864
|
+
width: 6px;
|
|
3865
|
+
background: transparent;
|
|
3866
|
+
}
|
|
3867
|
+
.widget-details-create-chat-ct :global(.prompt-chat-messages::-webkit-scrollbar-track) {
|
|
3868
|
+
background: transparent;
|
|
3869
|
+
}
|
|
3870
|
+
.widget-details-create-chat-ct :global(.prompt-chat-messages::-webkit-scrollbar-thumb) {
|
|
3871
|
+
background: rgba(0, 0, 0, 0.2);
|
|
3872
|
+
border-radius: 4px;
|
|
3589
3873
|
}
|
|
3590
3874
|
.widget-details-left-content::-webkit-scrollbar {
|
|
3591
|
-
width:
|
|
3875
|
+
width: 6px;
|
|
3592
3876
|
background: transparent;
|
|
3593
3877
|
}
|
|
3594
3878
|
.widget-details-left-content::-webkit-scrollbar-track {
|