@greatapps/greatauth-ui 0.3.13 → 0.3.14
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.d.ts +2 -0
- package/dist/index.js +68 -21
- package/dist/index.js.map +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +6 -1
- package/dist/ui.js.map +1 -1
- package/package.json +1 -1
- package/src/components/app-header.tsx +8 -1
- package/src/components/app-sidebar.tsx +29 -11
- package/src/components/ui/collapsible.tsx +7 -0
- package/src/components/ui/sidebar.tsx +1 -1
- package/src/theme.css +49 -24
- package/src/types/index.ts +2 -0
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import { Fragment, useMemo } from "react";
|
|
|
4
4
|
import { usePathname } from "next/navigation";
|
|
5
5
|
import Link from "next/link";
|
|
6
6
|
import type { AppShellConfig } from "../types";
|
|
7
|
-
import { SidebarTrigger } from "./ui/sidebar";
|
|
7
|
+
import { SidebarTrigger, useSidebar } from "./ui/sidebar";
|
|
8
8
|
import { Separator } from "./ui/separator";
|
|
9
9
|
import {
|
|
10
10
|
Breadcrumb,
|
|
@@ -23,6 +23,7 @@ interface AppHeaderProps {
|
|
|
23
23
|
|
|
24
24
|
export function AppHeader({ config }: AppHeaderProps) {
|
|
25
25
|
const pathname = usePathname();
|
|
26
|
+
const { state } = useSidebar();
|
|
26
27
|
const segments = pathname.split("/").filter(Boolean);
|
|
27
28
|
|
|
28
29
|
const breadcrumbs = useMemo(() => {
|
|
@@ -43,6 +44,12 @@ export function AppHeader({ config }: AppHeaderProps) {
|
|
|
43
44
|
return (
|
|
44
45
|
<header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
|
|
45
46
|
<SidebarTrigger className="-ml-1" />
|
|
47
|
+
{state === "collapsed" && config.appIcon && (
|
|
48
|
+
<>
|
|
49
|
+
<Separator orientation="vertical" className="!h-4" />
|
|
50
|
+
<div className="shrink-0 text-sidebar-foreground">{config.appIcon}</div>
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
46
53
|
<Separator orientation="vertical" className="mr-2 !h-4" />
|
|
47
54
|
|
|
48
55
|
<Breadcrumb className="flex-1">
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { usePathname, useRouter } from "next/navigation";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
-
import {
|
|
5
|
+
import { ChevronsUpDown, ChevronRight, LogOut } from "lucide-react";
|
|
6
6
|
import { useSession } from "../auth";
|
|
7
7
|
import type { AppShellConfig, MenuGroup, MenuItem } from "../types";
|
|
8
8
|
import { signOut } from "../auth";
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
SidebarMenu,
|
|
18
18
|
SidebarMenuButton,
|
|
19
19
|
SidebarMenuItem,
|
|
20
|
+
SidebarRail,
|
|
20
21
|
} from "./ui/sidebar";
|
|
21
22
|
import {
|
|
22
23
|
Collapsible,
|
|
@@ -49,15 +50,20 @@ function getUserInitials(name: string, email: string): string {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
function SimpleMenuItem({ item, pathname }: { item: MenuItem; pathname: string }) {
|
|
52
|
-
const isActive = pathname.startsWith(item.href);
|
|
53
|
+
const isActive = item.isActive ?? pathname.startsWith(item.href);
|
|
53
54
|
const Icon = item.icon;
|
|
54
55
|
|
|
55
56
|
return (
|
|
56
57
|
<SidebarMenuItem>
|
|
57
58
|
<SidebarMenuButton asChild isActive={isActive} tooltip={item.label}>
|
|
58
|
-
<Link href={item.href} onClick={item.onClick}>
|
|
59
|
+
<Link href={item.href} onClick={item.onClick} aria-current={isActive ? "page" : undefined}>
|
|
59
60
|
<Icon className="size-4" />
|
|
60
61
|
<span>{item.label}</span>
|
|
62
|
+
{item.badge != null && (
|
|
63
|
+
<span className="ml-auto flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/10 px-1.5 text-[10px] font-semibold text-primary tabular-nums">
|
|
64
|
+
{item.badge}
|
|
65
|
+
</span>
|
|
66
|
+
)}
|
|
61
67
|
</Link>
|
|
62
68
|
</SidebarMenuButton>
|
|
63
69
|
</SidebarMenuItem>
|
|
@@ -66,22 +72,33 @@ function SimpleMenuItem({ item, pathname }: { item: MenuItem; pathname: string }
|
|
|
66
72
|
|
|
67
73
|
function CollapsibleMenuItem({ item, pathname }: { item: MenuItem; pathname: string }) {
|
|
68
74
|
const Icon = item.icon;
|
|
69
|
-
const
|
|
75
|
+
const isParentActive = pathname.startsWith(item.href);
|
|
76
|
+
const isChildActive = item.children?.some((child) =>
|
|
77
|
+
child.isActive !== undefined ? child.isActive : pathname.startsWith(child.href)
|
|
78
|
+
) ?? false;
|
|
70
79
|
|
|
71
80
|
return (
|
|
72
|
-
<Collapsible defaultOpen={isChildActive} className="group/collapsible">
|
|
81
|
+
<Collapsible defaultOpen={isParentActive || isChildActive} className="group/collapsible">
|
|
73
82
|
<SidebarMenuItem>
|
|
74
|
-
<
|
|
75
|
-
<
|
|
83
|
+
<SidebarMenuButton asChild isActive={isParentActive} tooltip={item.label}>
|
|
84
|
+
<Link href={item.href} onClick={item.onClick}>
|
|
76
85
|
<Icon className="size-4" />
|
|
77
86
|
<span>{item.label}</span>
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
</Link>
|
|
88
|
+
</SidebarMenuButton>
|
|
89
|
+
<CollapsibleTrigger asChild>
|
|
90
|
+
<button
|
|
91
|
+
data-sidebar="menu-action"
|
|
92
|
+
className="absolute right-1 top-1.5 flex h-5 w-5 items-center justify-center rounded-md text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground outline-hidden focus-visible:ring-2 ring-sidebar-ring transition-colors group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 md:after:hidden"
|
|
93
|
+
aria-label="Expandir submenu"
|
|
94
|
+
>
|
|
95
|
+
<ChevronRight className="size-3.5 shrink-0 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
|
96
|
+
</button>
|
|
80
97
|
</CollapsibleTrigger>
|
|
81
98
|
<CollapsibleContent>
|
|
82
99
|
<SidebarMenu className="ml-4 border-l pl-2">
|
|
83
100
|
{item.children?.map((child) => (
|
|
84
|
-
<SimpleMenuItem key={child.href} item={child} pathname={pathname} />
|
|
101
|
+
<SimpleMenuItem key={child.href + child.label} item={child} pathname={pathname} />
|
|
85
102
|
))}
|
|
86
103
|
</SidebarMenu>
|
|
87
104
|
</CollapsibleContent>
|
|
@@ -156,7 +173,7 @@ export function AppSidebar({ config }: AppSidebarProps) {
|
|
|
156
173
|
<span className="truncate font-semibold">{userName}</span>
|
|
157
174
|
<span className="truncate text-xs text-muted-foreground">{userEmail}</span>
|
|
158
175
|
</div>
|
|
159
|
-
<
|
|
176
|
+
<ChevronsUpDown className="ml-auto size-4 group-data-[collapsible=icon]:hidden" />
|
|
160
177
|
</SidebarMenuButton>
|
|
161
178
|
</DropdownMenuTrigger>
|
|
162
179
|
<DropdownMenuContent
|
|
@@ -182,6 +199,7 @@ export function AppSidebar({ config }: AppSidebarProps) {
|
|
|
182
199
|
</SidebarMenuItem>
|
|
183
200
|
</SidebarMenu>
|
|
184
201
|
</SidebarFooter>
|
|
202
|
+
<SidebarRail />
|
|
185
203
|
</Sidebar>
|
|
186
204
|
);
|
|
187
205
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import { Collapsible as CollapsiblePrimitive } from "radix-ui"
|
|
5
5
|
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
|
|
6
8
|
function Collapsible({
|
|
7
9
|
...props
|
|
8
10
|
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
|
|
@@ -21,11 +23,16 @@ function CollapsibleTrigger({
|
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
function CollapsibleContent({
|
|
26
|
+
className,
|
|
24
27
|
...props
|
|
25
28
|
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
|
|
26
29
|
return (
|
|
27
30
|
<CollapsiblePrimitive.CollapsibleContent
|
|
28
31
|
data-slot="collapsible-content"
|
|
32
|
+
className={cn(
|
|
33
|
+
"overflow-hidden data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
29
36
|
{...props}
|
|
30
37
|
/>
|
|
31
38
|
)
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
const SIDEBAR_STORAGE_KEY = "sidebar_state"
|
|
28
28
|
const SIDEBAR_WIDTH = "16rem"
|
|
29
29
|
const SIDEBAR_WIDTH_MOBILE = "18rem"
|
|
30
|
-
const SIDEBAR_WIDTH_ICON = "
|
|
30
|
+
const SIDEBAR_WIDTH_ICON = "3.5rem"
|
|
31
31
|
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
|
32
32
|
|
|
33
33
|
type SidebarContextProps = {
|
package/src/theme.css
CHANGED
|
@@ -51,6 +51,8 @@
|
|
|
51
51
|
--radius-2xl: calc(var(--radius) + 8px);
|
|
52
52
|
--radius-3xl: calc(var(--radius) + 12px);
|
|
53
53
|
--radius-4xl: calc(var(--radius) + 16px);
|
|
54
|
+
--animate-collapsible-down: collapsible-down 200ms ease-out;
|
|
55
|
+
--animate-collapsible-up: collapsible-up 150ms ease-out;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
:root {
|
|
@@ -62,35 +64,35 @@
|
|
|
62
64
|
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
63
65
|
--primary: oklch(0.21 0.006 285.885);
|
|
64
66
|
--primary-foreground: oklch(0.985 0 0);
|
|
65
|
-
--secondary: oklch(0.
|
|
67
|
+
--secondary: oklch(0.955 0.004 285);
|
|
66
68
|
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
67
|
-
--muted: oklch(0.
|
|
68
|
-
--muted-foreground: oklch(0.
|
|
69
|
-
--accent: oklch(0.
|
|
69
|
+
--muted: oklch(0.965 0.002 286);
|
|
70
|
+
--muted-foreground: oklch(0.45 0.02 285);
|
|
71
|
+
--accent: oklch(0.945 0.012 270);
|
|
70
72
|
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
71
73
|
--destructive: oklch(0.577 0.245 27.325);
|
|
72
74
|
--success: oklch(0.527 0.154 150.069);
|
|
73
|
-
--border: oklch(0.
|
|
75
|
+
--border: oklch(0.91 0.005 286);
|
|
74
76
|
--input: oklch(0.92 0.004 286.32);
|
|
75
|
-
--ring: oklch(0.
|
|
77
|
+
--ring: oklch(0.55 0.06 275);
|
|
76
78
|
--chart-1: oklch(0.588 0.158 241.966);
|
|
77
79
|
--chart-2: oklch(0.637 0.179 163.223);
|
|
78
80
|
--chart-3: oklch(0.553 0.195 255.065);
|
|
79
81
|
--chart-4: oklch(0.705 0.213 47.604);
|
|
80
82
|
--chart-5: oklch(0.637 0.237 25.331);
|
|
81
83
|
--radius: 0.625rem;
|
|
82
|
-
--sidebar: oklch(0.
|
|
84
|
+
--sidebar: oklch(0.975 0.003 285);
|
|
83
85
|
--sidebar-foreground: oklch(0.141 0.005 285.823);
|
|
84
86
|
--sidebar-primary: oklch(0.21 0.006 285.885);
|
|
85
87
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
86
|
-
--sidebar-accent: oklch(0.
|
|
87
|
-
--sidebar-accent-foreground: oklch(0.
|
|
88
|
-
--sidebar-border: oklch(0.
|
|
89
|
-
--sidebar-ring: oklch(0.
|
|
88
|
+
--sidebar-accent: oklch(0.935 0.018 270);
|
|
89
|
+
--sidebar-accent-foreground: oklch(0.15 0.010 270);
|
|
90
|
+
--sidebar-border: oklch(0.90 0.008 280);
|
|
91
|
+
--sidebar-ring: oklch(0.60 0.05 275);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
.dark {
|
|
93
|
-
--background: oklch(0.
|
|
95
|
+
--background: oklch(0.145 0.006 285);
|
|
94
96
|
--foreground: oklch(0.985 0 0);
|
|
95
97
|
--card: oklch(0.21 0.006 285.885);
|
|
96
98
|
--card-foreground: oklch(0.985 0 0);
|
|
@@ -98,30 +100,30 @@
|
|
|
98
100
|
--popover-foreground: oklch(0.985 0 0);
|
|
99
101
|
--primary: oklch(0.92 0.004 286.32);
|
|
100
102
|
--primary-foreground: oklch(0.21 0.006 285.885);
|
|
101
|
-
--secondary: oklch(0.
|
|
103
|
+
--secondary: oklch(0.25 0.008 285);
|
|
102
104
|
--secondary-foreground: oklch(0.985 0 0);
|
|
103
|
-
--muted: oklch(0.
|
|
104
|
-
--muted-foreground: oklch(0.
|
|
105
|
-
--accent: oklch(0.
|
|
105
|
+
--muted: oklch(0.23 0.006 286);
|
|
106
|
+
--muted-foreground: oklch(0.65 0.015 286);
|
|
107
|
+
--accent: oklch(0.28 0.018 270);
|
|
106
108
|
--accent-foreground: oklch(0.985 0 0);
|
|
107
109
|
--destructive: oklch(0.704 0.191 22.216);
|
|
108
110
|
--success: oklch(0.696 0.17 162.48);
|
|
109
|
-
--border: oklch(1 0 0 /
|
|
111
|
+
--border: oklch(1 0 0 / 12%);
|
|
110
112
|
--input: oklch(1 0 0 / 15%);
|
|
111
|
-
--ring: oklch(0.
|
|
113
|
+
--ring: oklch(0.50 0.04 275);
|
|
112
114
|
--chart-1: oklch(0.688 0.158 241.966);
|
|
113
115
|
--chart-2: oklch(0.737 0.179 163.223);
|
|
114
116
|
--chart-3: oklch(0.653 0.195 255.065);
|
|
115
117
|
--chart-4: oklch(0.765 0.183 47.604);
|
|
116
118
|
--chart-5: oklch(0.717 0.217 25.331);
|
|
117
|
-
--sidebar: oklch(0.
|
|
119
|
+
--sidebar: oklch(0.185 0.008 280);
|
|
118
120
|
--sidebar-foreground: oklch(0.985 0 0);
|
|
119
|
-
--sidebar-primary: oklch(0.
|
|
121
|
+
--sidebar-primary: oklch(0.70 0.04 275);
|
|
120
122
|
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
121
|
-
--sidebar-accent: oklch(0.
|
|
122
|
-
--sidebar-accent-foreground: oklch(0.
|
|
123
|
-
--sidebar-border: oklch(1 0 0 /
|
|
124
|
-
--sidebar-ring: oklch(0.
|
|
123
|
+
--sidebar-accent: oklch(0.30 0.025 270);
|
|
124
|
+
--sidebar-accent-foreground: oklch(0.95 0.005 270);
|
|
125
|
+
--sidebar-border: oklch(1 0 0 / 14%);
|
|
126
|
+
--sidebar-ring: oklch(0.55 0.04 275);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
@layer base {
|
|
@@ -136,6 +138,29 @@
|
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
/* Collapsible animation */
|
|
142
|
+
@keyframes collapsible-down {
|
|
143
|
+
from {
|
|
144
|
+
height: 0;
|
|
145
|
+
opacity: 0;
|
|
146
|
+
}
|
|
147
|
+
to {
|
|
148
|
+
height: var(--radix-collapsible-content-height);
|
|
149
|
+
opacity: 1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@keyframes collapsible-up {
|
|
154
|
+
from {
|
|
155
|
+
height: var(--radix-collapsible-content-height);
|
|
156
|
+
opacity: 1;
|
|
157
|
+
}
|
|
158
|
+
to {
|
|
159
|
+
height: 0;
|
|
160
|
+
opacity: 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
139
164
|
/* View Transition — dark/light mode circle reveal */
|
|
140
165
|
::view-transition-old(root),
|
|
141
166
|
::view-transition-new(root) {
|