@cogito.ai/cli 0.4.2 → 0.4.3

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 (101) hide show
  1. package/README.md +29 -22
  2. package/dist/index.js +9 -15
  3. package/dist/templates/web-nextjs/.github/copilot-instructions.md +5 -6
  4. package/dist/templates/web-nextjs/README.md +25 -24
  5. package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +18 -8
  6. package/dist/templates/web-nextjs/apps/docs/.source/dynamic.ts +11 -5
  7. package/dist/templates/web-nextjs/apps/docs/.source/server.ts +37 -17
  8. package/dist/templates/web-nextjs/apps/docs/app/docs/[[...slug]]/page.tsx +1 -6
  9. package/dist/templates/web-nextjs/apps/docs/app/docs/layout.tsx +1 -4
  10. package/dist/templates/web-nextjs/apps/docs/app/llms-full.txt/route.ts +3 -1
  11. package/dist/templates/web-nextjs/apps/docs/next-env.d.ts +1 -1
  12. package/dist/templates/web-nextjs/apps/web/.github/copilot-instructions.md +53 -6
  13. package/dist/templates/web-nextjs/apps/web/.github/skills/impeccable/SKILL.md +55 -0
  14. package/dist/templates/web-nextjs/apps/web/DESIGN.md +65 -0
  15. package/dist/templates/web-nextjs/apps/web/messages/en.json +81 -5
  16. package/dist/templates/web-nextjs/apps/web/messages/zh.json +81 -5
  17. package/dist/templates/web-nextjs/apps/web/next.config.ts +3 -3
  18. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/forgot-password/page.tsx +174 -39
  19. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +13 -3
  20. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/reset-password/page.tsx +4 -1
  21. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +18 -17
  22. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +1 -5
  23. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/layout.tsx +1 -5
  24. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/profile/page.tsx +2 -8
  25. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/about/page.tsx +3 -6
  26. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/globals.css +17 -5
  27. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/help/page.tsx +1 -5
  28. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +10 -8
  29. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/page.tsx +22 -6
  30. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/privacy/page.tsx +3 -6
  31. package/dist/templates/web-nextjs/apps/web/src/app/[locale]/terms/page.tsx +1 -5
  32. package/dist/templates/web-nextjs/apps/web/src/app/auth/callback/route.ts +2 -3
  33. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/app-sidebar.tsx +13 -16
  34. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/chart-area-interactive.tsx +122 -146
  35. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data-table.tsx +84 -149
  36. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-documents.tsx +7 -16
  37. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-main.tsx +4 -4
  38. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-secondary.tsx +4 -4
  39. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-user.tsx +12 -21
  40. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/page.tsx +10 -13
  41. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/section-cards.tsx +5 -9
  42. package/dist/templates/web-nextjs/apps/web/src/components/dashboard/site-header.tsx +6 -7
  43. package/dist/templates/web-nextjs/apps/web/src/components/landing/features.tsx +63 -0
  44. package/dist/templates/web-nextjs/apps/web/src/components/landing/footer.tsx +48 -0
  45. package/dist/templates/web-nextjs/apps/web/src/components/landing/header.tsx +97 -0
  46. package/dist/templates/web-nextjs/apps/web/src/components/landing/hero.tsx +45 -0
  47. package/dist/templates/web-nextjs/apps/web/src/components/landing/how-it-works.tsx +35 -0
  48. package/dist/templates/web-nextjs/apps/web/src/components/landing/pricing-teaser.tsx +23 -0
  49. package/dist/templates/web-nextjs/apps/web/src/components/profile/profile-form.tsx +6 -4
  50. package/dist/templates/web-nextjs/apps/web/src/components/providers/theme-provider.tsx +16 -0
  51. package/dist/templates/web-nextjs/apps/web/src/components/ui/alert-dialog.tsx +32 -49
  52. package/dist/templates/web-nextjs/apps/web/src/components/ui/alert.tsx +16 -23
  53. package/dist/templates/web-nextjs/apps/web/src/components/ui/avatar.tsx +25 -38
  54. package/dist/templates/web-nextjs/apps/web/src/components/ui/badge.tsx +16 -18
  55. package/dist/templates/web-nextjs/apps/web/src/components/ui/breadcrumb.tsx +19 -26
  56. package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +23 -24
  57. package/dist/templates/web-nextjs/apps/web/src/components/ui/card.tsx +19 -36
  58. package/dist/templates/web-nextjs/apps/web/src/components/ui/chart.tsx +60 -94
  59. package/dist/templates/web-nextjs/apps/web/src/components/ui/checkbox.tsx +8 -11
  60. package/dist/templates/web-nextjs/apps/web/src/components/ui/collapsible.tsx +5 -17
  61. package/dist/templates/web-nextjs/apps/web/src/components/ui/command.tsx +25 -48
  62. package/dist/templates/web-nextjs/apps/web/src/components/ui/dialog.tsx +21 -35
  63. package/dist/templates/web-nextjs/apps/web/src/components/ui/drawer.tsx +24 -35
  64. package/dist/templates/web-nextjs/apps/web/src/components/ui/dropdown-menu.tsx +26 -55
  65. package/dist/templates/web-nextjs/apps/web/src/components/ui/field.tsx +62 -76
  66. package/dist/templates/web-nextjs/apps/web/src/components/ui/form.tsx +19 -34
  67. package/dist/templates/web-nextjs/apps/web/src/components/ui/input-otp.tsx +13 -20
  68. package/dist/templates/web-nextjs/apps/web/src/components/ui/input.tsx +6 -6
  69. package/dist/templates/web-nextjs/apps/web/src/components/ui/label.tsx +6 -6
  70. package/dist/templates/web-nextjs/apps/web/src/components/ui/pagination.tsx +21 -42
  71. package/dist/templates/web-nextjs/apps/web/src/components/ui/popover.tsx +16 -31
  72. package/dist/templates/web-nextjs/apps/web/src/components/ui/progress.tsx +5 -8
  73. package/dist/templates/web-nextjs/apps/web/src/components/ui/radio-group.tsx +8 -8
  74. package/dist/templates/web-nextjs/apps/web/src/components/ui/scroll-area.tsx +10 -12
  75. package/dist/templates/web-nextjs/apps/web/src/components/ui/select.tsx +26 -41
  76. package/dist/templates/web-nextjs/apps/web/src/components/ui/separator.tsx +7 -7
  77. package/dist/templates/web-nextjs/apps/web/src/components/ui/sheet.tsx +29 -38
  78. package/dist/templates/web-nextjs/apps/web/src/components/ui/sidebar.tsx +157 -189
  79. package/dist/templates/web-nextjs/apps/web/src/components/ui/skeleton.tsx +3 -3
  80. package/dist/templates/web-nextjs/apps/web/src/components/ui/slider.tsx +10 -15
  81. package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +13 -7
  82. package/dist/templates/web-nextjs/apps/web/src/components/ui/switch.tsx +9 -9
  83. package/dist/templates/web-nextjs/apps/web/src/components/ui/table.tsx +24 -48
  84. package/dist/templates/web-nextjs/apps/web/src/components/ui/tabs.tsx +21 -31
  85. package/dist/templates/web-nextjs/apps/web/src/components/ui/textarea.tsx +5 -5
  86. package/dist/templates/web-nextjs/apps/web/src/components/ui/theme-toggle.tsx +23 -0
  87. package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle-group.tsx +15 -16
  88. package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle.tsx +14 -15
  89. package/dist/templates/web-nextjs/apps/web/src/components/ui/tooltip.tsx +8 -12
  90. package/dist/templates/web-nextjs/apps/web/src/core/repositories/IAuthRepository.ts +2 -0
  91. package/dist/templates/web-nextjs/apps/web/src/core/types/auth.ts +1 -3
  92. package/dist/templates/web-nextjs/apps/web/src/features/auth/actions.ts +57 -1
  93. package/dist/templates/web-nextjs/apps/web/src/features/auth/index.ts +2 -0
  94. package/dist/templates/web-nextjs/apps/web/src/hooks/use-mobile.ts +4 -4
  95. package/dist/templates/web-nextjs/apps/web/src/i18n/config.ts +1 -1
  96. package/dist/templates/web-nextjs/apps/web/src/infra/db/SupabaseAuthRepository.ts +48 -4
  97. package/dist/templates/web-nextjs/apps/web/src/infra/db/client.ts +1 -4
  98. package/dist/templates/web-nextjs/apps/web/src/lib/utils.ts +2 -2
  99. package/dist/templates/web-nextjs/apps/web/src/lib/validations/auth.ts +13 -0
  100. package/dist/templates/web-nextjs/apps/web/src/styles/tokens.css +58 -0
  101. package/package.json +1 -1
@@ -1,17 +1,9 @@
1
- "use client"
1
+ 'use client'
2
2
 
3
3
  import Link from 'next/link'
4
- import {
5
- IconDotsVertical,
6
- IconLogout,
7
- IconUserCircle,
8
- } from "@tabler/icons-react"
4
+ import { IconDotsVertical, IconLogout, IconUserCircle } from '@tabler/icons-react'
9
5
 
10
- import {
11
- Avatar,
12
- AvatarFallback,
13
- AvatarImage,
14
- } from "@/components/ui/avatar"
6
+ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
15
7
  import {
16
8
  DropdownMenu,
17
9
  DropdownMenuContent,
@@ -20,13 +12,13 @@ import {
20
12
  DropdownMenuLabel,
21
13
  DropdownMenuSeparator,
22
14
  DropdownMenuTrigger,
23
- } from "@/components/ui/dropdown-menu"
15
+ } from '@/components/ui/dropdown-menu'
24
16
  import {
25
17
  SidebarMenu,
26
18
  SidebarMenuButton,
27
19
  SidebarMenuItem,
28
20
  useSidebar,
29
- } from "@/components/ui/sidebar"
21
+ } from '@/components/ui/sidebar'
30
22
  import { signOut } from '@/features/auth'
31
23
 
32
24
  export function NavUser({
@@ -57,16 +49,14 @@ export function NavUser({
57
49
  </Avatar>
58
50
  <div className="grid flex-1 text-left text-sm leading-tight">
59
51
  <span className="truncate font-medium">{user.name}</span>
60
- <span className="truncate text-xs text-muted-foreground">
61
- {user.email}
62
- </span>
52
+ <span className="truncate text-xs text-muted-foreground">{user.email}</span>
63
53
  </div>
64
54
  <IconDotsVertical className="ml-auto size-4" />
65
55
  </SidebarMenuButton>
66
56
  </DropdownMenuTrigger>
67
57
  <DropdownMenuContent
68
58
  className="w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
69
- side={isMobile ? "bottom" : "right"}
59
+ side={isMobile ? 'bottom' : 'right'}
70
60
  align="end"
71
61
  sideOffset={4}
72
62
  >
@@ -78,16 +68,17 @@ export function NavUser({
78
68
  </Avatar>
79
69
  <div className="grid flex-1 text-left text-sm leading-tight">
80
70
  <span className="truncate font-medium">{user.name}</span>
81
- <span className="truncate text-xs text-muted-foreground">
82
- {user.email}
83
- </span>
71
+ <span className="truncate text-xs text-muted-foreground">{user.email}</span>
84
72
  </div>
85
73
  </div>
86
74
  </DropdownMenuLabel>
87
75
  <DropdownMenuSeparator />
88
76
  <DropdownMenuGroup>
89
77
  <DropdownMenuItem asChild>
90
- <Link href={`/${locale}/settings/profile`} className="flex w-full items-center gap-2">
78
+ <Link
79
+ href={`/${locale}/settings/profile`}
80
+ className="flex w-full items-center gap-2"
81
+ >
91
82
  <IconUserCircle />
92
83
  Account
93
84
  </Link>
@@ -1,26 +1,23 @@
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 {
7
- SidebarInset,
8
- SidebarProvider,
9
- } from "@/components/ui/sidebar"
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'
10
7
 
11
- import data from "./data.json"
8
+ import data from './data.json'
12
9
 
13
10
  export default function Page() {
14
11
  return (
15
12
  <SidebarProvider
16
13
  style={
17
14
  {
18
- "--sidebar-width": "calc(var(--spacing) * 72)",
19
- "--header-height": "calc(var(--spacing) * 12)",
15
+ '--sidebar-width': 'calc(var(--spacing) * 72)',
16
+ '--header-height': 'calc(var(--spacing) * 12)',
20
17
  } as React.CSSProperties
21
18
  }
22
19
  >
23
- <AppSidebar variant="inset" user={{ name: "User", email: "", avatar: "" }} locale="en" />
20
+ <AppSidebar variant="inset" user={{ name: 'User', email: '', avatar: '' }} locale="en" />
24
21
  <SidebarInset>
25
22
  <SiteHeader />
26
23
  <div className="flex flex-1 flex-col">
@@ -1,6 +1,6 @@
1
- import { IconTrendingDown, IconTrendingUp } from "@tabler/icons-react"
1
+ import { IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'
2
2
 
3
- import { Badge } from "@/components/ui/badge"
3
+ import { Badge } from '@/components/ui/badge'
4
4
  import {
5
5
  Card,
6
6
  CardAction,
@@ -8,7 +8,7 @@ import {
8
8
  CardFooter,
9
9
  CardHeader,
10
10
  CardTitle,
11
- } from "@/components/ui/card"
11
+ } from '@/components/ui/card'
12
12
 
13
13
  export function SectionCards() {
14
14
  return (
@@ -30,9 +30,7 @@ export function SectionCards() {
30
30
  <div className="line-clamp-1 flex gap-2 font-medium">
31
31
  Trending up this month <IconTrendingUp className="size-4" />
32
32
  </div>
33
- <div className="text-muted-foreground">
34
- Visitors for the last 6 months
35
- </div>
33
+ <div className="text-muted-foreground">Visitors for the last 6 months</div>
36
34
  </CardFooter>
37
35
  </Card>
38
36
  <Card className="@container/card">
@@ -52,9 +50,7 @@ export function SectionCards() {
52
50
  <div className="line-clamp-1 flex gap-2 font-medium">
53
51
  Down 20% this period <IconTrendingDown className="size-4" />
54
52
  </div>
55
- <div className="text-muted-foreground">
56
- Acquisition needs attention
57
- </div>
53
+ <div className="text-muted-foreground">Acquisition needs attention</div>
58
54
  </CardFooter>
59
55
  </Card>
60
56
  <Card className="@container/card">
@@ -1,18 +1,17 @@
1
- import { Button } from "@/components/ui/button"
2
- import { Separator } from "@/components/ui/separator"
3
- import { SidebarTrigger } from "@/components/ui/sidebar"
1
+ import { Button } from '@/components/ui/button'
2
+ import { Separator } from '@/components/ui/separator'
3
+ import { SidebarTrigger } from '@/components/ui/sidebar'
4
+ import { ThemeToggle } from '@/components/ui/theme-toggle'
4
5
 
5
6
  export function SiteHeader() {
6
7
  return (
7
8
  <header className="flex h-(--header-height) shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
8
9
  <div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
9
10
  <SidebarTrigger className="-ml-1" />
10
- <Separator
11
- orientation="vertical"
12
- className="mx-2 data-[orientation=vertical]:h-4"
13
- />
11
+ <Separator orientation="vertical" className="mx-2 data-[orientation=vertical]:h-4" />
14
12
  <h1 className="text-base font-medium">Documents</h1>
15
13
  <div className="ml-auto flex items-center gap-2">
14
+ <ThemeToggle />
16
15
  <Button variant="ghost" asChild size="sm" className="hidden sm:flex">
17
16
  <a
18
17
  href="https://github.com/shadcn-ui/ui/tree/main/apps/v4/app/(examples)/dashboard"
@@ -0,0 +1,63 @@
1
+ import { useTranslations } from 'next-intl'
2
+ import { Shield, GitBranch, Bot, BookOpen } from 'lucide-react'
3
+
4
+ const icons = [Shield, GitBranch, Bot, BookOpen]
5
+
6
+ export function Features() {
7
+ const t = useTranslations('landing')
8
+
9
+ const features = [
10
+ {
11
+ key: 'auth',
12
+ icon: Shield,
13
+ },
14
+ {
15
+ key: 'monorepo',
16
+ icon: GitBranch,
17
+ },
18
+ {
19
+ key: 'aiCoding',
20
+ icon: Bot,
21
+ },
22
+ {
23
+ key: 'docs',
24
+ icon: BookOpen,
25
+ },
26
+ ]
27
+
28
+ return (
29
+ <section
30
+ id="features"
31
+ className="px-4 py-16 md:py-24"
32
+ style={{ padding: 'clamp(32px, 8vw, 80px) 0' }}
33
+ >
34
+ <div className="mx-auto max-w-7xl px-4 md:px-6">
35
+ <div className="mb-12 text-center">
36
+ <h2 className="text-3xl font-bold tracking-tight md:text-4xl">{t('features.title')}</h2>
37
+ <p className="mt-4 text-muted-foreground">{t('features.subtitle')}</p>
38
+ </div>
39
+ <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
40
+ {features.map((feature) => {
41
+ const Icon = feature.icon
42
+ return (
43
+ <div
44
+ key={feature.key}
45
+ className="group rounded-xl border bg-card p-6 transition-colors hover:border-primary/20"
46
+ >
47
+ <div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
48
+ <Icon className="h-5 w-5" />
49
+ </div>
50
+ <h3 className="text-lg font-semibold">
51
+ {t(`features.items.${feature.key}.title`)}
52
+ </h3>
53
+ <p className="mt-2 text-sm leading-relaxed text-muted-foreground">
54
+ {t(`features.items.${feature.key}.description`)}
55
+ </p>
56
+ </div>
57
+ )
58
+ })}
59
+ </div>
60
+ </div>
61
+ </section>
62
+ )
63
+ }
@@ -0,0 +1,48 @@
1
+ import Link from 'next/link'
2
+ import { useTranslations } from 'next-intl'
3
+ import { IconBrandGithub } from '@tabler/icons-react'
4
+
5
+ interface FooterProps {
6
+ locale: string
7
+ }
8
+
9
+ export function Footer({ locale }: FooterProps) {
10
+ const t = useTranslations('landing')
11
+ const year = new Date().getFullYear()
12
+
13
+ const links = [
14
+ { href: `/${locale}/help`, label: t('footer.help') },
15
+ { href: `/${locale}/privacy`, label: t('footer.privacy') },
16
+ { href: `/${locale}/about`, label: t('footer.about') },
17
+ ]
18
+
19
+ return (
20
+ <footer className="border-t bg-background px-4 py-8 md:py-12">
21
+ <div className="mx-auto flex max-w-7xl flex-col items-center justify-between gap-6 md:flex-row md:px-6">
22
+ <div className="flex items-center gap-4">
23
+ {links.map((link) => (
24
+ <Link
25
+ key={link.href}
26
+ href={link.href}
27
+ className="text-sm text-muted-foreground transition-colors hover:text-foreground"
28
+ >
29
+ {link.label}
30
+ </Link>
31
+ ))}
32
+ </div>
33
+ <div className="flex items-center gap-4">
34
+ <a
35
+ href="https://github.com"
36
+ target="_blank"
37
+ rel="noopener noreferrer"
38
+ aria-label="GitHub"
39
+ className="text-muted-foreground transition-colors hover:text-foreground"
40
+ >
41
+ <IconBrandGithub className="h-5 w-5" />
42
+ </a>
43
+ <span className="text-sm text-muted-foreground">{t('footer.copyright', { year })}</span>
44
+ </div>
45
+ </div>
46
+ </footer>
47
+ )
48
+ }
@@ -0,0 +1,97 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import Link from 'next/link'
5
+ import { useTranslations } from 'next-intl'
6
+ import { Menu } from 'lucide-react'
7
+ import { Button } from '@/components/ui/button'
8
+ import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
9
+ import { ThemeToggle } from '@/components/ui/theme-toggle'
10
+
11
+ interface HeaderProps {
12
+ locale: string
13
+ }
14
+
15
+ export function Header({ locale }: HeaderProps) {
16
+ const t = useTranslations('landing')
17
+ const [open, setOpen] = useState(false)
18
+
19
+ const navLinks = [
20
+ { href: `/${locale}/#features`, label: t('nav.features') },
21
+ { href: `/${locale}/#pricing`, label: t('nav.pricing') },
22
+ { href: '/docs', label: t('nav.docs') },
23
+ ]
24
+
25
+ return (
26
+ <header className="sticky top-0 z-50 w-full border-b bg-background/80 backdrop-blur-sm">
27
+ <div className="mx-auto flex h-(--header-height, 4rem) max-w-7xl items-center justify-between px-4 md:px-6">
28
+ {/* Logo */}
29
+ <Link href={`/${locale}`} className="flex items-center gap-2">
30
+ <span className="text-lg font-semibold tracking-tight">AgentDock</span>
31
+ </Link>
32
+
33
+ {/* Desktop Nav */}
34
+ <nav className="hidden items-center gap-6 md:flex">
35
+ {navLinks.map((link) => (
36
+ <Link
37
+ key={link.href}
38
+ href={link.href}
39
+ className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
40
+ >
41
+ {link.label}
42
+ </Link>
43
+ ))}
44
+ </nav>
45
+
46
+ {/* Desktop Actions */}
47
+ <div className="hidden items-center gap-2 md:flex">
48
+ <ThemeToggle />
49
+ <Button variant="ghost" asChild size="sm" className="min-h-[44px]">
50
+ <Link href={`/${locale}/login`}>{t('nav.login')}</Link>
51
+ </Button>
52
+ <Button asChild size="sm" className="min-h-[44px]">
53
+ <Link href={`/${locale}/signup`}>{t('nav.getStarted')}</Link>
54
+ </Button>
55
+ </div>
56
+
57
+ {/* Mobile Menu */}
58
+ <div className="flex items-center gap-2 md:hidden">
59
+ <ThemeToggle />
60
+ <Sheet open={open} onOpenChange={setOpen}>
61
+ <SheetTrigger asChild>
62
+ <Button variant="ghost" size="icon" className="min-h-[44px] min-w-[44px]">
63
+ <Menu className="h-5 w-5" />
64
+ <span className="sr-only">Open menu</span>
65
+ </Button>
66
+ </SheetTrigger>
67
+ <SheetContent side="right" className="w-[280px]">
68
+ <nav className="mt-8 flex flex-col gap-4">
69
+ {navLinks.map((link) => (
70
+ <Link
71
+ key={link.href}
72
+ href={link.href}
73
+ onClick={() => setOpen(false)}
74
+ className="text-base font-medium text-muted-foreground transition-colors hover:text-foreground"
75
+ >
76
+ {link.label}
77
+ </Link>
78
+ ))}
79
+ <hr className="my-2" />
80
+ <Button asChild className="w-full min-h-[44px]">
81
+ <Link href={`/${locale}/signup`} onClick={() => setOpen(false)}>
82
+ {t('nav.getStarted')}
83
+ </Link>
84
+ </Button>
85
+ <Button variant="outline" asChild className="w-full min-h-[44px]">
86
+ <Link href={`/${locale}/login`} onClick={() => setOpen(false)}>
87
+ {t('nav.login')}
88
+ </Link>
89
+ </Button>
90
+ </nav>
91
+ </SheetContent>
92
+ </Sheet>
93
+ </div>
94
+ </div>
95
+ </header>
96
+ )
97
+ }
@@ -0,0 +1,45 @@
1
+ import Link from 'next/link'
2
+ import { useTranslations } from 'next-intl'
3
+ import { Button } from '@/components/ui/button'
4
+ import { Badge } from '@/components/ui/badge'
5
+
6
+ interface HeroProps {
7
+ locale: string
8
+ }
9
+
10
+ export function Hero({ locale }: HeroProps) {
11
+ const t = useTranslations('landing')
12
+
13
+ return (
14
+ <section className="relative overflow-hidden px-4 py-16 md:py-24 lg:py-32">
15
+ <div className="mx-auto max-w-4xl text-center">
16
+ <Badge variant="secondary" className="mb-4">
17
+ {t('hero.badge')}
18
+ </Badge>
19
+ <h1
20
+ className="mx-auto max-w-3xl font-bold tracking-tight"
21
+ style={{ fontSize: 'clamp(2rem, 5vw + 1rem, 4rem)', lineHeight: 1.1 }}
22
+ >
23
+ {t('hero.title')}
24
+ </h1>
25
+ <p className="mx-auto mt-6 max-w-2xl text-lg leading-relaxed text-muted-foreground md:text-xl">
26
+ {t('hero.subtitle')}
27
+ </p>
28
+ <div className="mt-10 flex flex-col items-center justify-center gap-4 sm:flex-row">
29
+ <Button asChild size="lg" className="min-h-[44px] min-w-[44px] px-8">
30
+ <Link href={`/${locale}/signup`}>{t('hero.ctaPrimary')}</Link>
31
+ </Button>
32
+ <Button asChild variant="outline" size="lg" className="min-h-[44px] min-w-[44px] px-8">
33
+ <Link href="/docs">{t('hero.ctaSecondary')}</Link>
34
+ </Button>
35
+ </div>
36
+ </div>
37
+
38
+ {/* Decorative geometric shapes - CSS only, no custom SVG */}
39
+ <div className="pointer-events-none absolute inset-0 -z-10 overflow-hidden opacity-30">
40
+ <div className="absolute -left-20 -top-20 h-64 w-64 rounded-full bg-gradient-to-br from-primary/10 to-transparent blur-3xl" />
41
+ <div className="absolute -bottom-20 -right-20 h-64 w-64 rounded-full bg-gradient-to-tl from-primary/10 to-transparent blur-3xl" />
42
+ </div>
43
+ </section>
44
+ )
45
+ }
@@ -0,0 +1,35 @@
1
+ import { useTranslations } from 'next-intl'
2
+
3
+ export function HowItWorks() {
4
+ const t = useTranslations('landing')
5
+
6
+ const steps = [
7
+ { key: 'step1', number: '01' },
8
+ { key: 'step2', number: '02' },
9
+ { key: 'step3', number: '03' },
10
+ ]
11
+
12
+ return (
13
+ <section className="px-4 py-16 md:py-24" style={{ padding: 'clamp(32px, 8vw, 80px) 0' }}>
14
+ <div className="mx-auto max-w-7xl px-4 md:px-6">
15
+ <div className="mb-12 text-center">
16
+ <h2 className="text-3xl font-bold tracking-tight md:text-4xl">{t('howItWorks.title')}</h2>
17
+ <p className="mt-4 text-muted-foreground">{t('howItWorks.subtitle')}</p>
18
+ </div>
19
+ <div className="grid gap-8 md:grid-cols-3">
20
+ {steps.map((step) => (
21
+ <div key={step.key} className="relative text-center">
22
+ <div className="mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-primary/10 text-2xl font-bold text-primary">
23
+ {step.number}
24
+ </div>
25
+ <h3 className="text-lg font-semibold">{t(`howItWorks.steps.${step.key}.title`)}</h3>
26
+ <p className="mt-2 text-sm leading-relaxed text-muted-foreground">
27
+ {t(`howItWorks.steps.${step.key}.description`)}
28
+ </p>
29
+ </div>
30
+ ))}
31
+ </div>
32
+ </div>
33
+ </section>
34
+ )
35
+ }
@@ -0,0 +1,23 @@
1
+ import { useTranslations } from 'next-intl'
2
+ import { Button } from '@/components/ui/button'
3
+
4
+ export function PricingTeaser() {
5
+ const t = useTranslations('landing')
6
+
7
+ return (
8
+ <section
9
+ id="pricing"
10
+ className="px-4 py-16 md:py-24"
11
+ style={{ padding: 'clamp(32px, 8vw, 80px) 0' }}
12
+ >
13
+ <div className="mx-auto max-w-3xl px-4 text-center md:px-6">
14
+ <h2 className="text-3xl font-bold tracking-tight md:text-4xl">{t('pricing.title')}</h2>
15
+ <p className="mt-4 text-muted-foreground">{t('pricing.description')}</p>
16
+ <Button asChild className="mt-8 min-h-[44px] min-w-[44px]">
17
+ <a href="mailto:contact@agentdock.dev">{t('pricing.cta')}</a>
18
+ </Button>
19
+ {/* TODO: Integrate Stripe, see add-stripe-payments change */}
20
+ </div>
21
+ </section>
22
+ )
23
+ }
@@ -17,7 +17,11 @@ interface ProfileFormProps {
17
17
  }
18
18
 
19
19
  export function ProfileForm({ defaultName, locale }: ProfileFormProps) {
20
- const { register, formState: { errors }, reset } = useForm<DisplayNameInput>({
20
+ const {
21
+ register,
22
+ formState: { errors },
23
+ reset,
24
+ } = useForm<DisplayNameInput>({
21
25
  resolver: zodResolver(displayNameSchema),
22
26
  defaultValues: { name: defaultName },
23
27
  })
@@ -48,9 +52,7 @@ export function ProfileForm({ defaultName, locale }: ProfileFormProps) {
48
52
  {...register('name')}
49
53
  />
50
54
  {errors.name && (
51
- <FieldDescription className="text-destructive">
52
- {errors.name.message}
53
- </FieldDescription>
55
+ <FieldDescription className="text-destructive">{errors.name.message}</FieldDescription>
54
56
  )}
55
57
  </Field>
56
58
  <Field>
@@ -0,0 +1,16 @@
1
+ 'use client'
2
+
3
+ import { ThemeProvider as NextThemesProvider } from 'next-themes'
4
+
5
+ export function ThemeProvider({ children }: { children: React.ReactNode }) {
6
+ return (
7
+ <NextThemesProvider
8
+ attribute="class"
9
+ defaultTheme="system"
10
+ enableSystem
11
+ disableTransitionOnChange
12
+ >
13
+ {children}
14
+ </NextThemesProvider>
15
+ )
16
+ }