feat(settings): per-user message text size (LC-327) #340

Merged
longjacksonle merged 1 commit from feat/lc-327-message-text-size into main 2026-06-17 03:36:43 +02:00

What

A "Text size" control (Small / Normal / Large) in the Appearance settings that scales message body text for readability. Implements LC-327 / LC-328.

How

Purely device-local, mirroring the existing lc-sidebar / lc-unread-only preferences (localStorage only - a per-device reading ergonomic, not synced server-side):

  • Bootstrap (base.html): a block alongside the theme/density/sidebar/unread-only ones. Reads localStorage lc-textsize and sets data-lc-textsize on <html> before first paint (small/large; normal removes the attribute), so text never reflows after load. Exposes window.__lcSetTextSize(v).
  • CSS (main.css): [data-lc-textsize="small"] .lc-md { font-size: 0.875rem } and [..="large"] .lc-md { font-size: 1.125rem }. Scoped to .lc-md (the message body) so chrome / timestamps / sidebar are untouched; .lc-md code/pre are em-relative and scale with it. Default (no attribute) inherits the 1rem body size.
  • Control (settings/page.html): a <select> in the Appearance form, after density. It is name-less, so it is NOT submitted with the server-persisted theme/density POST - no user column, migration, or handler. onchange calls __lcSetTextSize; a small inline script initializes the select from localStorage (the server can't render selected state for a device-local pref).
  • i18n: en/es keys (settings-textsize, textsize-small/normal/large).

Scope / assumptions

  • Scales the message body only; markdown headings use rem and stay fixed (dominant content is paragraph text).
  • No cross-device sync (consistent with sidebar collapse + unread-only). Can later graduate to a users.text_size column like density if wanted.

Testing

  • just check (clippy standalone + saas, fmt; Askama compiles base.html + settings/page.html) clean.
  • just test and just test-saas green; en/es parity verified for the four new keys. No server contract changed, so the gate is template compilation + the i18n coverage the suites enforce.

Operator impact

None. No new env var, config, or contract change; no [operator-action] marker.

🤖 Generated with Claude Code

## What A "Text size" control (Small / Normal / Large) in the Appearance settings that scales message body text for readability. Implements LC-327 / LC-328. ## How Purely device-local, mirroring the existing `lc-sidebar` / `lc-unread-only` preferences (localStorage only - a per-device reading ergonomic, not synced server-side): - **Bootstrap** (`base.html`): a block alongside the theme/density/sidebar/unread-only ones. Reads localStorage `lc-textsize` and sets `data-lc-textsize` on `<html>` before first paint (`small`/`large`; `normal` removes the attribute), so text never reflows after load. Exposes `window.__lcSetTextSize(v)`. - **CSS** (`main.css`): `[data-lc-textsize="small"] .lc-md { font-size: 0.875rem }` and `[..="large"] .lc-md { font-size: 1.125rem }`. Scoped to `.lc-md` (the message body) so chrome / timestamps / sidebar are untouched; `.lc-md` code/pre are `em`-relative and scale with it. Default (no attribute) inherits the 1rem body size. - **Control** (`settings/page.html`): a `<select>` in the Appearance form, after density. It is **`name`-less**, so it is NOT submitted with the server-persisted theme/density POST - no user column, migration, or handler. `onchange` calls `__lcSetTextSize`; a small inline script initializes the select from localStorage (the server can't render selected state for a device-local pref). - **i18n**: en/es keys (`settings-textsize`, `textsize-small/normal/large`). ## Scope / assumptions - Scales the message body only; markdown headings use `rem` and stay fixed (dominant content is paragraph text). - No cross-device sync (consistent with sidebar collapse + unread-only). Can later graduate to a `users.text_size` column like density if wanted. ## Testing - `just check` (clippy standalone + saas, fmt; Askama compiles `base.html` + `settings/page.html`) clean. - `just test` and `just test-saas` green; en/es parity verified for the four new keys. No server contract changed, so the gate is template compilation + the i18n coverage the suites enforce. ## Operator impact None. No new env var, config, or contract change; no `[operator-action]` marker. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(settings): per-user message text size (LC-327)
All checks were successful
check-secrets / Nosey parker (push) Successful in 8s
check-secrets / Kingfisher (push) Successful in 9s
check-secrets / TruffleHog (push) Successful in 7s
check-secrets / Nosey parker (pull_request) Successful in 7s
check-secrets / TruffleHog (pull_request) Successful in 8s
check-secrets / Kingfisher (pull_request) Successful in 11s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 6m39s
cd9e2db87d
Add a Small / Normal / Large "Text size" control to the Appearance settings that scales message body text. Device-local, mirroring the sidebar/unread-only preferences: the base.html bootstrap reads localStorage `lc-textsize` and sets `data-lc-textsize` on <html> before first paint (no reflow on load), and pure CSS in main.css scales `.lc-md` (the message body) - 0.875rem small, 1.125rem large, 1rem default. Scoped to the message body so chrome, timestamps, and the sidebar are unaffected.

The select lives in the Appearance form but is name-less, so it is not submitted with the server-persisted theme/density POST - there is no user column, migration, or handler. `__lcSetTextSize` persists + applies on change; a small inline script initializes the select from localStorage since the server cannot render the selected state for a device-local pref. en/es parity.

#LC-327
#LC-328

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-327-message-text-size 2026-06-17 03:36:43 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!340
No description provided.