Skip to content

feat(webapp): light theme with System/Light/Dark switch - #272

Merged
isac322 merged 2 commits into
mainfrom
isac322/light-mode
Oct 6, 2026
Merged

isac322 merged 2 commits into
mainfrom
isac322/light-mode

Conversation

@isac322

@isac322 isac322 commented Oct 6, 2026

Copy link
Copy Markdown
Member

TL;DR

  • The web app now has a light theme, and by default it follows the OS (System).
  • You pick System, Light or Dark from the profile menu at the bottom left (a radio group). The choice is saved per browser and applied before first paint, so the page never flashes dark first.
  • The /auth sign-in pages follow the same preference.
  • Dark mode looks the same as before.
  • Known gap: surfaces without an account menu (volume mode, desktop signed-out) have no switch and just follow the OS.

How it works

  • src/lib/theme.ts owns the preference (localStorage["bdrive-theme"]: system|light|dark, default system) and resolves it onto <html data-theme> plus color-scheme. It follows live OS changes and changes made in other tabs. useTheme() is the hook components read.
  • An inline bootstrap in index.html applies the theme before any CSS paints. authlocal.go's page shell has the same bootstrap.
  • CSS: dark stays the unprefixed :root default. Light overrides it under :root[data-theme="light"] in both style.css and tw.css. The @theme literals in tw.css are untouched, because web/docs tokens.mjs and the cloud landing token check read them. Tailwind's dark: variant now keys off data-theme.
  • I audited hardcoded dark-only colours in style.css and the TS sources and either moved them to variables or added light overrides: danger reds, shadows, scrims, row hovers, and honey text. Honey is only about 2:1 on white, so text uses --accent-ink in light.
  • JS-side palettes follow the theme too: mermaid (re-rendered on switch), the Insights treemap and matrix, and sonner toasts.
  • Print is unchanged: it is always light.

Tests

  • e2e/playwright.config.ts now emulates a dark OS. The existing colour-pinning specs assert dark-theme colours, and headless Chromium reports light.
  • New e2e/theme.spec.ts covers:
    • System follows the OS live.
    • Light overrides a dark OS, persists across reload, and is already set when <body> parses.
    • Switching back to System returns control to the OS and clears the stored key.
    • The sign-in page honours the preference.
  • Ran: go build ./..., go vet ./internal/webapp, go test ./internal/webapp, tsc, check-dist.sh, and the Playwright hub project, then the theme, browse, dashboard and edit-url specs again after the config change.
  • Two Playwright specs fail identically on main (7fda326), so they are not from this change:
    • browse.spec.ts "tab title follows SPA navigation"
    • edit-url.spec.ts "a failing read leaves the editor"
  • One node unit test also fails: staleNote flags only hot-and-stale files. It lives in lib/heat.ts, which this PR doesn't touch, and looks date-dependent. I didn't re-run it on main.

Architecture changes

webapp-frontend.md: lib gains theme.ts (ThemePref, Theme, useTheme, setThemePref, initTheme), plus a new components --> lib : useTheme edge (AccountBar, FileView mermaid, Insights, toasts).

flowchart LR
  components["components (AccountBar, FileView, Insights, sonner)"]
  theme["✅ lib/theme.ts — ThemePref Theme useTheme setThemePref initTheme"]
  components -->|"✅ useTheme"| theme
Loading

@isac322 isac322 self-assigned this Oct 6, 2026
@isac322
isac322 requested a review from runbear-bot October 6, 2026 05:27

@runbear-bot runbear-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bobb's bot(Totoro) Review

Conclusion: not-ready

테마 저장·OS 추종·라이트 토큰·mermaid/Insights/toast 전환은 맞다. 다크(기본) 인쇄와, 라이트 OS에서 Dark를 고른 로그인에서 color-scheme만 빠진다.

  • 인쇄: html.style.colorScheme이 @media print의 color-scheme: light를 이긴다. 배경 그래픽을 끄면 어두운 캔버스에 어두운 글자. 이 PR 전에는 시트 규칙이 나중에 와서 인쇄가 라이트였다.
  • 로그인: auth :root에 color-scheme: dark가 없고 부트스트랩도 SPA와 다르다. Dark + 라이트 OS면 카드는 어두운데 autofill·스크롤바·네이티브 컨트롤은 라이트다.

막지 않음: 라이트 --add(#1a8f59)는 흰 배경 약 4.1:1. Insights .in-pt는 honey 50%라 밝은 차트에서 흐리다. 로그인 로고는 아직 --honey(흰 배경 약 2:1).

const t = resolveTheme(getThemePref());
const root = document.documentElement;
root.dataset.theme = t;
root.style.colorScheme = t;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyAndNotify와 frontend/index.html·static/index.html 부트스트랩이 html.style.colorScheme을 쓴다. 인라인 선언이라 style.css 인쇄 규칙(:root, :root[data-theme=light] { color-scheme: light }, !important 없음)이 못 이긴다. 다크로 인쇄하면 토큰은 검은 잉크로 바뀌는데 color-scheme은 dark로 남는다. 배경 그래픽을 끄면 어두운 캔버스 위 어두운 글자다. 이 PR 전에는 인라인이 없어서 인쇄 규칙이 :root의 dark를 이겼다.

수정: 그 인쇄 규칙만 color-scheme: light !important. 인라인 대입을 지우면 dev(frontend/index.html은 CSS가 body 끝 모듈에 있음)에서 첫 페인트 전에 scheme이 비게 된다.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다 (e5c777a). 지적이 맞습니다. html.style.colorScheme 인라인 선언이 @media print의 color-scheme: light를 이기고 있었습니다. 제안대로 인쇄 규칙만 color-scheme: light !important로 바꿨고, 인라인 대입은 dev 첫 페인트 때문에 남겨뒀습니다. e2e/theme.spec.ts에 회귀 검증을 추가했습니다: 다크 테마에서 emulateMedia({ media: "print" })를 걸면 <html>의 computed color-scheme이 light가 됩니다. theme/print/shell/sec12 스펙 24개 통과.

Comment thread internal/webapp/authlocal.go Outdated
fmt.Fprintf(w, `<!doctype html><html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><title>%s — BearDrive</title>
<script>(function(){var p="system";try{p=localStorage.getItem("bdrive-theme")||"system"}catch(e){}
if(p!=="light"&&p!=="dark"){p=window.matchMedia&&matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPA 부트스트랩(frontend/index.html)과 다르다. matchMedia가 없으면 light로 떨어지고(theme.ts / index.html은 dark), color-scheme을 세팅하지 않는다. :root에도 color-scheme: dark가 없고 light 블록만 color-scheme: light다. 라이트 OS에서 Dark를 고르면 카드는 어두운데 autofill·스크롤바·네이티브 컨트롤은 라이트다. SPA가 BEA-54로 막은 그 구멍이다.

수정: :root에 color-scheme:dark를 넣고, 부트스트랩은 index.html과 같이 맞출 것. 라이트 로고는 아직 color: var(--honey)(#f5a623, 흰 배경 약 2:1)라 light에서 .logo만 --honey-bright로 내리면 된다.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다 (e5c777a). auth :root에 color-scheme:dark를 넣었고, 부트스트랩을 SPA index.html과 같게 맞췄습니다. 이제 matchMedia가 없으면 dark로 떨어지고 style.colorScheme도 같이 설정합니다. light에서는 .logo만 --honey-bright(#a35f00)로 바꿨습니다. 검증으로 theme.spec에 "라이트 OS + Dark 선택 → /auth/login의 computed color-scheme이 dark" assert를 추가했고 통과했습니다. go test ./internal/webapp -run Auth|Login|Signup|Page|Reset도 통과. 리뷰 본문의 --add 지적도 받아서 light 값을 #17804f로 바꿨습니다(흰 배경 4.96:1, --bg-side 4.62:1, style.css/tw.css/auth 모두). .in-pt honey 50%는 글자가 아닌 차트 점이라 이번엔 그대로 뒀습니다.

@isac322
isac322 requested a review from runbear-bot October 6, 2026 06:13

@runbear-bot runbear-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bobb's bot(Totoro) Review

Conclusion: ready-with-notes

이전 두 지적은 e5c777a에서 닫혔다. 인쇄 color-scheme: light !important가 인라인 html.style.colorScheme을 이기고, 같은 규칙이 라이트 팔레트와 같은 특이성에 더 뒤에 있어서 인쇄 토큰이 유지된다. 로그인 :root는 color-scheme: dark이고, 부트스트랩은 SPA index.html과 같다. 라이트 로고는 --honey-bright, --add는 #17804f다.

막지 않음:

  • 히스토리 검색 취소·날짜 아이콘은 아직 filter: invert(.6)다. 라이트 color-scheme이면 UA 글리프가 이미 어두운데 invert가 옅게 만든다. 그 줄은 이번 diff 밖이라 인라인은 달지 않았다.
  • 인쇄 블록은 --add / --del / --danger-*를 안 덮는다. 다크 화면에서 인쇄하면 밝은 녹·적 잉크가 남는다. 원래 리터럴이라 회귀는 아니다.

@isac322
isac322 merged commit 1912bdf into main Oct 6, 2026
5 checks passed
@isac322
isac322 deleted the isac322/light-mode branch October 6, 2026 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants