|
98 | 98 | display: inline-flex; |
99 | 99 | align-items: center; |
100 | 100 | gap: 6px; |
| 101 | + /* PR-27: keeps .rhs (and the font toggle that follows it as a |
| 102 | + sibling) clustered at the right edge in the 3-child status bar. |
| 103 | + No-op for the pre-PR-27 2-child layout. */ |
| 104 | + margin-left: auto; |
101 | 105 | } |
102 | 106 | #status-bar .rhs::before { |
103 | 107 | content: "["; |
|
145 | 149 | visibility: hidden; |
146 | 150 | } |
147 | 151 | #status-bar.working .cursor { visibility: visible; } |
| 152 | + /* PR-27 (v2.0) — chat font-size toggle. Two-state glyph control |
| 153 | + (`a` / `A`) at the far right of the status bar; the active size |
| 154 | + lights up in --accent, the inactive in --muted. Click swaps the |
| 155 | + size class on <html>; the body has no other knowledge of the |
| 156 | + toggle, so the rest of the chat keeps its existing scale. |
| 157 | + Defaults to small (today's behavior) so existing users see no |
| 158 | + change unless they opt in. */ |
| 159 | + #font-toggle { |
| 160 | + background: transparent; |
| 161 | + border: 1px solid var(--rule); |
| 162 | + color: var(--muted); |
| 163 | + font-family: inherit; |
| 164 | + padding: 1px 7px 2px; |
| 165 | + margin-left: 10px; |
| 166 | + cursor: pointer; |
| 167 | + display: inline-flex; |
| 168 | + align-items: baseline; |
| 169 | + gap: 3px; |
| 170 | + letter-spacing: 0; /* override status-bar uppercase tracking */ |
| 171 | + text-transform: none; /* lowercase 'a' must stay lowercase */ |
| 172 | + line-height: 1; |
| 173 | + } |
| 174 | + #font-toggle:hover { |
| 175 | + border-color: var(--accent); |
| 176 | + background: var(--bg-3); |
| 177 | + } |
| 178 | + #font-toggle .fs-a { font-size: 9px; color: var(--muted); } |
| 179 | + #font-toggle .fs-A { font-size: 13px; color: var(--muted); } |
| 180 | + :root.fs-small #font-toggle .fs-a { color: var(--accent); } |
| 181 | + :root.fs-large #font-toggle .fs-A { color: var(--accent); } |
| 182 | + /* Scales chat content + input only — chrome (status bar, buttons, |
| 183 | + modal headers, badges) stays fixed at its designed scale so the |
| 184 | + layout doesn't reflow awkwardly. Tool-call summaries inherit |
| 185 | + from #history so they scale automatically. */ |
| 186 | + :root.fs-large #history { font-size: 17px; } |
| 187 | + :root.fs-large #input { font-size: 17px; } |
148 | 188 | @keyframes blink { |
149 | 189 | 0%, 49% { opacity: 1; } |
150 | 190 | 50%, 100% { opacity: 0; } |
|
670 | 710 | <span class="rhs"> |
671 | 711 | <span id="status-text">idle</span><span id="model-badge"></span><span id="token-meter"></span><span class="cursor">█</span> |
672 | 712 | </span> |
| 713 | + <button id="font-toggle" type="button" |
| 714 | + title="Toggle chat font size (small / large)" |
| 715 | + aria-label="Toggle chat font size"> |
| 716 | + <span class="fs-a">a</span><span class="fs-A">A</span> |
| 717 | + </button> |
673 | 718 | </div> |
674 | 719 | <!-- |
675 | 720 | History is intentionally empty on initial DOM. The IIFE injects the |
@@ -758,6 +803,27 @@ <h4>quickstart</h4> |
758 | 803 | const $modelBadge = document.getElementById('model-badge'); |
759 | 804 | const $tokenMeter = document.getElementById('token-meter'); |
760 | 805 | const $scrollJump = document.getElementById('scroll-jump'); |
| 806 | + const $fontToggle = document.getElementById('font-toggle'); |
| 807 | + |
| 808 | + // PR-27 (v2.0) — chat font-size toggle. Two states; the active one |
| 809 | + // is reflected as a class on <html>. Persisted per-browser via |
| 810 | + // localStorage so the choice survives reloads. Restored before any |
| 811 | + // history rendering happens so users with a saved 'large' setting |
| 812 | + // never see a small-text flash on page load. |
| 813 | + const FONT_KEY = 'tdpilot.fontMode'; |
| 814 | + function applyFontMode(mode) { |
| 815 | + if (mode !== 'small' && mode !== 'large') mode = 'small'; |
| 816 | + document.documentElement.classList.remove('fs-small', 'fs-large'); |
| 817 | + document.documentElement.classList.add('fs-' + mode); |
| 818 | + try { localStorage.setItem(FONT_KEY, mode); } catch (_) { /* private mode */ } |
| 819 | + } |
| 820 | + let _savedFontMode = 'small'; |
| 821 | + try { _savedFontMode = localStorage.getItem(FONT_KEY) || 'small'; } catch (_) { /* private mode */ } |
| 822 | + applyFontMode(_savedFontMode); |
| 823 | + $fontToggle.addEventListener('click', () => { |
| 824 | + const cur = document.documentElement.classList.contains('fs-large') ? 'large' : 'small'; |
| 825 | + applyFontMode(cur === 'large' ? 'small' : 'large'); |
| 826 | + }); |
761 | 827 |
|
762 | 828 | // Render the initial welcome from the same template fullSync uses, so |
763 | 829 | // the wizard DOM is guaranteed present. |
@@ -1822,6 +1888,19 @@ <h4>quickstart</h4> |
1822 | 1888 | $input.focus(); |
1823 | 1889 | return; |
1824 | 1890 | } |
| 1891 | + // PR-27 (v2.0) — Cmd/Ctrl + `+` / `-` toggles chat font size |
| 1892 | + // independently of the browser-native zoom (which still works). |
| 1893 | + // `=` matches `+` for the unshifted keycap on US/EU layouts. |
| 1894 | + if (cmd && (e.key === '+' || e.key === '=')) { |
| 1895 | + e.preventDefault(); |
| 1896 | + applyFontMode('large'); |
| 1897 | + return; |
| 1898 | + } |
| 1899 | + if (cmd && e.key === '-') { |
| 1900 | + e.preventDefault(); |
| 1901 | + applyFontMode('small'); |
| 1902 | + return; |
| 1903 | + } |
1825 | 1904 | // End — jump to bottom of history. Useful after scrolling up to |
1826 | 1905 | // read older content. |
1827 | 1906 | if (e.key === 'End' && !inInput) { |
|
0 commit comments