From b60c0ce3c43e01e99d349ceb7aa16a4050e2989f Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Fri, 13 Feb 2026 00:29:50 +0000 Subject: [PATCH] fix: migrate all components to theme-aware CSS variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ~150 hardcoded Tailwind color classes (bg-zinc-*, text-zinc-*, border-white/*, text-cyan-*, bg-cyan-*) with CSS custom properties (--pc-*) across all 17 components. Add @theme block in index.css for Tailwind v4 theme-aware utility classes (bg-pc-elevated, text-pc-text, border-pc-border, etc.). Add --pc-hover, --pc-hover-strong, --pc-separator variables per theme (white/alpha for dark/OLED, black/alpha for light). Theme switcher (dark/light/OLED) now actually works — all UI elements respond to theme changes in real-time. Fixes #55 --- src/components/Chat.tsx | 28 ++++++------ src/components/ChatInput.tsx | 22 +++++----- src/components/ChatMessage.tsx | 40 ++++++++--------- src/components/CodeBlock.tsx | 4 +- src/components/ErrorBoundary.tsx | 12 +++--- src/components/Header.tsx | 42 +++++++++--------- src/components/ImageBlock.tsx | 4 +- src/components/KeyboardShortcuts.tsx | 22 +++++----- src/components/LanguageSelector.tsx | 2 +- src/components/LoginScreen.tsx | 22 +++++----- src/components/SessionIcon.tsx | 2 +- src/components/Sidebar.tsx | 64 ++++++++++++++-------------- src/components/ThinkingBlock.tsx | 6 +-- src/components/ToolCall.tsx | 16 +++---- src/components/TypingIndicator.tsx | 10 ++--- src/contexts/ThemeContext.tsx | 9 ++++ src/index.css | 34 ++++++++++++--- 17 files changed, 184 insertions(+), 155 deletions(-) diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index ab41548..f93380d 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -136,30 +136,30 @@ export function Chat({ messages, isGenerating, isLoadingHistory, status, session
{messages.length === 0 && isLoadingHistory && ( -
- -
{t('chat.loadingHistory')}
+
+ +
{t('chat.loadingHistory')}
)} {messages.length === 0 && !isLoadingHistory && ( -
+
-
- +
+
-
{t('chat.welcome')}
-
{t('chat.welcomeSub')}
+
{t('chat.welcome')}
+
{t('chat.welcomeSub')}
)} {visibleMessages.map(({ msg, showSep }) => (
{showSep && (
-
- {formatDateSeparator(msg.timestamp, t)} -
+
+ {formatDateSeparator(msg.timestamp, t)} +
)} @@ -176,7 +176,7 @@ export function Chat({ messages, isGenerating, isLoadingHistory, status, session onClick={globalState === 'expand-all' ? collapseAll : expandAll} aria-label={globalState === 'expand-all' ? t('chat.collapseTools') : t('chat.expandTools')} title={globalState === 'expand-all' ? t('chat.collapseTools') : t('chat.expandTools')} - className="flex items-center gap-1.5 rounded-full border border-white/10 bg-zinc-800/90 backdrop-blur-lg px-3 py-2 text-xs text-zinc-300 shadow-lg hover:bg-zinc-700/90 transition-all hover:shadow-violet-500/10" + className="flex items-center gap-1.5 rounded-full border border-pc-border-strong bg-pc-elevated/90 backdrop-blur-lg px-3 py-2 text-xs text-pc-text shadow-lg hover:bg-pc-elevated/90 transition-all hover:shadow-violet-500/10" > {globalState === 'expand-all' ? : } @@ -185,9 +185,9 @@ export function Chat({ messages, isGenerating, isLoadingHistory, status, session )} diff --git a/src/components/ChatInput.tsx b/src/components/ChatInput.tsx index 832649c..6ea51e6 100644 --- a/src/components/ChatInput.tsx +++ b/src/components/ChatInput.tsx @@ -214,7 +214,7 @@ export function ChatInput({ onSend, onAbort, isGenerating, disabled, sessionKey return (
-
+
{/* File previews */} {files.length > 0 && (
{files.map(f => ( -
+
{f.preview ? ( ) : ( - + )}
-
{f.file.name}
-
{formatSize(f.file.size)}
+
{f.file.name}
+
{formatSize(f.file.size)}
))} @@ -253,7 +253,7 @@ export function ChatInput({ onSend, onAbort, isGenerating, disabled, sessionKey {open && pos && createPortal( -
+
{Object.entries(metadata).map(([k, v]) => (
- {k}: - {typeof v === 'object' ? JSON.stringify(v) : String(v)} + {k}: + {typeof v === 'object' ? JSON.stringify(v) : String(v)}
))}
, @@ -309,12 +309,12 @@ function SystemEventMessage({ message }: { message: ChatMessageType }) { return (
-
- - {label} - {display} +
+ + {label} + {display} {message.timestamp && ( - {formatTimestamp(message.timestamp)} + {formatTimestamp(message.timestamp)} )}
@@ -343,12 +343,12 @@ export function ChatMessageComponent({ message, onRetry, agentAvatarUrl }: { mes return (
{/* Avatar */} -
+
{isUser - ? + ? : agentAvatarUrl ? Agent - : + : }
@@ -356,8 +356,8 @@ export function ChatMessageComponent({ message, onRetry, agentAvatarUrl }: { mes
{/* Action buttons */} {!isUser && !message.isStreaming && getPlainText(message).trim() && ( @@ -370,7 +370,7 @@ export function ChatMessageComponent({ message, onRetry, agentAvatarUrl }: { mes {isUser && onRetry && (
{message.timestamp && ( -
+
{formatTimestamp(message.timestamp)}
)} diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx index 6749946..18bc291 100644 --- a/src/components/CodeBlock.tsx +++ b/src/components/CodeBlock.tsx @@ -60,14 +60,14 @@ export function CodeBlock(props: HTMLAttributes) { return (
{language && ( -
+
{formatLanguage(language)}
)}
       
               
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 4e92cda..e17eb3f 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -33,23 +33,23 @@ export function Header({ status, sessionKey, onToggleSidebar, activeSessionData,
 
   return (
     <>
-    
-
PinchChat
- {t('header.title')} - + {t('header.title')} +
- + {activeSessionData?.agentId && ( - + {activeSessionData.agentId} - · + · )} {sessionLabel} @@ -61,7 +61,7 @@ export function Header({ status, sessionKey, onToggleSidebar, activeSessionData, @@ -51,7 +51,7 @@ export function ImageBlock({ src, alt }: ImageBlockProps) { type="button" onClick={() => setLightbox(true)} aria-label={`View ${alt || 'image'} full size`} - className="block rounded-xl border border-white/8 cursor-pointer hover:brightness-110 transition-all focus:outline-none focus:ring-2 focus:ring-cyan-400/40" + className="block rounded-xl border border-pc-border cursor-pointer hover:brightness-110 transition-all focus:outline-none focus:ring-2 focus:ring-[var(--pc-accent-dim)]" > + {children} ); @@ -18,7 +18,7 @@ function Kbd({ children }: { children: React.ReactNode }) { function ShortcutRow({ keys, label }: { keys: React.ReactNode; label: string }) { return (
- {label} + {label}
{keys}
); @@ -26,7 +26,7 @@ function ShortcutRow({ keys, label }: { keys: React.ReactNode; label: string }) function SectionTitle({ children }: { children: React.ReactNode }) { return ( -
+
{children}
); @@ -56,18 +56,18 @@ export function KeyboardShortcuts({ open, onClose }: Props) { {/* Modal */}
e.stopPropagation()} > {/* Header */} -
+
- -

{t('shortcuts.title')}

+ +

{t('shortcuts.title')}

-

+

{t('login.storedLocally')}

diff --git a/src/components/SessionIcon.tsx b/src/components/SessionIcon.tsx index 9bc2230..30880cb 100644 --- a/src/components/SessionIcon.tsx +++ b/src/components/SessionIcon.tsx @@ -52,7 +52,7 @@ export function SessionIcon({ session, isActive, isCurrentSession }: { isCurrentSession?: boolean; }) { const size = 15; - const baseClass = isCurrentSession ? 'text-cyan-300/70' : isActive ? 'text-violet-400/70' : ''; + const baseClass = isCurrentSession ? 'text-pc-accent-light/70' : isActive ? 'text-violet-400/70' : ''; // Detect cron sessions from key pattern const isCron = session.key.includes(':cron:'); diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 40d19f7..d89cbb9 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -142,18 +142,18 @@ export function Sidebar({ sessions, activeSession, onSwitch, onDelete, open, onC return ( <> {open &&
} -