diff --git a/FEEDBACK.md b/FEEDBACK.md index aaae571..7ad2852 100644 --- a/FEEDBACK.md +++ b/FEEDBACK.md @@ -649,10 +649,17 @@ ## Item #60 - **Date:** 2026-02-13 - **Priority:** high -- **Status:** pending +- **Status:** done +- **Completed:** 2026-02-13 — commit `e596eea` - **Description:** Light theme fixes — 4 issues: - 1. Progress bar colors (sidebar + header) should follow accent color, not hardcoded cyan - 2. Send button gradient should adapt to theme/accent - 3. Tool call badges are unreadable in light theme (dark-only Tailwind classes like amber-950, sky-950) - 4. User message bubble background too subtle in light theme — needs more contrast - - Sub-agent working on this (session pinchchat-light-theme-fix) + 1. Progress bar colors (sidebar + header) should follow accent color, not hardcoded cyan — ✅ already using `--pc-accent-rgb` + 2. Send button gradient should adapt to theme/accent — ✅ already using `var(--pc-accent)` + 3. Tool call badges are unreadable in light theme (dark-only Tailwind classes like amber-950, sky-950) — ✅ fixed: darker text + higher bg opacity in light mode + 4. User message bubble background too subtle in light theme — needs more contrast — ✅ fixed: higher opacity bg + border in light mode + - Added `resolvedTheme` to ThemeContext for components to adapt to current theme + +## Item #61 +- **Date:** 2026-02-13 +- **Priority:** medium +- **Status:** pending +- **Description:** Markdown unordered lists (- item, * item) are not rendered properly in chat messages. They appear as raw text instead of formatted bullet points. Need to verify remarkGfm/ReactMarkdown config handles list rendering correctly, and ensure CSS styles are applied for ul/ol elements in the markdown-body class. diff --git a/src/components/ChatMessage.tsx b/src/components/ChatMessage.tsx index f0010fa..be1ec0c 100644 --- a/src/components/ChatMessage.tsx +++ b/src/components/ChatMessage.tsx @@ -7,6 +7,7 @@ import remarkBreaks from 'remark-breaks'; import rehypeHighlight from 'rehype-highlight'; import { rehypeHighlightOptions } from '../lib/highlight'; import type { ChatMessage as ChatMessageType, MessageBlock } from '../types'; +import { useTheme } from '../hooks/useTheme'; import { ThinkingBlock } from './ThinkingBlock'; import { ThinkingIndicator } from './ThinkingIndicator'; import { CodeBlock } from './CodeBlock'; @@ -382,6 +383,8 @@ function SystemEventMessage({ message }: { message: ChatMessageType }) { export function ChatMessageComponent({ message: rawMessage, onRetry, agentAvatarUrl }: { message: ChatMessageType; onRetry?: (text: string) => void; agentAvatarUrl?: string }) { useLocale(); // re-render on locale change + const { resolvedTheme } = useTheme(); + const isLight = resolvedTheme === 'light'; const [showRawJson, setShowRawJson] = useState(false); // Strip webhook/hook scaffolding from user messages before rendering @@ -446,7 +449,9 @@ export function ChatMessageComponent({ message: rawMessage, onRetry, agentAvatar
{/* Action buttons */} diff --git a/src/components/ToolCall.tsx b/src/components/ToolCall.tsx index 860513f..6ab2b89 100644 --- a/src/components/ToolCall.tsx +++ b/src/components/ToolCall.tsx @@ -2,6 +2,7 @@ import { useState, useCallback, useMemo, useEffect, useRef } from 'react'; import { ChevronRight, ChevronDown, Check, Copy, WrapText, AlignLeft } from 'lucide-react'; import hljs from '../lib/highlight'; import { useT } from '../hooks/useLocale'; +import { useTheme } from '../hooks/useTheme'; import { ImageBlock } from './ImageBlock'; import { useToolCollapse } from '../hooks/useToolCollapse'; @@ -31,13 +32,19 @@ const defaultRGB: ToolRGB = { r: 161, g: 161, b: 170 }; // zinc function rgbStr(c: ToolRGB): string { return `${c.r},${c.g},${c.b}`; } -function getColorStyles(name: string): { badge: React.CSSProperties; text: React.CSSProperties; expand: React.CSSProperties; glow: string } { +function getColorStyles(name: string, isLight = false): { badge: React.CSSProperties; text: React.CSSProperties; expand: React.CSSProperties; glow: string } { const c = toolRGBs[name] || defaultRGB; const rgb = rgbStr(c); + // Use darker text and higher bg opacity in light theme for readability + const badgeBgAlpha = isLight ? 0.15 : 0.10; + const expandBgAlpha = isLight ? 0.08 : 0.05; + const textColor = isLight + ? `rgb(${Math.round(c.r * 0.6)},${Math.round(c.g * 0.6)},${Math.round(c.b * 0.6)})` + : `rgb(${c.r},${c.g},${c.b})`; return { - badge: { borderColor: `rgba(${rgb},0.3)`, backgroundColor: `rgba(${rgb},0.10)` }, - text: { color: `rgb(${c.r},${c.g},${c.b})` }, - expand: { borderColor: `rgba(${rgb},0.2)`, backgroundColor: `rgba(${rgb},0.05)` }, + badge: { borderColor: `rgba(${rgb},0.3)`, backgroundColor: `rgba(${rgb},${badgeBgAlpha})` }, + text: { color: textColor }, + expand: { borderColor: `rgba(${rgb},0.2)`, backgroundColor: `rgba(${rgb},${expandBgAlpha})` }, glow: `shadow-[0_0_8px_rgba(${rgb},0.15)]`, }; } @@ -253,8 +260,9 @@ export function ToolCall({ name, input, result }: { name: string; input?: Record const [open, setOpen] = useState(false); const [wrap, setWrap] = useState(true); const { globalState, version } = useToolCollapse(); + const { resolvedTheme } = useTheme(); const lastVersion = useRef(version); - const cs = getColorStyles(name); + const cs = getColorStyles(name, resolvedTheme === 'light'); // Respond to global collapse/expand commands useEffect(() => { diff --git a/src/contexts/ThemeContext.tsx b/src/contexts/ThemeContext.tsx index f07ed6b..eb8e7c9 100644 --- a/src/contexts/ThemeContext.tsx +++ b/src/contexts/ThemeContext.tsx @@ -180,8 +180,10 @@ export function ThemeProvider({ children }: { children: ReactNode }) { return () => mq.removeEventListener('change', handler); }, [theme]); + const resolvedTheme = resolveTheme(theme); + return ( - + {children} ); diff --git a/src/contexts/ThemeContextDef.ts b/src/contexts/ThemeContextDef.ts index 6e7cb5d..950f704 100644 --- a/src/contexts/ThemeContextDef.ts +++ b/src/contexts/ThemeContextDef.ts @@ -6,6 +6,8 @@ export type AccentColor = 'cyan' | 'violet' | 'emerald' | 'amber' | 'rose' | 'bl export interface ThemeContextValue { theme: ThemeName; accent: AccentColor; + /** Resolved concrete theme (never 'system'). */ + resolvedTheme: 'dark' | 'light' | 'oled'; setTheme: (t: ThemeName) => void; setAccent: (a: AccentColor) => void; } @@ -13,6 +15,7 @@ export interface ThemeContextValue { export const ThemeContext = createContext({ theme: 'dark', accent: 'cyan', + resolvedTheme: 'dark', setTheme: () => {}, setAccent: () => {}, });