@arch-cadre/panel 1.0.6 → 1.0.9
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/actions/activity-log/index.cjs +1 -1
- package/dist/actions/activity-log/index.mjs +1 -1
- package/dist/actions/index.cjs +2 -2
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.mjs +2 -2
- package/dist/actions/profile.d.ts +1 -1
- package/dist/index.cjs +7 -7
- package/dist/index.mjs +7 -7
- package/dist/routes.cjs +10 -10
- package/dist/routes.mjs +10 -10
- package/dist/schema.cjs +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.mjs +1 -1
- package/dist/ui/activity-log/components/ActivityStatsWidget.cjs +1 -1
- package/dist/ui/activity-log/components/ActivityStatsWidget.mjs +1 -1
- package/dist/ui/activity-log/components/RecentLogsWidget.cjs +1 -1
- package/dist/ui/activity-log/components/RecentLogsWidget.mjs +1 -1
- package/dist/ui/activity-log/pages/log-list.cjs +2 -2
- package/dist/ui/activity-log/pages/log-list.mjs +1 -1
- package/dist/ui/components/app-content.cjs +1 -1
- package/dist/ui/components/app-content.mjs +1 -1
- package/dist/ui/components/app-sidebar.cjs +3 -3
- package/dist/ui/components/app-sidebar.mjs +2 -2
- package/dist/ui/components/app-user.cjs +5 -5
- package/dist/ui/components/app-user.mjs +4 -4
- package/dist/ui/components/breadcrumb-slot.cjs +2 -2
- package/dist/ui/components/breadcrumb-slot.mjs +1 -1
- package/dist/ui/components/manager/module-card.cjs +3 -3
- package/dist/ui/components/manager/module-card.mjs +2 -2
- package/dist/ui/components/manager/module-list.cjs +3 -3
- package/dist/ui/components/manager/module-list.mjs +2 -2
- package/dist/ui/components/manager/module-upload.cjs +3 -3
- package/dist/ui/components/manager/module-upload.mjs +2 -2
- package/dist/ui/components/profile/components.cjs +7 -7
- package/dist/ui/components/profile/components.d.ts +1 -1
- package/dist/ui/components/profile/components.mjs +3 -3
- package/dist/ui/components/profile/link.cjs +2 -2
- package/dist/ui/components/profile/link.mjs +1 -1
- package/dist/ui/components/profile/page.cjs +2 -6
- package/dist/ui/components/profile/page.mjs +3 -10
- package/dist/ui/components/sidebar-slot.cjs +1 -1
- package/dist/ui/components/sidebar-slot.mjs +1 -1
- package/dist/ui/dashboard/page.cjs +3 -3
- package/dist/ui/dashboard/page.mjs +1 -1
- package/dist/ui/dashboard/widgets/WelcomeBackUserWidget.cjs +1 -0
- package/dist/ui/dashboard/widgets/WelcomeBackUserWidget.mjs +5 -4
- package/dist/ui/error.cjs +2 -2
- package/dist/ui/error.mjs +1 -1
- package/dist/ui/layout.cjs +3 -3
- package/dist/ui/layout.mjs +3 -3
- package/dist/ui/modules/docs/page.cjs +1 -1
- package/dist/ui/modules/docs/page.mjs +1 -1
- package/dist/ui/modules/page.cjs +3 -3
- package/dist/ui/modules/page.mjs +3 -3
- package/dist/ui/rbac/pages/rbac-admin.cjs +16 -16
- package/dist/ui/rbac/pages/rbac-admin.mjs +2 -2
- package/dist/ui/router.cjs +1 -1
- package/dist/ui/router.mjs +1 -1
- package/dist/ui/session-manager/components/sessions-list.cjs +7 -7
- package/dist/ui/session-manager/components/sessions-list.mjs +3 -3
- package/dist/ui/session-manager/pages/sessions-page.cjs +4 -4
- package/dist/ui/session-manager/pages/sessions-page.mjs +3 -3
- package/dist/ui/settings-page.cjs +3 -3
- package/dist/ui/settings-page.mjs +2 -2
- package/package.json +7 -6
- package/src/actions/actions.ts +17 -0
- package/src/actions/activity-log/index.ts +17 -0
- package/src/actions/index.ts +2 -0
- package/src/actions/manager.ts +168 -0
- package/src/actions/profile.ts +173 -0
- package/src/actions/rbac/index.ts +131 -0
- package/src/actions/session-manager/index.ts +87 -0
- package/src/actions/settings.ts +34 -0
- package/src/index.ts +135 -0
- package/src/intl.d.ts +9 -0
- package/src/navigation.ts +57 -0
- package/src/routes.ts +107 -0
- package/src/schema/activity-log.ts +16 -0
- package/src/schema.ts +1 -0
- package/src/types.ts +18 -0
- package/src/ui/activity-log/components/ActivityStatsWidget.tsx +37 -0
- package/src/ui/activity-log/components/RecentLogsWidget.tsx +74 -0
- package/src/ui/activity-log/pages/log-list.tsx +91 -0
- package/src/ui/components/app-content.tsx +51 -0
- package/src/ui/components/app-header.tsx +65 -0
- package/src/ui/components/app-sidebar.tsx +249 -0
- package/src/ui/components/app-user.tsx +126 -0
- package/src/ui/components/breadcrumb-slot.tsx +52 -0
- package/src/ui/components/manager/module-card.tsx +327 -0
- package/src/ui/components/manager/module-list.tsx +59 -0
- package/src/ui/components/manager/module-upload.tsx +84 -0
- package/src/ui/components/profile/components.tsx +311 -0
- package/src/ui/components/profile/link.tsx +36 -0
- package/src/ui/components/profile/page.tsx +45 -0
- package/src/ui/components/sidebar-slot.tsx +47 -0
- package/src/ui/dashboard/page.tsx +17 -0
- package/src/ui/dashboard/widgets/WelcomeBackUserWidget.tsx +47 -0
- package/src/ui/error.tsx +82 -0
- package/src/ui/layout.tsx +54 -0
- package/src/ui/modules/docs/page.tsx +105 -0
- package/src/ui/modules/page.tsx +30 -0
- package/src/ui/page.tsx +15 -0
- package/src/ui/rbac/pages/rbac-admin.tsx +551 -0
- package/src/ui/router.tsx +69 -0
- package/src/ui/session-manager/components/sessions-list.tsx +303 -0
- package/src/ui/session-manager/pages/sessions-page.tsx +22 -0
- package/src/ui/settings/page.tsx +73 -0
- package/src/ui/settings-page.tsx +97 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
4
|
+
import { Logo } from "@arch-cadre/ui/brand/logo";
|
|
5
|
+
import {
|
|
6
|
+
Collapsible,
|
|
7
|
+
CollapsibleContent,
|
|
8
|
+
CollapsibleTrigger,
|
|
9
|
+
} from "@arch-cadre/ui/components/collapsible";
|
|
10
|
+
import { ScrollArea } from "@arch-cadre/ui/components/scroll-area";
|
|
11
|
+
import {
|
|
12
|
+
Sidebar,
|
|
13
|
+
SidebarContent,
|
|
14
|
+
SidebarFooter,
|
|
15
|
+
SidebarGroup,
|
|
16
|
+
SidebarGroupLabel,
|
|
17
|
+
SidebarHeader,
|
|
18
|
+
SidebarMenu,
|
|
19
|
+
SidebarMenuButton,
|
|
20
|
+
SidebarMenuItem,
|
|
21
|
+
SidebarMenuSub,
|
|
22
|
+
SidebarMenuSubButton,
|
|
23
|
+
SidebarMenuSubItem,
|
|
24
|
+
useSidebar,
|
|
25
|
+
} from "@arch-cadre/ui/components/sidebar";
|
|
26
|
+
import { cn } from "@arch-cadre/ui/lib/utils";
|
|
27
|
+
import { Icon } from "@iconify/react";
|
|
28
|
+
import { ChevronRight } from "lucide-react";
|
|
29
|
+
import Link from "next/link";
|
|
30
|
+
import { usePathname } from "next/navigation";
|
|
31
|
+
import * as React from "react";
|
|
32
|
+
import { useEffect, useState } from "react";
|
|
33
|
+
import { AppUser } from "./app-user.js";
|
|
34
|
+
|
|
35
|
+
export type SidebarItem = {
|
|
36
|
+
id?: string;
|
|
37
|
+
title: string;
|
|
38
|
+
url: string;
|
|
39
|
+
icon?: string;
|
|
40
|
+
items?: SidebarItem[];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type SidebarGroupType = {
|
|
44
|
+
title: string;
|
|
45
|
+
items: SidebarItem[];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export function AppSidebar({
|
|
49
|
+
isMain,
|
|
50
|
+
data,
|
|
51
|
+
...props
|
|
52
|
+
}: React.ComponentProps<typeof Sidebar> & {
|
|
53
|
+
isMain: boolean;
|
|
54
|
+
data: SidebarGroupType[];
|
|
55
|
+
}) {
|
|
56
|
+
const { open, setOpenMobile, isMobile } = useSidebar();
|
|
57
|
+
const { t } = useTranslation();
|
|
58
|
+
|
|
59
|
+
const pathname = usePathname();
|
|
60
|
+
// state to track if scrolled
|
|
61
|
+
const [scrolled, setScrolledState] = useState(false);
|
|
62
|
+
|
|
63
|
+
// for exact path matching
|
|
64
|
+
const matchPath = (path: string) => {
|
|
65
|
+
return path === pathname;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// for parent paths
|
|
69
|
+
const matchPaths = (path: string) => {
|
|
70
|
+
return path === pathname || (path.length > 1 && pathname.startsWith(path));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: <useExhaustiveDependencies>
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
// close sidebar if mobile and route changed
|
|
76
|
+
if (isMobile && open) {
|
|
77
|
+
setOpenMobile(false);
|
|
78
|
+
}
|
|
79
|
+
}, [pathname]);
|
|
80
|
+
|
|
81
|
+
// handle scroll to add shadow to header/footer
|
|
82
|
+
const setScrolled = (e: React.UIEvent<HTMLDivElement>) => {
|
|
83
|
+
const scrollTop = e.currentTarget.scrollTop;
|
|
84
|
+
|
|
85
|
+
if (scrollTop > 20) {
|
|
86
|
+
setScrolledState(true);
|
|
87
|
+
} else {
|
|
88
|
+
setScrolledState(false);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Sidebar className="lg:border-r-0!" collapsible="offcanvas" {...props}>
|
|
94
|
+
<SidebarHeader className="hidden md:flex h-[var(--header-height)] py-0">
|
|
95
|
+
<div className="flex shrink-0 items-center px-4 h-[var(--header-height)] w-[var(--sidebar-width)] ">
|
|
96
|
+
<Link href="/kryo" className="items-center flex">
|
|
97
|
+
<Logo className="h-auto w-[134px]" aria-hidden={true} />
|
|
98
|
+
</Link>
|
|
99
|
+
</div>
|
|
100
|
+
</SidebarHeader>
|
|
101
|
+
|
|
102
|
+
<SidebarHeader
|
|
103
|
+
className={cn(
|
|
104
|
+
"px-2",
|
|
105
|
+
scrolled
|
|
106
|
+
? "border-b border-border/50 shadow-[0_20px_20px_0px_rgb(246_246_246/90%)]"
|
|
107
|
+
: "",
|
|
108
|
+
)}
|
|
109
|
+
>
|
|
110
|
+
{isMain ? null : (
|
|
111
|
+
<SidebarMenuItem>
|
|
112
|
+
<SidebarMenuButton asChild>
|
|
113
|
+
<Link href="/kryo">
|
|
114
|
+
<span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
|
|
115
|
+
<Icon className="size-4" icon="solar:arrow-left-broken" />
|
|
116
|
+
</span>
|
|
117
|
+
<span>{t("Back to Dashboard")}</span>
|
|
118
|
+
</Link>
|
|
119
|
+
</SidebarMenuButton>
|
|
120
|
+
</SidebarMenuItem>
|
|
121
|
+
)}
|
|
122
|
+
</SidebarHeader>
|
|
123
|
+
|
|
124
|
+
<SidebarContent>
|
|
125
|
+
<ScrollArea
|
|
126
|
+
orientation="vertical"
|
|
127
|
+
className="h-full"
|
|
128
|
+
onScroll={(e) => setScrolled(e)}
|
|
129
|
+
>
|
|
130
|
+
{/* {isMain && (
|
|
131
|
+
<SidebarGroup className="group-data-[collapsible=icon]:hidden py-0">
|
|
132
|
+
<SidebarGroupLabel>General</SidebarGroupLabel>
|
|
133
|
+
<SidebarMenu>
|
|
134
|
+
<SidebarMenuItem>
|
|
135
|
+
<SidebarMenuButton
|
|
136
|
+
asChild
|
|
137
|
+
isActive={matchPaths("/dashboard")}
|
|
138
|
+
tooltip={t("sidebar.dashboard")}
|
|
139
|
+
>
|
|
140
|
+
<Link href="/dashboard">
|
|
141
|
+
<span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
|
|
142
|
+
<Icon className="size-4" icon="solar:home-2-broken" />
|
|
143
|
+
</span>
|
|
144
|
+
<span>{t("sidebar.dashboard")}</span>
|
|
145
|
+
</Link>
|
|
146
|
+
</SidebarMenuButton>
|
|
147
|
+
</SidebarMenuItem>
|
|
148
|
+
</SidebarMenu>
|
|
149
|
+
</SidebarGroup>
|
|
150
|
+
)} */}
|
|
151
|
+
|
|
152
|
+
{data.map((group) => (
|
|
153
|
+
<SidebarGroup
|
|
154
|
+
key={group.title}
|
|
155
|
+
className="group-data-[collapsible=icon]:hidden py-0"
|
|
156
|
+
>
|
|
157
|
+
<SidebarGroupLabel>{t(group.title as any)}</SidebarGroupLabel>
|
|
158
|
+
|
|
159
|
+
{group.items.map((item) => (
|
|
160
|
+
<SidebarMenu key={item.url}>
|
|
161
|
+
{item.items && item.items.length > 0 ? (
|
|
162
|
+
<Collapsible
|
|
163
|
+
key={item.url}
|
|
164
|
+
asChild
|
|
165
|
+
defaultOpen={matchPaths(item.url)}
|
|
166
|
+
className="group/collapsible"
|
|
167
|
+
>
|
|
168
|
+
<SidebarMenuItem>
|
|
169
|
+
<CollapsibleTrigger asChild>
|
|
170
|
+
<SidebarMenuButton
|
|
171
|
+
className="squircle"
|
|
172
|
+
isActive={matchPaths(item.url)}
|
|
173
|
+
tooltip={t(item.title as any)}
|
|
174
|
+
>
|
|
175
|
+
<span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
|
|
176
|
+
{item.icon && (
|
|
177
|
+
<Icon
|
|
178
|
+
className="size-4"
|
|
179
|
+
icon={item.icon as string}
|
|
180
|
+
/>
|
|
181
|
+
)}
|
|
182
|
+
</span>
|
|
183
|
+
|
|
184
|
+
<span>{t(item.title as any)}</span>
|
|
185
|
+
|
|
186
|
+
<ChevronRight className="ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
|
187
|
+
</SidebarMenuButton>
|
|
188
|
+
</CollapsibleTrigger>
|
|
189
|
+
|
|
190
|
+
<CollapsibleContent>
|
|
191
|
+
<SidebarMenuSub>
|
|
192
|
+
{item.items?.map((subItem) => (
|
|
193
|
+
<SidebarMenuSubItem key={subItem.url}>
|
|
194
|
+
<SidebarMenuSubButton
|
|
195
|
+
isActive={matchPath(subItem.url)}
|
|
196
|
+
asChild
|
|
197
|
+
>
|
|
198
|
+
<Link href={subItem.url}>
|
|
199
|
+
<span>{t(subItem.title as any)}</span>
|
|
200
|
+
</Link>
|
|
201
|
+
</SidebarMenuSubButton>
|
|
202
|
+
</SidebarMenuSubItem>
|
|
203
|
+
))}
|
|
204
|
+
</SidebarMenuSub>
|
|
205
|
+
</CollapsibleContent>
|
|
206
|
+
</SidebarMenuItem>
|
|
207
|
+
</Collapsible>
|
|
208
|
+
) : (
|
|
209
|
+
<SidebarMenuItem key={item.url}>
|
|
210
|
+
<SidebarMenuButton
|
|
211
|
+
className="squircle"
|
|
212
|
+
asChild
|
|
213
|
+
isActive={matchPath(item.url)}
|
|
214
|
+
>
|
|
215
|
+
<Link href={item.url}>
|
|
216
|
+
<span className="size-8 p-1 flex items-center justify-center rounded-lg bg-sidebar-accent backdrop-blur text-sidebar-accent-foreground">
|
|
217
|
+
{item.icon && (
|
|
218
|
+
<Icon
|
|
219
|
+
className="size-4"
|
|
220
|
+
icon={item.icon as string}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</span>
|
|
224
|
+
|
|
225
|
+
<span>{t(item.title as any)}</span>
|
|
226
|
+
</Link>
|
|
227
|
+
</SidebarMenuButton>
|
|
228
|
+
</SidebarMenuItem>
|
|
229
|
+
)}
|
|
230
|
+
</SidebarMenu>
|
|
231
|
+
))}
|
|
232
|
+
</SidebarGroup>
|
|
233
|
+
))}
|
|
234
|
+
</ScrollArea>
|
|
235
|
+
</SidebarContent>
|
|
236
|
+
|
|
237
|
+
<SidebarFooter
|
|
238
|
+
className={cn(
|
|
239
|
+
"px-2",
|
|
240
|
+
scrolled
|
|
241
|
+
? "border-t border-border/50 shadow-[0_-20px_20px_0px_rgb(246_246_246/90%)]"
|
|
242
|
+
: "",
|
|
243
|
+
)}
|
|
244
|
+
>
|
|
245
|
+
<AppUser />
|
|
246
|
+
</SidebarFooter>
|
|
247
|
+
</Sidebar>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
4
|
+
import { ExtensionPointClient } from "@arch-cadre/modules";
|
|
5
|
+
import {
|
|
6
|
+
Avatar,
|
|
7
|
+
AvatarFallback,
|
|
8
|
+
AvatarImage,
|
|
9
|
+
} from "@arch-cadre/ui/components/avatar";
|
|
10
|
+
import {
|
|
11
|
+
DropdownMenu,
|
|
12
|
+
DropdownMenuContent,
|
|
13
|
+
DropdownMenuGroup,
|
|
14
|
+
DropdownMenuItem,
|
|
15
|
+
DropdownMenuLabel,
|
|
16
|
+
DropdownMenuSeparator,
|
|
17
|
+
DropdownMenuTrigger,
|
|
18
|
+
} from "@arch-cadre/ui/components/dropdown-menu";
|
|
19
|
+
import {
|
|
20
|
+
SidebarMenu,
|
|
21
|
+
SidebarMenuButton,
|
|
22
|
+
SidebarMenuItem,
|
|
23
|
+
} from "@arch-cadre/ui/components/sidebar";
|
|
24
|
+
import { useIsMobile } from "@arch-cadre/ui/hooks/use-mobile";
|
|
25
|
+
import { useUser } from "@arch-cadre/ui/hooks/use-user";
|
|
26
|
+
import { cn } from "@arch-cadre/ui/lib/utils";
|
|
27
|
+
import { Icon } from "@iconify/react";
|
|
28
|
+
import * as React from "react";
|
|
29
|
+
import { toast } from "sonner";
|
|
30
|
+
import { logoutAction } from "../../actions/index.js";
|
|
31
|
+
|
|
32
|
+
export function AppUser() {
|
|
33
|
+
const { user, isLoading } = useUser();
|
|
34
|
+
const isMobile = useIsMobile();
|
|
35
|
+
const { t } = useTranslation();
|
|
36
|
+
|
|
37
|
+
if (!user) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const handleSignOut = async () => {
|
|
42
|
+
toast.promise(
|
|
43
|
+
async () => {
|
|
44
|
+
await logoutAction();
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
loading: t("Please wait..."),
|
|
48
|
+
success: t("Logout successful!"),
|
|
49
|
+
error: t("error_occurred"),
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<SidebarMenu>
|
|
56
|
+
<SidebarMenuItem>
|
|
57
|
+
<DropdownMenu>
|
|
58
|
+
<DropdownMenuTrigger asChild={true}>
|
|
59
|
+
<SidebarMenuButton
|
|
60
|
+
size="lg"
|
|
61
|
+
className={cn(
|
|
62
|
+
isLoading && "opacity-50",
|
|
63
|
+
"cursor-pointer squircle data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
<Avatar className="h-8 w-8 rounded-full">
|
|
67
|
+
<AvatarImage src={user.image ?? undefined} alt={user.name} />
|
|
68
|
+
<AvatarFallback className="rounded-full">
|
|
69
|
+
{user.name.charAt(0).toUpperCase()}
|
|
70
|
+
</AvatarFallback>
|
|
71
|
+
</Avatar>
|
|
72
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
73
|
+
<span className="truncate font-medium">{user.name}</span>
|
|
74
|
+
<span className="truncate text-xs">{user.email}</span>
|
|
75
|
+
</div>
|
|
76
|
+
{/*<ChevronsUpDown className="ml-auto size-4" />*/}
|
|
77
|
+
<Icon
|
|
78
|
+
icon="solar:menu-dots-broken"
|
|
79
|
+
aria-hidden="true"
|
|
80
|
+
className="mr-1 size-4 rotate-90"
|
|
81
|
+
/>
|
|
82
|
+
</SidebarMenuButton>
|
|
83
|
+
</DropdownMenuTrigger>
|
|
84
|
+
<DropdownMenuContent
|
|
85
|
+
className="squircle w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg"
|
|
86
|
+
side={isMobile ? "bottom" : "top"}
|
|
87
|
+
align="end"
|
|
88
|
+
sideOffset={4}
|
|
89
|
+
>
|
|
90
|
+
<DropdownMenuLabel className="p-0 font-normal">
|
|
91
|
+
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
|
|
92
|
+
<Avatar className="h-8 w-8 rounded-full">
|
|
93
|
+
<AvatarImage src={user.image ?? undefined} alt={user.name} />
|
|
94
|
+
<AvatarFallback className="rounded-full">
|
|
95
|
+
{user.name.charAt(0).toUpperCase()}
|
|
96
|
+
</AvatarFallback>
|
|
97
|
+
</Avatar>
|
|
98
|
+
<div className="grid flex-1 text-left text-sm leading-tight">
|
|
99
|
+
<span className="truncate font-medium">{user.name}</span>
|
|
100
|
+
<span className="truncate text-xs">{user.email}</span>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</DropdownMenuLabel>
|
|
104
|
+
|
|
105
|
+
<ExtensionPointClient module="panel" point="app-user:extra-link" />
|
|
106
|
+
|
|
107
|
+
<DropdownMenuSeparator />
|
|
108
|
+
|
|
109
|
+
<button
|
|
110
|
+
type="button"
|
|
111
|
+
onClick={() => {
|
|
112
|
+
handleSignOut();
|
|
113
|
+
}}
|
|
114
|
+
className="w-full"
|
|
115
|
+
>
|
|
116
|
+
<DropdownMenuItem className="cursor-pointer">
|
|
117
|
+
<Icon icon="solar:logout-broken" />
|
|
118
|
+
{t("Logout")}
|
|
119
|
+
</DropdownMenuItem>
|
|
120
|
+
</button>
|
|
121
|
+
</DropdownMenuContent>
|
|
122
|
+
</DropdownMenu>
|
|
123
|
+
</SidebarMenuItem>
|
|
124
|
+
</SidebarMenu>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
4
|
+
import {
|
|
5
|
+
Breadcrumb,
|
|
6
|
+
BreadcrumbItem,
|
|
7
|
+
BreadcrumbList,
|
|
8
|
+
BreadcrumbPage,
|
|
9
|
+
BreadcrumbSeparator,
|
|
10
|
+
} from "@arch-cadre/ui/components/breadcrumb";
|
|
11
|
+
import {
|
|
12
|
+
Tooltip,
|
|
13
|
+
TooltipContent,
|
|
14
|
+
TooltipTrigger,
|
|
15
|
+
} from "@arch-cadre/ui/components/tooltip";
|
|
16
|
+
import Image from "next/image";
|
|
17
|
+
import Link from "next/link";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
|
|
20
|
+
export default function BreadcrumbSlot() {
|
|
21
|
+
const { t } = useTranslation();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Breadcrumb className="hidden sm:block">
|
|
25
|
+
<BreadcrumbList>
|
|
26
|
+
<BreadcrumbItem>
|
|
27
|
+
<Tooltip>
|
|
28
|
+
<TooltipTrigger asChild>
|
|
29
|
+
<Link href="/kryo">
|
|
30
|
+
<Image
|
|
31
|
+
width={16}
|
|
32
|
+
height={16}
|
|
33
|
+
src="/favicon.svg"
|
|
34
|
+
alt="logo"
|
|
35
|
+
className="size-4"
|
|
36
|
+
aria-hidden={true}
|
|
37
|
+
/>
|
|
38
|
+
</Link>
|
|
39
|
+
</TooltipTrigger>
|
|
40
|
+
<TooltipContent>
|
|
41
|
+
<p>{t("Back to Dashboard")}</p>
|
|
42
|
+
</TooltipContent>
|
|
43
|
+
</Tooltip>
|
|
44
|
+
</BreadcrumbItem>
|
|
45
|
+
<BreadcrumbSeparator>•</BreadcrumbSeparator>
|
|
46
|
+
<BreadcrumbItem>
|
|
47
|
+
<BreadcrumbPage>{t("Dashboard")}</BreadcrumbPage>
|
|
48
|
+
</BreadcrumbItem>
|
|
49
|
+
</BreadcrumbList>
|
|
50
|
+
</Breadcrumb>
|
|
51
|
+
);
|
|
52
|
+
}
|