commit e31c9ea9d6f716f74721ef92139dfed3d77e8d27
parent f2f3e4dd26daabc3eb5db165f9e63832d4dffb63
Author: Hunter
Date: Wed, 4 Feb 2026 16:52:33 -0500
code cleanup (remove export functionality)
Diffstat:
8 files changed, 7 insertions(+), 454 deletions(-)
diff --git a/resources/codemirror-config.js b/resources/codemirror-config.js
@@ -97,7 +97,6 @@ export async function initializeCodeMirror(saveToStorageCallback, updatePreviewC
{key: "Mod-Shift-z", run: redo},
{key: "Mod-o", run: () => { window.loadFile(); return true; }},
{key: "Mod-s", run: () => { window.saveFile(); return true; }},
- {key: "Mod-e", run: () => { window.saveFileWithViewer(); return true; }},
{key: "F1", run: (view) => { toggleLineNumbers(view); return true; }},
{key: "F2", run: (view) => { toggleLineWrapping(view); return true; }},
indentWithTab,
diff --git a/resources/editor.js b/resources/editor.js
@@ -1,5 +1,5 @@
import { saveToStorage } from './storage.js';
-import { saveFile, saveFileWithViewer, loadFile } from './file-operations.js';
+import { saveFile, loadFile } from './file-operations.js';
import { updatePreview, setupPreviewPane } from './preview-manager.js';
import { navigateSpread, toggleFullscreen, initializeSpreadNav, getIsFullscreen } from './spread-navigation.js';
import { initializeCodeMirror } from './codemirror-config.js';
@@ -29,8 +29,6 @@ window.addEventListener('message', function(event) {
navigateSpread(1, updatePreviewWrapper);
} else if (event.data === 'saveFile') {
window.saveFile();
- } else if (event.data === 'saveFileWithViewer') {
- window.saveFileWithViewer();
} else if (event.data?.type === 'scaleChange') {
// Update background grid size and position to match zine preview
const previewPane = document.querySelector('.preview-pane');
@@ -60,10 +58,6 @@ window.saveFile = function() {
saveFile(() => editorView.state.doc.toString());
};
-window.saveFileWithViewer = function() {
- saveFileWithViewer(() => editorView.state.doc.toString());
-};
-
window.loadFile = function() {
loadFile(editorView, updatePreviewWrapper);
};
@@ -95,17 +89,11 @@ async function initializeEditor() {
// Keyboard shortcuts (only when editor not focused, since CodeMirror handles its own)
document.addEventListener('keydown', function(e) {
const {closeSearchPanel, openSearchPanel} = window.CodeMirror;
- const editorHasFocus = editorView.hasFocus;
if ((e.metaKey || e.ctrlKey) && e.key === 'f') {
e.preventDefault();
closeSearchPanel(editorView) || openSearchPanel(editorView);
}
- // Export with viewer (Cmd+E) - only handle when editor not focused
- if (!editorHasFocus && (e.metaKey || e.ctrlKey) && e.key === 'e') {
- e.preventDefault();
- window.saveFileWithViewer();
- }
// Print the iframe content instead of the parent page
if ((e.metaKey || e.ctrlKey) && e.key === 'p') {
e.preventDefault();
diff --git a/resources/file-operations.js b/resources/file-operations.js
@@ -1,5 +1,3 @@
-import { insertAfterHead, insertBeforeHeadClose } from './html-utils.js';
-import { generateViewerCode } from './viewer-generator.js';
import { saveToStorage } from './storage.js';
import { setCurrentSpread, updateSpreadIndicator } from './spread-navigation.js';
@@ -18,27 +16,6 @@ export function saveFile(getEditorContent) {
downloadHtmlFile(getEditorContent());
}
-export function saveFileWithViewer(getEditorContent) {
- const code = getEditorContent();
- const { css, js } = generateViewerCode();
-
- // Check if code has proper head tags
- const hasHead = /<head[^>]*>/i.test(code) && /<\/head>/i.test(code);
-
- let processedCode;
- if (hasHead) {
- // Inject viewer CSS at START of head (so user styles take precedence for page content)
- // Inject viewer JS at END of head (needs to run after DOM is ready)
- processedCode = insertAfterHead(code, `\n<style id="zine-viewer-css">${css}</style>`);
- processedCode = insertBeforeHeadClose(processedCode, `<script id="zine-viewer-js">${js}<\/script>\n`);
- } else {
- // No proper head found, wrap content
- processedCode = `<!DOCTYPE html>\n<html>\n<head>\n<style id="zine-viewer-css">${css}</style>\n<script id="zine-viewer-js">${js}<\/script>\n</head>\n<body>\n${code}\n</body>\n</html>`;
- }
-
- downloadHtmlFile(processedCode);
-}
-
export function loadFile(editorView, updatePreviewCallback) {
const input = document.createElement('input');
input.type = 'file';
diff --git a/resources/html-utils.js b/resources/html-utils.js
@@ -8,16 +8,6 @@ export function insertAfterHead(html, content) {
return html;
}
-// Insert content right before </head> tag in HTML string
-export function insertBeforeHeadClose(html, content) {
- const headEndMatch = html.match(/<\/head>/i);
- if (headEndMatch) {
- const insertPos = html.indexOf(headEndMatch[0]);
- return html.slice(0, insertPos) + content + html.slice(insertPos);
- }
- return html;
-}
-
// Extract title and favicon from user's HTML
export function extractTitleAndFavicon(htmlCode) {
const parser = new DOMParser();
diff --git a/resources/page-flip-animation.js b/resources/page-flip-animation.js
@@ -145,21 +145,18 @@ function processNextFlip() {
const nextFlip = pendingFlipQueue.shift();
// Use current spread index as fromSpread since we're now at a different position
- executePageFlip(currentSpreadIndex, nextFlip.toSpread, nextFlip.container, nextFlip.doc, nextFlip.onComplete);
+ executePageFlip(currentSpreadIndex, nextFlip.toSpread, nextFlip.doc, nextFlip.onComplete);
}
// Execute a single page flip (internal function)
-function executePageFlip(fromSpread, toSpread, container, doc, onComplete) {
+function executePageFlip(fromSpread, toSpread, doc, onComplete) {
isAnimating = true;
currentSpreadIndex = toSpread;
- console.log(`\n=== executePageFlip: ${fromSpread} → ${toSpread} ===`);
-
// Update book position synchronously with the flip animation
updateBookPosition(toSpread, true);
const direction = toSpread > fromSpread ? 'forward' : 'backward';
- console.log(`Direction: ${direction}`);
const leaves = doc.querySelectorAll('.zine-leaf');
if (direction === 'forward') {
@@ -238,25 +235,24 @@ function executePageFlip(fromSpread, toSpread, container, doc, onComplete) {
}
// Animate page flip with input buffering
-export function animatePageFlip(fromSpread, toSpread, container, doc, onComplete) {
+export function animatePageFlip(fromSpread, toSpread, doc, onComplete) {
// If already animating, queue this flip request
if (isAnimating) {
// Check if there's already a queued flip to the same target - if so, skip this one
// This prevents the queue from growing unnecessarily when users spam the same direction
const lastQueued = pendingFlipQueue[pendingFlipQueue.length - 1];
if (!lastQueued || lastQueued.toSpread !== toSpread) {
- pendingFlipQueue.push({ fromSpread, toSpread, container, doc, onComplete });
+ pendingFlipQueue.push({ fromSpread, toSpread, doc, onComplete });
}
return;
}
// Start the flip immediately
- executePageFlip(fromSpread, toSpread, container, doc, onComplete);
+ executePageFlip(fromSpread, toSpread, doc, onComplete);
}
// Set current spread without animation (for initial load)
export function setSpreadImmediate(spreadIndex, doc) {
- console.log(`\n=== setSpreadImmediate(${spreadIndex}) ===`);
currentSpreadIndex = spreadIndex;
updateLeafStates(spreadIndex, doc);
updateBookPosition(spreadIndex, false);
diff --git a/resources/preview-manager.js b/resources/preview-manager.js
@@ -173,9 +173,6 @@ export function updatePreview(editorView, isEditorFocused) {
} else if ((e.metaKey || e.ctrlKey) && e.key === 's') {
e.preventDefault();
parent.postMessage('saveFile', '*');
- } else if ((e.metaKey || e.ctrlKey) && e.key === 'e') {
- e.preventDefault();
- parent.postMessage('saveFileWithViewer', '*');
}
});
diff --git a/resources/spread-layout.js b/resources/spread-layout.js
@@ -48,7 +48,7 @@ export function setupSpreadLayout(container, spread, doc, useFlipAnimation = fal
export function navigateToSpread(container, spreadIndex, doc, useFlipAnimation = false, onComplete) {
if (useFlipAnimation && container.querySelector('.zine-book')) {
// Always call animatePageFlip - it now handles queueing internally
- animatePageFlip(currentFlipSpread, spreadIndex, container, doc, onComplete);
+ animatePageFlip(currentFlipSpread, spreadIndex, doc, onComplete);
currentFlipSpread = spreadIndex;
} else {
// Original non-animated behavior
diff --git a/resources/viewer-generator.js b/resources/viewer-generator.js
@@ -1,394 +0,0 @@
-import { PAGE_IDS, SPREADS, NAV_HEIGHT, NAV_BUTTON_CSS, NAV_BUTTON_STYLES } from './constants.js';
-import { ZINE_PAGE_CSS, ZINE_PRINT_CSS, ZINE_FLIP_CSS } from './zine-styles.js';
-
-// Generate standalone viewer CSS and JS (matches preview pane rendering)
-export function generateViewerCode() {
- const css = `
- * { margin: 0; padding: 0; box-sizing: border-box; }
-
- @media screen {
- html, body {
- height: 100% !important;
- overflow: hidden !important;
- }
- body {
- background: linear-gradient(to top, #2a2a2a, #3a3a3a) !important;
- display: flex !important;
- justify-content: center !important;
- align-items: center !important;
- padding-bottom: ${NAV_HEIGHT}px !important;
- }
- body > *:not(.zine-spread-container):not(.zine-nav) {
- display: none !important;
- }
- ${ZINE_PAGE_CSS}
- ${ZINE_FLIP_CSS}
-
- /* Dynamic z-index based on leaf state */
- .zine-leaf[data-state="closed"][data-leaf-index="0"] { z-index: 14 !important; }
- .zine-leaf[data-state="closed"][data-leaf-index="1"] { z-index: 13 !important; }
- .zine-leaf[data-state="closed"][data-leaf-index="2"] { z-index: 12 !important; }
- .zine-leaf[data-state="closed"][data-leaf-index="3"] { z-index: 11 !important; }
- .zine-leaf[data-state="open"][data-leaf-index="0"] { z-index: 4 !important; }
- .zine-leaf[data-state="open"][data-leaf-index="1"] { z-index: 3 !important; }
- .zine-leaf[data-state="open"][data-leaf-index="2"] { z-index: 2 !important; }
- .zine-leaf[data-state="open"][data-leaf-index="3"] { z-index: 1 !important; }
- .zine-leaf[data-state="flipping"] { z-index: 20 !important; }
-
- .zine-spread-container {
- display: flex !important;
- position: relative;
- }
- .zine-nav {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- height: ${NAV_HEIGHT}px;
- ${NAV_BUTTON_CSS}
- background: transparent;
- }
- .zine-nav button {
- ${NAV_BUTTON_STYLES}
- }
- .zine-nav button:hover:not(:disabled) { background: rgba(255,255,255,0.25); }
- .zine-nav button:disabled { opacity: 0.3; cursor: default; }
- .zine-nav span { color: white; font-size: 14px; min-width: 100px; text-align: center; font-family: monospace; }
- }
-
- @media print {
- ${ZINE_PRINT_CSS}
- }
-
- /* Hide content when viewport is very short */
- @media screen and (max-height: 200px) {
- .zine-spread-container, .zine-nav {
- display: none !important;
- }
- }
- `;
-
- // Serialize SPREADS array for the viewer
- const spreadsJson = JSON.stringify(SPREADS);
- const pageIdsJson = JSON.stringify(PAGE_IDS);
-
- const js = `
- const SPREADS = ${spreadsJson};
- const PAGE_IDS = ${pageIdsJson};
- const NAV_HEIGHT = ${NAV_HEIGHT};
- let currentSpread = 0;
- let container;
- let isAnimating = false;
- const USE_FLIP_ANIMATION = true;
-
- // Page leaf structure (front and back of each physical page)
- const PAGE_LEAVES = [
- { front: 'front-cover', back: 'page1' },
- { front: 'page2', back: 'page3' },
- { front: 'page4', back: 'page5' },
- { front: 'page6', back: 'back-cover' }
- ];
-
- function easeInOutCubic(t) {
- return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
- }
-
- function scaleToFit() {
- if (!container) return;
- const bookContainer = container.querySelector('.zine-book') || container;
- const vw = document.documentElement.clientWidth;
- const vh = document.documentElement.clientHeight - NAV_HEIGHT;
- const spreadWidthPx = bookContainer.offsetWidth;
- const spreadHeightPx = bookContainer.offsetHeight;
- if (spreadWidthPx === 0 || spreadHeightPx === 0) return;
- const scaleX = (vw - 40) / spreadWidthPx;
- const scaleY = (vh - 40) / spreadHeightPx;
- const scale = Math.min(scaleX, scaleY);
- bookContainer.style.zoom = scale;
- bookContainer.dataset.currentZoom = scale;
- }
-
- function updateBookPosition(spreadIndex, animated) {
- const bookContainer = container.querySelector('.zine-book');
- if (!bookContainer) return;
-
- // Spread 0 (front cover): single right page, shift left to center
- // Spread 4 (back cover): single left page, shift right to center
- // Doubled to compensate for flex re-centering (net visual shift = half)
- let shiftAmount = '0in';
- if (spreadIndex === 0) {
- shiftAmount = '-2.75in';
- } else if (spreadIndex === 4) {
- shiftAmount = '2.75in';
- }
-
- if (animated) {
- bookContainer.style.transition = 'margin-left 0.6s cubic-bezier(0.645, 0.045, 0.355, 1.000)';
- bookContainer.style.marginLeft = shiftAmount;
-
- // Remove transition after animation completes
- setTimeout(function() {
- bookContainer.style.transition = '';
- }, 650);
- } else {
- bookContainer.style.transition = 'none';
- bookContainer.style.marginLeft = shiftAmount;
- bookContainer.offsetHeight;
- bookContainer.style.transition = '';
- }
- }
-
- function initFlipMode() {
- const book = document.createElement('div');
- book.className = 'zine-book';
-
- // Create all leaves
- PAGE_LEAVES.forEach((leaf, index) => {
- const leafEl = document.createElement('div');
- leafEl.className = 'zine-leaf';
- leafEl.dataset.leafIndex = index;
- leafEl.dataset.state = 'closed';
- leafEl.style.zIndex = String(20 - index); // Initial z-index for closed state
-
- const frontSide = document.createElement('div');
- frontSide.className = 'zine-leaf-front';
- const frontPage = document.getElementById(leaf.front);
- if (frontPage) frontSide.appendChild(frontPage.cloneNode(true));
-
- const backSide = document.createElement('div');
- backSide.className = 'zine-leaf-back';
- const backPage = document.getElementById(leaf.back);
- if (backPage) backSide.appendChild(backPage.cloneNode(true));
-
- leafEl.appendChild(frontSide);
- leafEl.appendChild(backSide);
- book.appendChild(leafEl);
- });
-
- container.appendChild(book);
- }
-
- function animateFlip(fromSpread, toSpread, onComplete) {
- if (isAnimating) return;
- isAnimating = true;
-
- // Update book position synchronously with the flip animation
- updateBookPosition(toSpread, true);
-
- const direction = toSpread > fromSpread ? 'forward' : 'backward';
- const leaves = document.querySelectorAll('.zine-leaf');
-
- if (direction === 'forward') {
- const leafToFlip = leaves[fromSpread];
- if (leafToFlip) {
- leafToFlip.dataset.state = 'flipping';
- leafToFlip.style.zIndex = '100';
- const startTime = performance.now();
- const duration = 600;
-
- function animate(currentTime) {
- const elapsed = currentTime - startTime;
- const progress = Math.min(elapsed / duration, 1);
- const eased = easeInOutCubic(progress);
- const rotation = eased * -180;
- leafToFlip.style.transform = 'rotateY(' + rotation + 'deg)';
-
- if (progress < 1) {
- requestAnimationFrame(animate);
- } else {
- leafToFlip.dataset.state = 'open';
- leafToFlip.style.zIndex = String(fromSpread + 1);
- isAnimating = false;
- if (onComplete) onComplete();
- }
- }
- requestAnimationFrame(animate);
- }
- } else {
- const leafToFlip = leaves[toSpread];
- if (leafToFlip) {
- leafToFlip.dataset.state = 'flipping';
- leafToFlip.style.zIndex = '100';
- const startTime = performance.now();
- const duration = 600;
-
- function animate(currentTime) {
- const elapsed = currentTime - startTime;
- const progress = Math.min(elapsed / duration, 1);
- const eased = easeInOutCubic(progress);
- const rotation = -180 + (eased * 180);
- leafToFlip.style.transform = 'rotateY(' + rotation + 'deg)';
-
- if (progress < 1) {
- requestAnimationFrame(animate);
- } else {
- leafToFlip.dataset.state = 'closed';
- leafToFlip.style.zIndex = String(20 - toSpread);
- isAnimating = false;
- if (onComplete) onComplete();
- }
- }
- requestAnimationFrame(animate);
- }
- }
- }
-
- function showSpread(index, animated) {
- const spread = SPREADS[index];
-
- if (USE_FLIP_ANIMATION && animated && container.querySelector('.zine-book')) {
- animateFlip(currentSpread, index, () => {
- document.getElementById('zine-indicator').textContent = spread.label;
- document.getElementById('zine-prev').disabled = index === 0;
- document.getElementById('zine-next').disabled = index === SPREADS.length - 1;
- });
- return;
- }
-
- // Non-animated or initial setup
- const visible = [spread.left, spread.right].filter(Boolean);
- PAGE_IDS.forEach(id => {
- const page = document.getElementById(id);
- if (page) {
- page.style.display = 'none';
- document.body.appendChild(page);
- }
- });
-
- container.innerHTML = '';
-
- if (!spread.left && spread.right) {
- const empty = document.createElement('div');
- empty.className = 'zine-empty';
- container.appendChild(empty);
- }
-
- visible.forEach(id => {
- const el = document.getElementById(id);
- if (el) {
- el.style.display = 'block';
- container.appendChild(el);
- }
- });
-
- if (spread.left && !spread.right) {
- const empty = document.createElement('div');
- empty.className = 'zine-empty';
- container.appendChild(empty);
- }
-
- document.getElementById('zine-indicator').textContent = spread.label;
- document.getElementById('zine-prev').disabled = index === 0;
- document.getElementById('zine-next').disabled = index === SPREADS.length - 1;
- scaleToFit();
- }
-
- function navigate(delta) {
- const newIndex = currentSpread + delta;
- if (newIndex >= 0 && newIndex < SPREADS.length) {
- const oldSpread = currentSpread;
- currentSpread = newIndex;
- showSpread(currentSpread, true);
- }
- }
-
- document.addEventListener('DOMContentLoaded', () => {
- container = document.createElement('div');
- container.className = 'zine-spread-container';
- document.body.appendChild(container);
-
- const nav = document.createElement('div');
- nav.className = 'zine-nav';
- nav.innerHTML = '<button id="zine-prev" title="Previous spread">\\u2190</button><span id="zine-indicator"></span><button id="zine-next" title="Next spread">\\u2192</button>';
- document.body.appendChild(nav);
-
- document.getElementById('zine-prev').addEventListener('click', () => navigate(-1));
- document.getElementById('zine-next').addEventListener('click', () => navigate(1));
-
- document.addEventListener('keydown', e => {
- if (e.key === 'ArrowLeft') navigate(-1);
- else if (e.key === 'ArrowRight') navigate(1);
- else if ((e.metaKey || e.ctrlKey) && e.key === 'p') {
- e.preventDefault();
- window.print();
- }
- else if ((e.metaKey || e.ctrlKey) && (e.key === 's' || e.key === 'e')) {
- e.preventDefault();
- // Re-download this viewer file (clean version without dynamic elements)
- // Move pages back to body and remove dynamic elements temporarily
- PAGE_IDS.forEach(id => {
- const page = document.getElementById(id);
- if (page) {
- page.style.display = '';
- document.body.appendChild(page);
- }
- });
- const tempContainer = document.querySelector('.zine-spread-container');
- const tempNav = document.querySelector('.zine-nav');
- if (tempContainer) tempContainer.remove();
- if (tempNav) tempNav.remove();
-
- const html = '<!DOCTYPE html>' + document.documentElement.outerHTML;
-
- // Restore dynamic elements
- const newContainer = document.createElement('div');
- newContainer.className = 'zine-spread-container';
- document.body.appendChild(newContainer);
- container = newContainer;
-
- const newNav = document.createElement('div');
- newNav.className = 'zine-nav';
- newNav.innerHTML = '<button id="zine-prev" title="Previous spread">\\u2190</button><span id="zine-indicator"></span><button id="zine-next" title="Next spread">\\u2192</button>';
- document.body.appendChild(newNav);
- document.getElementById('zine-prev').addEventListener('click', () => navigate(-1));
- document.getElementById('zine-next').addEventListener('click', () => navigate(1));
-
- if (USE_FLIP_ANIMATION) {
- initFlipMode();
- const leaves = document.querySelectorAll('.zine-leaf');
- leaves.forEach((leaf, index) => {
- if (index < currentSpread) {
- leaf.dataset.state = 'open';
- leaf.style.transform = 'rotateY(-180deg)';
- leaf.style.zIndex = String(index + 1);
- }
- });
- scaleToFit();
- updateBookPosition(currentSpread, false);
- } else {
- showSpread(currentSpread, false);
- }
-
- const blob = new Blob([html], { type: 'text/html' });
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = 'my-zine.html';
- a.click();
- URL.revokeObjectURL(url);
- }
- });
-
- window.addEventListener('resize', function() {
- scaleToFit();
- if (USE_FLIP_ANIMATION) {
- updateBookPosition(currentSpread, false);
- }
- });
-
- // Initialize flip mode
- if (USE_FLIP_ANIMATION) {
- initFlipMode();
- document.getElementById('zine-indicator').textContent = SPREADS[0].label;
- document.getElementById('zine-prev').disabled = true;
- document.getElementById('zine-next').disabled = false;
- scaleToFit();
- updateBookPosition(0, false);
- } else {
- showSpread(0, false);
- }
- });
- `;
-
- return { css, js };
-}