From 13047a02017e3b6c0f38b4bd9a7a094bf6043c58 Mon Sep 17 00:00:00 2001 From: Sajal Chaplot Date: Thu, 23 Jul 2026 22:18:14 +0530 Subject: [PATCH 1/5] fix(assets): constrain candidates preview height to fit within viewport Preview container now uses a viewport-relative height (60vh capped at 30rem) instead of growing unconstrained with image content. --- templates/assets/app/global.css | 4 - .../assets/app/routes/brand-kits.$id.tsx | 308 ++++++++++-------- ...now-fills-the-full-width-with-a-large-p.md | 6 + 3 files changed, 180 insertions(+), 138 deletions(-) create mode 100644 templates/assets/changelog/2026-07-23-drafts-preview-panel-now-fills-the-full-width-with-a-large-p.md diff --git a/templates/assets/app/global.css b/templates/assets/app/global.css index 49da5b7d73..69dbf005ec 100644 --- a/templates/assets/app/global.css +++ b/templates/assets/app/global.css @@ -207,10 +207,6 @@ grid-template-columns: minmax(0, 1fr) 284px; } - .assets-live-candidates-grid { - grid-template-columns: minmax(0, 1fr) minmax(18rem, 22rem); - } - .assets-brand-kit-settings-grid { grid-template-columns: minmax(0, 1fr) 320px; } diff --git a/templates/assets/app/routes/brand-kits.$id.tsx b/templates/assets/app/routes/brand-kits.$id.tsx index 66e193d6c7..12201265f1 100644 --- a/templates/assets/app/routes/brand-kits.$id.tsx +++ b/templates/assets/app/routes/brand-kits.$id.tsx @@ -1521,6 +1521,7 @@ type LaneGalleryItem = { thumbnail: ReactNode; // i18n-ignore structural preview slot name menu?: ReactNode; primaryActions?: ReactNode; + headerActions?: ReactNode; onToggle?: (checked: boolean) => void; }; @@ -3909,6 +3910,89 @@ export function LiveCandidatesStage({ ); } + function candidateHeaderActions({ + canUseCandidate, + saving, + promoting, + candidateLibraryId, + onSaveCandidate, + onAddToReferences, + onUseCandidate, + onDismiss, + }: { + canUseCandidate: boolean; + saving?: boolean; + promoting?: boolean; + candidateLibraryId?: string | null; + onSaveCandidate?: (folderId: string | null) => void; + onAddToReferences?: () => void; + onUseCandidate?: () => void; + onDismiss: () => void; + }) { + const busy = saving || promoting || dismissing; + const actionLibraryId = candidateLibraryId || libraryId; + const candidateFolders = + foldersByLibraryId[actionLibraryId] ?? + (actionLibraryId === libraryId ? folders : []); + if (!canUseCandidate) { + return ( + + ); + } + return ( +
+ {onUseCandidate ? ( + + ) : null} + onSaveCandidate?.(folderId)} + /> + + +
+ ); + } + function slotItem(slot: VariantSlot): LaneGalleryItem { const isFailed = slot.status === "failed"; const canUseCandidate = slot.status === "ready" && Boolean(slot.assetId); @@ -3953,6 +4037,21 @@ export function LiveCandidatesStage({ slot, }), }), + headerActions: candidateHeaderActions({ + canUseCandidate, + saving, + promoting, + candidateLibraryId: libraryId, + onSaveCandidate: (folderId) => onSave(slot, folderId), + onAddToReferences: () => onMoveToReferences(slot), + onUseCandidate: onUse ? () => onUse(slot) : undefined, + onDismiss: () => + setDismissTarget({ + kind: "slot", + title, + slot, + }), + }), }; } @@ -3997,6 +4096,21 @@ export function LiveCandidatesStage({ asset, }), }), + headerActions: candidateHeaderActions({ + canUseCandidate: true, + saving, + promoting, + candidateLibraryId: asset.libraryId, + onSaveCandidate: (folderId) => onSaveDraft(asset, folderId), + onAddToReferences: () => onMoveDraftToReferences(asset), + onUseCandidate: onUseDraft ? () => onUseDraft(asset) : undefined, + onDismiss: () => + setDismissTarget({ + kind: "asset", + title: assetDisplayTitle(asset), + asset, + }), + }), }; } @@ -4063,13 +4177,12 @@ export function LiveCandidatesStage({
-
-
-

- {t("library.candidates")} -

-
-
+
+

+ {t("library.candidates")} +

+
+ {activeItem?.headerActions}
-
-
-
-
- {activeItem?.onOpen ? ( - - ) : activeItem?.href ? ( - - {activeItem.preview} - - ) : ( - activeItem?.preview - )} -
- {activeItem?.busy ? ( -
- -
- ) : null} +
+
+
{activeItem?.onOpen ? ( - + {activeItem.preview} + ) : activeItem?.href ? ( - - ) : null} -
-
- {items.map((item) => { - const active = item.id === activeItem?.id; - return ( - - ); - })} + + {activeItem.preview} + + ) : ( + activeItem?.preview + )}
-
- +
+
+ {items.map((item) => { + const active = item.id === activeItem?.id; + return ( + + ); + })} +
diff --git a/templates/assets/changelog/2026-07-23-drafts-preview-panel-now-fills-the-full-width-with-a-large-p.md b/templates/assets/changelog/2026-07-23-drafts-preview-panel-now-fills-the-full-width-with-a-large-p.md new file mode 100644 index 0000000000..2427300b1a --- /dev/null +++ b/templates/assets/changelog/2026-07-23-drafts-preview-panel-now-fills-the-full-width-with-a-large-p.md @@ -0,0 +1,6 @@ +--- +type: improved +date: 2026-07-23 +--- + +Drafts preview panel now fills the full width with a large preview area; save, add to references, and dismiss actions moved to the candidates header for all brand kits From 1ea499261c6c0d8c309b1767b3f709f6d2ef4d3b Mon Sep 17 00:00:00 2001 From: Sajal Chaplot Date: Thu, 23 Jul 2026 22:21:58 +0530 Subject: [PATCH 2/5] feat(assets): add open details link to candidates panel header Surfaces the asset detail link in the candidates header alongside Save/Add to References/Dismiss actions. Also removes the now-unused CandidateStatusPill component. --- .../assets/app/routes/brand-kits.$id.tsx | 47 +++++-------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/templates/assets/app/routes/brand-kits.$id.tsx b/templates/assets/app/routes/brand-kits.$id.tsx index 12201265f1..0adea73416 100644 --- a/templates/assets/app/routes/brand-kits.$id.tsx +++ b/templates/assets/app/routes/brand-kits.$id.tsx @@ -4183,6 +4183,19 @@ export function LiveCandidatesStage({
{activeItem?.headerActions} + {activeItem?.href ? ( + + ) : null} - - {label} - - ); -} function VariantPreview({ slot, From d6f8f4635b43fd93ddd51ff1d46f6125f9d0f91b Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Thu, 23 Jul 2026 17:04:45 +0000 Subject: [PATCH 3/5] fix(assets): fix oxfmt formatting --- templates/assets/app/routes/brand-kits.$id.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/assets/app/routes/brand-kits.$id.tsx b/templates/assets/app/routes/brand-kits.$id.tsx index 0adea73416..7e07f5e8e8 100644 --- a/templates/assets/app/routes/brand-kits.$id.tsx +++ b/templates/assets/app/routes/brand-kits.$id.tsx @@ -4276,7 +4276,6 @@ export function LiveCandidatesStage({ ); } - function VariantPreview({ slot, fit = "cover", From cab4f79455ed60aae7e540b819cdf3bbab10dc89 Mon Sep 17 00:00:00 2001 From: "Builder.io" Date: Fri, 24 Jul 2026 11:17:04 +0000 Subject: [PATCH 4/5] fix(assets): prefer preview dialog trigger over navigation in candidates header Reconciles with the AssetPreviewDialog introduced in #2296 so the header's Open details action opens the inline dialog when available, matching the click-through behavior already used on the image and elsewhere in the file. --- templates/assets/app/routes/brand-kits.$id.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/templates/assets/app/routes/brand-kits.$id.tsx b/templates/assets/app/routes/brand-kits.$id.tsx index 7e07f5e8e8..e47406e6c5 100644 --- a/templates/assets/app/routes/brand-kits.$id.tsx +++ b/templates/assets/app/routes/brand-kits.$id.tsx @@ -4183,7 +4183,17 @@ export function LiveCandidatesStage({
{activeItem?.headerActions} - {activeItem?.href ? ( + {activeItem?.onOpen ? ( + + ) : activeItem?.href ? (