Spaces:
Running
Running
Mobile: collapse model/voice control bars behind tap-to-expand
Browse filesOn phones the diary had two full control bars (model + voice) stacking ~830px of
controls above the story. Wrap each bar in a <details> that's open on desktop
(summary hidden) and collapsed on mobile (tap "⚙ Model" / "🔊 Voice" to expand),
so the war story / persona sits near the top on a phone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- web/diaryPanel.js +8 -2
- web/personaPanel.js +6 -1
- web/shell/persona.css +13 -0
web/diaryPanel.js
CHANGED
|
@@ -31,12 +31,18 @@ export function mountDiaryPanel(host) {
|
|
| 31 |
const ttsStatus = el('div', { class: 'persona-status tts-status' })
|
| 32 |
const out = el('div', { class: 'persona-about' }, 'A first-person diary entry, written by a small model in your browser — and read aloud on your device.')
|
| 33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
const controls = el('aside', { class: 'persona-controls' }, [
|
| 35 |
-
|
| 36 |
el('label', { class: 'persona-label' }, 'Unit'), unit,
|
| 37 |
el('label', { class: 'persona-label' }, 'Traits'), traits,
|
| 38 |
btn, stats, status,
|
| 39 |
-
|
| 40 |
])
|
| 41 |
const result = el('div', { class: 'persona-result' }, [out])
|
| 42 |
host.appendChild(el('div', { class: 'persona-view' }, [controls, result]))
|
|
|
|
| 31 |
const ttsStatus = el('div', { class: 'persona-status tts-status' })
|
| 32 |
const out = el('div', { class: 'persona-about' }, 'A first-person diary entry, written by a small model in your browser — and read aloud on your device.')
|
| 33 |
|
| 34 |
+
// On phones the model + voice bars collapse behind tap-to-expand summaries so the
|
| 35 |
+
// story isn't pushed off-screen; on desktop they stay open (summary hidden via CSS).
|
| 36 |
+
const modelWrap = el('details', { class: 'ctl-collapse' }, [el('summary', {}, '⚙ Model'), modelHost])
|
| 37 |
+
const ttsWrap = el('details', { class: 'ctl-collapse' }, [el('summary', {}, '🔊 Voice'), ttsHost])
|
| 38 |
+
modelWrap.open = ttsWrap.open = window.innerWidth > 768
|
| 39 |
+
|
| 40 |
const controls = el('aside', { class: 'persona-controls' }, [
|
| 41 |
+
modelWrap,
|
| 42 |
el('label', { class: 'persona-label' }, 'Unit'), unit,
|
| 43 |
el('label', { class: 'persona-label' }, 'Traits'), traits,
|
| 44 |
btn, stats, status,
|
| 45 |
+
ttsWrap, narrateBtn, ttsStatus,
|
| 46 |
])
|
| 47 |
const result = el('div', { class: 'persona-result' }, [out])
|
| 48 |
host.appendChild(el('div', { class: 'persona-view' }, [controls, result]))
|
web/personaPanel.js
CHANGED
|
@@ -35,8 +35,13 @@ export function mountPersonaPanel(host) {
|
|
| 35 |
const thinkEl = el('pre', { class: 'persona-think' })
|
| 36 |
const thinkWrap = el('details', { class: 'persona-think-wrap' }, [el('summary', {}, 'model output (raw)'), thinkEl])
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
const controls = el('aside', { class: 'persona-controls' }, [
|
| 39 |
-
|
| 40 |
el('label', { class: 'persona-label' }, 'Class'), sel,
|
| 41 |
el('label', { class: 'persona-label' }, 'Seed'), seed,
|
| 42 |
btn, stats, status,
|
|
|
|
| 35 |
const thinkEl = el('pre', { class: 'persona-think' })
|
| 36 |
const thinkWrap = el('details', { class: 'persona-think-wrap' }, [el('summary', {}, 'model output (raw)'), thinkEl])
|
| 37 |
|
| 38 |
+
// On phones the model bar collapses behind a tap-to-expand summary so the result
|
| 39 |
+
// isn't pushed off-screen; on desktop it stays open (summary hidden via CSS).
|
| 40 |
+
const modelWrap = el('details', { class: 'ctl-collapse' }, [el('summary', {}, '⚙ Model'), modelHost])
|
| 41 |
+
modelWrap.open = window.innerWidth > 768
|
| 42 |
+
|
| 43 |
const controls = el('aside', { class: 'persona-controls' }, [
|
| 44 |
+
modelWrap,
|
| 45 |
el('label', { class: 'persona-label' }, 'Class'), sel,
|
| 46 |
el('label', { class: 'persona-label' }, 'Seed'), seed,
|
| 47 |
btn, stats, status,
|
web/shell/persona.css
CHANGED
|
@@ -118,10 +118,23 @@
|
|
| 118 |
.persona-go-alt:hover { background: var(--p-paper-2) !important; color: var(--p-ink) !important; }
|
| 119 |
.tts-status { min-height: 14px; }
|
| 120 |
|
|
|
|
|
|
|
|
|
|
| 121 |
@media (max-width: 768px) {
|
| 122 |
/* The whole view scrolls as one column (instead of two fighting scroll panes in
|
| 123 |
a fixed-height box), so the story gets real room and the page scrolls. */
|
| 124 |
.persona-view { flex-direction: column; height: 100%; overflow-y: auto; -webkit-overflow-scrolling: touch; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
.persona-controls {
|
| 126 |
width: 100%; border-right: 0; border-bottom: 2px solid var(--p-ink);
|
| 127 |
overflow: visible; flex-shrink: 0; gap: 6px;
|
|
|
|
| 118 |
.persona-go-alt:hover { background: var(--p-paper-2) !important; color: var(--p-ink) !important; }
|
| 119 |
.tts-status { min-height: 14px; }
|
| 120 |
|
| 121 |
+
/* Collapsible control sections (model / voice). Desktop: no toggle, always shown. */
|
| 122 |
+
.ctl-collapse > summary { display: none; }
|
| 123 |
+
|
| 124 |
@media (max-width: 768px) {
|
| 125 |
/* The whole view scrolls as one column (instead of two fighting scroll panes in
|
| 126 |
a fixed-height box), so the story gets real room and the page scrolls. */
|
| 127 |
.persona-view { flex-direction: column; height: 100%; overflow-y: auto; -webkit-overflow-scrolling: touch; }
|
| 128 |
+
/* Mobile: tuck the model/voice bars behind a tap-to-expand summary. */
|
| 129 |
+
.ctl-collapse > summary {
|
| 130 |
+
display: block; cursor: pointer; list-style: none; margin-top: 6px;
|
| 131 |
+
font-family: var(--p-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
|
| 132 |
+
color: var(--p-ink); background: var(--p-card); border: 1.5px solid var(--p-ink); padding: 10px;
|
| 133 |
+
}
|
| 134 |
+
.ctl-collapse > summary::-webkit-details-marker { display: none; }
|
| 135 |
+
.ctl-collapse > summary::after { content: ' ▾'; float: right; color: var(--p-muted); }
|
| 136 |
+
.ctl-collapse[open] > summary::after { content: ' ▴'; }
|
| 137 |
+
.persona-label { margin-top: 4px; }
|
| 138 |
.persona-controls {
|
| 139 |
width: 100%; border-right: 0; border-bottom: 2px solid var(--p-ink);
|
| 140 |
overflow: visible; flex-shrink: 0; gap: 6px;
|