moelove commited on
Commit
204e35b
·
1 Parent(s): e1fb264

change style

Browse files

Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>

src/App.jsx CHANGED
@@ -135,47 +135,100 @@ function App() {
135
  };
136
 
137
  return (
138
- <div className="flex flex-col h-screen w-full overflow-hidden">
139
- <div className="flex justify-between items-center px-5 h-header border-b border-border bg-background">
140
- <div className="flex items-center gap-2">
 
141
  <button
142
- className="md:hidden bg-transparent border-0 text-base text-lightest-text cursor-pointer flex items-center justify-center z-10 w-8 h-8 hover:text-text"
143
  onClick={toggleMobileMenu}
144
  >
145
-
 
 
146
  </button>
147
- <h1 className="text-xl font-semibold text-text">Thinking Model Client</h1>
 
 
 
 
 
 
 
 
 
 
 
 
148
  </div>
149
- <div className="flex items-center gap-2.5">
 
 
 
150
  <div className="relative">
151
  <button
152
- className="py-1.5 px-3 bg-background border border-border rounded text-sm text-text cursor-pointer flex items-center gap-1.5"
153
  onClick={toggleProfileDropdown}
154
  >
155
- {activeProfile.name}
 
 
 
 
 
 
156
  </button>
 
157
  {showProfileDropdown && (
158
- <div className="absolute top-full right-0 w-[200px] bg-background border border-border rounded shadow-md z-10 mt-1.5">
159
- {profiles.map(profile => (
160
- <div
161
- key={profile.id}
162
- className={`p-3 cursor-pointer transition-colors duration-200 text-sm ${profile.id === activeProfileId ? 'bg-active font-medium' : 'hover:bg-hover'}`}
163
- onClick={() => handleProfileSelect(profile.id)}
164
- >
165
- {profile.name}
166
  </div>
167
- ))}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  </div>
169
  )}
170
  </div>
 
 
171
  <button
172
- className="py-1.5 px-3 bg-background border border-border rounded text-sm text-text cursor-pointer hover:bg-hover"
173
  onClick={toggleSettings}
174
  >
175
- Settings
 
 
 
 
176
  </button>
177
  </div>
178
- </div>
179
 
180
  <div className="flex flex-1 overflow-hidden">
181
  <div className={`sidebar ${sidebarCollapsed ? 'collapsed' : ''} ${mobileMenuOpen ? 'mobile-open' : ''}`}>
 
135
  };
136
 
137
  return (
138
+ <div className="flex flex-col h-screen w-full overflow-hidden bg-background-secondary">
139
+ {/* Modern Enterprise Header */}
140
+ <header className="flex justify-between items-center px-6 h-header bg-background-elevated border-b border-border shadow-sm">
141
+ <div className="flex items-center gap-4">
142
  <button
143
+ className="md:hidden bg-transparent border-0 text-lg text-muted cursor-pointer flex items-center justify-center z-10 w-10 h-10 rounded-lg hover:bg-background-secondary hover:text-primary transition-all duration-fast"
144
  onClick={toggleMobileMenu}
145
  >
146
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
147
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
148
+ </svg>
149
  </button>
150
+
151
+ {/* Brand Section */}
152
+ <div className="flex items-center gap-3">
153
+ <div className="w-8 h-8 bg-gradient-to-br from-primary to-primary-dark rounded-lg flex items-center justify-center shadow-sm">
154
+ <svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
155
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
156
+ </svg>
157
+ </div>
158
+ <div>
159
+ <h1 className="text-xl font-bold text-primary bg-gradient-to-r from-primary to-primary-dark bg-clip-text text-transparent">Thinking Model Client</h1>
160
+ <p className="text-xs text-muted hidden sm:block">Enterprise AI Assistant</p>
161
+ </div>
162
+ </div>
163
  </div>
164
+
165
+ {/* Controls Section */}
166
+ <div className="flex items-center gap-3">
167
+ {/* Profile Selector */}
168
  <div className="relative">
169
  <button
170
+ className="flex items-center gap-2 py-2 px-4 bg-background-secondary border border-border rounded-lg text-sm text-secondary hover:bg-background-tertiary hover:text-primary hover:border-primary transition-all duration-fast shadow-sm"
171
  onClick={toggleProfileDropdown}
172
  >
173
+ <div className="w-6 h-6 bg-primary rounded-full flex items-center justify-center text-xs text-white font-medium">
174
+ {activeProfile.name.charAt(0).toUpperCase()}
175
+ </div>
176
+ <span className="hidden sm:inline font-medium">{activeProfile.name}</span>
177
+ <svg className={`w-4 h-4 transition-transform duration-fast ${showProfileDropdown ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
178
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
179
+ </svg>
180
  </button>
181
+
182
  {showProfileDropdown && (
183
+ <div className="absolute top-full right-0 w-64 bg-background-elevated border border-border rounded-xl shadow-xl z-50 mt-2 animate-slide-up">
184
+ <div className="p-2">
185
+ <div className="px-3 py-2 text-xs font-semibold text-muted uppercase tracking-wider border-b border-border mb-2">
186
+ Select Profile
 
 
 
 
187
  </div>
188
+ {profiles.map(profile => (
189
+ <button
190
+ key={profile.id}
191
+ className={`w-full flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-all duration-fast text-sm text-left ${
192
+ profile.id === activeProfileId
193
+ ? 'bg-primary-light text-primary font-medium shadow-sm'
194
+ : 'hover:bg-background-secondary text-secondary'
195
+ }`}
196
+ onClick={() => handleProfileSelect(profile.id)}
197
+ >
198
+ <div className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-medium ${
199
+ profile.id === activeProfileId ? 'bg-primary text-white' : 'bg-background-tertiary text-muted'
200
+ }`}>
201
+ {profile.name.charAt(0).toUpperCase()}
202
+ </div>
203
+ <div className="flex-1">
204
+ <div className="font-medium">{profile.name}</div>
205
+ <div className="text-xs text-muted truncate">{profile.model}</div>
206
+ </div>
207
+ {profile.id === activeProfileId && (
208
+ <svg className="w-4 h-4 text-primary" fill="currentColor" viewBox="0 0 20 20">
209
+ <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
210
+ </svg>
211
+ )}
212
+ </button>
213
+ ))}
214
+ </div>
215
  </div>
216
  )}
217
  </div>
218
+
219
+ {/* Settings Button */}
220
  <button
221
+ className="flex items-center gap-2 py-2 px-4 bg-background-secondary border border-border rounded-lg text-sm text-secondary hover:bg-background-tertiary hover:text-primary hover:border-primary transition-all duration-fast shadow-sm"
222
  onClick={toggleSettings}
223
  >
224
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
225
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
226
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
227
+ </svg>
228
+ <span className="hidden sm:inline font-medium">Settings</span>
229
  </button>
230
  </div>
231
+ </header>
232
 
233
  <div className="flex flex-1 overflow-hidden">
234
  <div className={`sidebar ${sidebarCollapsed ? 'collapsed' : ''} ${mobileMenuOpen ? 'mobile-open' : ''}`}>
src/components/ChatList.jsx CHANGED
@@ -1,38 +1,146 @@
1
- import React from 'react';
2
 
3
  function ChatList({ chats, currentChat, onSelectChat, onDeleteChat, onCreateNewChat, collapsed, isStreamingChat }) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  return (
5
- <div className="chat-list">
6
- <button className="new-chat" onClick={onCreateNewChat}>
7
- New Chat
8
- </button>
9
- {chats.length === 0 ? (
10
- <div className="empty-state">No conversations yet</div>
11
- ) : (
12
- chats.map(chat => (
13
- <div
14
- key={chat.id}
15
- className={`chat-item ${chat.id === currentChat?.id ? 'active' : ''} ${isStreamingChat && typeof isStreamingChat === 'function' && isStreamingChat(chat.id) ? 'streaming' : ''}`}
16
- onClick={() => onSelectChat(chat.id)}
17
- >
18
- <div className="flex items-center gap-1">
19
- {isStreamingChat && typeof isStreamingChat === 'function' && isStreamingChat(chat.id) && (
20
- <span className="streaming-dot"></span>
21
- )}
22
- <span>{chat.title}</span>
 
 
 
 
23
  </div>
24
- <button
25
- className="delete-btn"
26
- onClick={(e) => {
27
- e.stopPropagation();
28
- onDeleteChat(chat.id);
29
- }}
30
- >
31
- Delete
32
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </div>
34
- ))
35
- )}
 
 
 
 
 
 
 
36
  </div>
37
  );
38
  }
 
1
+ import React, { useState } from 'react';
2
 
3
  function ChatList({ chats, currentChat, onSelectChat, onDeleteChat, onCreateNewChat, collapsed, isStreamingChat }) {
4
+ const [hoveredChat, setHoveredChat] = useState(null);
5
+
6
+ const formatDate = (timestamp) => {
7
+ const date = new Date(timestamp);
8
+ const now = new Date();
9
+ const diffTime = Math.abs(now - date);
10
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
11
+
12
+ if (diffDays === 1) return 'Today';
13
+ if (diffDays === 2) return 'Yesterday';
14
+ if (diffDays <= 7) return `${diffDays} days ago`;
15
+ return date.toLocaleDateString();
16
+ };
17
+
18
+ const truncateTitle = (title, maxLength = 25) => {
19
+ if (title.length <= maxLength) return title;
20
+ return title.substring(0, maxLength) + '...';
21
+ };
22
+
23
  return (
24
+ <div className="flex flex-col h-full bg-background-elevated">
25
+ {/* New Chat Button */}
26
+ <div className="p-3 border-b border-border">
27
+ <button
28
+ className="w-full flex items-center justify-center gap-2 py-3 px-4 bg-primary hover:bg-primary-hover text-white border-none rounded-xl cursor-pointer text-sm font-medium transition-all duration-fast shadow-sm hover:shadow-md active:scale-[0.98]"
29
+ onClick={onCreateNewChat}
30
+ >
31
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
32
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
33
+ </svg>
34
+ <span>New Conversation</span>
35
+ </button>
36
+ </div>
37
+
38
+ {/* Chat List */}
39
+ <div className="flex-1 overflow-y-auto p-2">
40
+ {chats.length === 0 ? (
41
+ <div className="flex flex-col items-center justify-center py-12 px-4 text-center">
42
+ <div className="w-16 h-16 bg-background-secondary rounded-full flex items-center justify-center mb-4">
43
+ <svg className="w-8 h-8 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
44
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
45
+ </svg>
46
  </div>
47
+ <h3 className="text-sm font-medium text-secondary mb-2">No conversations yet</h3>
48
+ <p className="text-xs text-muted">Start a new conversation to get started</p>
49
+ </div>
50
+ ) : (
51
+ <div className="space-y-1">
52
+ {chats.map(chat => {
53
+ const isActive = chat.id === currentChat?.id;
54
+ const isStreaming = isStreamingChat && typeof isStreamingChat === 'function' && isStreamingChat(chat.id);
55
+ const isHovered = hoveredChat === chat.id;
56
+
57
+ return (
58
+ <div
59
+ key={chat.id}
60
+ className={`group relative flex items-center p-3 rounded-lg cursor-pointer transition-all duration-fast ${
61
+ isActive
62
+ ? 'bg-primary-light border border-primary/20 shadow-sm'
63
+ : 'hover:bg-background-secondary border border-transparent'
64
+ }`}
65
+ onClick={() => onSelectChat(chat.id)}
66
+ onMouseEnter={() => setHoveredChat(chat.id)}
67
+ onMouseLeave={() => setHoveredChat(null)}
68
+ >
69
+ {/* Streaming indicator */}
70
+ {isStreaming && (
71
+ <div className="absolute left-0 top-0 bottom-0 w-1 bg-gradient-to-b from-info to-primary rounded-r-full animate-pulse" />
72
+ )}
73
+
74
+ <div className="flex-1 min-w-0">
75
+ <div className="flex items-center gap-2 mb-1">
76
+ {/* Chat icon */}
77
+ <div className={`flex-shrink-0 w-8 h-8 rounded-lg flex items-center justify-center ${
78
+ isActive ? 'bg-primary text-white' : 'bg-background-tertiary text-muted'
79
+ }`}>
80
+ {isStreaming ? (
81
+ <div className="w-2 h-2 bg-current rounded-full animate-pulse" />
82
+ ) : (
83
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
84
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
85
+ </svg>
86
+ )}
87
+ </div>
88
+
89
+ {/* Chat title */}
90
+ <div className="flex-1 min-w-0">
91
+ <h4 className={`text-sm font-medium truncate ${
92
+ isActive ? 'text-primary' : 'text-secondary'
93
+ }`}>
94
+ {truncateTitle(chat.title)}
95
+ </h4>
96
+
97
+ {/* Message count and date */}
98
+ <div className="flex items-center justify-between mt-1">
99
+ <span className="text-xs text-muted">
100
+ {chat.messages?.length || 0} messages
101
+ </span>
102
+ {chat.messages?.length > 0 && (
103
+ <span className="text-xs text-muted">
104
+ {formatDate(chat.messages[chat.messages.length - 1]?.timestamp || Date.now())}
105
+ </span>
106
+ )}
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ {/* Delete button */}
113
+ <button
114
+ className={`flex-shrink-0 ml-2 p-1.5 rounded-md transition-all duration-fast ${
115
+ isHovered || isActive
116
+ ? 'opacity-100 hover:bg-error-light hover:text-error'
117
+ : 'opacity-0 group-hover:opacity-100'
118
+ }`}
119
+ onClick={(e) => {
120
+ e.stopPropagation();
121
+ if (window.confirm('Are you sure you want to delete this conversation?')) {
122
+ onDeleteChat(chat.id);
123
+ }
124
+ }}
125
+ title="Delete conversation"
126
+ >
127
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
128
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
129
+ </svg>
130
+ </button>
131
+ </div>
132
+ );
133
+ })}
134
  </div>
135
+ )}
136
+ </div>
137
+
138
+ {/* Footer */}
139
+ <div className="p-3 border-t border-border">
140
+ <div className="text-xs text-muted text-center">
141
+ {chats.length} conversation{chats.length !== 1 ? 's' : ''}
142
+ </div>
143
+ </div>
144
  </div>
145
  );
146
  }
src/components/ChatWindow.jsx CHANGED
@@ -342,25 +342,7 @@ function ChatWindow({
342
  };
343
 
344
  return (
345
- <div className="chat-window relative">
346
- {/* Floating New Chat button */}
347
- <button
348
- onClick={() => {
349
- console.log('Floating new chat button clicked');
350
- // 在创建新聊天前添加一些日志
351
- if (typeof onCreateNewChat === 'function') {
352
- console.log('Calling onCreateNewChat function');
353
- onCreateNewChat();
354
- console.log('onCreateNewChat function called');
355
- } else {
356
- console.error('onCreateNewChat is not a function');
357
- }
358
- }}
359
- className="floating-new-chat"
360
- title="Create a new conversation"
361
- >
362
- <span className="text-xl">+</span>
363
- </button>
364
  <div className="chat-messages">
365
  {chat && chat.messages && chat.messages.map((message, index) => {
366
  const parsedMessage = message.role === 'assistant'
 
342
  };
343
 
344
  return (
345
+ <div className="flex flex-col h-full bg-background-primary">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  <div className="chat-messages">
347
  {chat && chat.messages && chat.messages.map((message, index) => {
348
  const parsedMessage = message.role === 'assistant'
src/index.css CHANGED
@@ -2,28 +2,78 @@
2
  @tailwind components;
3
  @tailwind utilities;
4
 
5
- /* Base styles */
6
  :root {
7
- --primary-color: #3e6ae1;
8
- --primary-hover: #2952c8;
9
- --text-color: #1a1a1a;
10
- --light-text: #4d4d4d;
11
- --lightest-text: #737373;
12
- --border-color: #e5e7eb;
13
- --background-color: #ffffff;
14
- --sidebar-width: 280px;
15
- --header-height: 60px;
16
- --reasoning-background: #f9fafb;
17
- --user-message-bg: #f9f8f6;
18
- --user-message-color: var(--text-color);
19
- --assistant-message-bg: #f9f9f9;
20
- --assistant-message-color: #1a1a1a;
21
- --hover-color: #f5f5f5;
22
- --active-color: #e6f2ff;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  /* Responsive sidebar width */
25
  --mobile-sidebar-width: 100%;
26
- --tablet-sidebar-width: 250px;
 
 
 
 
 
27
  }
28
 
29
  * {
 
2
  @tailwind components;
3
  @tailwind utilities;
4
 
5
+ /* Enterprise Design System */
6
  :root {
7
+ /* Primary Brand Colors */
8
+ --primary-color: #2563eb;
9
+ --primary-hover: #1d4ed8;
10
+ --primary-light: #dbeafe;
11
+ --primary-dark: #1e3a8a;
12
+
13
+ /* Secondary Colors */
14
+ --secondary-color: #64748b;
15
+ --secondary-hover: #475569;
16
+ --secondary-light: #f1f5f9;
17
+
18
+ /* Neutral Palette */
19
+ --text-color: #0f172a;
20
+ --text-secondary: #334155;
21
+ --text-muted: #64748b;
22
+ --text-light: #94a3b8;
23
+ --text-disabled: #cbd5e1;
24
+
25
+ /* Background System */
26
+ --background-primary: #ffffff;
27
+ --background-secondary: #f8fafc;
28
+ --background-tertiary: #f1f5f9;
29
+ --background-elevated: #ffffff;
30
+
31
+ /* Border System */
32
+ --border-color: #e2e8f0;
33
+ --border-light: #f1f5f9;
34
+ --border-dark: #cbd5e1;
35
+ --border-accent: #3b82f6;
36
+
37
+ /* Status Colors */
38
+ --success-color: #059669;
39
+ --success-light: #d1fae5;
40
+ --warning-color: #d97706;
41
+ --warning-light: #fef3c7;
42
+ --error-color: #dc2626;
43
+ --error-light: #fee2e2;
44
+ --info-color: #0284c7;
45
+ --info-light: #e0f2fe;
46
+
47
+ /* Layout Variables */
48
+ --sidebar-width: 320px;
49
+ --header-height: 64px;
50
+ --border-radius: 8px;
51
+ --border-radius-lg: 12px;
52
+ --border-radius-xl: 16px;
53
+
54
+ /* Shadow System */
55
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
56
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
57
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
58
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
59
+
60
+ /* Message Specific */
61
+ --reasoning-background: var(--background-tertiary);
62
+ --user-message-bg: var(--primary-color);
63
+ --user-message-color: #ffffff;
64
+ --assistant-message-bg: var(--background-elevated);
65
+ --assistant-message-color: var(--text-color);
66
+ --hover-color: var(--background-secondary);
67
+ --active-color: var(--primary-light);
68
 
69
  /* Responsive sidebar width */
70
  --mobile-sidebar-width: 100%;
71
+ --tablet-sidebar-width: 280px;
72
+
73
+ /* Animation System */
74
+ --transition-fast: 150ms ease-out;
75
+ --transition-normal: 250ms ease-out;
76
+ --transition-slow: 350ms ease-out;
77
  }
78
 
79
  * {
tailwind.config.js CHANGED
@@ -7,13 +7,62 @@ export default {
7
  theme: {
8
  extend: {
9
  colors: {
10
- primary: 'var(--primary-color)',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  'primary-hover': 'var(--primary-hover)',
12
- 'text': 'var(--text-color)',
13
- 'light-text': 'var(--light-text)',
14
- 'lightest-text': 'var(--lightest-text)',
15
- 'border': 'var(--border-color)',
16
- 'background': 'var(--background-color)',
17
  'reasoning-bg': 'var(--reasoning-background)',
18
  'user-message-bg': 'var(--user-message-bg)',
19
  'user-message-color': 'var(--user-message-color)',
@@ -26,14 +75,58 @@ export default {
26
  'sidebar': 'var(--sidebar-width)',
27
  'header': 'var(--header-height)',
28
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  animation: {
30
  'blink': 'blink 1s infinite',
 
 
 
 
31
  },
32
  keyframes: {
33
  blink: {
34
  '0%, 100%': { opacity: 1 },
35
  '50%': { opacity: 0 },
36
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  },
38
  },
39
  },
 
7
  theme: {
8
  extend: {
9
  colors: {
10
+ // Primary brand colors
11
+ primary: {
12
+ DEFAULT: 'var(--primary-color)',
13
+ hover: 'var(--primary-hover)',
14
+ light: 'var(--primary-light)',
15
+ dark: 'var(--primary-dark)',
16
+ },
17
+ // Secondary colors
18
+ secondary: {
19
+ DEFAULT: 'var(--secondary-color)',
20
+ hover: 'var(--secondary-hover)',
21
+ light: 'var(--secondary-light)',
22
+ },
23
+ // Text colors
24
+ text: {
25
+ DEFAULT: 'var(--text-color)',
26
+ secondary: 'var(--text-secondary)',
27
+ muted: 'var(--text-muted)',
28
+ light: 'var(--text-light)',
29
+ disabled: 'var(--text-disabled)',
30
+ },
31
+ // Background colors
32
+ background: {
33
+ DEFAULT: 'var(--background-primary)',
34
+ secondary: 'var(--background-secondary)',
35
+ tertiary: 'var(--background-tertiary)',
36
+ elevated: 'var(--background-elevated)',
37
+ },
38
+ // Border colors
39
+ border: {
40
+ DEFAULT: 'var(--border-color)',
41
+ light: 'var(--border-light)',
42
+ dark: 'var(--border-dark)',
43
+ accent: 'var(--border-accent)',
44
+ },
45
+ // Status colors
46
+ success: {
47
+ DEFAULT: 'var(--success-color)',
48
+ light: 'var(--success-light)',
49
+ },
50
+ warning: {
51
+ DEFAULT: 'var(--warning-color)',
52
+ light: 'var(--warning-light)',
53
+ },
54
+ error: {
55
+ DEFAULT: 'var(--error-color)',
56
+ light: 'var(--error-light)',
57
+ },
58
+ info: {
59
+ DEFAULT: 'var(--info-color)',
60
+ light: 'var(--info-light)',
61
+ },
62
+ // Legacy color mappings (for backwards compatibility)
63
  'primary-hover': 'var(--primary-hover)',
64
+ 'light-text': 'var(--text-light)',
65
+ 'lightest-text': 'var(--text-disabled)',
 
 
 
66
  'reasoning-bg': 'var(--reasoning-background)',
67
  'user-message-bg': 'var(--user-message-bg)',
68
  'user-message-color': 'var(--user-message-color)',
 
75
  'sidebar': 'var(--sidebar-width)',
76
  'header': 'var(--header-height)',
77
  },
78
+ borderRadius: {
79
+ 'DEFAULT': 'var(--border-radius)',
80
+ 'lg': 'var(--border-radius-lg)',
81
+ 'xl': 'var(--border-radius-xl)',
82
+ },
83
+ boxShadow: {
84
+ 'sm': 'var(--shadow-sm)',
85
+ 'DEFAULT': 'var(--shadow-md)',
86
+ 'md': 'var(--shadow-md)',
87
+ 'lg': 'var(--shadow-lg)',
88
+ 'xl': 'var(--shadow-xl)',
89
+ },
90
+ transitionDuration: {
91
+ 'fast': 'var(--transition-fast)',
92
+ 'normal': 'var(--transition-normal)',
93
+ 'slow': 'var(--transition-slow)',
94
+ },
95
  animation: {
96
  'blink': 'blink 1s infinite',
97
+ 'pulse-slow': 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
98
+ 'fade-in': 'fadeIn 0.5s ease-out',
99
+ 'slide-up': 'slideUp 0.3s ease-out',
100
+ 'scale-in': 'scaleIn 0.2s ease-out',
101
  },
102
  keyframes: {
103
  blink: {
104
  '0%, 100%': { opacity: 1 },
105
  '50%': { opacity: 0 },
106
  },
107
+ fadeIn: {
108
+ '0%': { opacity: 0 },
109
+ '100%': { opacity: 1 },
110
+ },
111
+ slideUp: {
112
+ '0%': { transform: 'translateY(10px)', opacity: 0 },
113
+ '100%': { transform: 'translateY(0)', opacity: 1 },
114
+ },
115
+ scaleIn: {
116
+ '0%': { transform: 'scale(0.95)', opacity: 0 },
117
+ '100%': { transform: 'scale(1)', opacity: 1 },
118
+ },
119
+ },
120
+ fontFamily: {
121
+ 'sans': ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'],
122
+ },
123
+ fontSize: {
124
+ 'xs': ['0.75rem', { lineHeight: '1rem' }],
125
+ 'sm': ['0.875rem', { lineHeight: '1.25rem' }],
126
+ 'base': ['1rem', { lineHeight: '1.5rem' }],
127
+ 'lg': ['1.125rem', { lineHeight: '1.75rem' }],
128
+ 'xl': ['1.25rem', { lineHeight: '1.75rem' }],
129
+ '2xl': ['1.5rem', { lineHeight: '2rem' }],
130
  },
131
  },
132
  },