diff --git a/src/index.html b/src/index.html
index dcb9db6..e016b5d 100644
--- a/src/index.html
+++ b/src/index.html
@@ -2558,7 +2558,7 @@
syncLayerInputs();
syncDesignerInputs();
updateBodyClasses();
- localStorage.setItem('case-cover-template-maker-autosave', JSON.stringify(state));
+ localStorage.setItem('case-cover-template-maker-autosave', JSON.stringify({ ...state, layers: nonGeneratedLayers() }));
}
function buildSlotControls() {
@@ -2939,6 +2939,16 @@
}
function renderDiscSlots() {
+ for (const layer of state.layers) {
+ if (String(layer.target || '').startsWith('disc-generated-')) {
+ layer._staleGenerated = true;
+ }
+ }
+
+ if (state.templateMode !== 'disc') {
+ state.layers = state.layers.filter(layer => !layer._staleGenerated);
+ }
+
for (const slotDef of discTemplate.slots) {
const designKey = state.discSheet[slotDef.key] || (slotDef.key === 'top' ? 'a' : 'b');
const disc = state.discDesigns[designKey] || state.discDesigns.a;
@@ -2966,8 +2976,12 @@
img.style.objectFit = disc.fit;
img.style.transform =
`translate(-50%, -50%) translate(${disc.x}%, ${disc.y}%) rotate(${disc.rotate}deg) scale(${disc.zoom})`;
+
+ if (state.templateMode === 'disc') syncGeneratedDiscLayers(slotDef, disc, designKey);
}
+ state.layers = state.layers.filter(layer => !layer._staleGenerated);
+
discTemplate.spineStrips.forEach((strip, index) => {
const el = $(`disc-spine-${index + 1}`);
el.style.left = inches(strip.x);
@@ -2989,6 +3003,40 @@
});
}
+ function syncGeneratedDiscLayers(slotDef, design, designKey) {
+ const sourceLayers = Array.isArray(design?.layers) ? design.layers : [];
+ const slotLeft = slotDef.centerX - discTemplate.discD / 2;
+ const slotTop = slotDef.centerY - discTemplate.discD / 2;
+ const baseZ = 2000 + (slotDef.key === 'top' ? 0 : 100);
+
+ sourceLayers.forEach((layer, index) => {
+ const id = `generated-${slotDef.key}-${designKey}-${layer.id || index}`;
+ const existing = state.layers.find(item => item.id === id);
+ const projected = {
+ ...layer,
+ id,
+ name: layer.name || `${design?.name || designKey} layer`,
+ target: `disc-generated-${slotDef.key}`,
+ x: slotLeft + (Number(layer.x) || 0),
+ y: slotTop + (Number(layer.y) || 0),
+ w: Number(layer.w) || 1,
+ h: Number(layer.h) || 1,
+ z: baseZ + index,
+ _generatedDiscLayer: true,
+ _staleGenerated: false
+ };
+ if (existing) {
+ Object.assign(existing, projected);
+ } else {
+ state.layers.push(projected);
+ }
+ });
+ }
+
+ function nonGeneratedLayers() {
+ return state.layers.filter(layer => !layer._generatedDiscLayer);
+ }
+
function renderJewelSlots() {
for (const slotDef of jewelTemplate.slots) {
const insert = state.jewelInserts[slotDef.key];
@@ -3222,7 +3270,8 @@
? layer.target === 'designer-disc'
: layer.target !== 'designer-disc'
);
- if (!visibleLayers.length) {
+ const listedLayers = visibleLayers.filter(layer => !layer._generatedDiscLayer);
+ if (!listedLayers.length) {
const empty = document.createElement('p');
empty.className = 'hint';
empty.textContent = 'No extra layers yet.';
@@ -3230,7 +3279,7 @@
return;
}
- const ordered = [...visibleLayers].sort((a, b) => (b.z || 0) - (a.z || 0));
+ const ordered = [...listedLayers].sort((a, b) => (b.z || 0) - (a.z || 0));
for (const layer of ordered) {
const item = document.createElement('button');
item.type = 'button';
@@ -3790,7 +3839,7 @@
meta: state.meta,
ui: { zoom: state.zoom, showGuides: state.showGuides, showBleed: state.showBleed, showCrops: state.showCrops, printGuides: state.printGuides, printCrops: state.printCrops },
coverTemplate: { preset: state.preset, panelW: state.panelW, trimH: state.trimH, spineW: state.spineW, bleed: state.bleed, safe: state.safe, artworkMode: state.artworkMode, slots: state.slots, combined: state.combined },
- layers: state.layers.filter(l => {
+ layers: nonGeneratedLayers().filter(l => {
const target = String(l.target || '');
return !target.startsWith('disc') && !target.startsWith('jewel');
})
@@ -3804,7 +3853,7 @@
meta: state.meta,
ui: { zoom: state.zoom },
discTemplate: { config: discTemplate, designs: state.discDesigns, sheet: state.discSheet, spineLabels: state.discSpineLabels },
- layers: state.layers.filter(l => String(l.target || '').startsWith('disc'))
+ layers: nonGeneratedLayers().filter(l => String(l.target || '').startsWith('disc'))
};
}
@@ -3815,7 +3864,7 @@
meta: state.meta,
ui: { zoom: state.zoom, showGuides: state.showGuides, printGuides: state.printGuides },
jewelTemplate: { config: jewelTemplate, inserts: state.jewelInserts },
- layers: state.layers.filter(l => String(l.target || '').startsWith('jewel'))
+ layers: nonGeneratedLayers().filter(l => String(l.target || '').startsWith('jewel'))
};
}
@@ -3837,7 +3886,7 @@
coverTemplate: { preset: state.preset, panelW: state.panelW, trimH: state.trimH, spineW: state.spineW, bleed: state.bleed, safe: state.safe, artworkMode: state.artworkMode, slots: state.slots, combined: state.combined },
discTemplate: { config: discTemplate, designs: state.discDesigns, sheet: state.discSheet, discs: state.discs, spineLabels: state.discSpineLabels },
jewelTemplate: { config: jewelTemplate, inserts: state.jewelInserts },
- layers: state.layers,
+ layers: nonGeneratedLayers(),
community: { relays: state.community.relays, query: state.community.query, kind: state.community.kind }
};
}
@@ -4225,7 +4274,10 @@
rows.forEach(row => {
wall.appendChild(buildFeedCard(row, () => {
if (row.mode === 'disc-design') {
- importDiscDesignFromPayload(row.payload, $('importDiscTarget')?.value || state.activeDiscDesign || 'a');
+ const target = state.appMode === 'designer'
+ ? ($('designerImportTarget')?.value || state.activeDiscDesign || 'a')
+ : ($('importDiscTarget')?.value || 'a');
+ importDiscDesignFromPayload(row.payload, target, { openDesigner: state.appMode === 'designer' });
} else {
loadProjectFromText(JSON.stringify(row.payload));
}
@@ -4266,7 +4318,10 @@
rows.slice(0, 60).forEach(row => {
wall.appendChild(buildFeedCard(row, () => {
if (row.mode === 'disc-design') {
- importDiscDesignFromPayload(row.payload, $('importDiscTarget')?.value || state.activeDiscDesign || 'a');
+ const target = state.appMode === 'designer'
+ ? ($('designerImportTarget')?.value || state.activeDiscDesign || 'a')
+ : ($('importDiscTarget')?.value || 'a');
+ importDiscDesignFromPayload(row.payload, target, { openDesigner: state.appMode === 'designer' });
} else {
loadProjectFromText(JSON.stringify(row.payload));
}
@@ -4417,7 +4472,10 @@
rows.slice(0, 40).forEach(row => {
out.appendChild(buildResultCard(row, () => {
if (row.mode === 'disc-design') {
- importDiscDesignFromPayload(row.payload, $('importDiscTarget')?.value || state.activeDiscDesign || 'a');
+ const target = state.appMode === 'designer'
+ ? ($('designerImportTarget')?.value || state.activeDiscDesign || 'a')
+ : ($('importDiscTarget')?.value || 'a');
+ importDiscDesignFromPayload(row.payload, target, { openDesigner: state.appMode === 'designer' });
} else {
loadProjectFromText(JSON.stringify(row.payload));
}
@@ -4449,9 +4507,10 @@
}
}
- function importDiscDesignFromPayload(payload, targetKey) {
+ function importDiscDesignFromPayload(payload, targetKey, options = {}) {
+ const openDesigner = options.openDesigner ?? true;
const key = targetKey || state.activeDiscDesign || 'a';
- persistDesignerLayers(state.activeDiscDesign || 'a');
+ if (state.appMode === 'designer') persistDesignerLayers(state.activeDiscDesign || 'a');
if (payload?.templateMode === 'disc-design' && payload.discDesign) {
const { key: _k, ...design } = payload.discDesign;
const importedLayers = Array.isArray(payload.layers)
@@ -4472,9 +4531,16 @@
const first = Object.values(payload.discDesigns).find(d => d?.src);
if (first) state.discDesigns[key] = { ...state.discDesigns[key], ...first };
}
- state.activeDiscDesign = key;
- state.appMode = 'designer';
- loadDesignerLayers(key);
+ if (openDesigner) {
+ state.activeDiscDesign = key;
+ state.appMode = 'designer';
+ loadDesignerLayers(key);
+ } else {
+ state.templateMode = 'disc';
+ state.appMode = 'template';
+ state.discSheet.top = state.discSheet.top || key;
+ state.discSheet.bottom = state.discSheet.bottom || key;
+ }
syncDiscAssignmentInputs();
syncDesignerInputs();
render();
@@ -4505,6 +4571,18 @@
runNostrSearch();
}
+ function openTemplateDiscDesignNostrSearch() {
+ const target = $('importDiscTarget')?.value || 'a';
+ const designerTarget = $('designerImportTarget');
+ if (designerTarget) designerTarget.value = target;
+ $('nostrType').value = 'disc-design';
+ $('nostrQuery').value = '';
+ $('nostrCategory').value = state.meta.category || '';
+ $('nostrModal').classList.add('open');
+ switchModalTab('Search');
+ runNostrSearch();
+ }
+
function syncModeTabsUI() {
const isDesigner = state.appMode === 'designer';
$('modeTabTemplate').classList.toggle('active', !isDesigner);
@@ -4832,7 +4910,7 @@
try {
const payload = JSON.parse(String(reader.result));
const target = $('importDiscTarget').value || 'a';
- importDiscDesignFromPayload(payload, target);
+ importDiscDesignFromPayload(payload, target, { openDesigner: false });
event.target.value = '';
} catch {
alert('Could not read that file as a disc design.');
@@ -4841,9 +4919,7 @@
reader.readAsText(file);
});
$('searchDiscNostrBtn').addEventListener('click', () => {
- const templateTarget = $('importDiscTarget')?.value;
- if (templateTarget && $('designerImportTarget')) $('designerImportTarget').value = templateTarget;
- openDiscDesignNostrSearch();
+ openTemplateDiscDesignNostrSearch();
});
$('designerNostrLoadBtn').addEventListener('click', openDiscDesignNostrSearch);