mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 08:40:39 +00:00
Premium publishing: support 'deck' template mode
A user trying to publish a premium slide deck hit "Premium preview not supported for mode 'deck'." — the publish flow couldn't render the watermarked preview because the mode-dispatch in _renderModeToExportCanvas had cases for cover / disc / jewel / customart / slide / pixelart / disc-design but not deck. Fix: - Add a deck branch to _premiumPreviewLongAxisInches that pulls width / height from state.deck.slides[0].slide (matches the customart / slide path: pixels → inches at 96 dpi). - Add a deck branch to _renderModeToExportCanvas that dispatches to a new renderDeckToExportCanvas. - renderDeckToExportCanvas mirrors renderCustomArtToExportCanvas but pulls the slide payload from the deck. Uses the currently- edited slide when deck.editingIndex is set (matches what the user sees while composing); otherwise falls back to slide 1 (the deck-thumbnail convention). composeSlideForDeck applies the deck theme so the preview shows the buyer what they'll actually unlock. Empty decks emit a blank canvas rather than throwing — the publish modal already gates on having content, so this is just a defensive fallback. With this commit every template mode supports premium publishing — including decks — so a creator can charge sats for a slide deck the same way they can for a cover or custom art. Decryption side is mode-agnostic (Premium.decryptPayload just returns the JSON, which loadProjectFromText already routes to the deck builder), so no buyer-side change needed.
This commit is contained in:
1 parent
f957adb99a
commit
8579789ddb
1 file changed
+50
@@ -17846,6 +17846,15 @@
|
||||
const h = (state.customArt?.height || 1080) / 96;
|
||||
return Math.max(w, h);
|
||||
}
|
||||
if (mode === 'deck') {
|
||||
// The preview renders the deck's first slide. Deck slides
|
||||
// default to 1920x1080 = 20x11.25in like customart / slide.
|
||||
const slides = state.deck?.slides || [];
|
||||
const sl = slides[0]?.slide || {};
|
||||
const w = (Number(sl.width) || 1920) / 96;
|
||||
const h = (Number(sl.height) || 1080) / 96;
|
||||
return Math.max(w, h);
|
||||
}
|
||||
// disc-sheet, jewel: letter-sized
|
||||
return 11;
|
||||
}
|
||||
@@ -17857,9 +17866,50 @@
|
||||
if (mode === 'jewel') return renderJewelSheetToExportCanvas(dpi);
|
||||
if (mode === 'customart' || mode === 'slide') return renderCustomArtToExportCanvas(dpi);
|
||||
if (mode === 'pixelart') return renderPixelArtToExportCanvas();
|
||||
if (mode === 'deck') return renderDeckToExportCanvas(dpi);
|
||||
throw new Error(`Premium preview not supported for mode "${mode}".`);
|
||||
}
|
||||
|
||||
// Render the deck's first slide (themed via composeSlideForDeck)
|
||||
// as the premium preview source. This is the slide buyers see
|
||||
// before unlocking — using slide 1 matches the deck-thumbnail
|
||||
// convention. Decks with zero slides produce an empty canvas
|
||||
// rather than throwing so the publish modal can still proceed.
|
||||
async function renderDeckToExportCanvas(dpi) {
|
||||
const deck = state.deck || {};
|
||||
const slides = Array.isArray(deck.slides) ? deck.slides : [];
|
||||
// Prefer the currently-edited slide if the user is mid-edit;
|
||||
// otherwise slide 1.
|
||||
let entry = null;
|
||||
if (deck.editingIndex != null && slides[deck.editingIndex]) {
|
||||
entry = slides[deck.editingIndex];
|
||||
} else if (slides[0]) {
|
||||
entry = slides[0];
|
||||
}
|
||||
if (!entry) {
|
||||
const canvas = document.createElement('canvas');
|
||||
setupExportCanvas(canvas, 20, 11.25, dpi);
|
||||
return canvas;
|
||||
}
|
||||
const composed = composeSlideForDeck(entry, deck.theme || {});
|
||||
const sl = composed.slide || {};
|
||||
const wIn = (Number(sl.width) || 1920) / 96;
|
||||
const hIn = (Number(sl.height) || 1080) / 96;
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = setupExportCanvas(canvas, wIn, hIn, dpi);
|
||||
const bg = sl.background || '#ffffff';
|
||||
if (bg && bg.toLowerCase() !== '#ffffff' && bg.toLowerCase() !== '#fff') {
|
||||
ctx.fillStyle = bg;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
const layers = (composed.layers || [])
|
||||
.filter(l => (l.target === 'canvas' || !l.target) && !l.hidden && !l._generatedDiscLayer)
|
||||
.slice()
|
||||
.sort((a, b) => (a.z || 0) - (b.z || 0));
|
||||
for (const layer of layers) await drawLayerToCanvas(ctx, layer, dpi);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Render the standalone pixel-art design (state.pixelArt frame 0) into
|
||||
// a canvas suitable for the premium watermarked preview. Native pixel
|
||||
// dimensions are tiny (32-128 px), so scale up by the largest integer
|
||||
|
||||
Reference in new issue
Block a user