feat(ui): polish pawwork theme to match mockups and enable dark mode#198
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 9 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis pull request enables dynamic color scheme selection for the pawwork theme. The preload script now computes color schemes from localStorage or system preferences instead of forcing light mode. The theme context removes restrictions that locked the default theme to light mode, and CSS variables are updated with light/dark mode variants. Component styling and theme tokens are adjusted accordingly. Changes
Sequence DiagramsequenceDiagram
participant Browser as Browser<br/>(Page Load)
participant Preload as Preload Script
participant Storage as localStorage
participant Prefs as System<br/>Preferences
participant DOM as DOM
Browser->>Preload: Execute preload script
Preload->>Storage: Read pawwork theme
Storage-->>Preload: Return stored theme
Preload->>Storage: Ensure theme is "pawwork"
Preload->>Storage: Read pawwork-color-scheme
Storage-->>Preload: Return scheme value
alt scheme is "light" or "dark"
Preload->>DOM: Set colorScheme directly
else scheme is "system"
Preload->>Prefs: Query prefers-color-scheme
Prefs-->>Preload: Return system preference
Preload->>DOM: Set colorScheme to system value
else invalid or empty
Preload->>Storage: Reset to "light"
Preload->>DOM: Set colorScheme to "light"
end
DOM->>DOM: Apply color-scheme CSS variables
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/app/src/index.css`:
- Around line 95-97: Add a blank line immediately before the existing
background: declaration to satisfy Stylelint's rule about spacing; locate the
background: block (the multi-line background property using
var(--shell-highlight-overlay) and linear-gradient(180deg,
var(--shell-background-base), var(--shell-background-weak))) and insert a single
empty line above it so the stylesheet has a separating blank line before that
declaration.
In `@packages/ui/src/theme/themes/pawwork.json`:
- Around line 32-33: The contrast between "button-primary-base" (`#FF5910`) and
"text-on-interactive-base" (`#FFFFFF`) is too low (3.14:1); update pawwork.json to
use colors that meet WCAG AA 4.5:1 for normal text by either darkening
"text-on-interactive-base" (choose a darker hex that yields ≥4.5:1 against
`#FF5910`) or darkening "button-primary-base" (choose a darker hex and keep text
white), then verify the new pair with a contrast checker and commit the adjusted
hex values for the "button-primary-base" and/or "text-on-interactive-base" keys.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ad5c8da2-3530-4696-9fb8-e54fd7bcbea3
📒 Files selected for processing (7)
packages/app/public/oc-theme-preload.jspackages/app/src/components/titlebar.tsxpackages/app/src/index.csspackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/app/src/theme-preload.test.tspackages/ui/src/theme/context.tsxpackages/ui/src/theme/themes/pawwork.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: unit-windows-opencode-server-tools
- GitHub Check: unit-windows-desktop
- GitHub Check: unit-windows-opencode-session
- GitHub Check: unit-windows-opencode-config-project
- GitHub Check: unit-opencode
- GitHub Check: unit-windows-app
- GitHub Check: unit-desktop
- GitHub Check: typecheck
- GitHub Check: unit-app
- GitHub Check: smoke-macos-arm64
- GitHub Check: analyze-js-ts
- GitHub Check: e2e-artifacts
🧰 Additional context used
📓 Path-based instructions (1)
packages/app/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/app/AGENTS.md)
Always prefer
createStoreover multiplecreateSignalcalls in SolidJS
Files:
packages/app/src/components/titlebar.tsxpackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/app/src/theme-preload.test.tspackages/app/public/oc-theme-preload.js
🧠 Learnings (16)
📓 Common learnings
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/ui/src/theme/context.tsx:11-16
Timestamp: 2026-04-22T09:32:52.535Z
Learning: In Astro-Han/pawwork (`packages/ui/src/theme/context.tsx` and related files), the renaming of localStorage theme keys from `opencode-*` to `pawwork-*` (THEME_ID, COLOR_SCHEME, THEME_CSS_LIGHT, THEME_CSS_DARK) is intentional and should NOT include a migration path from the old keys. Migrating would re-couple PawWork and OpenCode browser storage namespaces, which the PR is explicitly designed to avoid. A reset to the PawWork default theme on upgrade is acceptable by design.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 191
File: packages/app/src/components/session/pawwork-skill-meta.ts:38-39
Timestamp: 2026-04-23T15:10:21.635Z
Learning: In Astro-Han/pawwork, Tailwind v4 is configured with `--color-*: initial`, which resets the entire default palette. This means standard Tailwind color utilities like `text-violet-500` resolve to no CSS variable and render black (i.e., they are a no-op). For accent/brand colors that do not have a semantic design token (e.g., the violet writing-assistant accent `#8B5FBF`), use an inline style (e.g., `homeIconStyle: { color: "#8B5FBF" }`) and document the reason with a comment. Do NOT suggest replacing inline hex colors with Tailwind palette utilities in this repo.
📚 Learning: 2026-04-22T09:32:52.535Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/ui/src/theme/context.tsx:11-16
Timestamp: 2026-04-22T09:32:52.535Z
Learning: In Astro-Han/pawwork (`packages/ui/src/theme/context.tsx` and related files), the renaming of localStorage theme keys from `opencode-*` to `pawwork-*` (THEME_ID, COLOR_SCHEME, THEME_CSS_LIGHT, THEME_CSS_DARK) is intentional and should NOT include a migration path from the old keys. Migrating would re-couple PawWork and OpenCode browser storage namespaces, which the PR is explicitly designed to avoid. A reset to the PawWork default theme on upgrade is acceptable by design.
Applied to files:
packages/app/src/components/titlebar.tsxpackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/app/src/theme-preload.test.tspackages/app/public/oc-theme-preload.jspackages/app/src/index.csspackages/ui/src/theme/themes/pawwork.json
📚 Learning: 2026-04-23T07:23:23.849Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 180
File: packages/app/src/components/session/session-new-view.tsx:13-18
Timestamp: 2026-04-23T07:23:23.849Z
Learning: In pawwork (Astro-Han/pawwork), prefer using `createStore` instead of multiple `createSignal` calls only when the signals represent **coupled** object state that is updated together (i.e., there is at least one shared batch-update site where the state is changed in the same transaction). If the state fields are **independent** and are mutated by separate handlers (e.g., one handler updates only `selectedSkill` while another updates only `mode`), keep them as individual `createSignal` calls—using `createStore` for truly independent fields adds boilerplate without behavioral benefit.
Applied to files:
packages/app/src/components/titlebar.tsxpackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/app/src/theme-preload.test.tspackages/app/public/oc-theme-preload.js
📚 Learning: 2026-04-23T15:10:21.635Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 191
File: packages/app/src/components/session/pawwork-skill-meta.ts:38-39
Timestamp: 2026-04-23T15:10:21.635Z
Learning: This repo configures Tailwind v4 with `--color-*: initial`, which effectively breaks standard Tailwind palette utilities (e.g., `text-violet-500` can resolve to no CSS variable and render as a no-op/black). For brand/accent colors that are not backed by semantic design tokens, use inline styles with the exact hex value (e.g., `style={{ color: '#8B5FBF' }}` / `homeIconStyle: { color: '#8B5FBF' }`) and add a short comment explaining that Tailwind palette utilities won’t work due to the `--color-*: initial` setup. Do not suggest replacing these inline hex colors with Tailwind palette classes anywhere in this repo.
Applied to files:
packages/app/src/components/titlebar.tsxpackages/app/src/pages/layout/pawwork-sidebar.tsxpackages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-23T15:26:03.112Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 193
File: packages/app/src/pages/layout/sidebar-items.tsx:102-107
Timestamp: 2026-04-23T15:26:03.112Z
Learning: In Astro-Han/pawwork (`packages/app/src/pages/layout/sidebar-items.tsx`), the `indicator()` function in `SessionRow` intentionally renders `props.leadingSlot` (the pin button) only as a fallback when no status indicator (running/permission/error/unseen) is active. When a higher-priority status wins the slot, the pin button is removed from the DOM — this is a deliberate design choice for the merged leading slot (`#150`). The keyboard unpin path is preserved via: (1) focusing the row anchor triggers `group-focus-within` which reveals the dots menu trigger, then Tab → Enter → "Unpin Session"; (2) the context menu (right-click / Shift+F10) exposes "Unpin Session". The "always render + CSS overlay" approach was considered but rejected due to z-index/pointer-events complexity; residual `...` slot behavior is tracked in `#192`. Do NOT flag the absence of the pin button from the DOM when a status is active as an accessibility regression.
Applied to files:
packages/app/src/pages/layout/pawwork-sidebar.tsx
📚 Learning: 2026-04-22T09:32:52.535Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/ui/src/theme/context.tsx:11-16
Timestamp: 2026-04-22T09:32:52.535Z
Learning: In the PawWork UI theme module (e.g., packages/ui/src/theme/context.tsx and related files), do not add a browser storage migration for the theme localStorage keys renamed from `opencode-*` to `pawwork-*` (`THEME_ID`, `COLOR_SCHEME`, `THEME_CSS_LIGHT`, `THEME_CSS_DARK`). The rename is intentionally meant to keep PawWork and OpenCode storage namespaces decoupled; migrating would re-couple the namespaces. Resetting/using the PawWork default theme on upgrade is acceptable by design.
Applied to files:
packages/ui/src/theme/context.tsx
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Import test utilities from `../fixtures` instead of `playwright/test`
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use `expect.poll(...)` for probing mock or backend state rather than transient DOM visibility
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Prefer the `project` fixture for tests that need a dedicated project with LLM mocking
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Prefer Effect-aware helpers from `fixture/fixture.ts` over building manual runtimes in tests: use `tmpdirScoped()` for scoped temp directories, `provideInstance(dir)(effect)` for low-level binding without directory creation, `provideTmpdirInstance(...)` for single temp instance binding, or `provideTmpdirServer(...)` for tests that also need the test LLM server.
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/packages/app/src/testing/**/*.ts : Test-only hooks must be inert unless explicitly enabled and should not add normal-runtime listeners, reactive subscriptions, or per-update allocations
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-22T08:49:44.563Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/desktop-electron/src/main/index-sidecar-source.test.ts:3-11
Timestamp: 2026-04-22T08:49:44.563Z
Learning: In `packages/desktop-electron/src/main/index-sidecar-source.test.ts` (Astro-Han/pawwork), the test intentionally uses `expect(source).toContain` / `expect(source).not.toContain` string matching against the raw `index.ts` source text as a lightweight sidecar contract guard. The maintainer has explicitly chosen not to introduce an AST parser (e.g., `babel/parser` or acorn) for this purpose. Do not flag these string-based assertions as fragile or suggest converting them to AST-based matching.
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:04.099Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.099Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Test one feature per test file
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-22T09:32:52.806Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 126
File: packages/opencode/test/provider/provider.test.ts:64-85
Timestamp: 2026-04-22T09:32:52.806Z
Learning: In `packages/opencode/test/provider/provider.test.ts`, the file intentionally uses AppRuntime-based async helpers (`run`, `list`, `getProvider`, etc.) rather than `testEffect(...)` for all tests. Converting individual tests to `testEffect` while leaving the rest on the async pattern would create internal inconsistency. A full harness migration of this file is the right approach if the pattern needs to change, but that should be a separate PR.
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-20T14:36:31.017Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/opencode/test/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:31.017Z
Learning: Applies to packages/opencode/test/**/*.test.{ts,tsx} : Use `testEffect(...)` from `test/lib/effect.ts` for tests that exercise Effect services or Effect-based workflows.
Applied to files:
packages/app/src/theme-preload.test.ts
📚 Learning: 2026-04-23T15:10:21.635Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 191
File: packages/app/src/components/session/pawwork-skill-meta.ts:38-39
Timestamp: 2026-04-23T15:10:21.635Z
Learning: In Astro-Han/pawwork, Tailwind v4 is configured with `--color-*: initial`, which resets the entire default palette. This means standard Tailwind color utilities like `text-violet-500` resolve to no CSS variable and render black (i.e., they are a no-op). For accent/brand colors that do not have a semantic design token (e.g., the violet writing-assistant accent `#8B5FBF`), use an inline style (e.g., `homeIconStyle: { color: "#8B5FBF" }`) and document the reason with a comment. Do NOT suggest replacing inline hex colors with Tailwind palette utilities in this repo.
Applied to files:
packages/app/public/oc-theme-preload.jspackages/ui/src/theme/themes/pawwork.json
🪛 ast-grep (0.42.1)
packages/app/src/theme-preload.test.ts
[warning] 14-14: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.head.innerHTML = ""
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html
(dom-content-modification)
🪛 Stylelint (17.9.0)
packages/app/src/index.css
[error] 95-97: Expected empty line before declaration (declaration-empty-line-before)
(declaration-empty-line-before)
🔇 Additional comments (12)
packages/app/src/pages/layout/pawwork-sidebar.tsx (1)
241-258: LGTM!The sidebar background update and Button styling changes align well with the PR objectives. Using inline CSS variable overrides for the orange-tinted filled primary affordance is appropriate given the repo's Tailwind v4 configuration where
--color-*: initialbreaks standard palette utilities.packages/app/src/components/titlebar.tsx (2)
7-7: LGTM!The import cleanup is correct—
Tooltipis no longer needed after removing the back/forward chevron buttons. Keyboard navigation (⌘[ / ⌘]) remains functional viacommand.register.
144-149: LGTM!The spacing adjustment and retained conditional rendering logic are correct. The sidebar wrapper div's class change aligns with the titlebar cleanup.
packages/app/public/oc-theme-preload.js (1)
1-31: LGTM!The preload script correctly implements dynamic color scheme resolution:
- Directly uses stored
"light"/"dark"values- Resolves
"system"viamatchMediawith a defensivewindow.matchMedia &&guard- Falls back to
"light"for invalid/missing values- Clears cached CSS when migrating from non-pawwork themes while preserving the stored scheme
This aligns well with the test coverage in
packages/app/src/theme-preload.test.ts.packages/app/src/theme-preload.test.ts (3)
7-12: LGTM!The
setMatchMediahelper is well-designed withconfigurable: trueallowing proper reassignment between tests. ThebeforeEachsetup correctly initializes a deterministic state for scheme resolution tests.Also applies to: 14-19
22-50: LGTM!Test coverage is comprehensive:
- First-install defaults to
"light"with proper storage initialization- Stored
"dark"scheme is preserved and applied"system"resolves against mockedmatchMediaresult and persists the"system"preference (not the resolved value)
52-68: LGTM!The legacy migration tests correctly verify that cached CSS entries are cleared while the stored color scheme (
"dark") is preserved during theme migration. This aligns with the PR objective to preserve stored scheme across legacy theme migrations.packages/ui/src/theme/context.tsx (3)
98-100: LGTM!Removing the pawwork-specific coercion from
resolveModeis correct. The underscore prefix (_themeId) clearly signals the unused parameter for future extensibility.
147-148: LGTM!The fallback logic is well-designed:
- First-install users default to
"light"for a predictable initial experience- Returning users without a stored scheme get
"system"to respect their OS preference
264-268: LGTM!The simplified
setColorSchemefunction and unconditionalcanSwitchColorScheme: () => truecorrectly unlock scheme switching for all themes. This enables the color scheme selector in Settings → General and themod+shift+scommand (perpackages/app/src/pages/layout.tsx:1237-1262).Also applies to: 278-278
packages/app/src/index.css (2)
77-98: LGTM!The light mode shell token updates and highlight overlay integration look correct. The new
--shell-highlight-overlayproperty cleanly separates the radial gradient for reuse in both modes.
100-114: LGTM!The dark mode desktop-shell overrides are well-structured. The selector
:root[data-color-scheme="dark"] [data-component="desktop-shell"][data-platform="desktop"]correctly targets the shell when dark mode is active (driven by the preload script and theme context).
4c9b8c7 to
f0413d6
Compare
The back/forward chevrons in the titlebar duplicated keyboard shortcuts (⌘[ / ⌘]) which remain wired through command.register, and added visual noise that diverges from the PawWork home mockups. Drop the UI buttons along with the now-dead canBack / canForward / hasProjects memos and Tooltip import.
Light polish: - Invert the surface layering so content raises to white on top of a cream shell, reversing the previous darker-on-top gradient that read as muddy gray in the content area. - Pull shell, sidebar, and background-weak down to near-neutral cream (R≈G≈B) to match the mockup's clean off-white chrome. - Align brand accent to #FF5910 everywhere (replaces the #E8533A drift) and give the sidebar "new session" button an orange-tint fill with orange icon so it reads as the primary affordance. Dark palette: - Add a real pawwork dark palette (cool slate with warm interactive tint) derived from the dark mockups, replacing the placeholder that mirrored light values. In dark, sidebar sits slightly above content rather than below it, matching the mockup's layering. - Add the matching [data-color-scheme="dark"] shell overrides so the titlebar, frame, and chrome tokens also switch to the dark palette.
Now that pawwork ships a real dark palette, stop force-locking the theme to light. Drop the eight pawwork-special cases in the theme context (resolveMode, shouldCacheTheme, onStorage, mount, setTheme, setColorScheme) so canSwitchColorScheme returns true and Settings surfaces the light / dark / system picker. The preload script no longer overwrites pawwork-color-scheme on every boot; it respects stored light / dark and resolves "system" against prefers-color-scheme for the first paint. Legacy theme migrations continue to redirect to pawwork but preserve the user's stored scheme instead of stamping light. Tests cover first install, stored dark, system, and legacy migration paths.
f0413d6 to
d376d6e
Compare
Summary
Brings the PawWork home + session chrome in line with the latest light / dark mockups and turns on the bundled dark palette so users can switch color schemes from Settings.
#FF5910, and give the "新建会话" sidebar button an orange-tint fill with orange icon as the primary affordance.[data-color-scheme="dark"]shell overrides so the frame / titlebar also switch.light/dark/systeminstead of stamping light every boot, and preserve stored scheme across legacy theme migrations.canSwitchColorSchemeis always true now, so the Settings picker is visible.command.register.Test plan
bun dev:desktop— verify light home: sidebar + titlebar cream match the mockup, "新建会话" pill shows orange tint, content surfaces stay white.bun test packages/app/src/theme-preload.test.ts— 8 tests pass (first install, stored dark, system, legacy migration).bun typecheck— clean.Summary by CodeRabbit
New Features
Style