diff options
Diffstat (limited to 'src/index.html')
| -rw-r--r-- | src/index.html | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/src/index.html b/src/index.html index f87ca69..a6f3ae4 100644 --- a/src/index.html +++ b/src/index.html | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | <title>sent-web</title> | 7 | <title>sent-web</title> |
| 8 | <link rel="icon" type="image/svg+xml" href="/favicon.svg"> | 8 | <link rel="icon" type="image/svg+xml" href="/favicon.svg"> |
| 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: break-spaces; tab-size: 8; font-family: var(--sent-font); } #slide-content img { display: block; max-width: 85vw; max-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: break-spaces; tab-size: 4; font-family: var(--sent-font); } #slide-content img { display: block; max-width: 85vw; max-height: 85vh; object-fit: contain; } </style> |
| 11 | <script> | 11 | <script> |
| 12 | /* | 12 | /* |
| 13 | @licstart The following is the entire license notice for the | 13 | @licstart The following is the entire license notice for the |
| @@ -255,9 +255,11 @@ questions?</textarea> | |||
| 255 | document.getElementById('font-select').addEventListener('change', () => this.onFontChange()); | 255 | document.getElementById('font-select').addEventListener('change', () => this.onFontChange()); |
| 256 | document.getElementById('upload-input').addEventListener('change', e => this.handleUpload(e)); | 256 | document.getElementById('upload-input').addEventListener('change', e => this.handleUpload(e)); |
| 257 | 257 | ||
| 258 | document.getElementById('input').addEventListener('input', () => { | 258 | const input = document.getElementById('input'); |
| 259 | localStorage.setItem('sent-web-content', document.getElementById('input').value); | 259 | input.addEventListener('input', () => { |
| 260 | localStorage.setItem('sent-web-content', input.value); | ||
| 260 | }); | 261 | }); |
| 262 | input.addEventListener('keydown', e => this.handleEditorKeydown(e)); | ||
| 261 | 263 | ||
| 262 | document.addEventListener('keydown', e => this.handleKeydown(e)); | 264 | document.addEventListener('keydown', e => this.handleKeydown(e)); |
| 263 | 265 | ||
| @@ -297,6 +299,36 @@ questions?</textarea> | |||
| 297 | if (this.presenting) this.renderSlide(); | 299 | if (this.presenting) this.renderSlide(); |
| 298 | }, | 300 | }, |
| 299 | 301 | ||
| 302 | handleEditorKeydown(e) { | ||
| 303 | if (e.key !== 'Tab' || e.ctrlKey || e.metaKey || e.altKey) | ||
| 304 | return; | ||
| 305 | |||
| 306 | e.preventDefault(); | ||
| 307 | |||
| 308 | const ta = e.target; | ||
| 309 | if (!ta || typeof ta.selectionStart !== 'number' || typeof ta.selectionEnd !== 'number') | ||
| 310 | return; | ||
| 311 | |||
| 312 | const indent = ' '; | ||
| 313 | const start = ta.selectionStart; | ||
| 314 | const end = ta.selectionEnd; | ||
| 315 | |||
| 316 | if (start === end) { | ||
| 317 | ta.setRangeText(indent, start, end, 'end'); | ||
| 318 | } else { | ||
| 319 | const selected = ta.value.slice(start, end); | ||
| 320 | const indented = selected | ||
| 321 | .split('\n') | ||
| 322 | .map(line => indent + line) | ||
| 323 | .join('\n'); | ||
| 324 | ta.setRangeText(indented, start, end, 'select'); | ||
| 325 | ta.selectionStart = start; | ||
| 326 | ta.selectionEnd = start + indented.length; | ||
| 327 | } | ||
| 328 | |||
| 329 | localStorage.setItem('sent-web-content', ta.value); | ||
| 330 | }, | ||
| 331 | |||
| 300 | normalizeSentNewlines(text) { | 332 | normalizeSentNewlines(text) { |
| 301 | return text.replace(/\r\n?/g, '\n'); | 333 | return text.replace(/\r\n?/g, '\n'); |
| 302 | }, | 334 | }, |
