zine-styles.js (6.1 KB)


  1 import { PAGE_WIDTH_IN, PAGE_HEIGHT_IN, PAGE_PADDING_IN, ALL_PAGES_SELECTOR, RIGHT_PAGES_SELECTOR, LEFT_PAGES_SELECTOR, SPREADS } from './constants.js';
  2 
  3 // Shared print CSS for zine layout (used by both editor preview and exported viewer)
  4 export const ZINE_PRINT_CSS = `
  5 	@page { size: 8.5in 11in portrait; margin: 0; }
  6 	html, body { width: 8.5in; height: 11in; }
  7 	body {
  8 		display: grid !important;
  9 		grid-template-columns: repeat(4, ${PAGE_WIDTH_IN}in);
 10 		grid-template-rows: repeat(2, ${PAGE_HEIGHT_IN}in);
 11 		transform: rotate(90deg);
 12 		transform-origin: center center;
 13 		position: absolute;
 14 		top: calc(50% - ${PAGE_HEIGHT_IN}in);
 15 		left: calc(50% - 5.5in);
 16 		width: 11in;
 17 		height: 8.5in;
 18 	}
 19 	${ALL_PAGES_SELECTOR} {
 20 		display: block !important;
 21 		width: ${PAGE_WIDTH_IN}in !important;
 22 		height: ${PAGE_HEIGHT_IN}in !important;
 23 		padding: ${PAGE_PADDING_IN}in;
 24 		background: white;
 25 		overflow: hidden;
 26 		overflow-wrap: break-word;
 27 		aspect-ratio: auto !important;
 28 		box-shadow: none !important;
 29 		transform: none;
 30 	}
 31 	#front-cover { grid-row: 2; grid-column: 2; }
 32 	#page1 { grid-row: 2; grid-column: 3; }
 33 	#page2 { grid-row: 2; grid-column: 4; }
 34 	#page3 { grid-row: 1; grid-column: 4; transform: rotate(180deg); }
 35 	#page4 { grid-row: 1; grid-column: 3; transform: rotate(180deg); }
 36 	#page5 { grid-row: 1; grid-column: 2; transform: rotate(180deg); }
 37 	#page6 { grid-row: 1; grid-column: 1; transform: rotate(180deg); }
 38 	#back-cover { grid-row: 2; grid-column: 1; }
 39 	.zine-nav, .zine-empty, .spread-nav, .iframe-fullscreen-toggle, .zine-spread-container { display: contents !important; }
 40 	.zine-spread-container { transform: none !important; }
 41 	/* Hide flip animation elements for print - use original pages */
 42 	.zine-book { display: none !important; }
 43 	.page { display: block !important; }
 44 	a { color: black; }
 45 	img { max-width: 100%; height: auto; }
 46 `;
 47 
 48 // CSS for 3D page flip animation
 49 export const ZINE_FLIP_CSS = `
 50 	.zine-book {
 51 		position: relative;
 52 		width: ${PAGE_WIDTH_IN * 2}in;
 53 		height: ${PAGE_HEIGHT_IN}in;
 54 		perspective: 2000px;
 55 		transform-style: preserve-3d;
 56 		transform-origin: center center;
 57 	}
 58 
 59 	.zine-leaf {
 60 		position: absolute;
 61 		width: ${PAGE_WIDTH_IN}in;
 62 		height: ${PAGE_HEIGHT_IN}in;
 63 		left: ${PAGE_WIDTH_IN}in;
 64 		top: 0;
 65 		transform-origin: left center;
 66 		transform-style: preserve-3d;
 67 		transition: none;
 68 		will-change: transform;
 69 	}
 70 
 71 	/* When flipping, use high z-index so it's on top during animation */
 72 	.zine-leaf[data-state="flipping"] {
 73 		z-index: 20 !important;
 74 		transition: none;
 75 	}
 76 
 77 	.zine-leaf-front,
 78 	.zine-leaf-back {
 79 		position: absolute;
 80 		width: 100%;
 81 		height: 100%;
 82 		backface-visibility: hidden;
 83 		-webkit-backface-visibility: hidden;
 84 		transform: translateZ(0);
 85 	}
 86 
 87 	.zine-leaf-front {
 88 		transform: rotateY(0deg);
 89 		z-index: 2;
 90 	}
 91 
 92 	.zine-leaf-back {
 93 		transform: rotateY(180deg);
 94 		z-index: 1;
 95 	}
 96 
 97 	.zine-leaf-front .page,
 98 	.zine-leaf-back .page {
 99 		width: 100%;
100 		height: 100%;
101 		display: block !important;
102 	}
103 
104 	/* Base pages - shown beneath the flipping leaves */
105 	.zine-base-pages {
106 		position: absolute;
107 		width: 100%;
108 		height: 100%;
109 		display: flex;
110 		justify-content: center;
111 		align-items: center;
112 		z-index: 0;
113 	}
114 
115 	.zine-base-page {
116 		position: absolute;
117 		width: ${PAGE_WIDTH_IN}in;
118 		height: ${PAGE_HEIGHT_IN}in;
119 		display: none !important;
120 		z-index: 0;
121 	}
122 
123 	/* Position base pages */
124 	.zine-base-page[data-page-id="front-cover"],
125 	.zine-base-page[data-page-id="page2"],
126 	.zine-base-page[data-page-id="page4"],
127 	.zine-base-page[data-page-id="page6"] {
128 		right: 0;
129 	}
130 
131 	.zine-base-page[data-page-id="page1"],
132 	.zine-base-page[data-page-id="page3"],
133 	.zine-base-page[data-page-id="page5"],
134 	.zine-base-page[data-page-id="back-cover"] {
135 		left: 0;
136 	}
137 `;
138 
139 // Shared CSS for zine pages (used by both editor preview and exported viewer)
140 export const ZINE_PAGE_CSS = `
141 	${ALL_PAGES_SELECTOR} {
142 		display: none;
143 		width: ${PAGE_WIDTH_IN}in;
144 		height: ${PAGE_HEIGHT_IN}in;
145 		flex-shrink: 0;
146 		padding: ${PAGE_PADDING_IN}in;
147 		overflow: hidden;
148 		overflow-wrap: break-word;
149 	}
150 	.page {
151 		background: white;
152 	}
153 	.zine-spread-container {
154 		display: flex;
155 		transform-origin: center center;
156 	}
157 	${RIGHT_PAGES_SELECTOR} {
158 		box-shadow: inset 4px 0 1.3px -3px rgba(0, 0, 0, 0.09), inset 8px 0 6px -6px rgba(0, 0, 0, 0.15);
159 	}
160 	${LEFT_PAGES_SELECTOR} {
161 		box-shadow: inset -4px 0 1.5px -3px rgba(0, 0, 0, 0.09), inset -8px 0 6px -6px rgba(0, 0, 0, 0.15);
162 	}
163 	.zine-empty {
164 		width: ${PAGE_WIDTH_IN}in;
165 		height: ${PAGE_HEIGHT_IN}in;
166 		flex-shrink: 0;
167 		border: 1px dashed #666;
168 	}
169 	.zine-empty:first-child {
170 		border-right: none;
171 	}
172 	.zine-empty:last-child {
173 		border-left: none;
174 	}
175 	img {
176 		max-width: 100%;
177 	}
178 `;
179 
180 // Generate CSS to show only the current spread
181 export function generateSpreadCSS(spreadIndex) {
182 	const spread = SPREADS[spreadIndex];
183 	const visiblePages = [spread.left, spread.right].filter(Boolean);
184 
185 	return `
186 		/* Base styles for all views */
187 		* { margin: 0; padding: 0; box-sizing: border-box; }
188 
189 		/* Screen view: show spread at actual size, then scale to fit */
190 		@media screen {
191 			html, body {
192 				height: 100% !important;
193 				overflow: hidden !important;
194 			}
195 
196 			body {
197 				display: flex !important;
198 				justify-content: center !important;
199 				align-items: center !important;
200 			}
201 
202 			body > *:not(.zine-spread-container):not(.iframe-fullscreen-toggle) {
203 				display: none !important;
204 			}
205 
206 			${ZINE_PAGE_CSS}
207 
208 			.zine-spread-container {
209 				display: flex !important;
210 				position: relative;
211 			}
212 
213 			${ALL_PAGES_SELECTOR} {
214 				display: none !important;
215 				width: ${PAGE_WIDTH_IN}in !important;
216 				height: ${PAGE_HEIGHT_IN}in !important;
217 			}
218 
219 			/* Show visible pages */
220 			${visiblePages.map(id => `#${id}`).join(', ')} {
221 				display: block !important;
222 			}
223 
224 			.zine-empty {
225 				display: block !important;
226 				width: ${PAGE_WIDTH_IN}in !important;
227 				height: ${PAGE_HEIGHT_IN}in !important;
228 			}
229 		}
230 
231 		/* Print view: 8-page grid for mini-zine folding */
232 		@media print {
233 			${ZINE_PRINT_CSS}
234 		}
235 	`;
236 }