spaps-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,640 @@
1
+ # SPAPS Integration Step 11/12: UI Polish & Theme
2
+
3
+ ## Prerequisites Check
4
+
5
+ Before starting, confirm you have completed:
6
+ - ✅ Step 1-10: Full functionality implementation
7
+ - ✅ shadcn/ui components installed and working
8
+ - ✅ Tailwind CSS configured
9
+
10
+ ## Required TodoWrite List
11
+
12
+ Create a TodoWrite with EXACTLY these items:
13
+
14
+ ```javascript
15
+ TodoWrite({
16
+ todos: [
17
+ { content: "Install and configure next-themes", status: "pending", activeForm: "Installing next-themes" },
18
+ { content: "Add theme provider to app layout", status: "pending", activeForm: "Adding theme provider" },
19
+ { content: "Implement dark mode toggle component", status: "pending", activeForm: "Implementing theme toggle" },
20
+ { content: "Create minimalist layout with whitespace", status: "pending", activeForm: "Creating minimalist layout" },
21
+ { content: "Add loading states with shadcn/ui skeleton", status: "pending", activeForm: "Adding loading states" },
22
+ { content: "Ensure responsive design across devices", status: "pending", activeForm: "Ensuring responsive design" },
23
+ { content: "Add animations and transitions", status: "pending", activeForm: "Adding animations" },
24
+ { content: "Request step 12 of SPAPS integration wizard", status: "pending", activeForm: "Requesting next step" }
25
+ ]
26
+ })
27
+ ```
28
+
29
+ ## UI Polish Implementation
30
+
31
+ ### 1. Install Theme Support
32
+
33
+ ```bash
34
+ npm install next-themes
35
+ ```
36
+
37
+ ### 2. Theme Provider Setup
38
+
39
+ Create the theme provider:
40
+
41
+ ```typescript
42
+ // components/theme-provider.tsx
43
+ 'use client'
44
+
45
+ import * as React from "react"
46
+ import { ThemeProvider as NextThemesProvider } from "next-themes"
47
+ import { type ThemeProviderProps } from "next-themes/dist/types"
48
+
49
+ export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
50
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
51
+ }
52
+ ```
53
+
54
+ Update your root layout:
55
+
56
+ ```typescript
57
+ // app/layout.tsx
58
+ import { Inter } from 'next/font/google'
59
+ import { ThemeProvider } from "@/components/theme-provider"
60
+ import { Toaster } from "@/components/ui/sonner"
61
+ import './globals.css'
62
+
63
+ const inter = Inter({ subsets: ['latin'] })
64
+
65
+ export default function RootLayout({
66
+ children,
67
+ }: {
68
+ children: React.ReactNode
69
+ }) {
70
+ return (
71
+ <html lang="en" suppressHydrationWarning>
72
+ <body className={inter.className}>
73
+ <ThemeProvider
74
+ attribute="class"
75
+ defaultTheme="system"
76
+ enableSystem
77
+ disableTransitionOnChange
78
+ >
79
+ {children}
80
+ <Toaster />
81
+ </ThemeProvider>
82
+ </body>
83
+ </html>
84
+ )
85
+ }
86
+ ```
87
+
88
+ ### 3. Theme Toggle Component
89
+
90
+ ```typescript
91
+ // components/theme-toggle.tsx
92
+ 'use client'
93
+
94
+ import { Moon, Sun } from "lucide-react"
95
+ import { useTheme } from "next-themes"
96
+ import { Button } from "@/components/ui/button"
97
+ import {
98
+ DropdownMenu,
99
+ DropdownMenuContent,
100
+ DropdownMenuItem,
101
+ DropdownMenuTrigger,
102
+ } from "@/components/ui/dropdown-menu"
103
+
104
+ export function ThemeToggle() {
105
+ const { setTheme } = useTheme()
106
+
107
+ return (
108
+ <DropdownMenu>
109
+ <DropdownMenuTrigger asChild>
110
+ <Button variant="outline" size="icon">
111
+ <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
112
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
113
+ <span className="sr-only">Toggle theme</span>
114
+ </Button>
115
+ </DropdownMenuTrigger>
116
+ <DropdownMenuContent align="end">
117
+ <DropdownMenuItem onClick={() => setTheme("light")}>
118
+ Light
119
+ </DropdownMenuItem>
120
+ <DropdownMenuItem onClick={() => setTheme("dark")}>
121
+ Dark
122
+ </DropdownMenuItem>
123
+ <DropdownMenuItem onClick={() => setTheme("system")}>
124
+ System
125
+ </DropdownMenuItem>
126
+ </DropdownMenuContent>
127
+ </DropdownMenu>
128
+ )
129
+ }
130
+ ```
131
+
132
+ ### 4. Minimalist Layout Component
133
+
134
+ ```typescript
135
+ // components/layout/app-layout.tsx
136
+ 'use client'
137
+
138
+ import { ReactNode } from 'react'
139
+ import { ThemeToggle } from '@/components/theme-toggle'
140
+ import { Button } from '@/components/ui/button'
141
+ import { useRouter } from 'next/navigation'
142
+ import { TokenManager } from 'spaps-sdk'
143
+ import { LogOut, User } from 'lucide-react'
144
+
145
+ interface AppLayoutProps {
146
+ children: ReactNode
147
+ user?: any
148
+ }
149
+
150
+ export function AppLayout({ children, user }: AppLayoutProps) {
151
+ const router = useRouter()
152
+
153
+ const handleLogout = () => {
154
+ TokenManager.clearTokens()
155
+ router.push('/auth')
156
+ }
157
+
158
+ return (
159
+ <div className="min-h-screen bg-background">
160
+ {/* Header */}
161
+ <header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
162
+ <div className="container flex h-16 items-center justify-between">
163
+ <div className="flex items-center gap-6">
164
+ <a href="/" className="flex items-center space-x-2">
165
+ <span className="font-bold text-xl">SPAPS</span>
166
+ </a>
167
+ <nav className="hidden md:flex items-center gap-6">
168
+ <a href="/dashboard" className="text-sm font-medium transition-colors hover:text-primary">
169
+ Dashboard
170
+ </a>
171
+ <a href="/payments" className="text-sm font-medium transition-colors hover:text-primary">
172
+ Payments
173
+ </a>
174
+ {user?.isAdmin && (
175
+ <a href="/admin" className="text-sm font-medium transition-colors hover:text-primary">
176
+ Admin
177
+ </a>
178
+ )}
179
+ </nav>
180
+ </div>
181
+
182
+ <div className="flex items-center gap-4">
183
+ {user && (
184
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
185
+ <User className="h-4 w-4" />
186
+ {user.email}
187
+ </div>
188
+ )}
189
+ <ThemeToggle />
190
+ {user && (
191
+ <Button
192
+ variant="ghost"
193
+ size="icon"
194
+ onClick={handleLogout}
195
+ >
196
+ <LogOut className="h-4 w-4" />
197
+ </Button>
198
+ )}
199
+ </div>
200
+ </div>
201
+ </header>
202
+
203
+ {/* Main Content */}
204
+ <main className="container mx-auto py-8 px-4 md:px-6 lg:px-8">
205
+ <div className="mx-auto max-w-7xl">
206
+ {children}
207
+ </div>
208
+ </main>
209
+
210
+ {/* Footer */}
211
+ <footer className="border-t mt-auto">
212
+ <div className="container py-8 md:py-12">
213
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-8">
214
+ <div>
215
+ <h3 className="text-sm font-semibold mb-3">Product</h3>
216
+ <ul className="space-y-2 text-sm text-muted-foreground">
217
+ <li><a href="#" className="hover:text-primary transition-colors">Features</a></li>
218
+ <li><a href="#" className="hover:text-primary transition-colors">Pricing</a></li>
219
+ <li><a href="#" className="hover:text-primary transition-colors">Documentation</a></li>
220
+ </ul>
221
+ </div>
222
+ <div>
223
+ <h3 className="text-sm font-semibold mb-3">Company</h3>
224
+ <ul className="space-y-2 text-sm text-muted-foreground">
225
+ <li><a href="#" className="hover:text-primary transition-colors">About</a></li>
226
+ <li><a href="#" className="hover:text-primary transition-colors">Blog</a></li>
227
+ <li><a href="#" className="hover:text-primary transition-colors">Contact</a></li>
228
+ </ul>
229
+ </div>
230
+ <div>
231
+ <h3 className="text-sm font-semibold mb-3">Legal</h3>
232
+ <ul className="space-y-2 text-sm text-muted-foreground">
233
+ <li><a href="#" className="hover:text-primary transition-colors">Privacy</a></li>
234
+ <li><a href="#" className="hover:text-primary transition-colors">Terms</a></li>
235
+ </ul>
236
+ </div>
237
+ <div>
238
+ <h3 className="text-sm font-semibold mb-3">Connect</h3>
239
+ <ul className="space-y-2 text-sm text-muted-foreground">
240
+ <li><a href="#" className="hover:text-primary transition-colors">GitHub</a></li>
241
+ <li><a href="#" className="hover:text-primary transition-colors">Twitter</a></li>
242
+ <li><a href="#" className="hover:text-primary transition-colors">Discord</a></li>
243
+ </ul>
244
+ </div>
245
+ </div>
246
+ <div className="border-t mt-8 pt-8">
247
+ <p className="text-center text-sm text-muted-foreground">
248
+ © 2024 SPAPS. Built with Next.js and shadcn/ui.
249
+ </p>
250
+ </div>
251
+ </div>
252
+ </footer>
253
+ </div>
254
+ )
255
+ }
256
+ ```
257
+
258
+ ### 5. Loading States with Skeleton
259
+
260
+ ```typescript
261
+ // components/ui/loading-states.tsx
262
+ import { Skeleton } from "@/components/ui/skeleton"
263
+ import { Card, CardContent, CardHeader } from "@/components/ui/card"
264
+
265
+ export function AuthFormSkeleton() {
266
+ return (
267
+ <Card className="w-[400px]">
268
+ <CardHeader>
269
+ <Skeleton className="h-8 w-[200px]" />
270
+ <Skeleton className="h-4 w-[250px]" />
271
+ </CardHeader>
272
+ <CardContent className="space-y-4">
273
+ <div className="space-y-2">
274
+ <Skeleton className="h-4 w-[60px]" />
275
+ <Skeleton className="h-10 w-full" />
276
+ </div>
277
+ <div className="space-y-2">
278
+ <Skeleton className="h-4 w-[80px]" />
279
+ <Skeleton className="h-10 w-full" />
280
+ </div>
281
+ <Skeleton className="h-10 w-full" />
282
+ </CardContent>
283
+ </Card>
284
+ )
285
+ }
286
+
287
+ export function ProductListSkeleton() {
288
+ return (
289
+ <div className="space-y-4">
290
+ {[1, 2, 3].map((i) => (
291
+ <Card key={i}>
292
+ <CardContent className="p-4">
293
+ <div className="space-y-2">
294
+ <Skeleton className="h-5 w-[150px]" />
295
+ <Skeleton className="h-4 w-full" />
296
+ <div className="flex justify-between items-center mt-4">
297
+ <Skeleton className="h-6 w-[80px]" />
298
+ <Skeleton className="h-9 w-[100px]" />
299
+ </div>
300
+ </div>
301
+ </CardContent>
302
+ </Card>
303
+ ))}
304
+ </div>
305
+ )
306
+ }
307
+
308
+ export function TableSkeleton() {
309
+ return (
310
+ <div className="space-y-3">
311
+ <div className="flex gap-3">
312
+ <Skeleton className="h-10 flex-1" />
313
+ <Skeleton className="h-10 flex-1" />
314
+ <Skeleton className="h-10 flex-1" />
315
+ <Skeleton className="h-10 flex-1" />
316
+ </div>
317
+ {[1, 2, 3, 4, 5].map((i) => (
318
+ <div key={i} className="flex gap-3">
319
+ <Skeleton className="h-12 flex-1" />
320
+ <Skeleton className="h-12 flex-1" />
321
+ <Skeleton className="h-12 flex-1" />
322
+ <Skeleton className="h-12 flex-1" />
323
+ </div>
324
+ ))}
325
+ </div>
326
+ )
327
+ }
328
+ ```
329
+
330
+ ### 6. Responsive Design Utilities
331
+
332
+ ```typescript
333
+ // components/ui/responsive-container.tsx
334
+ import { cn } from "@/lib/utils"
335
+ import { ReactNode } from "react"
336
+
337
+ interface ResponsiveContainerProps {
338
+ children: ReactNode
339
+ className?: string
340
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
341
+ }
342
+
343
+ export function ResponsiveContainer({
344
+ children,
345
+ className,
346
+ size = 'lg'
347
+ }: ResponsiveContainerProps) {
348
+ const sizeClasses = {
349
+ sm: 'max-w-2xl',
350
+ md: 'max-w-4xl',
351
+ lg: 'max-w-6xl',
352
+ xl: 'max-w-7xl',
353
+ full: 'w-full'
354
+ }
355
+
356
+ return (
357
+ <div className={cn(
358
+ "mx-auto px-4 sm:px-6 lg:px-8",
359
+ sizeClasses[size],
360
+ className
361
+ )}>
362
+ {children}
363
+ </div>
364
+ )
365
+ }
366
+
367
+ // Responsive Grid
368
+ export function ResponsiveGrid({
369
+ children,
370
+ cols = { default: 1, sm: 2, md: 3, lg: 4 },
371
+ gap = 4,
372
+ className
373
+ }: {
374
+ children: ReactNode
375
+ cols?: { default: number; sm?: number; md?: number; lg?: number; xl?: number }
376
+ gap?: number
377
+ className?: string
378
+ }) {
379
+ const gridCols = cn(
380
+ `grid gap-${gap}`,
381
+ `grid-cols-${cols.default}`,
382
+ cols.sm && `sm:grid-cols-${cols.sm}`,
383
+ cols.md && `md:grid-cols-${cols.md}`,
384
+ cols.lg && `lg:grid-cols-${cols.lg}`,
385
+ cols.xl && `xl:grid-cols-${cols.xl}`,
386
+ className
387
+ )
388
+
389
+ return (
390
+ <div className={gridCols}>
391
+ {children}
392
+ </div>
393
+ )
394
+ }
395
+ ```
396
+
397
+ ### 7. Animations and Transitions
398
+
399
+ Add to your global CSS:
400
+
401
+ ```css
402
+ /* app/globals.css */
403
+ @layer utilities {
404
+ /* Smooth transitions */
405
+ .transition-smooth {
406
+ @apply transition-all duration-300 ease-in-out;
407
+ }
408
+
409
+ /* Fade animations */
410
+ @keyframes fade-in {
411
+ from {
412
+ opacity: 0;
413
+ transform: translateY(10px);
414
+ }
415
+ to {
416
+ opacity: 1;
417
+ transform: translateY(0);
418
+ }
419
+ }
420
+
421
+ .animate-fade-in {
422
+ animation: fade-in 0.5s ease-out;
423
+ }
424
+
425
+ /* Slide animations */
426
+ @keyframes slide-in-right {
427
+ from {
428
+ transform: translateX(100%);
429
+ }
430
+ to {
431
+ transform: translateX(0);
432
+ }
433
+ }
434
+
435
+ .animate-slide-in-right {
436
+ animation: slide-in-right 0.3s ease-out;
437
+ }
438
+
439
+ /* Pulse animation for loading */
440
+ @keyframes pulse-scale {
441
+ 0%, 100% {
442
+ transform: scale(1);
443
+ }
444
+ 50% {
445
+ transform: scale(1.05);
446
+ }
447
+ }
448
+
449
+ .animate-pulse-scale {
450
+ animation: pulse-scale 2s ease-in-out infinite;
451
+ }
452
+ }
453
+
454
+ /* Minimalist spacing */
455
+ .section-spacing {
456
+ @apply py-12 md:py-16 lg:py-20;
457
+ }
458
+
459
+ .content-spacing {
460
+ @apply space-y-6 md:space-y-8 lg:space-y-10;
461
+ }
462
+
463
+ /* Clean card styles */
464
+ .card-hover {
465
+ @apply transition-all duration-200 hover:shadow-lg hover:-translate-y-1;
466
+ }
467
+
468
+ /* Focus styles */
469
+ .focus-ring {
470
+ @apply focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-background;
471
+ }
472
+ ```
473
+
474
+ ### 8. Minimalist Dashboard Example
475
+
476
+ ```typescript
477
+ // app/dashboard/page.tsx
478
+ 'use client'
479
+
480
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
481
+ import { ResponsiveContainer, ResponsiveGrid } from "@/components/ui/responsive-container"
482
+ import { Button } from "@/components/ui/button"
483
+ import { ArrowRight, CreditCard, Shield, Zap } from "lucide-react"
484
+
485
+ export default function Dashboard() {
486
+ return (
487
+ <ResponsiveContainer size="xl" className="section-spacing">
488
+ <div className="content-spacing">
489
+ {/* Hero Section */}
490
+ <div className="text-center space-y-4 py-12">
491
+ <h1 className="text-4xl md:text-5xl font-bold tracking-tight animate-fade-in">
492
+ Welcome to SPAPS
493
+ </h1>
494
+ <p className="text-lg text-muted-foreground max-w-2xl mx-auto">
495
+ Complete authentication and payment solution with a minimalist design
496
+ </p>
497
+ </div>
498
+
499
+ {/* Feature Cards */}
500
+ <ResponsiveGrid cols={{ default: 1, md: 3 }} gap={6}>
501
+ <Card className="card-hover">
502
+ <CardHeader>
503
+ <Shield className="h-8 w-8 mb-2 text-primary" />
504
+ <CardTitle>Secure Authentication</CardTitle>
505
+ <CardDescription>
506
+ Multi-method auth with email, wallet, and magic links
507
+ </CardDescription>
508
+ </CardHeader>
509
+ <CardContent>
510
+ <Button variant="ghost" className="group">
511
+ Learn more
512
+ <ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
513
+ </Button>
514
+ </CardContent>
515
+ </Card>
516
+
517
+ <Card className="card-hover">
518
+ <CardHeader>
519
+ <CreditCard className="h-8 w-8 mb-2 text-primary" />
520
+ <CardTitle>Stripe Payments</CardTitle>
521
+ <CardDescription>
522
+ Seamless payment processing and subscription management
523
+ </CardDescription>
524
+ </CardHeader>
525
+ <CardContent>
526
+ <Button variant="ghost" className="group">
527
+ View pricing
528
+ <ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
529
+ </Button>
530
+ </CardContent>
531
+ </Card>
532
+
533
+ <Card className="card-hover">
534
+ <CardHeader>
535
+ <Zap className="h-8 w-8 mb-2 text-primary" />
536
+ <CardTitle>Lightning Fast</CardTitle>
537
+ <CardDescription>
538
+ Built with Next.js 15 and optimized for performance
539
+ </CardDescription>
540
+ </CardHeader>
541
+ <CardContent>
542
+ <Button variant="ghost" className="group">
543
+ Get started
544
+ <ArrowRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
545
+ </Button>
546
+ </CardContent>
547
+ </Card>
548
+ </ResponsiveGrid>
549
+
550
+ {/* Stats Section */}
551
+ <Card>
552
+ <CardContent className="py-8">
553
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-8">
554
+ {[
555
+ { label: 'Active Users', value: '2,451' },
556
+ { label: 'API Calls', value: '48.2k' },
557
+ { label: 'Uptime', value: '99.9%' },
558
+ { label: 'Response Time', value: '45ms' }
559
+ ].map((stat) => (
560
+ <div key={stat.label} className="text-center">
561
+ <p className="text-3xl font-bold">{stat.value}</p>
562
+ <p className="text-sm text-muted-foreground">{stat.label}</p>
563
+ </div>
564
+ ))}
565
+ </div>
566
+ </CardContent>
567
+ </Card>
568
+ </div>
569
+ </ResponsiveContainer>
570
+ )
571
+ }
572
+ ```
573
+
574
+ ## Validation Checklist
575
+
576
+ ✅ **Theme Support**:
577
+ - next-themes installed and configured
578
+ - Theme provider wraps app
579
+ - Dark mode toggle works
580
+ - System preference respected
581
+
582
+ ✅ **Minimalist Design**:
583
+ - Plenty of whitespace
584
+ - Clean typography
585
+ - Subtle animations
586
+ - Consistent spacing
587
+
588
+ ✅ **Loading States**:
589
+ - Skeleton loaders for all async content
590
+ - Loading buttons with spinners
591
+ - Smooth transitions
592
+
593
+ ✅ **Responsive Design**:
594
+ - Mobile-first approach
595
+ - Works on all screen sizes
596
+ - Touch-friendly buttons
597
+ - Readable on small screens
598
+
599
+ ## Common Mistakes to Avoid
600
+
601
+ ❌ **Forgetting suppressHydrationWarning**:
602
+ ```html
603
+ <!-- WRONG - Causes hydration mismatch -->
604
+ <html lang="en">
605
+
606
+ <!-- CORRECT -->
607
+ <html lang="en" suppressHydrationWarning>
608
+ ```
609
+
610
+ ❌ **Too many animations**:
611
+ ```css
612
+ /* WRONG - Overwhelming */
613
+ .everything { animation: bounce 1s infinite; }
614
+ ```
615
+
616
+ ❌ **Inconsistent spacing**:
617
+ ```tsx
618
+ // WRONG - Random spacing
619
+ <div className="p-3 m-7 pt-9">
620
+ ```
621
+
622
+ ## Next Step
623
+
624
+ When ALL todos are ✅ complete:
625
+
626
+ ```javascript
627
+ mcp__product-manager__get_agent_instructions({
628
+ category: "spaps-integration",
629
+ project: "spaps-demo",
630
+ step: 12
631
+ })
632
+ ```
633
+
634
+ ## Summary
635
+
636
+ UI polish provides:
637
+ - **Professional appearance** - Clean, modern design
638
+ - **Better UX** - Smooth transitions and loading states
639
+ - **Accessibility** - Dark mode and responsive design
640
+ - **Brand consistency** - Unified design language