@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.
- package/dist/index.js +77 -6
- package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +1 -1
- package/dist/templates/web-nextjs/apps/docs/.source/server.ts +3 -2
- package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/meta.json +1 -1
- package/dist/templates/web-nextjs/apps/docs/content/docs/decisions/turbo-package-manager.mdx +70 -0
- package/dist/templates/web-nextjs/apps/docs/package.json +1 -1
- package/dist/templates/web-nextjs/apps/web/middleware.ts +6 -13
- package/dist/templates/web-nextjs/apps/web/package.json +26 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +87 -93
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +116 -98
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +38 -29
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/layout.tsx +2 -5
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +11 -8
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/privacy/page.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/terms/page.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/app/route.ts +13 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/app-sidebar.tsx +188 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/chart-area-interactive.tsx +291 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data-table.tsx +807 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data.json +614 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-documents.tsx +92 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-main.tsx +58 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-secondary.tsx +42 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-user.tsx +118 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/page.tsx +40 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/section-cards.tsx +102 -0
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/site-header.tsx +30 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/alert-dialog.tsx +196 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/avatar.tsx +109 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/badge.tsx +48 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/breadcrumb.tsx +109 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +14 -2
- package/dist/templates/web-nextjs/apps/web/src/components/ui/card.tsx +92 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/chart.tsx +374 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/checkbox.tsx +32 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/collapsible.tsx +33 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/command.tsx +184 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dialog.tsx +158 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/drawer.tsx +135 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dropdown-menu.tsx +257 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/field.tsx +248 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/input-otp.tsx +77 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/pagination.tsx +127 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/popover.tsx +89 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/progress.tsx +31 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/radio-group.tsx +45 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/scroll-area.tsx +58 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/select.tsx +190 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/separator.tsx +29 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sheet.tsx +143 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sidebar.tsx +726 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/skeleton.tsx +13 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/slider.tsx +63 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +11 -25
- package/dist/templates/web-nextjs/apps/web/src/components/ui/switch.tsx +35 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/table.tsx +116 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tabs.tsx +91 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/textarea.tsx +18 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle-group.tsx +83 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle.tsx +47 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tooltip.tsx +57 -0
- package/dist/templates/web-nextjs/apps/web/src/features/auth/server.ts +15 -0
- package/dist/templates/web-nextjs/apps/web/src/hooks/use-mobile.ts +21 -0
- package/dist/templates/web-nextjs/package.json +10 -1
- package/dist/templates/web-nextjs/packages/openspec-docs-sync/package.json +1 -3
- package/dist/templates/web-nextjs/pnpm-lock.yaml +1562 -100
- package/dist/templates/web-nextjs/pnpm-workspace.yaml +15 -0
- package/dist/templates/web-nextjs/turbo.json +1 -0
- package/package.json +2 -2
- /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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
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
|
-
|
|
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-
|
|
54
|
-
<div className="w-full max-w-sm
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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-
|
|
69
|
-
<div className="w-full max-w-sm
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
<
|
|
76
|
-
<
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
</
|
|
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 {
|
|
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
|
|
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=
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
+
}
|