Skip to content

Commit e7a97d7

Browse files
committed
feat: implement theme provider and enhance UI with dark/light mode support
- Added ThemeProvider component to manage theme switching. - Integrated theme context into various components for consistent styling. - Updated CSS for custom scrollbars and Prism.js theme switching. - Refactored multiple components to utilize theme-aware styles for improved UI consistency. 🤖 Generated with [Claude Code](https://claude.ai/code)
1 parent 4625d29 commit e7a97d7

20 files changed

+307
-99
lines changed

src/App.css

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,146 @@
117117
body {
118118
@apply bg-background text-foreground;
119119
}
120+
121+
/* Custom scrollbar for webkit browsers */
122+
::-webkit-scrollbar {
123+
width: 6px;
124+
height: 6px;
125+
}
126+
127+
::-webkit-scrollbar-track {
128+
background: transparent;
129+
}
130+
131+
::-webkit-scrollbar-thumb {
132+
background: hsl(var(--muted-foreground) / 0.3);
133+
border-radius: 3px;
134+
}
135+
136+
::-webkit-scrollbar-thumb:hover {
137+
background: hsl(var(--muted-foreground) / 0.5);
138+
}
139+
140+
/* For Firefox */
141+
* {
142+
scrollbar-width: thin;
143+
scrollbar-color: hsl(var(--muted-foreground) / 0.3) transparent;
144+
}
145+
}
146+
147+
/* Prism.js theme switching */
148+
.light pre[class*="language-"],
149+
.light code[class*="language-"] {
150+
color: #657b83 !important;
151+
background: #fdf6e3 !important;
152+
}
153+
154+
.dark pre[class*="language-"],
155+
.dark code[class*="language-"] {
156+
color: #f8f8f2 !important;
157+
background: #272822 !important;
158+
}
159+
160+
.light .token.comment,
161+
.light .token.prolog,
162+
.light .token.doctype,
163+
.light .token.cdata {
164+
color: #93a1a1 !important;
165+
}
166+
167+
.dark .token.comment,
168+
.dark .token.prolog,
169+
.dark .token.doctype,
170+
.dark .token.cdata {
171+
color: #75715e !important;
172+
}
173+
174+
.light .token.property,
175+
.light .token.tag,
176+
.light .token.constant,
177+
.light .token.symbol,
178+
.light .token.deleted {
179+
color: #dc322f !important;
180+
}
181+
182+
.dark .token.property,
183+
.dark .token.tag,
184+
.dark .token.constant,
185+
.dark .token.symbol,
186+
.dark .token.deleted {
187+
color: #f92672 !important;
188+
}
189+
190+
.light .token.boolean,
191+
.light .token.number {
192+
color: #d33682 !important;
193+
}
194+
195+
.dark .token.boolean,
196+
.dark .token.number {
197+
color: #ae81ff !important;
198+
}
199+
200+
.light .token.selector,
201+
.light .token.attr-name,
202+
.light .token.string,
203+
.light .token.char,
204+
.light .token.builtin,
205+
.light .token.inserted {
206+
color: #859900 !important;
207+
}
208+
209+
.dark .token.selector,
210+
.dark .token.attr-name,
211+
.dark .token.string,
212+
.dark .token.char,
213+
.dark .token.builtin,
214+
.dark .token.inserted {
215+
color: #a6e22e !important;
216+
}
217+
218+
.light .token.atrule,
219+
.light .token.attr-value,
220+
.light .token.keyword {
221+
color: #268bd2 !important;
222+
}
223+
224+
.dark .token.atrule,
225+
.dark .token.attr-value,
226+
.dark .token.keyword {
227+
color: #66d9ef !important;
228+
}
229+
230+
.light .token.function,
231+
.light .token.class-name {
232+
color: #b58900 !important;
233+
}
234+
235+
.dark .token.function,
236+
.dark .token.class-name {
237+
color: #e6db74 !important;
238+
}
239+
240+
/* Specific scrollbar styles for conversation list and other containers */
241+
.conversation-list-scroll::-webkit-scrollbar,
242+
.overflow-y-auto::-webkit-scrollbar {
243+
width: 6px;
244+
}
245+
246+
.conversation-list-scroll::-webkit-scrollbar-track,
247+
.overflow-y-auto::-webkit-scrollbar-track {
248+
background: transparent;
249+
}
250+
251+
.conversation-list-scroll::-webkit-scrollbar-thumb,
252+
.overflow-y-auto::-webkit-scrollbar-thumb {
253+
background: hsl(var(--muted-foreground) / 0.3);
254+
border-radius: 3px;
255+
}
256+
257+
.conversation-list-scroll::-webkit-scrollbar-thumb:hover,
258+
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
259+
background: hsl(var(--muted-foreground) / 0.5);
120260
}
121261

122262
/* Streaming message styles */

src/App.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import DxtPage from "./pages/dxt";
77
import SettingsPage from "./pages/settings";
88
import UsagePage from "./pages/usage";
99
import { useLayoutStore } from "./stores/layoutStore";
10+
import { ThemeProvider } from "@/components/common/ThemeProvider";
1011
import "./App.css";
1112

1213
export default function App() {
@@ -47,5 +48,9 @@ export default function App() {
4748
}
4849
}, []);
4950

50-
return <RouterProvider router={router} />;
51+
return (
52+
<ThemeProvider>
53+
<RouterProvider router={router} />
54+
</ThemeProvider>
55+
);
5156
}

src/components/ChatView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export const ChatView: React.FC = () => {
183183
<div className="flex h-full min-h-0">
184184
{showSessionList && (
185185
<div className="w-64 border-r h-full overflow-y-auto flex-shrink-0">
186-
<div className="flex flex-col h-full bg-gray-50">
186+
<div className="flex flex-col h-full bg-background">
187187

188188
<DebugInfo
189189
conversationListTab={conversationListTab}

src/components/NotesView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const NotesView: React.FC = () => {
88
return (
99
<div className="flex h-full min-h-0">
1010
{showNotesList && (
11-
<div className="w-64 border-r h-full flex-shrink-0">
11+
<div className="w-64 border-r h-full flex-shrink-0 dark:border-gray-700">
1212
<NoteList />
1313
</div>
1414
)}

src/components/chat/ChatInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
8787
};
8888

8989
return (
90-
<div className="flex-shrink-0 border-t p-4 bg-white">
90+
<div className="flex-shrink-0 border-t p-4 bg-background">
9191
<div className="relative">
9292
{/* File references and media attachments inside textarea */}
9393
{(fileReferences.length > 0 || mediaAttachments.length > 0) && (
@@ -111,7 +111,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
111111
onChange={(e) => onInputChange(e.target.value)}
112112
onKeyDown={handleKeyPress}
113113
placeholder={placeholderOverride || "Ask Codex to do anything"}
114-
className={`min-h-[60px] max-h-[200px] pr-32 bg-gray-100 resize-none overflow-y-auto pb-8 ${
114+
className={`min-h-[60px] max-h-[200px] pr-32 bg-muted/50 resize-none overflow-y-auto pb-8 ${
115115
(fileReferences.length > 0 || mediaAttachments.length > 0) ? 'pt-8' : ''
116116
}`}
117117
disabled={false}
@@ -136,7 +136,7 @@ export const ChatInput: React.FC<ChatInputProps> = ({
136136
<Button
137137
onClick={handleStopStreaming}
138138
size="sm"
139-
className="bg-red-500 hover:bg-red-600 text-white h-8 w-8 p-0"
139+
className="bg-destructive hover:bg-destructive/90 text-destructive-foreground h-8 w-8 p-0"
140140
variant="default"
141141
>
142142
<Square className="w-4 h-4" />

src/components/chat/ConversationItem.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,40 +67,40 @@ export function ConversationItem({
6767
<div
6868
key={`${tabPrefix}-${conversation.id}-${index}`}
6969
className={cn(
70-
"group relative p-3 rounded-lg cursor-pointer border transition-all hover:bg-white hover:shadow-sm",
70+
"group relative p-3 rounded-lg cursor-pointer border transition-all hover:bg-accent hover:shadow-sm",
7171
isCurrentlySelected
72-
? "bg-blue-100 border-blue-300 shadow-sm"
73-
: "bg-white border-transparent hover:border-gray-200",
72+
? "bg-primary/10 border-primary/30 shadow-sm"
73+
: "bg-card border-transparent hover:border-border",
7474
)}
7575
onClick={() => onSelectConversation(conversation)}
7676
>
7777
<div className="flex items-start justify-between gap-2">
7878
<div className="flex-1 min-w-0">
7979
<div className="flex items-center gap-2 mb-1">
80-
<MessageSquare className="h-3 w-3 text-gray-400 flex-shrink-0" />
81-
<h4 className="text-sm font-medium truncate flex-1 text-gray-900">
80+
<MessageSquare className="h-3 w-3 text-muted-foreground flex-shrink-0" />
81+
<h4 className="text-sm font-medium truncate flex-1 text-foreground">
8282
{conversation.title}
8383
</h4>
8484
{isFavorited && (
8585
<Star className="h-3 w-3 text-yellow-500 fill-current" />
8686
)}
8787
</div>
88-
<p className="text-xs text-gray-500 mt-1 line-clamp-2">
88+
<p className="text-xs text-muted-foreground mt-1 line-clamp-2">
8989
{getPreviewText(conversation)}
9090
</p>
9191
{showSessionId && (
9292
<div className="mt-1 mb-1">
93-
<span className="text-xs text-blue-600 font-mono bg-blue-50 px-1 py-0.5 rounded">
93+
<span className="text-xs text-primary font-mono bg-primary/10 px-1 py-0.5 rounded">
9494
ID: {conversation.id.substring(0, 8)}...
9595
</span>
9696
</div>
9797
)}
9898

9999
<div className="flex items-center justify-between mt-2">
100-
<span className="text-xs text-gray-400">
100+
<span className="text-xs text-muted-foreground/70">
101101
{formatDate(conversation.updatedAt)}
102102
</span>
103-
<span className="text-xs text-gray-400">
103+
<span className="text-xs text-muted-foreground/70">
104104
{conversation.messages.length} messages
105105
</span>
106106
</div>
@@ -134,7 +134,7 @@ export function ConversationItem({
134134
<DropdownMenuContent align="end">
135135
<DropdownMenuItem
136136
onClick={(e) => onDeleteConversation(conversation.id, e)}
137-
className="text-red-600 hover:text-red-700"
137+
className="text-destructive hover:text-destructive/80"
138138
>
139139
<Trash2 className="h-3 w-3 mr-2" />
140140
Delete

src/components/chat/ConversationList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function ConversationList({
2525

2626
if (conversations.length === 0) {
2727
return (
28-
<div className="p-4 text-center text-gray-500 text-sm">
28+
<div className="p-4 text-center text-muted-foreground text-sm">
2929
{isFav ? (
3030
<>
3131
<p>No favorite conversations</p>
@@ -46,7 +46,7 @@ export function ConversationList({
4646
}
4747

4848
return (
49-
<div className="space-y-1 p-2 overflow-y-auto">
49+
<div className="space-y-1 p-2 overflow-y-auto conversation-list-scroll">
5050
{conversations.map((conversation: Conversation, index: number) => {
5151
const isCurrentlySelected = currentConversationId === conversation.id;
5252
const isFavorited = isFav ? true : favoriteStatuses[conversation.id] || false;

src/components/chat/ConversationTabs.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ export function ConversationTabs({
9494
key={`sessions-${conversation.id}-${index}`}
9595
className={`group relative p-3 rounded-lg cursor-pointer border transition-all hover:shadow-sm ${
9696
isCurrentlySelected
97-
? 'bg-blue-50 border-blue-300 shadow-sm'
98-
: 'bg-white border-gray-200 hover:bg-white'
97+
? 'bg-primary/10 border-primary/30 shadow-sm'
98+
: 'bg-card border-border hover:bg-accent'
9999
}`}
100100
onClick={() => onSelectConversation(conversation)}
101101
>
@@ -104,22 +104,22 @@ export function ConversationTabs({
104104
<div className="flex items-center gap-2 mb-1">
105105
<Circle className="h-3 w-3 text-green-500 fill-current flex-shrink-0" />
106106
<h4 className={`text-sm font-medium ${
107-
isCurrentlySelected ? 'text-blue-900' : 'text-gray-900'
107+
isCurrentlySelected ? 'text-primary' : 'text-foreground'
108108
}`}>
109109
{conversation.title}
110110
{isCurrentlySelected && (
111-
<span className="ml-1 text-xs text-blue-600 font-normal">
111+
<span className="ml-1 text-xs text-primary/80 font-normal">
112112
(Current)
113113
</span>
114114
)}
115115
</h4>
116116
</div>
117-
<p className="text-xs text-gray-500 font-mono truncate">
117+
<p className="text-xs text-muted-foreground font-mono truncate">
118118
{conversation.id}
119119
</p>
120120
<div className="flex items-center justify-between mt-2">
121121
<span className="text-xs text-green-600">Active</span>
122-
<span className="text-xs text-gray-400">
122+
<span className="text-xs text-muted-foreground/70">
123123
{conversation.messages.length} messages
124124
</span>
125125
</div>
@@ -129,7 +129,7 @@ export function ConversationTabs({
129129
<Button
130130
variant="ghost"
131131
size="sm"
132-
className="h-6 w-6 p-0 text-red-600 hover:text-red-700"
132+
className="h-6 w-6 p-0 text-destructive hover:text-destructive/80"
133133
onClick={(e) => {
134134
e.stopPropagation();
135135
onKillSession?.(conversation.id);
@@ -160,10 +160,10 @@ export function ConversationTabs({
160160
</TabsList>
161161

162162
<TabsContent value="all" className="flex-1 overflow-y-auto mt-0">
163-
<div className="p-3 bg-white border-b">
163+
<div className="p-3 bg-background border-b">
164164
<div className="flex gap-2">
165165
<div className="relative flex-1">
166-
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-gray-400" />
166+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
167167
<Input
168168
placeholder="Search all conversations..."
169169
value={searchQueries.all}
@@ -195,9 +195,9 @@ export function ConversationTabs({
195195
</TabsContent>
196196

197197
<TabsContent value="favorites" className="flex-1 overflow-y-auto mt-0">
198-
<div className="p-3 bg-white border-b">
198+
<div className="p-3 bg-background border-b">
199199
<div className="relative">
200-
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-gray-400" />
200+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
201201
<Input
202202
placeholder="Search favorite conversations..."
203203
value={searchQueries.favorites}
@@ -219,9 +219,9 @@ export function ConversationTabs({
219219
</TabsContent>
220220

221221
<TabsContent value="sessions" className="flex-1 overflow-y-auto mt-0">
222-
<div className="p-3 bg-white border-b">
222+
<div className="p-3 bg-background border-b">
223223
<div className="relative">
224-
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-gray-400" />
224+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-3 w-3 text-muted-foreground" />
225225
<Input
226226
placeholder="Search active sessions..."
227227
value={searchQueries.sessions}
@@ -231,7 +231,7 @@ export function ConversationTabs({
231231
</div>
232232
</div>
233233
{filteredConversations.length === 0 ? (
234-
<div className="p-4 text-center text-gray-500 text-sm">
234+
<div className="p-4 text-center text-muted-foreground text-sm">
235235
<p>No active sessions</p>
236236
<p className="text-xs mt-1">
237237
Send a message to create a session

0 commit comments

Comments
 (0)