diff --git a/templates/assets/app/global.css b/templates/assets/app/global.css index 47561c76a4..3c5e19deb6 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..e47406e6c5 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,154 +4177,103 @@ export function LiveCandidatesStage({
-
-
-

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

-
-
- -
-
-
-
-
-
- {activeItem?.onOpen ? ( - - ) : activeItem?.href ? ( - - {activeItem.preview} - - ) : ( - activeItem?.preview - )} -
- {activeItem?.busy ? ( -
- -
- ) : null} - {activeItem?.onOpen ? ( - - ) : activeItem?.href ? ( - - ) : null} -
-
- {items.map((item) => { - const active = item.id === activeItem?.id; - return ( - - ); - })} -
-
- + +
+ +
+
+
+ {activeItem?.onOpen ? ( + + ) : activeItem?.href ? ( + + {activeItem.preview} + + ) : ( + activeItem?.preview + )} +
+ {activeItem?.busy ? ( +
+ +
+ ) : null} +
+
+ {items.map((item) => { + const active = item.id === activeItem?.id; + return ( + + ); + })} +
@@ -4223,41 +4286,6 @@ export function LiveCandidatesStage({ ); } -function CandidateStatusPill({ status }: { status: string }) { - const t = useT(); - const normalized = status.toLowerCase(); - const label = - normalized === "pending" - ? t("library.generating") - : normalized === "ready" - ? t("library.ready") - : normalized === "failed" - ? t("library.failed") - : normalized === "draft" - ? t("library.draft") - : status; - const className = - normalized === "ready" - ? "border-primary/30 bg-primary/10 text-primary" - : normalized === "failed" - ? "border-destructive/30 bg-destructive/10 text-destructive" - : normalized === "pending" - ? "border-border bg-muted/70 text-muted-foreground" - : "border-border bg-background text-muted-foreground"; - - return ( - - - {label} - - ); -} - function VariantPreview({ slot, fit = "cover", 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