polats Claude Opus 4.8 (1M context) commited on
Commit
0218dca
·
1 Parent(s): db5fc22

Mobile: collapse model/voice control bars behind tap-to-expand

Browse files

On 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 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
- modelHost,
36
  el('label', { class: 'persona-label' }, 'Unit'), unit,
37
  el('label', { class: 'persona-label' }, 'Traits'), traits,
38
  btn, stats, status,
39
- ttsHost, narrateBtn, ttsStatus,
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
- modelHost,
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;