Skip to content

Commit 5c00185

Browse files
committed
feat: add AdminDashboard component for managing tutorials, site content, and pages.
1 parent 831e492 commit 5c00185

1 file changed

Lines changed: 60 additions & 63 deletions

File tree

src/pages/AdminDashboard.jsx

Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ const AdminDashboard = () => {
9898
}, [showForm])
9999
return (
100100
<div className="min-h-screen bg-gray-50 dark:bg-slate-950 text-gray-900 dark:text-slate-100">
101-
{}
101+
{/* Header */}
102102
<header className="bg-white/90 dark:bg-slate-900/80 shadow-md backdrop-blur">
103103
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
104104
<div className="flex justify-between items-center">
105-
{}
105+
{/* Left Side: Logo & Title */}
106106
<div className="flex items-center space-x-3">
107-
{}
107+
{/* Logo Icon */}
108108
<div className="bg-gradient-to-r from-primary-600 to-primary-800 p-2 rounded-lg shadow-lg shadow-primary-900/20">
109109
<Terminal className="w-6 h-6 text-white" />
110110
</div>
@@ -113,17 +113,17 @@ const AdminDashboard = () => {
113113
<p className="text-sm text-gray-600 dark:text-slate-400">Willkommen, {user?.username}</p>
114114
</div>
115115
</div>
116-
{}
116+
{/* Right Side: Actions */}
117117
<div className="flex space-x-3">
118-
{}
118+
{/* Home Button */}
119119
<button
120120
onClick={() => navigate('/')}
121121
className="flex items-center space-x-2 px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
122122
>
123123
<Home className="w-4 h-4" />
124124
<span>Startseite</span>
125125
</button>
126-
{}
126+
{/* Logout Button */}
127127
<button
128128
onClick={handleLogout}
129129
className="flex items-center space-x-2 px-4 py-2 bg-red-100 text-red-700 rounded-lg hover:bg-red-200 transition-colors duration-200 dark:bg-red-900/30 dark:text-red-300 dark:hover:bg-red-900/50"
@@ -136,63 +136,60 @@ const AdminDashboard = () => {
136136
</div>
137137
</header>
138138
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
139-
{}
140-
{}
139+
{/* Tabs Navigation */}
140+
{/* Mobile: Stacked, Desktop: Inline */}
141141
<div className="mb-8 flex flex-col gap-3 border-b border-gray-200 pb-3 sm:flex-row sm:items-center sm:justify-between dark:border-slate-800">
142142
<div className="flex flex-wrap items-center gap-2">
143-
{}
143+
{/* Tutorials Tab */}
144144
<button
145145
type="button"
146146
onClick={() => setActiveTab('tutorials')}
147-
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${
148-
activeTab === 'tutorials'
147+
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${activeTab === 'tutorials'
149148
? 'bg-primary-600 text-white shadow-lg shadow-primary-900/20' // Active state
150149
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700' // Inactive state
151-
}`}
150+
}`}
152151
>
153152
<LayoutDashboard className="h-4 w-4" />
154-
Tutorials
153+
Blog Beiträge
155154
</button>
156-
{}
155+
{/* Content Tab */}
157156
<button
158157
type="button"
159158
onClick={() => setActiveTab('content')}
160-
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${
161-
activeTab === 'content'
159+
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${activeTab === 'content'
162160
? 'bg-primary-600 text-white shadow-lg shadow-primary-900/20' // Active state
163161
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700' // Inactive state
164-
}`}
162+
}`}
165163
>
166164
<Paintbrush className="h-4 w-4" />
167165
Seiteninhalte
168166
</button>
169-
{}
167+
{/* Pages Tab */}
170168
<button
171169
type="button"
172170
onClick={() => setActiveTab('pages')}
173-
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${
174-
activeTab === 'pages'
171+
className={`inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-all ${activeTab === 'pages'
175172
? 'bg-primary-600 text-white shadow-lg shadow-primary-900/20' // Active state
176173
: 'bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700' // Inactive state
177-
}`}
174+
}`}
178175
>
179176
<FileText className="h-4 w-4" />
180177
Seiten & Beiträge
181178
</button>
182179
</div>
183180
</div>
184-
{}
181+
{/* Tab Content: Tutorials */}
185182
{activeTab === 'tutorials' && (
186183
<>
187-
{}
188-
{}
184+
{/* Section Header */}
185+
{/* Mobile: Stacked, Desktop: Row */}
189186
<div className="mb-8 flex flex-col gap-4 md:flex-row md:justify-between md:items-center">
190187
<div>
191-
<h2 className="text-2xl font-bold text-gray-800 dark:text-gray-100">Tutorial Verwaltung</h2>
192-
<p className="text-gray-600 dark:text-gray-300 mt-1">Erstelle, bearbeite und verwalte deine Tutorials</p>
188+
<h2 className="text-2xl font-bold text-gray-800 dark:text-gray-100">Blog Verwaltung</h2>
189+
<p className="text-gray-600 dark:text-gray-300 mt-1">Erstelle, bearbeite und verwalte deine Blog-Beiträge</p>
193190
</div>
194191
<div className="flex flex-col sm:flex-row gap-3">
195-
{}
192+
{/* Refresh Button */}
196193
<button
197194
onClick={() => refreshTutorials()}
198195
className="flex items-center justify-center gap-2 px-5 py-3 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors duration-200 disabled:opacity-60"
@@ -201,7 +198,7 @@ const AdminDashboard = () => {
201198
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
202199
<span>{loading ? 'Aktualisiere…' : 'Aktualisieren'}</span>
203200
</button>
204-
{}
201+
{/* New Tutorial Button */}
205202
<button
206203
onClick={() => {
207204
setEditingTutorial(null)
@@ -210,23 +207,23 @@ const AdminDashboard = () => {
210207
className="flex items-center justify-center gap-2 px-6 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-lg hover:from-primary-700 hover:to-primary-800 transition-all duration-200 shadow-lg hover:shadow-xl"
211208
>
212209
<Plus className="w-5 h-5" />
213-
<span>Neues Tutorial</span>
210+
<span>Neuer Beitrag</span>
214211
</button>
215212
</div>
216213
</div>
217-
{}
218-
{}
214+
{/* Error Message */}
215+
{/* Displayed if data fetching fails */}
219216
{error && (
220217
<div className="mb-6 rounded-xl border border-red-200 bg-red-50 p-4 flex items-start gap-3 text-red-700" role="alert">
221218
<AlertCircle className="w-5 h-5 flex-shrink-0" aria-hidden="true" />
222219
<div>
223-
<p className="font-semibold">Fehler beim Laden der Tutorials</p>
220+
<p className="font-semibold">Fehler beim Laden der Beiträge</p>
224221
<p className="text-sm">{error?.message || String(error)}</p>
225222
</div>
226223
</div>
227224
)}
228-
{}
229-
{}
225+
{/* Modal Form */}
226+
{/* Overlay for creating/editing tutorials */}
230227
{showForm && (
231228
<div
232229
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
@@ -243,38 +240,38 @@ const AdminDashboard = () => {
243240
className="bg-white rounded-2xl shadow-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"
244241
role="document"
245242
>
246-
{}
243+
{/* Tutorial Form Component */}
247244
<TutorialForm
248245
tutorial={editingTutorial}
249246
onClose={handleCloseForm}
250247
/>
251248
</div>
252249
</div>
253250
)}
254-
{}
255-
{}
251+
{/* Tutorials Grid */}
252+
{/* Responsive grid layout for tutorial cards */}
256253
{loading && tutorials.length === 0 ? (
257-
<div className="py-16 text-center text-gray-600">Lade Tutorials</div>
254+
<div className="py-16 text-center text-gray-600">Lade Beiträge</div>
258255
) : (
259256
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
260257
{sortedTutorials.map((tutorial) => (
261258
<div
262259
key={tutorial.id}
263260
className="rounded-xl border border-gray-100 bg-white shadow-md hover:shadow-lg transition-shadow duration-300 overflow-hidden dark:border-slate-800 dark:bg-slate-900/80"
264261
>
265-
{}
262+
{/* Color Strip */}
266263
<div className={`h-2 bg-gradient-to-r ${tutorial.color}`}></div>
267264
<div className="p-6">
268-
{}
265+
{/* Title */}
269266
<h3 className="text-xl font-bold text-gray-800 dark:text-slate-100 mb-2">{tutorial.title}</h3>
270-
{}
267+
{/* Description */}
271268
<p className="text-gray-600 dark:text-slate-300 text-sm mb-4 line-clamp-2">
272269
{tutorial.description}
273270
</p>
274-
{}
271+
{/* Topics Tags */}
275272
<div className="mb-4">
276273
<div className="flex flex-wrap gap-2">
277-
{}
274+
{/* Display first 3 topics */}
278275
{(tutorial.topics || []).slice(0, 3).map((topic, index) => (
279276
<span
280277
key={index}
@@ -283,25 +280,25 @@ const AdminDashboard = () => {
283280
{topic}
284281
</span>
285282
))}
286-
{}
283+
{/* Show count of remaining topics */}
287284
{tutorial.topics && tutorial.topics.length > 3 && (
288285
<span className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full dark:bg-slate-800 dark:text-slate-300">
289286
+{tutorial.topics.length - 3} mehr
290287
</span>
291288
)}
292289
</div>
293290
</div>
294-
{}
291+
{/* Action Buttons */}
295292
<div className="flex space-x-2 pt-4 border-t border-gray-100 dark:border-slate-800">
296-
{}
293+
{/* Edit Button */}
297294
<button
298295
onClick={() => handleEdit(tutorial)}
299296
className="flex-1 flex items-center justify-center space-x-2 px-4 py-2 bg-primary-50 text-primary-700 rounded-lg hover:bg-primary-100 transition-colors duration-200 dark:bg-primary-900/40 dark:text-primary-200 dark:hover:bg-primary-900/60"
300297
>
301298
<Edit className="w-4 h-4" />
302299
<span>Bearbeiten</span>
303300
</button>
304-
{}
301+
{/* Delete Button / Confirmation */}
305302
{confirmingId === tutorial.id ? (
306303
<div className="flex-1 flex items-center justify-center gap-2">
307304
<button
@@ -330,7 +327,7 @@ const AdminDashboard = () => {
330327
</button>
331328
)}
332329
</div>
333-
{}
330+
{/* Delete Error Message */}
334331
{deleteError?.id === tutorial.id && (
335332
<p className="mt-3 text-sm text-red-600 dark:text-red-400" role="alert">
336333
{deleteError.message}
@@ -341,51 +338,51 @@ const AdminDashboard = () => {
341338
))}
342339
</div>
343340
)}
344-
{}
345-
{}
341+
{/* Empty State */}
342+
{/* Displayed when no tutorials exist */}
346343
{!loading && tutorials.length === 0 && !error && (
347344
<div className="text-center py-16">
348-
{}
345+
{/* Icon */}
349346
<div className="inline-flex items-center justify-center w-16 h-16 bg-gray-100 rounded-full mb-4">
350347
<Terminal className="w-8 h-8 text-gray-400" />
351348
</div>
352-
{}
349+
{/* Title */}
353350
<h3 className="text-xl font-semibold text-gray-800 dark:text-gray-100 mb-2">
354-
Noch keine Tutorials vorhanden
351+
Noch keine Beiträge vorhanden
355352
</h3>
356-
{}
353+
{/* Description */}
357354
<p className="text-gray-600 dark:text-gray-300 mb-6">
358-
Erstelle dein erstes Tutorial, um loszulegen.
355+
Erstelle deinen ersten Beitrag, um loszulegen.
359356
</p>
360-
{}
357+
{/* Action Button */}
361358
<button
362359
onClick={() => setShowForm(true)}
363360
className="inline-flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-primary-600 to-primary-700 text-white rounded-lg hover:from-primary-700 hover:to-primary-800 transition-all duration-200"
364361
>
365362
<Plus className="w-5 h-5" />
366-
<span>Erstes Tutorial erstellen</span>
363+
<span>Ersten Beitrag erstellen</span>
367364
</button>
368365
</div>
369366
)}
370367
</>
371368
)}
372-
{}
373-
{}
369+
{/* Tab Content: Site Content */}
370+
{/* Editor for static site content (Hero, Features, etc.) */}
374371
{activeTab === 'content' && (
375372
<div className="space-y-6">
376-
{}
373+
{/* Loading Indicator */}
377374
{contentLoading && (
378375
<div className="flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-4 py-3 text-sm text-gray-600">
379376
<RefreshCw className="h-4 w-4 animate-spin" />
380377
Inhalte werden geladen…
381378
</div>
382379
)}
383-
{}
380+
{/* Content Editor Component */}
384381
<SiteContentEditor />
385382
</div>
386383
)}
387-
{}
388-
{}
384+
{/* Tab Content: Pages */}
385+
{/* Manager for dynamic pages and their posts */}
389386
{activeTab === 'pages' && (
390387
<PageManager />
391388
)}

0 commit comments

Comments
 (0)