summaryrefslogtreecommitdiff
path: root/src/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/index.php')
-rw-r--r--src/index.php35
1 files changed, 27 insertions, 8 deletions
diff --git a/src/index.php b/src/index.php
index 5360366..40bd103 100644
--- a/src/index.php
+++ b/src/index.php
@@ -7,7 +7,7 @@
7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0">
8 <title>sent-web</title> 8 <title>sent-web</title>
9 <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kj-sh604/noir.css@latest/out/noir.min.css"> 9 <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kj-sh604/noir.css@latest/out/noir.min.css">
10 <style> :root { --sent-fg: #000000; --sent-bg: #ffffff; --sent-font: 'Noto Color Emoji', 'DejaVu Sans', sans-serif; } body { max-width: 960px; margin: 0 auto; padding: 1rem; } .subtitle { opacity: 0.6; font-size: 0.9em; margin-top: -0.8em; } /* ── controls ── */ #controls { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin-bottom: 1rem; padding: 0.75rem; border: 1px solid currentColor; border-radius: 4px; } #controls label { display: flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; } #controls input[type="color"] { width: 2rem; height: 2rem; padding: 0; border: 1px solid currentColor; cursor: pointer; background: none; } #controls select { max-width: 200px; } .upload-area { display: flex; align-items: center; gap: 0.5rem; } #upload-input { display: none; } #upload-status { font-size: 0.85rem; opacity: 0.7; } /* ── editor ── */ #input { width: 100%; min-height: 420px; font-family: monospace; font-size: 0.95rem; resize: vertical; tab-size: 4; } .btn-row { display: flex; gap: 0.5rem; margin-top: 0.5rem; } .hint { font-size: 0.8rem; opacity: 0.5; margin-top: 0.25rem; } /* ── presentation overlay ── */ #presentation { position: fixed; inset: 0; z-index: 9999; display: none; align-items: center; justify-content: flex-start; background: var(--sent-bg); color: var(--sent-fg); cursor: none; overflow: hidden; padding-left: 7.5%; } #presentation.active { display: flex; } #slide-content { text-align: left; white-space: pre-line; word-wrap: break-word; font-family: var(--sent-font); } #slide-content img { max-width: 85vw; max-height: 85vh; width: 85vw; height: 85vh; object-fit: contain; } </style> 10 <style> :root { --sent-fg: #000000; --sent-bg: #ffffff; --sent-font: 'Noto Color Emoji', 'DejaVu Sans', sans-serif; } body { max-width: 960px; margin: 0 auto; padding: 1rem; } .subtitle { opacity: 0.6; font-size: 0.9em; margin-top: -0.8em; } /* ── controls ── */ #controls { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin-bottom: 1rem; padding: 0.75rem; border: 1px solid currentColor; border-radius: 4px; } #controls label { display: flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; } #controls input[type="color"] { width: 2rem; height: 2rem; padding: 0; border: 1px solid currentColor; cursor: pointer; background: none; } #controls select { max-width: 200px; } .upload-area { display: flex; align-items: center; gap: 0.5rem; } #upload-input { display: none; } #upload-status { font-size: 0.85rem; opacity: 0.7; } /* ── editor ── */ #input { width: 100%; min-height: 420px; font-family: monospace; font-size: 0.95rem; resize: vertical; tab-size: 4; } .btn-row { display: flex; gap: 0.5rem; margin-top: 0.5rem; } .hint { font-size: 0.8rem; opacity: 0.5; margin-top: 0.25rem; } /* ── presentation overlay ── */ #presentation { position: fixed; inset: 0; z-index: 9999; display: none; align-items: center; justify-content: flex-start; background: var(--sent-bg); color: var(--sent-fg); cursor: none; overflow: hidden; padding-left: 7.5%; } #presentation.active { display: flex; } #slide-content { text-align: left; white-space: pre-line; word-wrap: break-word; font-family: var(--sent-font); } #slide-content img { display: block; max-width: 85vw; max-height: 85vh; object-fit: contain; } </style>
11</head> 11</head>
12 12
13<body> 13<body>
@@ -105,8 +105,8 @@ questions?</textarea>
105 bg: '#ffffff', 105 bg: '#ffffff',
106 fontFamily: '', 106 fontFamily: '',
107 lineSpacing: 1.25, 107 lineSpacing: 1.25,
108 usableWidth: 0.80, 108 usableWidth: 0.85,
109 usableHeight: 0.80, 109 usableHeight: 0.85,
110 }, 110 },
111 111
112 init() { 112 init() {
@@ -245,10 +245,15 @@ questions?</textarea>
245 }); 245 });
246 246
247 // stop presentation whenever fullscreen is exited (covers browser- 247 // stop presentation whenever fullscreen is exited (covers browser-
248 // intercepted Escape that never reaches the keydown handler) 248 // intercepted Escape that never reaches the keydown handler).
249 // Re-render on enter so the slide is drawn with the settled fullscreen
250 // viewport dimensions (requestFullscreen is async, so the initial
251 // renderSlide() call may use pre-fullscreen vw/vh values).
249 document.addEventListener('fullscreenchange', () => { 252 document.addEventListener('fullscreenchange', () => {
250 if (!document.fullscreenElement && this.presenting) { 253 if (!document.fullscreenElement && this.presenting) {
251 this.stopPresentation(); 254 this.stopPresentation();
255 } else if (document.fullscreenElement && this.presenting) {
256 this.renderSlide();
252 } 257 }
253 }); 258 });
254 }, 259 },
@@ -361,6 +366,10 @@ questions?</textarea>
361 content.innerHTML = ''; 366 content.innerHTML = '';
362 367
363 if (slide.img) { 368 if (slide.img) {
369 // center image slides — override the text-layout defaults
370 pres.style.justifyContent = 'center';
371 pres.style.alignItems = 'center';
372 pres.style.paddingLeft = '0';
364 const img = document.createElement('img'); 373 const img = document.createElement('img');
365 if (slide.img.startsWith('http://') || slide.img.startsWith('https://')) { 374 if (slide.img.startsWith('http://') || slide.img.startsWith('https://')) {
366 img.src = slide.img; 375 img.src = slide.img;
@@ -368,13 +377,23 @@ questions?</textarea>
368 img.src = 'uploads/' + slide.img; 377 img.src = 'uploads/' + slide.img;
369 } 378 }
370 img.alt = slide.img; 379 img.alt = slide.img;
371 img.style.maxWidth = (this.settings.usableWidth * 100) + 'vw'; 380 // changed to reflect the fullscreen viewport.
372 img.style.maxHeight = (this.settings.usableHeight * 100) + 'vh'; 381 const pw = pres.offsetWidth || window.innerWidth;
373 img.style.width = (this.settings.usableWidth * 100) + 'vw'; 382 const ph = pres.offsetHeight || window.innerHeight;
374 img.style.height = (this.settings.usableHeight * 100) + 'vh'; 383 const maxW = Math.floor(pw * this.settings.usableWidth);
384 const maxH = Math.floor(ph * this.settings.usableHeight);
385 img.style.width = maxW + 'px';
386 img.style.height = maxH + 'px';
387 img.style.maxWidth = maxW + 'px';
388 img.style.maxHeight = maxH + 'px';
375 img.style.objectFit = 'contain'; 389 img.style.objectFit = 'contain';
390 img.style.display = 'block';
376 content.appendChild(img); 391 content.appendChild(img);
377 } else { 392 } else {
393 // restore text-layout defaults
394 pres.style.justifyContent = 'flex-start';
395 pres.style.alignItems = 'center';
396 pres.style.paddingLeft = '7.5%';
378 const fontSize = this.calcFontSize(slide.lines); 397 const fontSize = this.calcFontSize(slide.lines);
379 content.style.fontSize = fontSize + 'px'; 398 content.style.fontSize = fontSize + 'px';
380 content.style.lineHeight = String(this.settings.lineSpacing); 399 content.style.lineHeight = String(this.settings.lineSpacing);