From 9df07fc2cdc59cefb2054c52a130d7767e84cf17 Mon Sep 17 00:00:00 2001 From: sasha Date: Tue, 14 Jul 2026 18:09:54 +0300 Subject: [PATCH 1/3] feat(review): add System option to theme mode toggle The review editor Options menu only offered Light/Dark, while the plan editor menu and Settings theme tab already exposed the System mode that ThemeProvider supports. Bring the review menu in line: - map over light/dark/system with the shared themeIcons (SystemIcon) - highlight the stored mode directly instead of collapsing system to the resolved mode, so the System button shows as selected - drop the local Sun/Moon SVG duplicates in favor of the shared icons --- .../components/ReviewHeaderMenu.tsx | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/packages/review-editor/components/ReviewHeaderMenu.tsx b/packages/review-editor/components/ReviewHeaderMenu.tsx index 35dcf5f96..698f41ae2 100644 --- a/packages/review-editor/components/ReviewHeaderMenu.tsx +++ b/packages/review-editor/components/ReviewHeaderMenu.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React from 'react'; import { ActionMenu, ActionMenuDivider, @@ -6,6 +6,7 @@ import { ActionMenuSectionLabel, } from '@plannotator/ui/components/ActionMenu'; import { useTheme } from '@plannotator/ui/components/ThemeProvider'; +import { SunIcon, MoonIcon, SystemIcon } from '@plannotator/ui/components/icons/themeIcons'; import { MenuVersionSection } from '@plannotator/ui/components/MenuVersionSection'; import { TextShimmer } from '@plannotator/ui/components/TextShimmer'; import { modKey } from '@plannotator/ui/utils/platform'; @@ -37,10 +38,7 @@ export const ReviewHeaderMenu: React.FC = ({ origin, isWSL = false, }) => { - const { theme, resolvedMode, setTheme } = useTheme(); - const activeTheme = useMemo<'light' | 'dark'>(() => { - return theme === 'system' ? resolvedMode : theme; - }, [resolvedMode, theme]); + const { theme, setTheme } = useTheme(); const showUpdateDot = !!updateInfo?.updateAvailable && !updateInfo.dismissed; @@ -80,7 +78,7 @@ export const ReviewHeaderMenu: React.FC = ({
Theme
- {(['light', 'dark'] as const).map((mode) => ( + {(['light', 'dark', 'system'] as const).map((mode) => ( ))} @@ -181,19 +179,6 @@ const ExportIcon = () => ( ); -const SunIcon = () => ( - - - - -); - -const MoonIcon = () => ( - - - -); - const FileTreeMenuIcon = () => ( From c216b5bcacbebdea5d54034a94d6f61485f6ee47 Mon Sep 17 00:00:00 2001 From: sasha Date: Tue, 14 Jul 2026 18:27:18 +0300 Subject: [PATCH 2/3] fix(ui): widen ActionMenu panel to fit three theme mode buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Options dropdown defaults to w-56 (224px), which is too narrow for the Light/Dark/System segmented control — the System button clipped past the panel edge. Bump the default to w-64; PlanHeaderMenu and ReviewHeaderMenu are the only ActionMenu consumers and both render the three-button theme row. --- packages/ui/components/ActionMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/components/ActionMenu.tsx b/packages/ui/components/ActionMenu.tsx index 3ca1f8883..fd6eb26ad 100644 --- a/packages/ui/components/ActionMenu.tsx +++ b/packages/ui/components/ActionMenu.tsx @@ -50,7 +50,7 @@ export const ActionMenu: React.FC = ({ })} {isOpen && ( -
+
{children({ closeMenu: () => setIsOpen(false) })}
)} From b36df617abbde6d082d3aa6aa6ccc68542c230d1 Mon Sep 17 00:00:00 2001 From: sasha Date: Tue, 14 Jul 2026 18:27:18 +0300 Subject: [PATCH 3/3] fix(ui): disable incompatible mode button for single-mode color themes Dark-only palettes silently ignore light mode (and vice versa) in ThemeProvider, letting the toggle no-op. Add getUnsupportedMode() to the theme registry and use it in both header menus to disable the dead button and highlight the mode actually rendered. --- .../components/ReviewHeaderMenu.tsx | 18 ++++++++++++++---- packages/ui/components/PlanHeaderMenu.tsx | 18 ++++++++++++++---- packages/ui/utils/themeRegistry.ts | 13 +++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/review-editor/components/ReviewHeaderMenu.tsx b/packages/review-editor/components/ReviewHeaderMenu.tsx index 698f41ae2..585ab21d0 100644 --- a/packages/review-editor/components/ReviewHeaderMenu.tsx +++ b/packages/review-editor/components/ReviewHeaderMenu.tsx @@ -7,6 +7,7 @@ import { } from '@plannotator/ui/components/ActionMenu'; import { useTheme } from '@plannotator/ui/components/ThemeProvider'; import { SunIcon, MoonIcon, SystemIcon } from '@plannotator/ui/components/icons/themeIcons'; +import { getUnsupportedMode } from '@plannotator/ui/utils/themeRegistry'; import { MenuVersionSection } from '@plannotator/ui/components/MenuVersionSection'; import { TextShimmer } from '@plannotator/ui/components/TextShimmer'; import { modKey } from '@plannotator/ui/utils/platform'; @@ -38,7 +39,12 @@ export const ReviewHeaderMenu: React.FC = ({ origin, isWSL = false, }) => { - const { theme, setTheme } = useTheme(); + const { theme, setTheme, colorTheme } = useTheme(); + const unsupportedMode = getUnsupportedMode(colorTheme); + // When the palette can't render the stored mode, the UI is forced to the + // opposite — highlight the mode actually shown instead of the dead one. + const highlightedTheme = + theme === unsupportedMode ? (unsupportedMode === 'light' ? 'dark' : 'light') : theme; const showUpdateDot = !!updateInfo?.updateAvailable && !updateInfo.dismissed; @@ -81,14 +87,18 @@ export const ReviewHeaderMenu: React.FC = ({ {(['light', 'dark', 'system'] as const).map((mode) => (