linguabot commited on
Commit
6e0c85e
·
verified ·
1 Parent(s): 7d6128a

Upload folder using huggingface_hub

Browse files
client/src/components/HitokotoBar.tsx CHANGED
@@ -60,18 +60,18 @@ const HitokotoBar: React.FC = () => {
60
  if (hidden) return null;
61
 
62
  return (
63
- <div className="fixed bottom-0 left-0 right-0 z-50">
64
- <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 pb-3">
65
- <div className="bg-white border border-gray-200 shadow-md rounded-lg px-4 py-2 flex items-center justify-between">
66
  <div className="flex items-center min-w-0">
67
- <span className="mr-2 text-indigo-600">💬</span>
68
  <div className="min-w-0">
69
  {loading ? (
70
- <div className="text-sm text-gray-600">Loading…</div>
71
  ) : error ? (
72
  <div className="text-sm text-red-600">{error}</div>
73
  ) : (
74
- <div className="text-sm text-gray-800 truncate">
75
  {quote ? `『${quote.hitokoto}』 — ${quote.from_who || quote.from || 'Hitokoto'}` : ' '}
76
  </div>
77
  )}
@@ -80,14 +80,14 @@ const HitokotoBar: React.FC = () => {
80
  <div className="flex items-center space-x-2 flex-shrink-0">
81
  <button
82
  onClick={fetchQuote}
83
- className="text-xs px-2 py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700"
84
  title="Next quote"
85
  >
86
  Next
87
  </button>
88
  <button
89
  onClick={() => { setHidden(true); localStorage.setItem(LOCAL_HIDE_KEY, '1'); }}
90
- className="text-xs px-2 py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700"
91
  title="Hide"
92
  >
93
  Hide
 
60
  if (hidden) return null;
61
 
62
  return (
63
+ <div className="fixed bottom-0 right-0 z-50 w-[calc(100%-240px)] md:w-[calc(100%-240px)]">
64
+ <div className="ml-auto max-w-7xl px-4 sm:px-6 lg:px-8 pb-3">
65
+ <div className="bg-white border border-ui-bg shadow-md rounded-lg px-4 py-2 flex items-center justify-between">
66
  <div className="flex items-center min-w-0">
67
+ <span className="mr-2 text-ui-navy">💬</span>
68
  <div className="min-w-0">
69
  {loading ? (
70
+ <div className="text-sm text-ui-navy/70">Loading…</div>
71
  ) : error ? (
72
  <div className="text-sm text-red-600">{error}</div>
73
  ) : (
74
+ <div className="text-sm text-ui-navy truncate">
75
  {quote ? `『${quote.hitokoto}』 — ${quote.from_who || quote.from || 'Hitokoto'}` : ' '}
76
  </div>
77
  )}
 
80
  <div className="flex items-center space-x-2 flex-shrink-0">
81
  <button
82
  onClick={fetchQuote}
83
+ className="text-xs px-2 py-1 rounded bg-ui-bg hover:bg-white border border-ui-bg text-ui-navy"
84
  title="Next quote"
85
  >
86
  Next
87
  </button>
88
  <button
89
  onClick={() => { setHidden(true); localStorage.setItem(LOCAL_HIDE_KEY, '1'); }}
90
+ className="text-xs px-2 py-1 rounded bg-ui-bg hover:bg-white border border-ui-bg text-ui-navy"
91
  title="Hide"
92
  >
93
  Hide
client/src/components/Layout.tsx CHANGED
@@ -8,8 +8,6 @@ import {
8
  WrenchScrewdriverIcon,
9
  UserIcon,
10
  ArrowRightOnRectangleIcon,
11
- MagnifyingGlassIcon,
12
- UserCircleIcon,
13
  PowerIcon
14
  } from '@heroicons/react/24/outline';
15
  import HitokotoBar from './HitokotoBar';
@@ -137,9 +135,11 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
137
  }, [user?.role]);
138
 
139
  const handleLogout = () => {
140
- localStorage.removeItem('token');
141
- localStorage.removeItem('user');
142
- window.location.href = '/';
 
 
143
  };
144
 
145
  let navigation = [
@@ -163,46 +163,19 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
163
  }
164
 
165
  return (
166
- <div className="min-h-screen bg-antique text-eclipse">
167
- {/* Top Bar (search + user profile) */}
168
- <header className="sticky top-0 z-40 bg-white/80 backdrop-blur border-b border-primrose">
169
  <div className="px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between">
170
- <Link to="/dashboard" className="text-lg font-bold text-lyons">TransHub</Link>
171
- <div className="flex-1 mx-4 hidden md:block">
172
- <form
173
- onSubmit={(e) => {
174
- e.preventDefault();
175
- const form = e.currentTarget as HTMLFormElement;
176
- const input = form.querySelector('input[name="q"]') as HTMLInputElement | null;
177
- const q = (input?.value || '').trim();
178
- const target = q ? `/search?q=${encodeURIComponent(q)}` : '/search';
179
- window.location.href = target;
180
- }}
181
- >
182
- <div className="relative">
183
- <MagnifyingGlassIcon className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-eclipse/50" />
184
- <input
185
- name="q"
186
- type="search"
187
- placeholder="Search…"
188
- className="w-full pl-10 pr-3 py-2 rounded-lg border border-primrose/60 bg-white placeholder-eclipse/40 focus:outline-none focus:ring-2 focus:ring-lyons"
189
- />
190
- </div>
191
- </form>
192
- </div>
193
- <div className="flex items-center space-x-3">
194
- <div className="hidden sm:flex items-center">
195
- <UserCircleIcon className="h-7 w-7 text-lyons" />
196
- {user && <span className="ml-2 text-sm font-medium">{user.name}</span>}
197
- </div>
198
- </div>
199
  </div>
200
  </header>
201
 
202
  {/* Shell: Sidebar + Content */}
203
  <div className="flex">
204
  {/* Sidebar */}
205
- <aside className="hidden md:flex md:flex-col w-60 min-h-[calc(100vh-56px)] border-r border-primrose bg-white">
206
  <nav className="p-3 space-y-1 flex-1">
207
  {navigation.map((item) => {
208
  const isActive = location.pathname === item.href;
@@ -211,7 +184,7 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
211
  key={item.name}
212
  to={item.href}
213
  className={`flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors ${
214
- isActive ? 'bg-primrose text-eclipse' : 'text-eclipse/80 hover:bg-primrose/60'
215
  }`}
216
  >
217
  <item.icon className="h-4 w-4 mr-2" />
@@ -220,14 +193,14 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
220
  );
221
  })}
222
  </nav>
223
- <div className="p-3 border-t border-primrose">
224
  {user ? (
225
- <button onClick={handleLogout} className="w-full flex items-center justify-start px-3 py-2 rounded-md text-sm font-medium text-eclipse/80 hover:bg-primrose/60">
226
  <PowerIcon className="h-4 w-4 mr-2" />
227
  Log Out
228
  </button>
229
  ) : (
230
- <Link to="/login" className="w-full flex items-center justify-start px-3 py-2 rounded-md text-sm font-medium text-eclipse/80 hover:bg-primrose/60">
231
  <PowerIcon className="h-4 w-4 mr-2" />
232
  Log In
233
  </Link>
@@ -245,8 +218,8 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
245
  {isTransitioning && (
246
  <div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50">
247
  <div className="bg-white rounded-lg shadow-lg p-4 flex items-center space-x-3">
248
- <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-lyons"></div>
249
- <span className="text-eclipse font-medium">Loading...</span>
250
  </div>
251
  </div>
252
  )}
 
8
  WrenchScrewdriverIcon,
9
  UserIcon,
10
  ArrowRightOnRectangleIcon,
 
 
11
  PowerIcon
12
  } from '@heroicons/react/24/outline';
13
  import HitokotoBar from './HitokotoBar';
 
135
  }, [user?.role]);
136
 
137
  const handleLogout = () => {
138
+ try {
139
+ localStorage.removeItem('token');
140
+ localStorage.removeItem('user');
141
+ } catch {}
142
+ window.location.href = '/login';
143
  };
144
 
145
  let navigation = [
 
163
  }
164
 
165
  return (
166
+ <div className="min-h-screen bg-ui-bg text-ui-navy">
167
+ {/* Top Bar */}
168
+ <header className="sticky top-0 z-40 bg-white/80 backdrop-blur border-b border-ui-bg">
169
  <div className="px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between">
170
+ <Link to="/dashboard" className="text-lg font-bold text-ui-navy">TransHub</Link>
171
+ <div />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  </div>
173
  </header>
174
 
175
  {/* Shell: Sidebar + Content */}
176
  <div className="flex">
177
  {/* Sidebar */}
178
+ <aside className="hidden md:flex md:flex-col w-60 min-h-[calc(100vh-56px)] border-r border-ui-bg bg-white">
179
  <nav className="p-3 space-y-1 flex-1">
180
  {navigation.map((item) => {
181
  const isActive = location.pathname === item.href;
 
184
  key={item.name}
185
  to={item.href}
186
  className={`flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors ${
187
+ isActive ? 'bg-white text-ui-navy shadow-sm' : 'text-ui-navy/80 hover:bg-ui-bg'
188
  }`}
189
  >
190
  <item.icon className="h-4 w-4 mr-2" />
 
193
  );
194
  })}
195
  </nav>
196
+ <div className="p-3 border-t border-ui-bg">
197
  {user ? (
198
+ <button onClick={handleLogout} className="w-full flex items-center justify-start px-3 py-2 rounded-md text-sm font-medium text-ui-navy/80 hover:bg-ui-bg">
199
  <PowerIcon className="h-4 w-4 mr-2" />
200
  Log Out
201
  </button>
202
  ) : (
203
+ <Link to="/login" className="w-full flex items-center justify-start px-3 py-2 rounded-md text-sm font-medium text-ui-navy/80 hover:bg-ui-bg">
204
  <PowerIcon className="h-4 w-4 mr-2" />
205
  Log In
206
  </Link>
 
218
  {isTransitioning && (
219
  <div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50">
220
  <div className="bg-white rounded-lg shadow-lg p-4 flex items-center space-x-3">
221
+ <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-ui-navy"></div>
222
+ <span className="text-ui-navy font-medium">Loading...</span>
223
  </div>
224
  </div>
225
  )}
client/src/index.css CHANGED
@@ -7,29 +7,29 @@
7
  font-family: 'Inter', system-ui, sans-serif;
8
  }
9
  body {
10
- @apply bg-antique text-eclipse;
11
  }
12
  }
13
 
14
  @layer components {
15
  .btn-primary {
16
- @apply bg-lyons hover:bg-lyons/90 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200;
17
  }
18
 
19
  .btn-secondary {
20
- @apply bg-primrose hover:bg-primrose/80 text-eclipse font-medium py-2 px-4 rounded-lg transition-colors duration-200;
21
  }
22
 
23
  .btn-danger {
24
- @apply bg-chili hover:bg-chili/90 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200;
25
  }
26
 
27
  .input-field {
28
- @apply w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-lyons focus:border-transparent;
29
  }
30
 
31
  .card {
32
- @apply bg-white rounded-lg shadow-md border border-gray-200 p-6;
33
  }
34
 
35
  .highlight-cultural {
@@ -37,7 +37,7 @@
37
  }
38
 
39
  .text-gradient {
40
- @apply bg-gradient-to-r from-lyons to-damson bg-clip-text text-transparent;
41
  }
42
 
43
  .font-smiley {
 
7
  font-family: 'Inter', system-ui, sans-serif;
8
  }
9
  body {
10
+ @apply bg-ui-bg text-ui-navy;
11
  }
12
  }
13
 
14
  @layer components {
15
  .btn-primary {
16
+ @apply bg-ui-navy hover:bg-ui-navy/90 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200;
17
  }
18
 
19
  .btn-secondary {
20
+ @apply bg-white hover:bg-ui-bg text-ui-navy font-medium py-2 px-4 rounded-lg border border-ui-bg transition-colors duration-200;
21
  }
22
 
23
  .btn-danger {
24
+ @apply bg-red-600 hover:bg-red-700 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200;
25
  }
26
 
27
  .input-field {
28
+ @apply w-full px-3 py-2 border border-ui-bg rounded-lg focus:outline-none focus:ring-2 focus:ring-ui-navy focus:border-transparent;
29
  }
30
 
31
  .card {
32
+ @apply bg-white rounded-xl shadow-sm border border-ui-bg p-6;
33
  }
34
 
35
  .highlight-cultural {
 
37
  }
38
 
39
  .text-gradient {
40
+ @apply bg-gradient-to-r from-ui-navy to-ui-teal bg-clip-text text-transparent;
41
  }
42
 
43
  .font-smiley {
client/src/pages/Dashboard.tsx CHANGED
@@ -113,15 +113,15 @@ const Dashboard: React.FC = () => {
113
  <div className="mb-8">
114
  <div className="flex items-center justify-between">
115
  <div>
116
- <h1 className="text-3xl font-bold text-damson">{getGreeting()}</h1>
117
- <p className="text-eclipse/70 mt-2">
118
  Ready to practice your translation skills?
119
  </p>
120
  </div>
121
  <div className="flex items-center space-x-3">
122
- <span className="text-sm text-eclipse/70">{getRoleDisplay()}</span>
123
  {user.role === 'admin' && (
124
- <span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-primrose text-eclipse border border-eclipse/10">
125
  Admin
126
  </span>
127
  )}
@@ -131,21 +131,21 @@ const Dashboard: React.FC = () => {
131
 
132
  {/* Quick Actions */}
133
  <div className="mb-8">
134
- <h2 className="text-lg font-semibold text-damson mb-4">Quick Actions</h2>
135
  <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
136
  {actionsToShow.map((action) => (
137
  <Link
138
  key={action.name}
139
  to={action.href}
140
- className="bg-white rounded-xl shadow-sm border border-primrose/60 p-6 hover:shadow-md hover:border-primrose transition"
141
  >
142
  <div className="flex items-center">
143
- <div className={`p-3 rounded-lg bg-lyons`}>
144
  <action.icon className="h-6 w-6 text-white" />
145
  </div>
146
  <div className="ml-4">
147
- <h3 className="text-lg font-medium text-eclipse">{action.name}</h3>
148
- <p className="text-eclipse/70">{action.description}</p>
149
  </div>
150
  </div>
151
  </Link>
@@ -176,23 +176,23 @@ const Dashboard: React.FC = () => {
176
  )}
177
 
178
  {/* Overview */}
179
- <div className="bg-white rounded-xl shadow-sm border border-primrose/60 p-6">
180
  <div className="flex items-center mb-4">
181
- <ChartBarIcon className="h-6 w-6 text-lyons mr-3" />
182
- <h3 className="text-lg font-semibold text-damson">Course Overview</h3>
183
  </div>
184
  <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
185
  <div className="text-center">
186
- <div className="text-2xl font-bold text-lyons">6</div>
187
- <div className="text-sm text-eclipse/70">Weeks</div>
188
  </div>
189
  <div className="text-center">
190
- <div className="text-2xl font-bold text-lyons">2</div>
191
- <div className="text-sm text-eclipse/70">Task Types</div>
192
  </div>
193
  <div className="text-center">
194
- <div className="text-2xl font-bold text-damson">Voting</div>
195
- <div className="text-sm text-eclipse/70">Peer Review</div>
196
  </div>
197
  </div>
198
  </div>
 
113
  <div className="mb-8">
114
  <div className="flex items-center justify-between">
115
  <div>
116
+ <h1 className="text-3xl font-bold text-ui-navy">{getGreeting()}</h1>
117
+ <p className="text-ui-navy/70 mt-2">
118
  Ready to practice your translation skills?
119
  </p>
120
  </div>
121
  <div className="flex items-center space-x-3">
122
+ <span className="text-sm text-ui-navy/70">{getRoleDisplay()}</span>
123
  {user.role === 'admin' && (
124
+ <span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-ui-gold/20 text-ui-navy border border-ui-bg">
125
  Admin
126
  </span>
127
  )}
 
131
 
132
  {/* Quick Actions */}
133
  <div className="mb-8">
134
+ <h2 className="text-lg font-semibold text-ui-navy mb-4">Quick Actions</h2>
135
  <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
136
  {actionsToShow.map((action) => (
137
  <Link
138
  key={action.name}
139
  to={action.href}
140
+ className="bg-white rounded-xl shadow-sm border border-ui-bg p-6 hover:shadow-md hover:border-ui-bg transition"
141
  >
142
  <div className="flex items-center">
143
+ <div className={`p-3 rounded-lg bg-ui-teal`}>
144
  <action.icon className="h-6 w-6 text-white" />
145
  </div>
146
  <div className="ml-4">
147
+ <h3 className="text-lg font-medium text-ui-navy">{action.name}</h3>
148
+ <p className="text-ui-navy/70">{action.description}</p>
149
  </div>
150
  </div>
151
  </Link>
 
176
  )}
177
 
178
  {/* Overview */}
179
+ <div className="bg-white rounded-xl shadow-sm border border-ui-bg p-6">
180
  <div className="flex items-center mb-4">
181
+ <ChartBarIcon className="h-6 w-6 text-ui-navy mr-3" />
182
+ <h3 className="text-lg font-semibold text-ui-navy">Course Overview</h3>
183
  </div>
184
  <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
185
  <div className="text-center">
186
+ <div className="text-2xl font-bold text-ui-navy">6</div>
187
+ <div className="text-sm text-ui-navy/70">Weeks</div>
188
  </div>
189
  <div className="text-center">
190
+ <div className="text-2xl font-bold text-ui-navy">2</div>
191
+ <div className="text-sm text-ui-navy/70">Task Types</div>
192
  </div>
193
  <div className="text-center">
194
+ <div className="text-2xl font-bold text-ui-navy">Voting</div>
195
+ <div className="text-sm text-ui-navy/70">Peer Review</div>
196
  </div>
197
  </div>
198
  </div>
client/tailwind.config.js CHANGED
@@ -6,13 +6,13 @@ module.exports = {
6
  theme: {
7
  extend: {
8
  colors: {
9
- // Pantone-inspired palette approximations
10
- antique: '#FAEBD7', // Antique White 11-0105 TCX
11
- lyons: '#0B5F73', // Lyons Blue 19-4340 TCX (approx)
12
- primrose: '#F2D7DD', // Primrose Pink 12-2904 TCX (approx)
13
- damson: '#7A3E57', // Damson 18-1716 TCX (approx)
14
- eclipse: '#2F2B3A', // Eclipse 19-3810 TCX (approx)
15
- chili: '#8A3332', // Chili Oil 18-1440 TCX (approx)
16
  },
17
  fontFamily: {
18
  sans: ['Inter', 'system-ui', 'sans-serif'],
 
6
  theme: {
7
  extend: {
8
  colors: {
9
+ // Dashboard palette (sampled from provided image)
10
+ ui: {
11
+ bg: '#EDEDED', // light gray background
12
+ gold: '#E1AB3D', // accent badges/buttons
13
+ teal: '#63C6AF', // charts/highlights
14
+ navy: '#242B3E', // primary text/buttons
15
+ },
16
  },
17
  fontFamily: {
18
  sans: ['Inter', 'system-ui', 'sans-serif'],