doo-boilerplate 0.1.9 → 0.1.11
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/package.json +1 -1
- package/templates/template-nextjs/src/app/(dashboard)/dashboard/page.tsx +26 -0
- package/templates/template-nextjs/src/app/(dashboard)/page.tsx +3 -25
- package/templates/template-nextjs/src/components/layout/header.tsx +45 -0
- package/templates/template-vite/src/components/layout/header.tsx +36 -2
- /package/templates/template-nextjs/src/app/(dashboard)/{profile → dashboard/profile}/page.tsx +0 -0
- /package/templates/template-nextjs/src/app/(dashboard)/{settings → dashboard/settings}/page.tsx +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PageLayout } from '@/components/layout/page-layout'
|
|
2
|
+
|
|
3
|
+
function StatCard({ label, value }: { label: string; value: string }) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="rounded-lg border bg-card p-6 text-card-foreground shadow-sm">
|
|
6
|
+
<p className="text-sm font-medium text-muted-foreground">{label}</p>
|
|
7
|
+
<p className="mt-2 text-3xl font-bold">{value}</p>
|
|
8
|
+
</div>
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function DashboardPage() {
|
|
13
|
+
return (
|
|
14
|
+
<PageLayout
|
|
15
|
+
title="Dashboard"
|
|
16
|
+
description="Welcome to your portal. Here's an overview of your account."
|
|
17
|
+
>
|
|
18
|
+
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
19
|
+
<StatCard label="Total Users" value="1,024" />
|
|
20
|
+
<StatCard label="Active Sessions" value="42" />
|
|
21
|
+
<StatCard label="Requests Today" value="8,390" />
|
|
22
|
+
<StatCard label="Uptime" value="99.9%" />
|
|
23
|
+
</div>
|
|
24
|
+
</PageLayout>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -1,27 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { redirect } from 'next/navigation'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return (
|
|
6
|
-
<div className="rounded-lg border bg-card p-6 text-card-foreground shadow-sm">
|
|
7
|
-
<p className="text-sm font-medium text-muted-foreground">{label}</p>
|
|
8
|
-
<p className="mt-2 text-3xl font-bold">{value}</p>
|
|
9
|
-
</div>
|
|
10
|
-
)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default function DashboardPage() {
|
|
14
|
-
return (
|
|
15
|
-
<PageLayout
|
|
16
|
-
title="Dashboard"
|
|
17
|
-
description="Welcome to your portal. Here's an overview of your account."
|
|
18
|
-
>
|
|
19
|
-
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
20
|
-
<StatCard label="Total Users" value="1,024" />
|
|
21
|
-
<StatCard label="Active Sessions" value="42" />
|
|
22
|
-
<StatCard label="Requests Today" value="8,390" />
|
|
23
|
-
<StatCard label="Uptime" value="99.9%" />
|
|
24
|
-
</div>
|
|
25
|
-
</PageLayout>
|
|
26
|
-
)
|
|
3
|
+
export default function DashboardRootPage() {
|
|
4
|
+
redirect('/dashboard')
|
|
27
5
|
}
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { LogOut, Menu, User } from 'lucide-react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
+
import { useLocale } from 'next-intl'
|
|
6
|
+
import { useRouter } from 'next/navigation'
|
|
5
7
|
|
|
6
8
|
import { useSignOut } from '@/features/auth/hooks/use-auth'
|
|
7
9
|
import { useAuthStore } from '@/stores/auth-store'
|
|
10
|
+
import { ThemeToggle } from '@/components/common/theme-toggle'
|
|
8
11
|
|
|
9
12
|
import { Avatar, AvatarFallback } from '../ui/avatar'
|
|
10
13
|
import { Button } from '../ui/button'
|
|
@@ -18,6 +21,42 @@ import {
|
|
|
18
21
|
} from '../ui/dropdown-menu'
|
|
19
22
|
import { useSidebarStore } from './sidebar'
|
|
20
23
|
|
|
24
|
+
const LANGUAGES = [
|
|
25
|
+
{ code: 'en', label: 'EN' },
|
|
26
|
+
{ code: 'vi', label: 'VI' },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
function LangSwitcher() {
|
|
30
|
+
const locale = useLocale()
|
|
31
|
+
const router = useRouter()
|
|
32
|
+
|
|
33
|
+
function switchLocale(code: string) {
|
|
34
|
+
document.cookie = `NEXT_LOCALE=${code}; path=/; max-age=${365 * 24 * 60 * 60}`
|
|
35
|
+
router.refresh()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<DropdownMenu>
|
|
40
|
+
<DropdownMenuTrigger asChild>
|
|
41
|
+
<Button variant="ghost" size="sm" className="w-10 px-0 font-medium">
|
|
42
|
+
{locale.toUpperCase().slice(0, 2)}
|
|
43
|
+
</Button>
|
|
44
|
+
</DropdownMenuTrigger>
|
|
45
|
+
<DropdownMenuContent align="end">
|
|
46
|
+
{LANGUAGES.map(({ code, label }) => (
|
|
47
|
+
<DropdownMenuItem
|
|
48
|
+
key={code}
|
|
49
|
+
onClick={() => switchLocale(code)}
|
|
50
|
+
className={locale === code ? 'font-semibold' : ''}
|
|
51
|
+
>
|
|
52
|
+
{label}
|
|
53
|
+
</DropdownMenuItem>
|
|
54
|
+
))}
|
|
55
|
+
</DropdownMenuContent>
|
|
56
|
+
</DropdownMenu>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
21
60
|
interface HeaderProps {
|
|
22
61
|
title?: string
|
|
23
62
|
}
|
|
@@ -52,6 +91,11 @@ export function Header({ title = 'Dashboard' }: HeaderProps) {
|
|
|
52
91
|
<h2 className="text-lg font-semibold">{title}</h2>
|
|
53
92
|
</div>
|
|
54
93
|
|
|
94
|
+
{/* Controls */}
|
|
95
|
+
<div className="flex items-center gap-1">
|
|
96
|
+
<LangSwitcher />
|
|
97
|
+
<ThemeToggle />
|
|
98
|
+
|
|
55
99
|
{/* User dropdown */}
|
|
56
100
|
<DropdownMenu>
|
|
57
101
|
<DropdownMenuTrigger asChild>
|
|
@@ -86,6 +130,7 @@ export function Header({ title = 'Dashboard' }: HeaderProps) {
|
|
|
86
130
|
</DropdownMenuItem>
|
|
87
131
|
</DropdownMenuContent>
|
|
88
132
|
</DropdownMenu>
|
|
133
|
+
</div>
|
|
89
134
|
</header>
|
|
90
135
|
)
|
|
91
136
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { LogOut, User } from 'lucide-react'
|
|
2
|
+
import { useTranslation } from 'react-i18next'
|
|
2
3
|
|
|
3
4
|
import { useSignOut } from '@/features/auth/hooks/use-auth'
|
|
4
5
|
import { useAuthStore } from '@/stores/auth-store'
|
|
6
|
+
import { ThemeToggle } from '@/components/common/theme-toggle'
|
|
5
7
|
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
|
|
8
|
+
import { Button } from '@/components/ui/button'
|
|
6
9
|
import {
|
|
7
10
|
DropdownMenu,
|
|
8
11
|
DropdownMenuContent,
|
|
@@ -11,7 +14,35 @@ import {
|
|
|
11
14
|
DropdownMenuSeparator,
|
|
12
15
|
DropdownMenuTrigger,
|
|
13
16
|
} from '@/components/ui/dropdown-menu'
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
const LANGUAGES = [
|
|
19
|
+
{ code: 'en', label: 'EN' },
|
|
20
|
+
{ code: 'vi', label: 'VI' },
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
function LangSwitcher() {
|
|
24
|
+
const { i18n } = useTranslation()
|
|
25
|
+
return (
|
|
26
|
+
<DropdownMenu>
|
|
27
|
+
<DropdownMenuTrigger asChild>
|
|
28
|
+
<Button variant='ghost' size='sm' className='w-10 px-0 font-medium'>
|
|
29
|
+
{i18n.language.toUpperCase().slice(0, 2)}
|
|
30
|
+
</Button>
|
|
31
|
+
</DropdownMenuTrigger>
|
|
32
|
+
<DropdownMenuContent align='end'>
|
|
33
|
+
{LANGUAGES.map(({ code, label }) => (
|
|
34
|
+
<DropdownMenuItem
|
|
35
|
+
key={code}
|
|
36
|
+
onClick={() => i18n.changeLanguage(code)}
|
|
37
|
+
className={i18n.language === code ? 'font-semibold' : ''}
|
|
38
|
+
>
|
|
39
|
+
{label}
|
|
40
|
+
</DropdownMenuItem>
|
|
41
|
+
))}
|
|
42
|
+
</DropdownMenuContent>
|
|
43
|
+
</DropdownMenu>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
15
46
|
|
|
16
47
|
export function Header() {
|
|
17
48
|
const { user } = useAuthStore()
|
|
@@ -25,9 +56,12 @@ export function Header() {
|
|
|
25
56
|
.slice(0, 2)
|
|
26
57
|
|
|
27
58
|
return (
|
|
28
|
-
<header className='flex h-14 items-center border-b bg-background px-4 gap-
|
|
59
|
+
<header className='flex h-14 items-center border-b bg-background px-4 gap-2'>
|
|
29
60
|
<div className='flex-1' />
|
|
30
61
|
|
|
62
|
+
<LangSwitcher />
|
|
63
|
+
<ThemeToggle />
|
|
64
|
+
|
|
31
65
|
<DropdownMenu>
|
|
32
66
|
<DropdownMenuTrigger asChild>
|
|
33
67
|
<Button variant='ghost' size='icon' className='rounded-full' aria-label='User menu'>
|
/package/templates/template-nextjs/src/app/(dashboard)/{profile → dashboard/profile}/page.tsx
RENAMED
|
File without changes
|
/package/templates/template-nextjs/src/app/(dashboard)/{settings → dashboard/settings}/page.tsx
RENAMED
|
File without changes
|