@cogito.ai/cli 0.3.4 → 0.4.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.
Files changed (70) hide show
  1. package/dist/index.js +77 -6
  2. package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +1 -1
  3. package/dist/templates/web-nextjs/apps/docs/.source/server.ts +3 -2
  4. package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/meta.json +1 -1
  5. package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/turbo-package-manager.mdx +70 -0
  6. package/dist/templates/web-nextjs/apps/docs/package.json +1 -1
  7. package/dist/templates/web-nextjs/apps/web/middleware.ts +6 -13
  8. package/dist/templates/web-nextjs/apps/web/package.json +26 -0
  9. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +87 -93
  10. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +116 -98
  11. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +38 -29
  12. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/layout.tsx +2 -5
  13. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +11 -8
  14. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/privacy/page.tsx +23 -0
  15. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/terms/page.tsx +23 -0
  16. package/dist/templates/web-nextjs/apps/web/src/app/route.ts +13 -0
  17. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/app-sidebar.tsx +188 -0
  18. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/chart-area-interactive.tsx +291 -0
  19. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data-table.tsx +807 -0
  20. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data.json +614 -0
  21. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-documents.tsx +92 -0
  22. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-main.tsx +58 -0
  23. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-secondary.tsx +42 -0
  24. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-user.tsx +118 -0
  25. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/page.tsx +40 -0
  26. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/section-cards.tsx +102 -0
  27. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/site-header.tsx +30 -0
  28. package/dist/templates/web-nextjs/apps/web/src/components/ui/alert-dialog.tsx +196 -0
  29. package/dist/templates/web-nextjs/apps/web/src/components/ui/avatar.tsx +109 -0
  30. package/dist/templates/web-nextjs/apps/web/src/components/ui/badge.tsx +48 -0
  31. package/dist/templates/web-nextjs/apps/web/src/components/ui/breadcrumb.tsx +109 -0
  32. package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +14 -2
  33. package/dist/templates/web-nextjs/apps/web/src/components/ui/card.tsx +92 -0
  34. package/dist/templates/web-nextjs/apps/web/src/components/ui/chart.tsx +374 -0
  35. package/dist/templates/web-nextjs/apps/web/src/components/ui/checkbox.tsx +32 -0
  36. package/dist/templates/web-nextjs/apps/web/src/components/ui/collapsible.tsx +33 -0
  37. package/dist/templates/web-nextjs/apps/web/src/components/ui/command.tsx +184 -0
  38. package/dist/templates/web-nextjs/apps/web/src/components/ui/dialog.tsx +158 -0
  39. package/dist/templates/web-nextjs/apps/web/src/components/ui/drawer.tsx +135 -0
  40. package/dist/templates/web-nextjs/apps/web/src/components/ui/dropdown-menu.tsx +257 -0
  41. package/dist/templates/web-nextjs/apps/web/src/components/ui/field.tsx +248 -0
  42. package/dist/templates/web-nextjs/apps/web/src/components/ui/input-otp.tsx +77 -0
  43. package/dist/templates/web-nextjs/apps/web/src/components/ui/pagination.tsx +127 -0
  44. package/dist/templates/web-nextjs/apps/web/src/components/ui/popover.tsx +89 -0
  45. package/dist/templates/web-nextjs/apps/web/src/components/ui/progress.tsx +31 -0
  46. package/dist/templates/web-nextjs/apps/web/src/components/ui/radio-group.tsx +45 -0
  47. package/dist/templates/web-nextjs/apps/web/src/components/ui/scroll-area.tsx +58 -0
  48. package/dist/templates/web-nextjs/apps/web/src/components/ui/select.tsx +190 -0
  49. package/dist/templates/web-nextjs/apps/web/src/components/ui/separator.tsx +29 -0
  50. package/dist/templates/web-nextjs/apps/web/src/components/ui/sheet.tsx +143 -0
  51. package/dist/templates/web-nextjs/apps/web/src/components/ui/sidebar.tsx +726 -0
  52. package/dist/templates/web-nextjs/apps/web/src/components/ui/skeleton.tsx +13 -0
  53. package/dist/templates/web-nextjs/apps/web/src/components/ui/slider.tsx +63 -0
  54. package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +11 -25
  55. package/dist/templates/web-nextjs/apps/web/src/components/ui/switch.tsx +35 -0
  56. package/dist/templates/web-nextjs/apps/web/src/components/ui/table.tsx +116 -0
  57. package/dist/templates/web-nextjs/apps/web/src/components/ui/tabs.tsx +91 -0
  58. package/dist/templates/web-nextjs/apps/web/src/components/ui/textarea.tsx +18 -0
  59. package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle-group.tsx +83 -0
  60. package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle.tsx +47 -0
  61. package/dist/templates/web-nextjs/apps/web/src/components/ui/tooltip.tsx +57 -0
  62. package/dist/templates/web-nextjs/apps/web/src/features/auth/server.ts +15 -0
  63. package/dist/templates/web-nextjs/apps/web/src/hooks/use-mobile.ts +21 -0
  64. package/dist/templates/web-nextjs/package.json +10 -1
  65. package/dist/templates/web-nextjs/packages/openspec-docs-sync/package.json +1 -3
  66. package/dist/templates/web-nextjs/pnpm-lock.yaml +1562 -100
  67. package/dist/templates/web-nextjs/pnpm-workspace.yaml +15 -0
  68. package/dist/templates/web-nextjs/turbo.json +1 -0
  69. package/package.json +2 -2
  70. /package/dist/templates/web-nextjs/{.env.example → apps/web/.env.example} +0 -0
@@ -6,18 +6,17 @@ import { useParams } from 'next/navigation'
6
6
  import { useTranslations } from 'next-intl'
7
7
  import { useForm } from 'react-hook-form'
8
8
  import { zodResolver } from '@hookform/resolvers/zod'
9
+ import { GalleryVerticalEnd } from 'lucide-react'
9
10
  import { toast } from 'sonner'
10
11
  import { Button } from '@/components/ui/button'
12
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
11
13
  import { Input } from '@/components/ui/input'
12
14
  import {
13
- Form,
14
- FormControl,
15
- FormDescription,
16
- FormField,
17
- FormItem,
18
- FormLabel,
19
- FormMessage,
20
- } from '@/components/ui/form'
15
+ Field,
16
+ FieldDescription,
17
+ FieldGroup,
18
+ FieldLabel,
19
+ } from '@/components/ui/field'
21
20
  import { signUp } from '@/features/auth'
22
21
  import { signUpSchema, type SignUpInput } from '@/lib/validations/auth'
23
22
  import type { ActionResult } from '@/core/types/auth'
@@ -29,7 +28,7 @@ export default function SignupPage() {
29
28
  const locale = routeParams.locale ?? 'en'
30
29
  const [verifyEmail, setVerifyEmail] = useState<string | null>(null)
31
30
 
32
- const form = useForm<SignUpInput>({
31
+ const { register, formState: { errors } } = useForm<SignUpInput>({
33
32
  resolver: zodResolver(signUpSchema),
34
33
  defaultValues: { email: '', password: '', confirmPassword: '' },
35
34
  })
@@ -40,111 +39,130 @@ export default function SignupPage() {
40
39
  )
41
40
 
42
41
  useEffect(() => {
43
- if (state?.error) {
44
- toast.error(state.error)
45
- }
46
- if (state?.data?.success) {
47
- setVerifyEmail(state.data.email)
48
- }
42
+ if (state?.error) toast.error(state.error)
43
+ if (state?.data?.success) setVerifyEmail(state.data.email)
49
44
  }, [state])
50
45
 
51
46
  if (verifyEmail) {
52
47
  return (
53
- <div className="flex min-h-screen items-center justify-center px-4 py-12">
54
- <div className="w-full max-w-sm space-y-4 text-center">
55
- <h1 className="text-2xl font-bold">{t('verifyEmailTitle')}</h1>
56
- <p className="text-muted-foreground">
57
- {t('verifyEmailMessage', { email: verifyEmail })}
58
- </p>
59
- <Link href={`/${locale}/login`} className="text-sm underline underline-offset-4">
60
- {t('signInLink')}
48
+ <div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
49
+ <div className="flex w-full max-w-sm flex-col gap-6">
50
+ <Link href={`/${locale}`} className="flex items-center gap-2 self-center font-medium">
51
+ <div className="flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
52
+ <GalleryVerticalEnd className="size-4" />
53
+ </div>
54
+ AgentDock
61
55
  </Link>
56
+ <Card>
57
+ <CardHeader className="text-center">
58
+ <CardTitle className="text-xl">{t('verifyEmailTitle')}</CardTitle>
59
+ <CardDescription>
60
+ {t('verifyEmailMessage', { email: verifyEmail })}
61
+ </CardDescription>
62
+ </CardHeader>
63
+ <CardContent>
64
+ <div className="text-center">
65
+ <Link href={`/${locale}/login`} className="underline underline-offset-4 text-sm">
66
+ {t('signInLink')}
67
+ </Link>
68
+ </div>
69
+ </CardContent>
70
+ </Card>
62
71
  </div>
63
72
  </div>
64
73
  )
65
74
  }
66
75
 
67
76
  return (
68
- <div className="flex min-h-screen items-center justify-center px-4 py-12">
69
- <div className="w-full max-w-sm space-y-6">
70
- <div className="space-y-2 text-center">
71
- <h1 className="text-3xl font-bold">{t('signupTitle')}</h1>
72
- <p className="text-muted-foreground">{t('signupSubtitle')}</p>
73
- </div>
77
+ <div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
78
+ <div className="flex w-full max-w-sm flex-col gap-6">
79
+ <Link href={`/${locale}`} className="flex items-center gap-2 self-center font-medium">
80
+ <div className="flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
81
+ <GalleryVerticalEnd className="size-4" />
82
+ </div>
83
+ AgentDock
84
+ </Link>
74
85
 
75
- <Form {...form}>
76
- <form action={formAction} className="space-y-4">
77
- <input type="hidden" name="locale" value={locale} />
78
- <FormField
79
- control={form.control}
80
- name="email"
81
- render={({ field }) => (
82
- <FormItem>
83
- <FormLabel>{t('emailLabel')}</FormLabel>
84
- <FormControl>
86
+ <div className="flex flex-col gap-6">
87
+ <Card>
88
+ <CardHeader className="text-center">
89
+ <CardTitle className="text-xl">{t('signupTitle')}</CardTitle>
90
+ <CardDescription>{t('signupSubtitle')}</CardDescription>
91
+ </CardHeader>
92
+ <CardContent>
93
+ <form action={formAction}>
94
+ <input type="hidden" name="locale" value={locale} />
95
+ <FieldGroup>
96
+ <Field>
97
+ <FieldLabel htmlFor="email">{t('emailLabel')}</FieldLabel>
85
98
  <Input
99
+ id="email"
86
100
  type="email"
87
101
  placeholder={t('emailPlaceholder')}
88
- {...field}
89
- />
90
- </FormControl>
91
- <FormDescription>{t('emailHelperText')}</FormDescription>
92
- <FormMessage />
93
- </FormItem>
94
- )}
95
- />
96
-
97
- <FormField
98
- control={form.control}
99
- name="password"
100
- render={({ field }) => (
101
- <FormItem>
102
- <FormLabel>{t('passwordLabel')}</FormLabel>
103
- <FormControl>
104
- <Input
105
- type="password"
106
- placeholder={t('passwordPlaceholder')}
107
- {...field}
102
+ autoComplete="email"
103
+ {...register('email')}
108
104
  />
109
- </FormControl>
110
- <FormMessage />
111
- </FormItem>
112
- )}
113
- />
114
-
115
- <FormField
116
- control={form.control}
117
- name="confirmPassword"
118
- render={({ field }) => (
119
- <FormItem>
120
- <FormLabel>{t('confirmPasswordLabel')}</FormLabel>
121
- <FormControl>
122
- <Input
123
- type="password"
124
- placeholder={t('confirmPasswordPlaceholder')}
125
- {...field}
126
- />
127
- </FormControl>
128
- <FormMessage />
129
- </FormItem>
130
- )}
131
- />
132
-
133
- <Button type="submit" className="w-full" disabled={isPending}>
134
- {isPending ? '...' : t('signUpButton')}
135
- </Button>
136
- </form>
137
- </Form>
138
-
139
- <p className="text-center text-sm text-muted-foreground">
140
- {t('hasAccountText')}{' '}
141
- <Link
142
- href={`/${locale}/login`}
143
- className="underline underline-offset-4 hover:text-primary"
144
- >
145
- {t('signInLink')}
146
- </Link>
147
- </p>
105
+ {errors.email && (
106
+ <FieldDescription className="text-destructive">
107
+ {errors.email.message}
108
+ </FieldDescription>
109
+ )}
110
+ <FieldDescription>{t('emailHelperText')}</FieldDescription>
111
+ </Field>
112
+ <Field className="grid grid-cols-2 gap-4">
113
+ <Field>
114
+ <FieldLabel htmlFor="password">{t('passwordLabel')}</FieldLabel>
115
+ <Input
116
+ id="password"
117
+ type="password"
118
+ placeholder={t('passwordPlaceholder')}
119
+ autoComplete="new-password"
120
+ {...register('password')}
121
+ />
122
+ {errors.password && (
123
+ <FieldDescription className="text-destructive">
124
+ {errors.password.message}
125
+ </FieldDescription>
126
+ )}
127
+ </Field>
128
+ <Field>
129
+ <FieldLabel htmlFor="confirmPassword">{t('confirmPasswordLabel')}</FieldLabel>
130
+ <Input
131
+ id="confirmPassword"
132
+ type="password"
133
+ placeholder={t('confirmPasswordPlaceholder')}
134
+ autoComplete="new-password"
135
+ {...register('confirmPassword')}
136
+ />
137
+ {errors.confirmPassword && (
138
+ <FieldDescription className="text-destructive">
139
+ {errors.confirmPassword.message}
140
+ </FieldDescription>
141
+ )}
142
+ </Field>
143
+ </Field>
144
+ <Field>
145
+ <Button type="submit" className="w-full" disabled={isPending}>
146
+ {isPending ? '\u2026' : t('signUpButton')}
147
+ </Button>
148
+ <FieldDescription className="text-center">
149
+ {t('hasAccountText')}{' '}
150
+ <Link href={`/${locale}/login`} className="underline underline-offset-4">
151
+ {t('signInLink')}
152
+ </Link>
153
+ </FieldDescription>
154
+ </Field>
155
+ </FieldGroup>
156
+ </form>
157
+ </CardContent>
158
+ </Card>
159
+ <FieldDescription className="px-6 text-center">
160
+ {t('termsText')}{' '}
161
+ <Link href={`/${locale}/terms`} className="underline underline-offset-4">{t('termsLink')}</Link>
162
+ {' '}{t('andText')}{' '}
163
+ <Link href={`/${locale}/privacy`} className="underline underline-offset-4">{t('privacyLink')}</Link>.
164
+ </FieldDescription>
165
+ </div>
148
166
  </div>
149
167
  </div>
150
168
  )
@@ -1,7 +1,12 @@
1
- import { getTranslations } from 'next-intl/server'
2
- import { getServerClient } from '@/infra/db/client'
3
- import { signOut } from '@/features/auth'
4
- import { Button } from '@/components/ui/button'
1
+ import { AppSidebar } from '@/components/dashboard/app-sidebar'
2
+ import { ChartAreaInteractive } from '@/components/dashboard/chart-area-interactive'
3
+ import { DataTable } from '@/components/dashboard/data-table'
4
+ import { SectionCards } from '@/components/dashboard/section-cards'
5
+ import { SiteHeader } from '@/components/dashboard/site-header'
6
+ import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar'
7
+ import { getCurrentUser } from '@/features/auth/server'
8
+
9
+ import data from '@/components/dashboard/data.json'
5
10
 
6
11
  export default async function DashboardPage({
7
12
  params,
@@ -9,34 +14,38 @@ export default async function DashboardPage({
9
14
  params: Promise<{ locale: string }>
10
15
  }) {
11
16
  const { locale } = await params
12
- const t = await getTranslations({ locale, namespace: 'auth' })
13
- const supabase = await getServerClient()
14
- const {
15
- data: { user },
16
- } = await supabase.auth.getUser()
17
+ const user = await getCurrentUser()
18
+
19
+ const userInfo = {
20
+ name: user?.user_metadata?.full_name ?? user?.email?.split('@')[0] ?? 'User',
21
+ email: user?.email ?? '',
22
+ avatar: user?.user_metadata?.avatar_url ?? '',
23
+ }
17
24
 
18
25
  return (
19
- <div className="min-h-screen bg-background">
20
- <header className="border-b">
21
- <div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
22
- <h1 className="text-xl font-semibold">{t('dashboardTitle')}</h1>
23
- <div className="flex items-center gap-4">
24
- <span className="text-sm text-muted-foreground">{user?.email}</span>
25
- <form action={signOut}>
26
- <input type="hidden" name="locale" value={locale} />
27
- <Button type="submit" variant="outline" size="sm">
28
- {t('signOutButton')}
29
- </Button>
30
- </form>
26
+ <SidebarProvider
27
+ style={
28
+ {
29
+ '--sidebar-width': 'calc(var(--spacing) * 72)',
30
+ '--header-height': 'calc(var(--spacing) * 12)',
31
+ } as React.CSSProperties
32
+ }
33
+ >
34
+ <AppSidebar variant="inset" user={userInfo} locale={locale} />
35
+ <SidebarInset>
36
+ <SiteHeader />
37
+ <div className="flex flex-1 flex-col">
38
+ <div className="@container/main flex flex-1 flex-col gap-2">
39
+ <div className="flex flex-col gap-4 py-4 md:gap-6 md:py-6">
40
+ <SectionCards />
41
+ <div className="px-4 lg:px-6">
42
+ <ChartAreaInteractive />
43
+ </div>
44
+ <DataTable data={data} />
45
+ </div>
31
46
  </div>
32
47
  </div>
33
- </header>
34
-
35
- <main className="mx-auto max-w-7xl px-4 py-8">
36
- <p className="text-muted-foreground">
37
- {t('dashboardWelcome', { email: user?.email ?? '' })}
38
- </p>
39
- </main>
40
- </div>
48
+ </SidebarInset>
49
+ </SidebarProvider>
41
50
  )
42
51
  }
@@ -1,5 +1,5 @@
1
1
  import { redirect } from 'next/navigation'
2
- import { getServerClient } from '@/infra/db/client'
2
+ import { getCurrentUser } from '@/features/auth/server'
3
3
 
4
4
  export default async function ProtectedLayout({
5
5
  children,
@@ -9,10 +9,7 @@ export default async function ProtectedLayout({
9
9
  params: Promise<{ locale: string }>
10
10
  }) {
11
11
  const { locale } = await params
12
- const supabase = await getServerClient()
13
- const {
14
- data: { user },
15
- } = await supabase.auth.getUser()
12
+ const user = await getCurrentUser()
16
13
 
17
14
  if (!user) {
18
15
  redirect(`/${locale}/login`)
@@ -1,12 +1,17 @@
1
1
  import type { Metadata } from 'next'
2
+ import { Inter } from 'next/font/google'
2
3
  import { NextIntlClientProvider } from 'next-intl'
3
4
  import { getMessages } from 'next-intl/server'
4
- import { ThemeProvider } from 'next-themes'
5
5
  import { notFound } from 'next/navigation'
6
6
  import { Toaster } from '@/components/ui/sonner'
7
7
  import { isLocale } from '@/i18n/config'
8
8
  import './globals.css'
9
9
 
10
+ const inter = Inter({
11
+ subsets: ['latin'],
12
+ variable: '--font-sans',
13
+ })
14
+
10
15
  export const metadata: Metadata = {
11
16
  title: 'AgentDock Web Template',
12
17
  description: 'Generated by AgentDock scaffold platform',
@@ -29,13 +34,11 @@ export default async function LocaleLayout({
29
34
 
30
35
  return (
31
36
  <html lang={locale} suppressHydrationWarning>
32
- <body className="min-h-screen bg-background font-sans antialiased">
33
- <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
34
- <NextIntlClientProvider messages={messages}>
35
- {children}
36
- </NextIntlClientProvider>
37
- <Toaster />
38
- </ThemeProvider>
37
+ <body className={`${inter.variable} min-h-screen bg-background font-sans antialiased`}>
38
+ <NextIntlClientProvider messages={messages}>
39
+ {children}
40
+ </NextIntlClientProvider>
41
+ <Toaster />
39
42
  </body>
40
43
  </html>
41
44
  )
@@ -0,0 +1,23 @@
1
+ import Link from 'next/link'
2
+
3
+ export default async function PrivacyPage({
4
+ params,
5
+ }: {
6
+ params: Promise<{ locale: string }>
7
+ }) {
8
+ const { locale } = await params
9
+
10
+ return (
11
+ <main className="mx-auto max-w-3xl px-4 py-10">
12
+ <h1 className="text-2xl font-semibold">Privacy Policy</h1>
13
+ <p className="mt-4 text-muted-foreground">
14
+ This template page is a placeholder. Replace it with your actual privacy policy before shipping.
15
+ </p>
16
+ <p className="mt-6">
17
+ <Link href={`/${locale}/signup`} className="underline underline-offset-4">
18
+ Back to sign up
19
+ </Link>
20
+ </p>
21
+ </main>
22
+ )
23
+ }
@@ -0,0 +1,23 @@
1
+ import Link from 'next/link'
2
+
3
+ export default async function TermsPage({
4
+ params,
5
+ }: {
6
+ params: Promise<{ locale: string }>
7
+ }) {
8
+ const { locale } = await params
9
+
10
+ return (
11
+ <main className="mx-auto max-w-3xl px-4 py-10">
12
+ <h1 className="text-2xl font-semibold">Terms of Service</h1>
13
+ <p className="mt-4 text-muted-foreground">
14
+ This template page is a placeholder. Replace it with your actual terms before shipping.
15
+ </p>
16
+ <p className="mt-6">
17
+ <Link href={`/${locale}/signup`} className="underline underline-offset-4">
18
+ Back to sign up
19
+ </Link>
20
+ </p>
21
+ </main>
22
+ )
23
+ }
@@ -0,0 +1,13 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { defaultLocale } from '@/i18n/config'
3
+
4
+ /**
5
+ * Handles GET / — next-intl middleware should redirect to /${defaultLocale}
6
+ * first, but this route handler is the belt-and-suspenders fallback for edge
7
+ * cases where the middleware matcher doesn't fire (e.g. Turbopack dev quirks).
8
+ */
9
+ export function GET(request: Request) {
10
+ const url = new URL(request.url)
11
+ url.pathname = `/${defaultLocale}`
12
+ return NextResponse.redirect(url, { status: 307 })
13
+ }
@@ -0,0 +1,188 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ IconCamera,
6
+ IconChartBar,
7
+ IconDashboard,
8
+ IconDatabase,
9
+ IconFileAi,
10
+ IconFileDescription,
11
+ IconFileWord,
12
+ IconFolder,
13
+ IconHelp,
14
+ IconInnerShadowTop,
15
+ IconListDetails,
16
+ IconReport,
17
+ IconSearch,
18
+ IconSettings,
19
+ IconUsers,
20
+ } from "@tabler/icons-react"
21
+
22
+ import { NavDocuments } from "@/components/dashboard/nav-documents"
23
+ import { NavMain } from "@/components/dashboard/nav-main"
24
+ import { NavSecondary } from "@/components/dashboard/nav-secondary"
25
+ import { NavUser } from "@/components/dashboard/nav-user"
26
+ import {
27
+ Sidebar,
28
+ SidebarContent,
29
+ SidebarFooter,
30
+ SidebarHeader,
31
+ SidebarMenu,
32
+ SidebarMenuButton,
33
+ SidebarMenuItem,
34
+ } from "@/components/ui/sidebar"
35
+
36
+ const data = {
37
+ user: {
38
+ name: "shadcn",
39
+ email: "m@example.com",
40
+ avatar: "/avatars/shadcn.jpg",
41
+ },
42
+ navMain: [
43
+ {
44
+ title: "Dashboard",
45
+ url: "#",
46
+ icon: IconDashboard,
47
+ },
48
+ {
49
+ title: "Lifecycle",
50
+ url: "#",
51
+ icon: IconListDetails,
52
+ },
53
+ {
54
+ title: "Analytics",
55
+ url: "#",
56
+ icon: IconChartBar,
57
+ },
58
+ {
59
+ title: "Projects",
60
+ url: "#",
61
+ icon: IconFolder,
62
+ },
63
+ {
64
+ title: "Team",
65
+ url: "#",
66
+ icon: IconUsers,
67
+ },
68
+ ],
69
+ navClouds: [
70
+ {
71
+ title: "Capture",
72
+ icon: IconCamera,
73
+ isActive: true,
74
+ url: "#",
75
+ items: [
76
+ {
77
+ title: "Active Proposals",
78
+ url: "#",
79
+ },
80
+ {
81
+ title: "Archived",
82
+ url: "#",
83
+ },
84
+ ],
85
+ },
86
+ {
87
+ title: "Proposal",
88
+ icon: IconFileDescription,
89
+ url: "#",
90
+ items: [
91
+ {
92
+ title: "Active Proposals",
93
+ url: "#",
94
+ },
95
+ {
96
+ title: "Archived",
97
+ url: "#",
98
+ },
99
+ ],
100
+ },
101
+ {
102
+ title: "Prompts",
103
+ icon: IconFileAi,
104
+ url: "#",
105
+ items: [
106
+ {
107
+ title: "Active Proposals",
108
+ url: "#",
109
+ },
110
+ {
111
+ title: "Archived",
112
+ url: "#",
113
+ },
114
+ ],
115
+ },
116
+ ],
117
+ navSecondary: [
118
+ {
119
+ title: "Settings",
120
+ url: "#",
121
+ icon: IconSettings,
122
+ },
123
+ {
124
+ title: "Get Help",
125
+ url: "#",
126
+ icon: IconHelp,
127
+ },
128
+ {
129
+ title: "Search",
130
+ url: "#",
131
+ icon: IconSearch,
132
+ },
133
+ ],
134
+ documents: [
135
+ {
136
+ name: "Data Library",
137
+ url: "#",
138
+ icon: IconDatabase,
139
+ },
140
+ {
141
+ name: "Reports",
142
+ url: "#",
143
+ icon: IconReport,
144
+ },
145
+ {
146
+ name: "Word Assistant",
147
+ url: "#",
148
+ icon: IconFileWord,
149
+ },
150
+ ],
151
+ }
152
+
153
+ export function AppSidebar({
154
+ user,
155
+ locale,
156
+ ...props
157
+ }: React.ComponentProps<typeof Sidebar> & {
158
+ user: { name: string; email: string; avatar: string }
159
+ locale: string
160
+ }) {
161
+ return (
162
+ <Sidebar collapsible="offcanvas" {...props}>
163
+ <SidebarHeader>
164
+ <SidebarMenu>
165
+ <SidebarMenuItem>
166
+ <SidebarMenuButton
167
+ asChild
168
+ className="data-[slot=sidebar-menu-button]:p-1.5!"
169
+ >
170
+ <a href={`/${locale}/dashboard`}>
171
+ <IconInnerShadowTop className="size-5!" />
172
+ <span className="text-base font-semibold">AgentDock</span>
173
+ </a>
174
+ </SidebarMenuButton>
175
+ </SidebarMenuItem>
176
+ </SidebarMenu>
177
+ </SidebarHeader>
178
+ <SidebarContent>
179
+ <NavMain items={data.navMain} />
180
+ <NavDocuments items={data.documents} />
181
+ <NavSecondary items={data.navSecondary} className="mt-auto" />
182
+ </SidebarContent>
183
+ <SidebarFooter>
184
+ <NavUser user={user} locale={locale} />
185
+ </SidebarFooter>
186
+ </Sidebar>
187
+ )
188
+ }