@pelatform/starter.shared 0.1.0 → 0.2.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 CHANGED
@@ -1,10 +1,1138 @@
1
1
  "use client";
2
2
 
3
+ // src/components/layouts/auth.tsx
4
+ import Link3 from "next/link";
5
+ import { usePathname } from "next/navigation";
6
+ import { useTranslations as useTranslations4 } from "next-intl";
7
+ import { useConfig as useConfig3 } from "@pelatform/starter.hook";
8
+ import { LayoutBlank } from "pelatform-ui/components";
9
+
10
+ // src/components/logo.tsx
11
+ import Link from "next/link";
12
+ import { useConfig } from "@pelatform/starter.hook";
13
+ import { cn } from "pelatform-ui";
14
+ import { Logo } from "pelatform-ui/components";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function LogoWithName({ className }) {
17
+ const { app } = useConfig();
18
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), children: [
19
+ /* @__PURE__ */ jsx(Logo, { className: "size-7" }),
20
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-lg text-mono", children: app.name })
21
+ ] });
22
+ }
23
+ function LogoWithHref({ className, href = "/" }) {
24
+ const { app } = useConfig();
25
+ return /* @__PURE__ */ jsxs(Link, { href, className: cn("flex items-center gap-2", className), children: [
26
+ /* @__PURE__ */ jsx(Logo, { className: "size-7" }),
27
+ /* @__PURE__ */ jsx("span", { className: "font-semibold text-lg text-mono", children: app.name })
28
+ ] });
29
+ }
30
+
31
+ // src/components/signed-in-hint.tsx
32
+ import Link2 from "next/link";
33
+ import { useTranslations } from "next-intl";
34
+ import { useSession } from "@pelatform/starter.hook";
35
+ import { Button } from "pelatform-ui/default";
36
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
37
+ function SignedInHint({ linkHref = "/signin" }) {
38
+ const t = useTranslations();
39
+ const { isPending, user } = useSession();
40
+ return /* @__PURE__ */ jsxs2("div", { className: "fixed start-0 bottom-0 z-40 m-5 flex flex-col gap-2", children: [
41
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
42
+ t("ui.common.signed.text"),
43
+ " ",
44
+ isPending || !user ? /* @__PURE__ */ jsx2("span", { className: "h-3 w-32 animate-pulse rounded-md border bg-muted-foreground" }) : /* @__PURE__ */ jsx2("b", { className: "text-foreground", children: user.email })
45
+ ] }),
46
+ /* @__PURE__ */ jsx2(Button, { variant: "mono", className: "h-8 w-fit rounded-lg px-3 text-xs shadow-sm", children: /* @__PURE__ */ jsx2(Link2, { href: linkHref, children: t("ui.common.signed.button") }) })
47
+ ] });
48
+ }
49
+
50
+ // src/components/layouts/loader.tsx
51
+ import { useTranslations as useTranslations2 } from "next-intl";
52
+ import { useSession as useSession2 } from "@pelatform/starter.hook";
53
+ import { ScreenLoader } from "pelatform-ui/components";
54
+ import { jsx as jsx3 } from "react/jsx-runtime";
55
+ function LayoutLoader({ children }) {
56
+ const t = useTranslations2();
57
+ const { isPending } = useSession2();
58
+ if (isPending) {
59
+ return /* @__PURE__ */ jsx3(ScreenLoader, { loadingText: t("common.status.loading") });
60
+ }
61
+ return children;
62
+ }
63
+
64
+ // src/components/layouts/toolbar.tsx
65
+ import { Suspense } from "react";
66
+ import { cn as cn2 } from "pelatform-ui";
67
+ import { ModeSwitcher } from "pelatform-ui/components";
68
+
69
+ // src/components/language-switcher.tsx
70
+ import Image from "next/image";
71
+ import { useRouter } from "next/navigation";
72
+ import { useLocale, useTranslations as useTranslations3 } from "next-intl";
73
+ import { useConfig as useConfig2 } from "@pelatform/starter.hook";
74
+ import {
75
+ LanguageSwitcher as LanguageSwitcherBase
76
+ } from "pelatform-ui/components";
77
+ import { jsx as jsx4 } from "react/jsx-runtime";
78
+ function LanguageSwitcher({
79
+ className,
80
+ type,
81
+ variant,
82
+ size,
83
+ showNames,
84
+ showFlags
85
+ }) {
86
+ const { i18n } = useConfig2();
87
+ const router = useRouter();
88
+ const t = useTranslations3();
89
+ const currentLocale = useLocale();
90
+ const availableLocales = (() => {
91
+ if (!i18n.enabled) {
92
+ return [i18n.defaultLocale];
93
+ }
94
+ const availableLocales2 = Object.keys(i18n.locales);
95
+ return availableLocales2;
96
+ })();
97
+ const languages = availableLocales.map((locale) => {
98
+ const localeConfig = i18n.locales[locale] || null;
99
+ return {
100
+ code: locale,
101
+ name: localeConfig?.name || locale.toUpperCase(),
102
+ flag: `/flags/${localeConfig?.flag}.svg` || ""
103
+ };
104
+ });
105
+ function handleLanguageChange(newLocale) {
106
+ if (newLocale === currentLocale) {
107
+ return;
108
+ }
109
+ document.cookie = `${i18n.localeCookieName}=${newLocale}; max-age=${60 * 60 * 24 * 365}; path=/`;
110
+ router.refresh();
111
+ }
112
+ return /* @__PURE__ */ jsx4(
113
+ LanguageSwitcherBase,
114
+ {
115
+ className,
116
+ type,
117
+ variant,
118
+ size,
119
+ showNames,
120
+ showFlags,
121
+ label: t("ui.common.language"),
122
+ i18nEnabled: i18n.enabled,
123
+ currentLocale,
124
+ locales: languages,
125
+ onLocaleChange: handleLanguageChange,
126
+ customFlagUrl: true,
127
+ Image
128
+ }
129
+ );
130
+ }
131
+
132
+ // src/components/layouts/toolbar.tsx
133
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
134
+ var DEFAULT_SHOW = ["darkmode"];
135
+ function Toolbar(props) {
136
+ return /* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5("div", { className: cn2("fixed end-0 bottom-0 z-40 m-5", props.className), children: /* @__PURE__ */ jsx5(ToolbarRSC, { ...props }) }) });
137
+ }
138
+ function ToolbarRSC({ show = DEFAULT_SHOW }) {
139
+ return /* @__PURE__ */ jsx5("div", { className: "flex flex-col items-center gap-2.5", children: /* @__PURE__ */ jsxs3("div", { className: "shrink-0", children: [
140
+ show.includes("darkmode") && /* @__PURE__ */ jsx5(ModeSwitcher, { variant: "outline", size: "lg", className: "size-10 rounded-full border" }),
141
+ show.includes("help") && /* @__PURE__ */ jsx5("div", { className: "hidden" }),
142
+ show.includes("language") && /* @__PURE__ */ jsx5(LanguageSwitcher, { variant: "outline", size: "lg", className: "size-10 rounded-full border" }),
143
+ show.includes("onboarding") && /* @__PURE__ */ jsx5("div", { className: "hidden" })
144
+ ] }) });
145
+ }
146
+
147
+ // src/components/layouts/auth.tsx
148
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
149
+ function AuthLayout({
150
+ children,
151
+ logo = /* @__PURE__ */ jsx6(LogoWithName, {}),
152
+ disableFooter = false,
153
+ signInHint = false,
154
+ signInHref
155
+ }) {
156
+ const { app, path } = useConfig3();
157
+ const pathname = usePathname();
158
+ const t = useTranslations4();
159
+ const footer = /* @__PURE__ */ jsxs4("p", { className: "px-20 py-4 text-center font-medium text-muted-foreground text-xs md:px-0", children: [
160
+ t("ui.common.agree"),
161
+ " ",
162
+ /* @__PURE__ */ jsx6(
163
+ Link3,
164
+ {
165
+ href: path.main.TERMS,
166
+ target: "_blank",
167
+ className: "font-semibold text-foreground hover:text-primary",
168
+ children: t("ui.common.terms")
169
+ }
170
+ ),
171
+ " ",
172
+ /* @__PURE__ */ jsx6(
173
+ Link3,
174
+ {
175
+ href: path.main.PRIVACY,
176
+ target: "_blank",
177
+ className: "font-semibold text-foreground hover:text-primary",
178
+ children: t("ui.common.privacy")
179
+ }
180
+ )
181
+ ] });
182
+ return /* @__PURE__ */ jsxs4(LayoutLoader, { children: [
183
+ /* @__PURE__ */ jsx6(Toolbar, { show: ["language"], className: "top-0!" }),
184
+ /* @__PURE__ */ jsx6(
185
+ LayoutBlank,
186
+ {
187
+ className: "[&_.max-w-4xl]:max-w-sm [&_.max-w-4xl]:px-0",
188
+ logo,
189
+ logoHref: app.baseUrl,
190
+ footer: disableFooter || pathname === path.auth.SIGN_OUT || pathname === path.auth.CALLBACK ? null : footer,
191
+ children
192
+ }
193
+ ),
194
+ /* @__PURE__ */ jsx6(Toolbar, { show: ["darkmode"] }),
195
+ signInHint && /* @__PURE__ */ jsx6(SignedInHint, { linkHref: signInHref || path.auth.SIGN_OUT })
196
+ ] });
197
+ }
198
+
199
+ // src/components/layouts/header.tsx
200
+ import { useEffect as useEffect2, useState as useState2 } from "react";
201
+ import { usePathname as usePathname2 } from "next/navigation";
202
+ import { Menu, PanelRight } from "lucide-react";
203
+ import { useLayout } from "@pelatform/starter.hook";
204
+ import {
205
+ Button as Button2,
206
+ Sheet,
207
+ SheetBody,
208
+ SheetContent,
209
+ SheetDescription,
210
+ SheetHeader,
211
+ SheetTitle,
212
+ SheetTrigger
213
+ } from "pelatform-ui/default";
214
+
215
+ // src/components/user-menu.tsx
216
+ import { Fragment as Fragment2, useCallback, useEffect, useState } from "react";
217
+ import Link4 from "next/link";
218
+ import { useRouter as useRouter2 } from "next/navigation";
219
+ import { LogOut, PlusCircleIcon, Settings, Shield, UserStar } from "lucide-react";
220
+ import { useTranslations as useTranslations7 } from "next-intl";
221
+ import {
222
+ useConfig as useConfig4,
223
+ useListDeviceSessions,
224
+ useSession as useSession3,
225
+ useSetActiveSession
226
+ } from "@pelatform/starter.hook";
227
+ import { getUserName as getUserName3 } from "@pelatform/starter.utils";
228
+ import { ModeSwitcher as ModeSwitcher2, UserAvatar as UserAvatar2 } from "pelatform-ui/components";
229
+ import {
230
+ Badge,
231
+ DropdownMenu,
232
+ DropdownMenuContent,
233
+ DropdownMenuItem,
234
+ DropdownMenuSeparator,
235
+ DropdownMenuTrigger,
236
+ Skeleton as Skeleton3
237
+ } from "pelatform-ui/default";
238
+
239
+ // src/components/view.tsx
240
+ import { KeyRoundIcon } from "lucide-react";
241
+ import { useLocale as useLocale2, useTranslations as useTranslations6 } from "next-intl";
242
+ import { getUserName as getUserName2 } from "@pelatform/starter.utils";
243
+ import { cn as cn4 } from "pelatform-ui";
244
+ import { Skeleton as Skeleton2 } from "pelatform-ui/default";
245
+
246
+ // src/components/avatar.tsx
247
+ import { BuildingIcon, UserRoundIcon } from "lucide-react";
248
+ import { useTranslations as useTranslations5 } from "next-intl";
249
+ import { getSizeAvatar, getUserName } from "@pelatform/starter.utils";
250
+ import { cn as cn3 } from "pelatform-ui";
251
+ import { getInitials } from "pelatform-ui/components";
252
+ import { Avatar, AvatarFallback, AvatarImage, Skeleton } from "pelatform-ui/default";
253
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
254
+ function UserAvatar({
255
+ className,
256
+ classNames,
257
+ image,
258
+ isPending,
259
+ size,
260
+ user,
261
+ ...props
262
+ }) {
263
+ const t = useTranslations5();
264
+ const name = getUserName(user);
265
+ const src = user?.image;
266
+ if (isPending) {
267
+ return /* @__PURE__ */ jsx7(
268
+ Skeleton,
269
+ {
270
+ className: cn3(
271
+ "shrink-0 rounded-full",
272
+ getSizeAvatar(size),
273
+ className,
274
+ classNames?.base,
275
+ classNames?.skeleton
276
+ )
277
+ }
278
+ );
279
+ }
280
+ return /* @__PURE__ */ jsxs5(
281
+ Avatar,
282
+ {
283
+ className: cn3("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
284
+ ...props,
285
+ children: [
286
+ /* @__PURE__ */ jsx7(
287
+ AvatarImage,
288
+ {
289
+ src: image || src || void 0,
290
+ alt: name || t("ui.navigation.user"),
291
+ className: classNames?.image
292
+ }
293
+ ),
294
+ /* @__PURE__ */ jsx7(
295
+ AvatarFallback,
296
+ {
297
+ className: cn3("text-foreground uppercase", classNames?.fallback),
298
+ delayMs: src ? 600 : void 0,
299
+ children: getInitials(name, 2) || /* @__PURE__ */ jsx7(UserRoundIcon, { className: cn3("size-[50%]", classNames?.fallbackIcon) })
300
+ }
301
+ )
302
+ ]
303
+ }
304
+ );
305
+ }
306
+ function WorkspaceLogo({
307
+ className,
308
+ classNames,
309
+ image,
310
+ isPending,
311
+ size,
312
+ workspace,
313
+ ...props
314
+ }) {
315
+ const t = useTranslations5();
316
+ const name = workspace?.name;
317
+ const src = workspace?.logo;
318
+ if (isPending) {
319
+ return /* @__PURE__ */ jsx7(
320
+ Skeleton,
321
+ {
322
+ className: cn3(
323
+ "shrink-0 rounded-full",
324
+ getSizeAvatar(size),
325
+ className,
326
+ classNames?.base,
327
+ classNames?.skeleton
328
+ )
329
+ }
330
+ );
331
+ }
332
+ return /* @__PURE__ */ jsxs5(
333
+ Avatar,
334
+ {
335
+ className: cn3("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
336
+ ...props,
337
+ children: [
338
+ /* @__PURE__ */ jsx7(
339
+ AvatarImage,
340
+ {
341
+ src: image || src || void 0,
342
+ alt: name || t("ui.navigation.workspace"),
343
+ className: classNames?.image
344
+ }
345
+ ),
346
+ /* @__PURE__ */ jsx7(
347
+ AvatarFallback,
348
+ {
349
+ className: cn3("text-foreground", classNames?.fallback),
350
+ delayMs: src ? 600 : void 0,
351
+ children: /* @__PURE__ */ jsx7(BuildingIcon, { className: cn3("size-[50%]", classNames?.fallbackIcon) })
352
+ }
353
+ )
354
+ ]
355
+ }
356
+ );
357
+ }
358
+
359
+ // src/components/view.tsx
360
+ import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
361
+ function UserView({ className, classNames, isPending, size, user }) {
362
+ const t = useTranslations6();
363
+ return /* @__PURE__ */ jsxs6("div", { className: cn4("flex items-center gap-2", className, classNames?.base), children: [
364
+ /* @__PURE__ */ jsx8(
365
+ UserAvatar,
366
+ {
367
+ className: cn4(size !== "sm" && "my-0.5"),
368
+ classNames: classNames?.avatar,
369
+ isPending,
370
+ size,
371
+ user
372
+ }
373
+ ),
374
+ /* @__PURE__ */ jsx8("div", { className: cn4("grid flex-1 text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs6(Fragment, { children: [
375
+ /* @__PURE__ */ jsx8(
376
+ Skeleton2,
377
+ {
378
+ className: cn4(
379
+ "max-w-full",
380
+ size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
381
+ classNames?.title,
382
+ classNames?.skeleton
383
+ )
384
+ }
385
+ ),
386
+ size !== "sm" && /* @__PURE__ */ jsx8(
387
+ Skeleton2,
388
+ {
389
+ className: cn4(
390
+ "mt-1.5 max-w-full",
391
+ size === "lg" ? "h-3.5 w-40" : "h-3 w-32",
392
+ classNames?.subtitle,
393
+ classNames?.skeleton
394
+ )
395
+ }
396
+ )
397
+ ] }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
398
+ /* @__PURE__ */ jsx8(
399
+ "span",
400
+ {
401
+ className: cn4(
402
+ "truncate font-semibold",
403
+ size === "lg" ? "text-base" : "text-sm",
404
+ classNames?.title
405
+ ),
406
+ children: getUserName2(user) || t("ui.navigation.user")
407
+ }
408
+ ),
409
+ !user?.isAnonymous && size !== "sm" && (user?.name || user?.username) && /* @__PURE__ */ jsx8(
410
+ "span",
411
+ {
412
+ className: cn4(
413
+ "truncate opacity-70",
414
+ size === "lg" ? "text-sm" : "text-xs",
415
+ classNames?.subtitle
416
+ ),
417
+ children: user?.email
418
+ }
419
+ )
420
+ ] }) })
421
+ ] });
422
+ }
423
+ function ApiKeyView({ className, classNames, apiKey }) {
424
+ const t = useTranslations6();
425
+ const locale = useLocale2();
426
+ const formatExpiration = () => {
427
+ if (!apiKey.expiresAt) return t("common.time.neverExpires");
428
+ const expiresDate = new Date(apiKey.expiresAt);
429
+ return `${t("common.time.expires")} ${expiresDate.toLocaleDateString(locale ?? "en", {
430
+ month: "short",
431
+ day: "numeric",
432
+ year: "numeric"
433
+ })}`;
434
+ };
435
+ return /* @__PURE__ */ jsxs6("div", { className: cn4("flex items-center gap-3 truncate", className, classNames?.base), children: [
436
+ /* @__PURE__ */ jsx8(KeyRoundIcon, { className: cn4("size-4 shrink-0", classNames?.icon) }),
437
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-col truncate text-start", children: [
438
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
439
+ /* @__PURE__ */ jsx8("span", { className: "truncate font-semibold text-sm", children: apiKey.name }),
440
+ /* @__PURE__ */ jsxs6("span", { className: "flex-1 truncate text-muted-foreground text-sm", children: [
441
+ apiKey.start,
442
+ "******"
443
+ ] })
444
+ ] }),
445
+ /* @__PURE__ */ jsx8("div", { className: "truncate text-muted-foreground text-xs", children: formatExpiration() })
446
+ ] })
447
+ ] });
448
+ }
449
+ function WorkspaceView({ className, classNames, isPending, size, workspace }) {
450
+ const t = useTranslations6();
451
+ return /* @__PURE__ */ jsxs6("div", { className: cn4("flex items-center gap-2 truncate", className, classNames?.base), children: [
452
+ /* @__PURE__ */ jsx8(
453
+ WorkspaceLogo,
454
+ {
455
+ className: cn4(size !== "sm" && "my-0.5"),
456
+ classNames: classNames?.avatar,
457
+ isPending,
458
+ workspace,
459
+ size
460
+ }
461
+ ),
462
+ /* @__PURE__ */ jsx8("div", { className: cn4("flex flex-col truncate text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs6(Fragment, { children: [
463
+ /* @__PURE__ */ jsx8(
464
+ Skeleton2,
465
+ {
466
+ className: cn4(
467
+ "max-w-full",
468
+ size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
469
+ classNames?.title,
470
+ classNames?.skeleton
471
+ )
472
+ }
473
+ ),
474
+ size !== "sm" && /* @__PURE__ */ jsx8(
475
+ Skeleton2,
476
+ {
477
+ className: cn4(
478
+ "mt-1.5 max-w-full",
479
+ size === "lg" ? "h-3.5 w-24" : "h-3 w-16",
480
+ classNames?.subtitle,
481
+ classNames?.skeleton
482
+ )
483
+ }
484
+ )
485
+ ] }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
486
+ /* @__PURE__ */ jsx8(
487
+ "span",
488
+ {
489
+ className: cn4(
490
+ "truncate font-semibold",
491
+ size === "lg" ? "text-base" : "text-sm",
492
+ classNames?.title
493
+ ),
494
+ children: workspace?.name || t("ui.navigation.workspace")
495
+ }
496
+ ),
497
+ size !== "sm" && workspace?.slug && /* @__PURE__ */ jsx8(
498
+ "span",
499
+ {
500
+ className: cn4(
501
+ "truncate opacity-70",
502
+ size === "lg" ? "text-sm" : "text-xs",
503
+ classNames?.subtitle
504
+ ),
505
+ children: workspace.slug
506
+ }
507
+ )
508
+ ] }) })
509
+ ] });
510
+ }
511
+
512
+ // src/components/user-menu.tsx
513
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
514
+ function UserMenu({ hiddenSwitcher = false }) {
515
+ const { features, path } = useConfig4();
516
+ const router = useRouter2();
517
+ const t = useTranslations7();
518
+ const { isPending: sessionPending, user } = useSession3();
519
+ const { setActiveSessionAsync } = useSetActiveSession();
520
+ const { data: deviceSessions, isPending: deviceSessionsPending } = useListDeviceSessions({
521
+ enabled: features.multiSession
522
+ });
523
+ const [activeSessionPending, setActiveSessionPending] = useState(false);
524
+ const isPending = sessionPending || activeSessionPending;
525
+ const switchAccount = useCallback(
526
+ async (sessionToken) => {
527
+ setActiveSessionPending(true);
528
+ try {
529
+ await setActiveSessionAsync({ sessionToken });
530
+ router.refresh();
531
+ setActiveSessionPending(false);
532
+ } catch (error) {
533
+ console.error("Error switching account:", error);
534
+ setActiveSessionPending(false);
535
+ }
536
+ },
537
+ [router, setActiveSessionAsync]
538
+ );
539
+ useEffect(() => {
540
+ if (!features.multiSession) return;
541
+ setActiveSessionPending(false);
542
+ }, [features.multiSession, user?.id]);
543
+ const userEmail = user?.email || "user@example.com";
544
+ const userName = getUserName3(user);
545
+ const userAvatar = user?.image || void 0;
546
+ const userRole = user?.role || "user";
547
+ return /* @__PURE__ */ jsxs7(DropdownMenu, { children: [
548
+ /* @__PURE__ */ jsx9(DropdownMenuTrigger, { className: "focus:outline-none focus:ring-0", children: isPending ? /* @__PURE__ */ jsx9(Skeleton3, { className: "size-8 shrink-0 rounded-full" }) : /* @__PURE__ */ jsx9(UserAvatar2, { className: "size-8", indicator: true, src: userAvatar, alt: userName }) }),
549
+ /* @__PURE__ */ jsxs7(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", sideOffset: 11, children: [
550
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 px-3 py-2", children: [
551
+ /* @__PURE__ */ jsx9(UserAvatar2, { src: userAvatar, alt: userName }),
552
+ /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
553
+ /* @__PURE__ */ jsx9("span", { className: "truncate font-semibold text-foreground text-sm", children: userName }),
554
+ /* @__PURE__ */ jsx9("span", { className: "block w-full truncate text-muted-foreground text-xs", children: userEmail }),
555
+ /* @__PURE__ */ jsx9(Badge, { variant: "success", appearance: "outline", size: "sm", className: "mt-1", children: userRole.toUpperCase() })
556
+ ] })
557
+ ] }),
558
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
559
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.account.SETTINGS, children: [
560
+ /* @__PURE__ */ jsx9(Settings, {}),
561
+ /* @__PURE__ */ jsx9("span", { children: t("ui.navigation.preferences") })
562
+ ] }) }),
563
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.account.SECURITY, children: [
564
+ /* @__PURE__ */ jsx9(Shield, {}),
565
+ /* @__PURE__ */ jsx9("span", { children: t("ui.navigation.security") })
566
+ ] }) }),
567
+ "admin" === userRole && /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.admin.OVERVIEW, children: [
568
+ /* @__PURE__ */ jsx9(UserStar, {}),
569
+ /* @__PURE__ */ jsx9("span", { children: "Admin Dashboard" })
570
+ ] }) }),
571
+ !hiddenSwitcher && /* @__PURE__ */ jsxs7(Fragment3, { children: [
572
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
573
+ /* @__PURE__ */ jsx9(
574
+ ModeSwitcher2,
575
+ {
576
+ type: "sub-dropdown",
577
+ label: {
578
+ system: t("ui.common.system"),
579
+ dark: t("ui.common.dark"),
580
+ light: t("ui.common.light")
581
+ }
582
+ }
583
+ ),
584
+ /* @__PURE__ */ jsx9(LanguageSwitcher, { type: "sub-dropdown" })
585
+ ] }),
586
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
587
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.auth.SIGN_OUT, children: [
588
+ /* @__PURE__ */ jsx9(LogOut, {}),
589
+ /* @__PURE__ */ jsx9("span", { children: t("ui.navigation.signOut") })
590
+ ] }) }),
591
+ user && features.multiSession && /* @__PURE__ */ jsxs7(Fragment3, { children: [
592
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
593
+ !deviceSessions && deviceSessionsPending && /* @__PURE__ */ jsxs7(Fragment3, { children: [
594
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { disabled: true, children: /* @__PURE__ */ jsx9(UserView, { isPending: true }) }),
595
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {})
596
+ ] }),
597
+ deviceSessions?.filter((sessionData) => sessionData.user.id !== user?.id).map(({ session, user: multiUser }) => {
598
+ const userData = multiUser;
599
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
600
+ /* @__PURE__ */ jsxs7(DropdownMenuItem, { onClick: () => switchAccount(session.token), children: [
601
+ /* @__PURE__ */ jsx9(UserAvatar2, { src: userData?.image || void 0, alt: getUserName3(userData) }),
602
+ /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
603
+ /* @__PURE__ */ jsx9("span", { className: "truncate font-semibold text-foreground text-xs", children: getUserName3(userData) }),
604
+ /* @__PURE__ */ jsx9("span", { className: "block w-full truncate text-muted-foreground text-xs", children: userData?.email })
605
+ ] })
606
+ ] }),
607
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {})
608
+ ] }, session.id);
609
+ }),
610
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.auth.SIGN_IN, children: [
611
+ /* @__PURE__ */ jsx9(PlusCircleIcon, {}),
612
+ t("common.actions.add"),
613
+ " ",
614
+ t("ui.navigation.account")
615
+ ] }) })
616
+ ] })
617
+ ] })
618
+ ] });
619
+ }
620
+
621
+ // src/components/layouts/header.tsx
622
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
623
+ function Header({ children }) {
624
+ return /* @__PURE__ */ jsx10("header", { className: "fixed start-0 end-0 top-0 z-10 flex h-(--header-height-mobile) shrink-0 items-stretch border-border border-b bg-background/95 pe-(--removed-body-scroll-bar-size,0px) backdrop-blur-sm supports-backdrop-filter:bg-background/60 lg:h-(--header-height)", children: /* @__PURE__ */ jsx10("div", { className: "@container flex grow items-stretch justify-between gap-2.5 pe-5", children }) });
625
+ }
626
+ function HeaderLeft() {
627
+ const { logoHeader, sidebarToggle } = useLayout();
628
+ return /* @__PURE__ */ jsx10("div", { className: "flex items-center gap-2 px-5 lg:w-(--sidebar-width)", children: /* @__PURE__ */ jsxs8("div", { className: "flex w-full items-center justify-between", children: [
629
+ logoHeader,
630
+ /* @__PURE__ */ jsx10(
631
+ Button2,
632
+ {
633
+ mode: "icon",
634
+ variant: "ghost",
635
+ onClick: sidebarToggle,
636
+ className: "hidden text-muted-foreground hover:text-foreground lg:inline-flex",
637
+ children: /* @__PURE__ */ jsx10(PanelRight, { className: "-rotate-180 in-data-[sidebar-open=false]:rotate-0 opacity-100" })
638
+ }
639
+ )
640
+ ] }) });
641
+ }
642
+ function HeaderRight({ sidebar, button }) {
643
+ const { isMobile } = useLayout();
644
+ return /* @__PURE__ */ jsxs8("nav", { className: "flex items-center gap-1.5 lg:gap-2.5", children: [
645
+ button,
646
+ isMobile && sidebar,
647
+ /* @__PURE__ */ jsx10(UserMenu, {})
648
+ ] });
649
+ }
650
+ function HeaderSidebarMobile({ children }) {
651
+ const pathname = usePathname2();
652
+ const [isSheetOpen, setIsSheetOpen] = useState2(false);
653
+ useEffect2(() => {
654
+ setIsSheetOpen(false);
655
+ }, [pathname]);
656
+ return /* @__PURE__ */ jsxs8(Sheet, { open: isSheetOpen, onOpenChange: setIsSheetOpen, children: [
657
+ /* @__PURE__ */ jsx10(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(Button2, { variant: "ghost", mode: "icon", size: "icon", children: /* @__PURE__ */ jsx10(Menu, { className: "size-4" }) }) }),
658
+ /* @__PURE__ */ jsxs8(SheetContent, { className: "w-(--sidebar-width) gap-0 p-0", side: "left", close: false, children: [
659
+ /* @__PURE__ */ jsxs8(SheetHeader, { className: "hidden space-y-0 p-0", children: [
660
+ /* @__PURE__ */ jsx10(SheetTitle, { className: "sr-only", children: "Navigation menu" }),
661
+ /* @__PURE__ */ jsx10(SheetDescription, { className: "sr-only", children: "NavigatSheet Description" })
662
+ ] }),
663
+ /* @__PURE__ */ jsx10(SheetBody, { className: "flex grow flex-col p-0", children })
664
+ ] })
665
+ ] });
666
+ }
667
+
668
+ // src/components/layouts/sidebar.tsx
669
+ import { useCallback as useCallback2, useMemo } from "react";
670
+ import Link5 from "next/link";
671
+ import { usePathname as usePathname3 } from "next/navigation";
672
+ import { useTranslations as useTranslations8 } from "next-intl";
673
+ import { useLayout as useLayout2 } from "@pelatform/starter.hook";
674
+ import { BackLink } from "pelatform-ui/components";
675
+ import {
676
+ AccordionMenu,
677
+ AccordionMenuGroup,
678
+ AccordionMenuIndicator,
679
+ AccordionMenuItem,
680
+ AccordionMenuLabel,
681
+ AccordionMenuSub,
682
+ AccordionMenuSubContent,
683
+ AccordionMenuSubTrigger,
684
+ Badge as Badge2,
685
+ ScrollArea
686
+ } from "pelatform-ui/default";
687
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
688
+ function Sidebar({ children }) {
689
+ const { isMobile } = useLayout2();
690
+ if (isMobile) {
691
+ return null;
692
+ }
693
+ return /* @__PURE__ */ jsxs9("aside", { className: "in-data-[sidebar-open=false]:-start-full fixed start-0 top-(--header-height) bottom-0 flex w-(--sidebar-width) shrink-0 flex-col items-stretch border-border border-e transition-all duration-300", children: [
694
+ children,
695
+ /* @__PURE__ */ jsx11("div", {})
696
+ ] });
697
+ }
698
+ function SidebarHeaderBack({
699
+ linkHref = "/",
700
+ admin = false
701
+ }) {
702
+ const t = useTranslations8();
703
+ return /* @__PURE__ */ jsx11("div", { className: "flex h-14 shrink-0 items-center gap-2 border-border border-b px-2.5 lg:h-15", children: /* @__PURE__ */ jsx11(BackLink, { Link: Link5, href: linkHref, children: admin ? t("common.actions.back") : t("ui.navigation.settings") }) });
704
+ }
705
+ function SidebarContent({ children }) {
706
+ return /* @__PURE__ */ jsx11(ScrollArea, { className: "mt-2 mb-2.5 h-[calc(100vh-5.5rem)] grow lg:mt-4 lg:mb-7.5 lg:h-[calc(100vh-4rem)]", children });
707
+ }
708
+ function SidebarContentMenu({
709
+ menu,
710
+ type = "default"
711
+ }) {
712
+ const pathname = usePathname3();
713
+ const normalize = useCallback2((p) => {
714
+ if (!p) return "/";
715
+ if (p !== "/" && p.endsWith("/")) return p.replace(/\/+$/, "");
716
+ return p;
717
+ }, []);
718
+ const current = useMemo(() => normalize(pathname), [pathname, normalize]);
719
+ const allPaths = useMemo(
720
+ () => menu.flatMap(
721
+ (g) => (g.children ?? []).map((c) => c.path).filter((p) => !!p && p !== "#")
722
+ ),
723
+ [menu]
724
+ );
725
+ const activePath = useMemo(() => {
726
+ const candidates = allPaths.map(normalize);
727
+ let best = "";
728
+ for (const p of candidates) {
729
+ if (p === "/") {
730
+ if (current === "/") {
731
+ best = "/";
732
+ }
733
+ continue;
734
+ }
735
+ if (current === p || current.startsWith(`${p}/`)) {
736
+ if (p.length > best.length) {
737
+ best = p;
738
+ }
739
+ }
740
+ }
741
+ return best;
742
+ }, [allPaths, current, normalize]);
743
+ const matchPath = useCallback2(
744
+ (path) => normalize(path) === activePath,
745
+ [activePath, normalize]
746
+ );
747
+ if (type === "toggle") {
748
+ return /* @__PURE__ */ jsx11(
749
+ AccordionMenu,
750
+ {
751
+ type: "single",
752
+ selectedValue: "menu-trigger",
753
+ defaultValue: "menu-trigger",
754
+ matchPath,
755
+ collapsible: true,
756
+ className: "space-y-7.5 px-2.5",
757
+ classNames: {
758
+ item: "h-8.5 px-2.5 text-sm font-normal text-foreground hover:text-primary data-[selected=true]:bg-muted data-[selected=true]:text-foreground [&[data-selected=true]_svg]:opacity-100",
759
+ subTrigger: "text-xs font-normal text-muted-foreground hover:bg-transparent",
760
+ subContent: "ps-0"
761
+ },
762
+ children: menu.map((item, index) => /* @__PURE__ */ jsxs9(AccordionMenuSub, { value: item.title || "menu", children: [
763
+ /* @__PURE__ */ jsxs9(AccordionMenuSubTrigger, { value: "menu-trigger", children: [
764
+ /* @__PURE__ */ jsx11("span", { children: item.title }),
765
+ /* @__PURE__ */ jsx11(AccordionMenuIndicator, {})
766
+ ] }),
767
+ /* @__PURE__ */ jsx11(AccordionMenuSubContent, { type: "single", collapsible: true, parentValue: "menu-trigger", children: item.children?.map((child, idx) => {
768
+ const content = /* @__PURE__ */ jsxs9(Fragment4, { children: [
769
+ child.icon && /* @__PURE__ */ jsx11(child.icon, {}),
770
+ /* @__PURE__ */ jsx11("span", { children: child.title }),
771
+ child.badge && /* @__PURE__ */ jsx11(
772
+ Badge2,
773
+ {
774
+ size: "sm",
775
+ variant: child.badgeVariant ?? "destructive",
776
+ appearance: "light",
777
+ children: child.badge
778
+ }
779
+ )
780
+ ] });
781
+ if (child.external && child.path) {
782
+ return /* @__PURE__ */ jsx11(
783
+ Link5,
784
+ {
785
+ href: child.path,
786
+ target: "_blank",
787
+ rel: "noopener noreferrer",
788
+ className: "relative flex h-8.5 w-full cursor-pointer select-none items-center gap-2 rounded-lg px-2.5 py-1.5 text-start font-normal text-foreground text-sm outline-hidden transition-colors hover:bg-accent hover:text-primary focus-visible:bg-accent focus-visible:text-accent-foreground disabled:bg-transparent disabled:opacity-50 data-[selected=true]:bg-muted data-[selected=true]:text-foreground [&[data-selected=true]_svg]:opacity-100 [&>a]:w-full [&>a]:items-center [&>a]:gap-2 [&_a]:flex [&_svg:not([class*=size-])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:opacity-60",
789
+ children: content
790
+ },
791
+ child.path || `ext-${idx}`
792
+ );
793
+ }
794
+ return /* @__PURE__ */ jsx11(AccordionMenuItem, { value: child.path || "#", children: /* @__PURE__ */ jsx11(Link5, { href: child.path || "#", children: content }) }, idx);
795
+ }) })
796
+ ] }, index))
797
+ }
798
+ );
799
+ }
800
+ return /* @__PURE__ */ jsx11(
801
+ AccordionMenu,
802
+ {
803
+ type: "multiple",
804
+ selectedValue: pathname,
805
+ matchPath,
806
+ className: "space-y-7.5 px-2.5",
807
+ classNames: {
808
+ label: "text-xs font-normal text-muted-foreground mb-2",
809
+ item: "h-8.5 px-2.5 text-sm font-normal text-foreground hover:text-primary data-[selected=true]:bg-muted data-[selected=true]:font-medium data-[selected=true]:text-foreground [&[data-selected=true]_svg]:opacity-100",
810
+ group: ""
811
+ },
812
+ children: menu.map((item, index) => {
813
+ return /* @__PURE__ */ jsxs9(AccordionMenuGroup, { children: [
814
+ /* @__PURE__ */ jsx11(AccordionMenuLabel, { children: item.title }),
815
+ item.children?.map((child, idx) => {
816
+ const content = /* @__PURE__ */ jsxs9(Fragment4, { children: [
817
+ child.icon && /* @__PURE__ */ jsx11(child.icon, {}),
818
+ /* @__PURE__ */ jsx11("span", { children: child.title }),
819
+ child.badge && /* @__PURE__ */ jsx11(
820
+ Badge2,
821
+ {
822
+ size: "sm",
823
+ variant: child.badgeVariant ?? "destructive",
824
+ appearance: "light",
825
+ children: child.badge
826
+ }
827
+ )
828
+ ] });
829
+ if (child.external && child.path) {
830
+ return /* @__PURE__ */ jsx11(
831
+ Link5,
832
+ {
833
+ href: child.path,
834
+ target: "_blank",
835
+ rel: "noopener noreferrer",
836
+ className: "relative flex h-8.5 w-full cursor-pointer select-none items-center gap-2 rounded-lg px-2.5 py-1.5 text-start font-normal text-foreground text-sm outline-hidden transition-colors hover:bg-accent hover:text-primary focus-visible:bg-accent focus-visible:text-accent-foreground disabled:bg-transparent disabled:opacity-50 data-[selected=true]:bg-muted data-[selected=true]:font-medium data-[selected=true]:text-foreground [&[data-selected=true]_svg]:opacity-100 [&>a]:w-full [&>a]:items-center [&>a]:gap-2 [&_a]:flex [&_svg:not([class*=size-])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:opacity-60",
837
+ children: content
838
+ },
839
+ child.path || `ext-${idx}`
840
+ );
841
+ }
842
+ return /* @__PURE__ */ jsx11(AccordionMenuItem, { value: child.path || "#", children: /* @__PURE__ */ jsx11(Link5, { href: child.path || "#", children: content }) }, idx);
843
+ })
844
+ ] }, index);
845
+ })
846
+ }
847
+ );
848
+ }
849
+
850
+ // src/components/layouts/site-footer.tsx
851
+ import Link6 from "next/link";
852
+ import { useTranslations as useTranslations9 } from "next-intl";
853
+ import { useConfig as useConfig5 } from "@pelatform/starter.hook";
854
+ import { cn as cn5 } from "pelatform-ui";
855
+ import { SiteFooter as UISiteFooter } from "pelatform-ui/components";
856
+ import { Button as Button3 } from "pelatform-ui/default";
857
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
858
+ function SiteFooter({ disableProjectBy = false }) {
859
+ const { app } = useConfig5();
860
+ const t = useTranslations9();
861
+ return /* @__PURE__ */ jsxs10(UISiteFooter, { className: cn5("*:gap-2! *:py-0!", disableProjectBy ? "*:justify-center!" : ""), children: [
862
+ /* @__PURE__ */ jsxs10("div", { className: "text-balance text-center text-muted-foreground text-sm leading-loose md:text-left", children: [
863
+ "\xA9 ",
864
+ (/* @__PURE__ */ new Date()).getFullYear(),
865
+ " ",
866
+ app.name,
867
+ ". ",
868
+ t("ui.common.copyright")
869
+ ] }),
870
+ !disableProjectBy && /* @__PURE__ */ jsx12("div", { className: "flex items-center gap-2.5 text-balance text-sm leading-loose", children: /* @__PURE__ */ jsxs10("div", { className: "inline-flex items-center gap-1", children: [
871
+ /* @__PURE__ */ jsx12("span", { className: "text-muted-foreground", children: t("ui.common.projectBy") }),
872
+ " ",
873
+ /* @__PURE__ */ jsx12(Button3, { mode: "link", underline: "dashed", children: /* @__PURE__ */ jsx12(
874
+ Link6,
875
+ {
876
+ href: "https://pelatform.com",
877
+ target: "_blank",
878
+ className: "font-medium text-foreground",
879
+ children: "Pelatform"
880
+ }
881
+ ) })
882
+ ] }) })
883
+ ] });
884
+ }
885
+
886
+ // src/components/layouts/site-header.tsx
887
+ import { useState as useState3 } from "react";
888
+ import Link7 from "next/link";
889
+ import { usePathname as usePathname4, useRouter as useRouter3 } from "next/navigation";
890
+ import { useTranslations as useTranslations10 } from "next-intl";
891
+ import { useConfig as useConfig6, useSession as useSession4 } from "@pelatform/starter.hook";
892
+ import {
893
+ MainNav,
894
+ MobileNav,
895
+ MobileNavItemRenderer,
896
+ ModeSwitcher as ModeSwitcher3,
897
+ SiteHeader as UISiteHeader
898
+ } from "pelatform-ui/components";
899
+ import { Button as Button4, Separator } from "pelatform-ui/default";
900
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
901
+ function SiteHeader({
902
+ menu,
903
+ logo = /* @__PURE__ */ jsx13(LogoWithHref, { href: "/home" })
904
+ }) {
905
+ const { path } = useConfig6();
906
+ const pathname = usePathname4();
907
+ const router = useRouter3();
908
+ const t = useTranslations10();
909
+ const { isPending, session, user } = useSession4();
910
+ const [, setMobileNavOpen] = useState3(false);
911
+ const isAuthenticated = !isPending && session && user;
912
+ return /* @__PURE__ */ jsxs11(UISiteHeader, { className: "backdrop-blur-none supports-backdrop-filter:bg-background", children: [
913
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4.5", children: [
914
+ logo,
915
+ /* @__PURE__ */ jsx13(MainNav, { Link: Link7, pathname, items: menu })
916
+ ] }),
917
+ /* @__PURE__ */ jsx13("div", { className: "flex items-center justify-end gap-3", children: /* @__PURE__ */ jsxs11("nav", { className: "flex items-center gap-0 md:gap-1", children: [
918
+ /* @__PURE__ */ jsx13(ModeSwitcher3, {}),
919
+ /* @__PURE__ */ jsx13(LanguageSwitcher, {}),
920
+ /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "mx-3 h-5 max-lg:hidden" }),
921
+ /* @__PURE__ */ jsx13(MobileNav, { children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col space-y-3", children: [
922
+ menu?.map(
923
+ (item, navIndex) => item.href || item.children ? /* @__PURE__ */ jsx13(
924
+ MobileNavItemRenderer,
925
+ {
926
+ item,
927
+ Link: Link7,
928
+ pathname,
929
+ level: 1,
930
+ onOpenChange: setMobileNavOpen
931
+ },
932
+ `nav-${navIndex}-${item.href}`
933
+ ) : null
934
+ ),
935
+ /* @__PURE__ */ jsx13("div", { className: "border-t pt-3", children: isAuthenticated ? /* @__PURE__ */ jsx13(
936
+ Button4,
937
+ {
938
+ variant: "outline",
939
+ size: "sm",
940
+ className: "w-full",
941
+ onClick: () => router.push(path.auth.SIGN_OUT),
942
+ children: t("ui.navigation.signOut")
943
+ }
944
+ ) : /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "w-full", children: /* @__PURE__ */ jsx13(Link7, { href: path.auth.SIGN_IN, children: t("ui.navigation.signIn") }) }) })
945
+ ] }) }),
946
+ isAuthenticated ? /* @__PURE__ */ jsx13(UserMenu, { hiddenSwitcher: true }) : /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "hidden md:flex", children: /* @__PURE__ */ jsx13(Link7, { href: path.auth.SIGN_IN, children: t("ui.navigation.signIn") }) })
947
+ ] }) })
948
+ ] });
949
+ }
950
+ function SiteHeaderSecondary({
951
+ menu,
952
+ logo = /* @__PURE__ */ jsx13(LogoWithHref, { href: "/home" }),
953
+ loginLink
954
+ }) {
955
+ const pathname = usePathname4();
956
+ const t = useTranslations10();
957
+ const [, setMobileNavOpen] = useState3(false);
958
+ return /* @__PURE__ */ jsxs11(UISiteHeader, { className: "backdrop-blur-none supports-backdrop-filter:bg-background", children: [
959
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4.5", children: [
960
+ logo,
961
+ /* @__PURE__ */ jsx13(MainNav, { Link: Link7, pathname, items: menu })
962
+ ] }),
963
+ /* @__PURE__ */ jsx13("div", { className: "flex items-center justify-end gap-3", children: /* @__PURE__ */ jsxs11("nav", { className: "flex items-center gap-0 md:gap-1", children: [
964
+ /* @__PURE__ */ jsx13(ModeSwitcher3, {}),
965
+ /* @__PURE__ */ jsx13(LanguageSwitcher, {}),
966
+ /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "mx-3 h-5 max-lg:hidden" }),
967
+ /* @__PURE__ */ jsx13(MobileNav, { children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col space-y-3", children: [
968
+ menu?.map(
969
+ (item, navIndex) => item.href || item.children ? /* @__PURE__ */ jsx13(
970
+ MobileNavItemRenderer,
971
+ {
972
+ item,
973
+ Link: Link7,
974
+ pathname,
975
+ level: 1,
976
+ onOpenChange: setMobileNavOpen
977
+ },
978
+ `nav-${navIndex}-${item.href}`
979
+ ) : null
980
+ ),
981
+ loginLink && /* @__PURE__ */ jsx13("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "w-full", children: /* @__PURE__ */ jsx13(Link7, { href: loginLink, children: t("ui.navigation.signIn") }) }) })
982
+ ] }) }),
983
+ loginLink && /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "hidden md:flex", children: /* @__PURE__ */ jsx13(Link7, { href: loginLink, children: t("ui.navigation.signIn") }) })
984
+ ] }) })
985
+ ] });
986
+ }
987
+
988
+ // src/components/providers/layout.tsx
989
+ import { useEffect as useEffect3, useState as useState4 } from "react";
990
+ import { LayoutContext } from "@pelatform/starter.hook";
991
+ import { cn as cn6 } from "pelatform-ui";
992
+ import { useIsMobile } from "pelatform-ui/hooks";
993
+ import { jsx as jsx14 } from "react/jsx-runtime";
994
+ var SIDEBAR_WIDTH = "240px";
995
+ var HEADER_HEIGHT = "54px";
996
+ var SIDEBAR_WIDTH_MOBILE = "240px";
997
+ var HEADER_HEIGHT_MOBILE = "54px";
998
+ function LayoutProvider({
999
+ children,
1000
+ style: customStyle,
1001
+ bodyClassName = "",
1002
+ className = "",
1003
+ logoHeader = /* @__PURE__ */ jsx14(LogoWithHref, {})
1004
+ }) {
1005
+ const isMobile = useIsMobile();
1006
+ const [isSidebarOpen, setIsSidebarOpen] = useState4(true);
1007
+ const defaultStyle = {
1008
+ "--sidebar-width": SIDEBAR_WIDTH,
1009
+ "--header-height": HEADER_HEIGHT,
1010
+ "--sidebar-width-mobile": SIDEBAR_WIDTH_MOBILE,
1011
+ "--header-height-mobile": HEADER_HEIGHT_MOBILE
1012
+ };
1013
+ const style = {
1014
+ ...defaultStyle,
1015
+ ...customStyle
1016
+ };
1017
+ const sidebarToggle = () => setIsSidebarOpen((open) => !open);
1018
+ useEffect3(() => {
1019
+ if (bodyClassName) {
1020
+ const body = document.body;
1021
+ const existingClasses = body.className;
1022
+ body.className = `${existingClasses} ${bodyClassName}`.trim();
1023
+ return () => {
1024
+ body.className = existingClasses;
1025
+ };
1026
+ }
1027
+ }, [bodyClassName]);
1028
+ return /* @__PURE__ */ jsx14(
1029
+ LayoutContext.Provider,
1030
+ {
1031
+ value: {
1032
+ bodyClassName,
1033
+ style,
1034
+ isMobile,
1035
+ isSidebarOpen,
1036
+ sidebarToggle,
1037
+ logoHeader
1038
+ },
1039
+ children: /* @__PURE__ */ jsx14(
1040
+ "div",
1041
+ {
1042
+ "data-slot": "layout-wrapper",
1043
+ className: cn6("flex grow", className),
1044
+ "data-sidebar-open": isSidebarOpen,
1045
+ style,
1046
+ children
1047
+ }
1048
+ )
1049
+ }
1050
+ );
1051
+ }
1052
+
1053
+ // src/components/layouts/wrapper.tsx
1054
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1055
+ function LayoutWrapper({
1056
+ children,
1057
+ sidebarHeader,
1058
+ sidebarMenu,
1059
+ logoHeader
1060
+ }) {
1061
+ const sidebarContent = /* @__PURE__ */ jsxs12(Fragment5, { children: [
1062
+ sidebarHeader,
1063
+ /* @__PURE__ */ jsx15(SidebarContent, { children: sidebarMenu })
1064
+ ] });
1065
+ return /* @__PURE__ */ jsxs12(LayoutProvider, { logoHeader, children: [
1066
+ /* @__PURE__ */ jsxs12(Header, { children: [
1067
+ /* @__PURE__ */ jsx15(HeaderLeft, {}),
1068
+ /* @__PURE__ */ jsx15(HeaderRight, { sidebar: /* @__PURE__ */ jsx15(HeaderSidebarMobile, { children: sidebarContent }) })
1069
+ ] }),
1070
+ /* @__PURE__ */ jsxs12("div", { className: "flex grow pt-(--header-height-mobile) lg:pt-(--header-height)", children: [
1071
+ /* @__PURE__ */ jsx15(Sidebar, { children: sidebarContent }),
1072
+ /* @__PURE__ */ jsx15("main", { className: "grow transition-all duration-300 lg:in-data-[sidebar-open=false]:ps-0 lg:ps-(--sidebar-width)", children })
1073
+ ] })
1074
+ ] });
1075
+ }
1076
+
1077
+ // src/components/providers/config.tsx
1078
+ import { useMemo as useMemo2 } from "react";
1079
+ import { defaultConfig, mergeConfig } from "@pelatform/starter.config";
1080
+ import {
1081
+ ConfigContext,
1082
+ defaultAuthQueryOptions,
1083
+ QueryContext
1084
+ } from "@pelatform/starter.hook";
1085
+ import { jsx as jsx16 } from "react/jsx-runtime";
1086
+ function ConfigProvider({ config, authClient, children, ...props }) {
1087
+ const mergedConfig = useMemo2(() => {
1088
+ return mergeConfig(defaultConfig, config);
1089
+ }, [config]);
1090
+ const configWithAuth = {
1091
+ ...mergedConfig,
1092
+ authClient
1093
+ };
1094
+ return /* @__PURE__ */ jsx16(
1095
+ QueryContext.Provider,
1096
+ {
1097
+ value: {
1098
+ ...defaultAuthQueryOptions,
1099
+ ...props
1100
+ },
1101
+ children: /* @__PURE__ */ jsx16(ConfigContext.Provider, { value: configWithAuth, children })
1102
+ }
1103
+ );
1104
+ }
1105
+
1106
+ // src/components/providers/shared.tsx
1107
+ import { Suspense as Suspense2 } from "react";
1108
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
1109
+ import { NextIntlClientProvider } from "next-intl";
1110
+ import { useConfig as useConfig7 } from "@pelatform/starter.hook";
1111
+ import { QueryProvider, ThemeProvider } from "pelatform-ui/components";
1112
+ import { Toaster as Sonner } from "pelatform-ui/default";
1113
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1114
+ function SharedProviders({
1115
+ children,
1116
+ locale,
1117
+ messages,
1118
+ timeZone = "Asia/Jakarta",
1119
+ sonnerPosition = "top-center"
1120
+ }) {
1121
+ const config = useConfig7();
1122
+ return /* @__PURE__ */ jsxs13(QueryProvider, { children: [
1123
+ /* @__PURE__ */ jsx17(ThemeProvider, { defaultTheme: config.ui.defaultTheme, children: /* @__PURE__ */ jsx17(NextIntlClientProvider, { locale, messages, timeZone, children: /* @__PURE__ */ jsxs13(Suspense2, { children: [
1124
+ children,
1125
+ /* @__PURE__ */ jsx17(Sonner, { position: sonnerPosition })
1126
+ ] }) }) }),
1127
+ /* @__PURE__ */ jsx17(ReactQueryDevtools, { initialIsOpen: false })
1128
+ ] });
1129
+ }
1130
+
3
1131
  // src/components/utils/card.tsx
4
1132
  import { useFormState } from "react-hook-form";
5
- import { cn } from "pelatform-ui";
6
- import { Button, Card, CardContent, CardFooter, Skeleton, Spinner } from "pelatform-ui/default";
7
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1133
+ import { cn as cn7 } from "pelatform-ui";
1134
+ import { Button as Button5, Card, CardContent, CardFooter, Skeleton as Skeleton4, Spinner } from "pelatform-ui/default";
1135
+ import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
8
1136
  function CardComponent({
9
1137
  children,
10
1138
  className,
@@ -20,10 +1148,10 @@ function CardComponent({
20
1148
  isSubmitting,
21
1149
  ...props
22
1150
  }) {
23
- return /* @__PURE__ */ jsxs(
1151
+ return /* @__PURE__ */ jsxs14(
24
1152
  Card,
25
1153
  {
26
- className: cn(
1154
+ className: cn7(
27
1155
  "w-full overflow-hidden",
28
1156
  isDestructive && "border-destructive/70",
29
1157
  className,
@@ -31,8 +1159,8 @@ function CardComponent({
31
1159
  ),
32
1160
  ...props,
33
1161
  children: [
34
- /* @__PURE__ */ jsxs(CardContent, { className: cn("space-y-6 p-5 sm:p-10", classNames?.content), children: [
35
- /* @__PURE__ */ jsx(
1162
+ /* @__PURE__ */ jsxs14(CardContent, { className: cn7("space-y-6 p-5 sm:p-10", classNames?.content), children: [
1163
+ /* @__PURE__ */ jsx18(
36
1164
  CardHeaderComponent,
37
1165
  {
38
1166
  classNames,
@@ -43,7 +1171,7 @@ function CardComponent({
43
1171
  ),
44
1172
  children
45
1173
  ] }),
46
- /* @__PURE__ */ jsx(
1174
+ /* @__PURE__ */ jsx18(
47
1175
  CardFooterComponent,
48
1176
  {
49
1177
  classNames,
@@ -67,12 +1195,12 @@ function CardHeaderComponent({
67
1195
  description,
68
1196
  isPending
69
1197
  }) {
70
- return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
71
- /* @__PURE__ */ jsx(Skeleton, { className: cn("h-7 w-1/3", classNames?.skeleton) }),
72
- description && /* @__PURE__ */ jsx(Skeleton, { className: cn("h-5 w-2/3", classNames?.skeleton) })
73
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
74
- /* @__PURE__ */ jsx("h2", { className: cn("font-medium text-xl", classNames?.title), children: title }),
75
- description && /* @__PURE__ */ jsx("p", { className: cn("text-muted-foreground text-sm", classNames?.description), children: description })
1198
+ return /* @__PURE__ */ jsx18("div", { className: cn7("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1199
+ /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-7 w-1/3", classNames?.skeleton) }),
1200
+ description && /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-5 w-2/3", classNames?.skeleton) })
1201
+ ] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
1202
+ /* @__PURE__ */ jsx18("h2", { className: cn7("font-medium text-xl", classNames?.title), children: title }),
1203
+ description && /* @__PURE__ */ jsx18("p", { className: cn7("text-muted-foreground text-sm", classNames?.description), children: description })
76
1204
  ] }) });
77
1205
  }
78
1206
  function CardFooterComponent({
@@ -86,40 +1214,40 @@ function CardFooterComponent({
86
1214
  isPending,
87
1215
  isSubmitting
88
1216
  }) {
89
- return /* @__PURE__ */ jsx(
1217
+ return /* @__PURE__ */ jsx18(
90
1218
  CardFooter,
91
1219
  {
92
- className: cn(
1220
+ className: cn7(
93
1221
  "flex items-center justify-between space-x-4 bg-muted p-3 sm:px-10",
94
1222
  isDestructive && "border-destructive/70",
95
1223
  className,
96
1224
  classNames?.footer
97
1225
  ),
98
- children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
99
- instructions && /* @__PURE__ */ jsx(
100
- Skeleton,
1226
+ children: isPending ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1227
+ instructions && /* @__PURE__ */ jsx18(
1228
+ Skeleton4,
101
1229
  {
102
- className: cn(
1230
+ className: cn7(
103
1231
  "h-4 w-48 max-w-full bg-muted-foreground/10 md:h-5 md:w-60",
104
1232
  classNames?.skeleton
105
1233
  )
106
1234
  }
107
1235
  ),
108
- actionLabel && /* @__PURE__ */ jsx(
109
- Skeleton,
1236
+ actionLabel && /* @__PURE__ */ jsx18(
1237
+ Skeleton4,
110
1238
  {
111
- className: cn("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
1239
+ className: cn7("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
112
1240
  }
113
1241
  )
114
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
115
- instructions && /* @__PURE__ */ jsx(
1242
+ ] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
1243
+ instructions && /* @__PURE__ */ jsx18(
116
1244
  "div",
117
1245
  {
118
- className: cn("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
1246
+ className: cn7("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
119
1247
  children: instructions
120
1248
  }
121
1249
  ),
122
- actionLabel && /* @__PURE__ */ jsx(
1250
+ actionLabel && /* @__PURE__ */ jsx18(
123
1251
  CardActionComponent,
124
1252
  {
125
1253
  classNames,
@@ -147,13 +1275,13 @@ function CardActionComponent({
147
1275
  const formState = useFormState();
148
1276
  isSubmitting = formState.isSubmitting;
149
1277
  }
150
- return /* @__PURE__ */ jsxs(
151
- Button,
1278
+ return /* @__PURE__ */ jsxs14(
1279
+ Button5,
152
1280
  {
153
1281
  type: onClick ? "button" : "submit",
154
1282
  variant: isDestructive ? "destructive" : "primary",
155
1283
  size: "sm",
156
- className: cn(
1284
+ className: cn7(
157
1285
  "ms-auto",
158
1286
  isSubmitting || disabled ? "pointer-events-auto! cursor-not-allowed" : "",
159
1287
  classNames?.button,
@@ -163,7 +1291,7 @@ function CardActionComponent({
163
1291
  disabled: isSubmitting || disabled,
164
1292
  ...props,
165
1293
  children: [
166
- isSubmitting && /* @__PURE__ */ jsx(Spinner, {}),
1294
+ isSubmitting && /* @__PURE__ */ jsx18(Spinner, {}),
167
1295
  actionLabel
168
1296
  ]
169
1297
  }
@@ -171,10 +1299,10 @@ function CardActionComponent({
171
1299
  }
172
1300
 
173
1301
  // src/components/utils/dialog.tsx
174
- import { useTranslations } from "next-intl";
175
- import { cn as cn2 } from "pelatform-ui";
1302
+ import { useTranslations as useTranslations11 } from "next-intl";
1303
+ import { cn as cn8 } from "pelatform-ui";
176
1304
  import {
177
- Button as Button2,
1305
+ Button as Button6,
178
1306
  Dialog,
179
1307
  DialogContent,
180
1308
  DialogDescription,
@@ -182,7 +1310,7 @@ import {
182
1310
  DialogHeader,
183
1311
  DialogTitle
184
1312
  } from "pelatform-ui/default";
185
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1313
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
186
1314
  function DialogComponent({
187
1315
  children,
188
1316
  classNames,
@@ -195,18 +1323,18 @@ function DialogComponent({
195
1323
  button,
196
1324
  ...props
197
1325
  }) {
198
- return /* @__PURE__ */ jsx2(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs2(
1326
+ return /* @__PURE__ */ jsx19(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs15(
199
1327
  DialogContent,
200
1328
  {
201
1329
  onOpenAutoFocus: (e) => e.preventDefault(),
202
1330
  className: classNames?.dialog?.content,
203
1331
  children: [
204
- /* @__PURE__ */ jsxs2(DialogHeader, { className: cn2("space-y-2", classNames?.header), children: [
205
- /* @__PURE__ */ jsx2(DialogTitle, { className: classNames?.title, children: title }),
206
- description && /* @__PURE__ */ jsx2(DialogDescription, { className: classNames?.description, children: description })
1332
+ /* @__PURE__ */ jsxs15(DialogHeader, { className: cn8("space-y-2", classNames?.header), children: [
1333
+ /* @__PURE__ */ jsx19(DialogTitle, { className: classNames?.title, children: title }),
1334
+ description && /* @__PURE__ */ jsx19(DialogDescription, { className: classNames?.description, children: description })
207
1335
  ] }),
208
1336
  children,
209
- !disableFooter && /* @__PURE__ */ jsx2(
1337
+ !disableFooter && /* @__PURE__ */ jsx19(
210
1338
  DialogFooterComponent,
211
1339
  {
212
1340
  classNames,
@@ -228,14 +1356,14 @@ function DialogFooterComponent({
228
1356
  cancelButtonDisabled,
229
1357
  button
230
1358
  }) {
231
- const t = useTranslations();
232
- return /* @__PURE__ */ jsxs2(DialogFooter, { className: cn2(className, classNames?.dialog?.footer), children: [
233
- cancelButton && /* @__PURE__ */ jsx2(
234
- Button2,
1359
+ const t = useTranslations11();
1360
+ return /* @__PURE__ */ jsxs15(DialogFooter, { className: cn8(className, classNames?.dialog?.footer), children: [
1361
+ cancelButton && /* @__PURE__ */ jsx19(
1362
+ Button6,
235
1363
  {
236
1364
  type: "button",
237
1365
  variant: "secondary",
238
- className: cn2(classNames?.button, classNames?.secondaryButton),
1366
+ className: cn8(classNames?.button, classNames?.secondaryButton),
239
1367
  onClick: () => onOpenChange?.(false),
240
1368
  disabled: cancelButtonDisabled,
241
1369
  children: t("common.actions.cancel")
@@ -246,154 +1374,41 @@ function DialogFooterComponent({
246
1374
  }
247
1375
 
248
1376
  // src/components/utils/skeleton.tsx
249
- import { cn as cn3 } from "pelatform-ui";
250
- import { Card as Card2, Skeleton as Skeleton2 } from "pelatform-ui/default";
251
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1377
+ import { cn as cn9 } from "pelatform-ui";
1378
+ import { Card as Card2, Skeleton as Skeleton5 } from "pelatform-ui/default";
1379
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
252
1380
  function SkeletonViewComponent({ classNames }) {
253
- return /* @__PURE__ */ jsxs3(Card2, { className: cn3("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
254
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
255
- /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("size-5 rounded-full", classNames?.skeleton) }),
256
- /* @__PURE__ */ jsx3("div", { children: /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-4 w-32", classNames?.skeleton) }) })
1381
+ return /* @__PURE__ */ jsxs16(Card2, { className: cn9("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
1382
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
1383
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("size-5 rounded-full", classNames?.skeleton) }),
1384
+ /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }) })
257
1385
  ] }),
258
- /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("ms-auto size-8 w-16", classNames?.skeleton) })
1386
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("ms-auto size-8 w-16", classNames?.skeleton) })
259
1387
  ] });
260
1388
  }
261
1389
  function SkeletonInputComponent({ classNames }) {
262
- return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1.5", children: [
263
- /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-4 w-32", classNames?.skeleton) }),
264
- /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("h-9 w-full", classNames?.skeleton) })
1390
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
1391
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }),
1392
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-9 w-full", classNames?.skeleton) })
265
1393
  ] });
266
1394
  }
267
1395
 
268
- // src/components/avatar.tsx
269
- import { BuildingIcon, UserRoundIcon } from "lucide-react";
270
- import { useTranslations as useTranslations2 } from "next-intl";
271
- import { getSizeAvatar, getUserName } from "@pelatform/starter.utils";
272
- import { cn as cn4 } from "pelatform-ui";
273
- import { getInitials } from "pelatform-ui/components";
274
- import { Avatar, AvatarFallback, AvatarImage, Skeleton as Skeleton3 } from "pelatform-ui/default";
275
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
276
- function UserAvatar({
277
- className,
278
- classNames,
279
- image,
280
- isPending,
281
- size,
282
- user,
283
- ...props
284
- }) {
285
- const t = useTranslations2();
286
- const name = getUserName(user);
287
- const src = user?.image;
288
- if (isPending) {
289
- return /* @__PURE__ */ jsx4(
290
- Skeleton3,
291
- {
292
- className: cn4(
293
- "shrink-0 rounded-full",
294
- getSizeAvatar(size),
295
- className,
296
- classNames?.base,
297
- classNames?.skeleton
298
- )
299
- }
300
- );
301
- }
302
- return /* @__PURE__ */ jsxs4(
303
- Avatar,
304
- {
305
- className: cn4("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
306
- ...props,
307
- children: [
308
- /* @__PURE__ */ jsx4(
309
- AvatarImage,
310
- {
311
- src: image || src || void 0,
312
- alt: name || t("ui.navigation.user"),
313
- className: classNames?.image
314
- }
315
- ),
316
- /* @__PURE__ */ jsx4(
317
- AvatarFallback,
318
- {
319
- className: cn4("text-foreground uppercase", classNames?.fallback),
320
- delayMs: src ? 600 : void 0,
321
- children: getInitials(name, 2) || /* @__PURE__ */ jsx4(UserRoundIcon, { className: cn4("size-[50%]", classNames?.fallbackIcon) })
322
- }
323
- )
324
- ]
325
- }
326
- );
327
- }
328
- function WorkspaceLogo({
329
- className,
330
- classNames,
331
- image,
332
- isPending,
333
- size,
334
- workspace,
335
- ...props
336
- }) {
337
- const t = useTranslations2();
338
- const name = workspace?.name;
339
- const src = workspace?.logo;
340
- if (isPending) {
341
- return /* @__PURE__ */ jsx4(
342
- Skeleton3,
343
- {
344
- className: cn4(
345
- "shrink-0 rounded-full",
346
- getSizeAvatar(size),
347
- className,
348
- classNames?.base,
349
- classNames?.skeleton
350
- )
351
- }
352
- );
353
- }
354
- return /* @__PURE__ */ jsxs4(
355
- Avatar,
356
- {
357
- className: cn4("rounded-full bg-accent", getSizeAvatar(size), className, classNames?.base),
358
- ...props,
359
- children: [
360
- /* @__PURE__ */ jsx4(
361
- AvatarImage,
362
- {
363
- src: image || src || void 0,
364
- alt: name || t("ui.navigation.workspace"),
365
- className: classNames?.image
366
- }
367
- ),
368
- /* @__PURE__ */ jsx4(
369
- AvatarFallback,
370
- {
371
- className: cn4("text-foreground", classNames?.fallback),
372
- delayMs: src ? 600 : void 0,
373
- children: /* @__PURE__ */ jsx4(BuildingIcon, { className: cn4("size-[50%]", classNames?.fallbackIcon) })
374
- }
375
- )
376
- ]
377
- }
378
- );
379
- }
380
-
381
1396
  // src/components/display-id.tsx
382
1397
  import { useRef } from "react";
383
1398
  import { CheckIcon, CopyIcon } from "lucide-react";
384
- import { useTranslations as useTranslations3 } from "next-intl";
385
- import { cn as cn5 } from "pelatform-ui";
1399
+ import { useTranslations as useTranslations12 } from "next-intl";
1400
+ import { cn as cn10 } from "pelatform-ui";
386
1401
  import {
387
- Button as Button3,
1402
+ Button as Button7,
388
1403
  Input,
389
- Skeleton as Skeleton4,
1404
+ Skeleton as Skeleton6,
390
1405
  Tooltip,
391
1406
  TooltipContent,
392
1407
  TooltipProvider,
393
1408
  TooltipTrigger
394
1409
  } from "pelatform-ui/default";
395
1410
  import { useCopyToClipboard } from "pelatform-ui/hooks";
396
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1411
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
397
1412
  function DisplayIdCard({
398
1413
  className,
399
1414
  classNames,
@@ -403,217 +1418,133 @@ function DisplayIdCard({
403
1418
  description,
404
1419
  ...props
405
1420
  }) {
406
- const t = useTranslations3();
1421
+ const t = useTranslations12();
407
1422
  const { copy, copied } = useCopyToClipboard();
408
1423
  const inputRef = useRef(null);
409
1424
  const handleCopy = () => {
410
1425
  if (inputRef.current) {
411
1426
  copy(inputRef.current.value);
412
1427
  }
413
- };
414
- return /* @__PURE__ */ jsx5(
415
- CardComponent,
416
- {
417
- className,
418
- classNames,
419
- title,
420
- description,
421
- isPending,
422
- ...props,
423
- children: isPending ? /* @__PURE__ */ jsx5(Skeleton4, { className: cn5("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs5(
424
- "div",
425
- {
426
- className: cn5(
427
- "flex w-full max-w-md items-center justify-between rounded-md border p-2",
428
- classNames?.grid
429
- ),
430
- children: [
431
- /* @__PURE__ */ jsx5(Input, { value: id, ref: inputRef, disabled: true, className: "border-none! bg-transparent!" }),
432
- /* @__PURE__ */ jsx5(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs5(Tooltip, { children: [
433
- /* @__PURE__ */ jsx5(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx5(Button3, { variant: "dim", onClick: handleCopy, disabled: copied, children: copied ? /* @__PURE__ */ jsx5(CheckIcon, { className: cn5("stroke-green-600", classNames?.icon) }) : /* @__PURE__ */ jsx5(CopyIcon, { className: classNames?.icon }) }) }),
434
- /* @__PURE__ */ jsx5(TooltipContent, { className: "px-2 py-1 text-xs", children: t("common.actions.copy") })
435
- ] }) })
436
- ]
437
- }
438
- )
439
- }
440
- );
441
- }
442
-
443
- // src/components/empty-state.tsx
444
- import Link from "next/link";
445
- import { useTranslations as useTranslations4 } from "next-intl";
446
- import { cn as cn6 } from "pelatform-ui";
447
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
448
- function EmptyState({
449
- className,
450
- icon: Icon,
451
- title,
452
- description,
453
- learnMore,
454
- learnMoreText,
455
- children
456
- }) {
457
- const t = useTranslations4();
458
- return /* @__PURE__ */ jsxs6("div", { className: cn6("flex flex-col items-center justify-center gap-y-4", className), children: [
459
- Icon && /* @__PURE__ */ jsx6("div", { className: "flex size-14 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx6(Icon, { className: "size-6 text-foreground" }) }),
460
- /* @__PURE__ */ jsx6("p", { className: "text-center font-medium text-base text-foreground", children: title }),
461
- description && /* @__PURE__ */ jsxs6("p", { className: "max-w-sm text-balance text-center text-muted-foreground text-sm", children: [
462
- description,
463
- " ",
464
- learnMore && /* @__PURE__ */ jsxs6(
465
- Link,
466
- {
467
- href: learnMore,
468
- className: "text-foreground underline underline-offset-2 transition-colors hover:text-primary",
469
- children: [
470
- learnMoreText ?? t("ui.common.learnMore"),
471
- " \u2197"
472
- ]
473
- }
474
- )
475
- ] }),
476
- children
477
- ] });
478
- }
479
-
480
- // src/components/language-switcher.tsx
481
- import Image from "next/image";
482
- import { useRouter } from "next/navigation";
483
- import { useLocale, useTranslations as useTranslations5 } from "next-intl";
484
- import { useConfig } from "@pelatform/starter.hook";
485
- import {
486
- LanguageSwitcher as LanguageSwitcherBase
487
- } from "pelatform-ui/components";
488
- import { jsx as jsx7 } from "react/jsx-runtime";
489
- function LanguageSwitcher({
490
- className,
491
- type,
492
- variant,
493
- size,
494
- showNames,
495
- showFlags
496
- }) {
497
- const { i18n } = useConfig();
498
- const router = useRouter();
499
- const t = useTranslations5();
500
- const currentLocale = useLocale();
501
- const availableLocales = (() => {
502
- if (!i18n.enabled) {
503
- return [i18n.defaultLocale];
504
- }
505
- const availableLocales2 = Object.keys(i18n.locales);
506
- return availableLocales2;
507
- })();
508
- const languages = availableLocales.map((locale) => {
509
- const localeConfig = i18n.locales[locale] || null;
510
- return {
511
- code: locale,
512
- name: localeConfig?.name || locale.toUpperCase(),
513
- flag: `/flags/${localeConfig?.flag}.svg` || ""
514
- };
515
- });
516
- function handleLanguageChange(newLocale) {
517
- if (newLocale === currentLocale) {
518
- return;
519
- }
520
- document.cookie = `${i18n.localeCookieName}=${newLocale}; max-age=${60 * 60 * 24 * 365}; path=/`;
521
- router.refresh();
522
- }
523
- return /* @__PURE__ */ jsx7(
524
- LanguageSwitcherBase,
525
- {
526
- className,
527
- type,
528
- variant,
529
- size,
530
- showNames,
531
- showFlags,
532
- label: t("ui.common.language"),
533
- i18nEnabled: i18n.enabled,
534
- currentLocale,
535
- locales: languages,
536
- onLocaleChange: handleLanguageChange,
537
- customFlagUrl: true,
538
- Image
539
- }
1428
+ };
1429
+ return /* @__PURE__ */ jsx21(
1430
+ CardComponent,
1431
+ {
1432
+ className,
1433
+ classNames,
1434
+ title,
1435
+ description,
1436
+ isPending,
1437
+ ...props,
1438
+ children: isPending ? /* @__PURE__ */ jsx21(Skeleton6, { className: cn10("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs17(
1439
+ "div",
1440
+ {
1441
+ className: cn10(
1442
+ "flex w-full max-w-md items-center justify-between rounded-md border p-2",
1443
+ classNames?.grid
1444
+ ),
1445
+ children: [
1446
+ /* @__PURE__ */ jsx21(Input, { value: id, ref: inputRef, disabled: true, className: "border-none! bg-transparent!" }),
1447
+ /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs17(Tooltip, { children: [
1448
+ /* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(Button7, { variant: "dim", onClick: handleCopy, disabled: copied, children: copied ? /* @__PURE__ */ jsx21(CheckIcon, { className: cn10("stroke-green-600", classNames?.icon) }) : /* @__PURE__ */ jsx21(CopyIcon, { className: classNames?.icon }) }) }),
1449
+ /* @__PURE__ */ jsx21(TooltipContent, { className: "px-2 py-1 text-xs", children: t("common.actions.copy") })
1450
+ ] }) })
1451
+ ]
1452
+ }
1453
+ )
1454
+ }
540
1455
  );
541
1456
  }
542
1457
 
543
- // src/components/logo.tsx
544
- import Link2 from "next/link";
545
- import { useConfig as useConfig2 } from "@pelatform/starter.hook";
546
- import { cn as cn7 } from "pelatform-ui";
547
- import { Logo } from "pelatform-ui/components";
548
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
549
- function LogoWithName({ className }) {
550
- const { app } = useConfig2();
551
- return /* @__PURE__ */ jsxs7("div", { className: cn7("flex items-center gap-2", className), children: [
552
- /* @__PURE__ */ jsx8(Logo, { className: "size-7" }),
553
- /* @__PURE__ */ jsx8("span", { className: "font-semibold text-lg text-mono", children: app.name })
554
- ] });
555
- }
556
- function LogoWithHref({ className, href = "/" }) {
557
- const { app } = useConfig2();
558
- return /* @__PURE__ */ jsxs7(Link2, { href, className: cn7("flex items-center gap-2", className), children: [
559
- /* @__PURE__ */ jsx8(Logo, { className: "size-7" }),
560
- /* @__PURE__ */ jsx8("span", { className: "font-semibold text-lg text-mono", children: app.name })
1458
+ // src/components/empty-state.tsx
1459
+ import Link8 from "next/link";
1460
+ import { useTranslations as useTranslations13 } from "next-intl";
1461
+ import { cn as cn11 } from "pelatform-ui";
1462
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
1463
+ function EmptyState({
1464
+ className,
1465
+ icon: Icon,
1466
+ title,
1467
+ description,
1468
+ learnMore,
1469
+ learnMoreText,
1470
+ children
1471
+ }) {
1472
+ const t = useTranslations13();
1473
+ return /* @__PURE__ */ jsxs18("div", { className: cn11("flex flex-col items-center justify-center gap-y-4", className), children: [
1474
+ Icon && /* @__PURE__ */ jsx22("div", { className: "flex size-14 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx22(Icon, { className: "size-6 text-foreground" }) }),
1475
+ /* @__PURE__ */ jsx22("p", { className: "text-center font-medium text-base text-foreground", children: title }),
1476
+ description && /* @__PURE__ */ jsxs18("p", { className: "max-w-sm text-balance text-center text-muted-foreground text-sm", children: [
1477
+ description,
1478
+ " ",
1479
+ learnMore && /* @__PURE__ */ jsxs18(
1480
+ Link8,
1481
+ {
1482
+ href: learnMore,
1483
+ className: "text-foreground underline underline-offset-2 transition-colors hover:text-primary",
1484
+ children: [
1485
+ learnMoreText ?? t("ui.common.learnMore"),
1486
+ " \u2197"
1487
+ ]
1488
+ }
1489
+ )
1490
+ ] }),
1491
+ children
561
1492
  ] });
562
1493
  }
563
1494
 
564
1495
  // src/components/otp-input-group.tsx
565
1496
  import { InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "pelatform-ui/default";
566
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1497
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
567
1498
  function OTPInputGroup({ otpSeparators = 0 }) {
568
1499
  if (otpSeparators === 0) {
569
- return /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
570
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
571
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 }),
572
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 }),
573
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 }),
574
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
575
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
1500
+ return /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1501
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1502
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 }),
1503
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 }),
1504
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 }),
1505
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1506
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
576
1507
  ] });
577
1508
  }
578
1509
  if (otpSeparators === 1) {
579
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
580
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
581
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
582
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 }),
583
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 })
1510
+ return /* @__PURE__ */ jsxs19(Fragment7, { children: [
1511
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1512
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1513
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 }),
1514
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 })
584
1515
  ] }),
585
- /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
586
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
587
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 }),
588
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
589
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
1516
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1517
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1518
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 }),
1519
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1520
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
590
1521
  ] })
591
1522
  ] });
592
1523
  }
593
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
594
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
595
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
596
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 })
1524
+ return /* @__PURE__ */ jsxs19(Fragment7, { children: [
1525
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1526
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1527
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 })
597
1528
  ] }),
598
- /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
599
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
600
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 }),
601
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 })
1529
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1530
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1531
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 }),
1532
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 })
602
1533
  ] }),
603
- /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
604
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
605
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
606
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
1534
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1535
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1536
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1537
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
607
1538
  ] })
608
1539
  ] });
609
1540
  }
610
1541
 
611
1542
  // src/components/password-input.tsx
612
- import { useState } from "react";
1543
+ import { useState as useState5 } from "react";
613
1544
  import { EyeIcon, EyeOffIcon } from "lucide-react";
614
- import { cn as cn8 } from "pelatform-ui";
615
- import { Button as Button4, Input as Input2 } from "pelatform-ui/default";
616
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1545
+ import { cn as cn12 } from "pelatform-ui";
1546
+ import { Button as Button8, Input as Input2 } from "pelatform-ui/default";
1547
+ import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
617
1548
  function PasswordInput({
618
1549
  className,
619
1550
  variant,
@@ -621,15 +1552,15 @@ function PasswordInput({
621
1552
  onChange,
622
1553
  ...props
623
1554
  }) {
624
- const [disabled, setDisabled] = useState(true);
625
- const [isVisible, setIsVisible] = useState(false);
626
- return /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
627
- /* @__PURE__ */ jsx10(
1555
+ const [disabled, setDisabled] = useState5(true);
1556
+ const [isVisible, setIsVisible] = useState5(false);
1557
+ return /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
1558
+ /* @__PURE__ */ jsx24(
628
1559
  Input2,
629
1560
  {
630
1561
  type: isVisible && enableToggle ? "text" : "password",
631
1562
  variant,
632
- className: cn8(enableToggle && "pe-10", className),
1563
+ className: cn12(enableToggle && "pe-10", className),
633
1564
  ...props,
634
1565
  onChange: (event) => {
635
1566
  setDisabled(!event.target.value);
@@ -637,9 +1568,9 @@ function PasswordInput({
637
1568
  }
638
1569
  }
639
1570
  ),
640
- enableToggle && /* @__PURE__ */ jsxs9(Fragment3, { children: [
641
- /* @__PURE__ */ jsx10(
642
- Button4,
1571
+ enableToggle && /* @__PURE__ */ jsxs20(Fragment8, { children: [
1572
+ /* @__PURE__ */ jsx24(
1573
+ Button8,
643
1574
  {
644
1575
  type: "button",
645
1576
  variant: "ghost",
@@ -647,10 +1578,10 @@ function PasswordInput({
647
1578
  className: "absolute end-0 top-0 bg-transparent!",
648
1579
  onClick: () => setIsVisible(!isVisible),
649
1580
  disabled,
650
- children: isVisible ? /* @__PURE__ */ jsx10(EyeIcon, {}) : /* @__PURE__ */ jsx10(EyeOffIcon, {})
1581
+ children: isVisible ? /* @__PURE__ */ jsx24(EyeIcon, {}) : /* @__PURE__ */ jsx24(EyeOffIcon, {})
651
1582
  }
652
1583
  ),
653
- /* @__PURE__ */ jsx10("style", { children: `
1584
+ /* @__PURE__ */ jsx24("style", { children: `
654
1585
  .hide-password-toggle::-ms-reveal,
655
1586
  .hide-password-toggle::-ms-clear {
656
1587
  visibility: hidden;
@@ -661,330 +1592,43 @@ function PasswordInput({
661
1592
  ] })
662
1593
  ] });
663
1594
  }
664
-
665
- // src/components/signed-in-hint.tsx
666
- import Link3 from "next/link";
667
- import { useTranslations as useTranslations6 } from "next-intl";
668
- import { useSession } from "@pelatform/starter.hook";
669
- import { Button as Button5 } from "pelatform-ui/default";
670
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
671
- function SignedInHint({ linkHref = "/signin" }) {
672
- const t = useTranslations6("ui.common.signed");
673
- const { isPending, user } = useSession();
674
- return /* @__PURE__ */ jsxs10("div", { className: "fixed start-0 bottom-0 z-40 m-5 flex flex-col gap-2", children: [
675
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-muted-foreground text-xs", children: [
676
- t("text"),
677
- " ",
678
- isPending || !user ? /* @__PURE__ */ jsx11("span", { className: "h-3 w-32 animate-pulse rounded-md border bg-muted-foreground" }) : /* @__PURE__ */ jsx11("b", { className: "text-foreground", children: user.email })
679
- ] }),
680
- /* @__PURE__ */ jsx11(Button5, { variant: "mono", className: "h-8 w-fit rounded-lg px-3 text-xs shadow-sm", children: /* @__PURE__ */ jsx11(Link3, { href: linkHref, children: t("button") }) })
681
- ] });
682
- }
683
-
684
- // src/components/user-menu.tsx
685
- import { Fragment as Fragment5, useCallback, useEffect, useState as useState2 } from "react";
686
- import Link4 from "next/link";
687
- import { useRouter as useRouter2 } from "next/navigation";
688
- import { LogOut, PlusCircleIcon, Settings, Shield, UserStar } from "lucide-react";
689
- import { useTranslations as useTranslations8 } from "next-intl";
690
- import {
691
- useConfig as useConfig3,
692
- useListDeviceSessions,
693
- useSession as useSession2,
694
- useSetActiveSession
695
- } from "@pelatform/starter.hook";
696
- import { getUserName as getUserName3 } from "@pelatform/starter.utils";
697
- import { ModeSwitcher, UserAvatar as UserAvatar2 } from "pelatform-ui/components";
698
- import {
699
- Badge,
700
- DropdownMenu,
701
- DropdownMenuContent,
702
- DropdownMenuItem,
703
- DropdownMenuSeparator,
704
- DropdownMenuTrigger,
705
- Skeleton as Skeleton6
706
- } from "pelatform-ui/default";
707
-
708
- // src/components/view.tsx
709
- import { KeyRoundIcon } from "lucide-react";
710
- import { useLocale as useLocale2, useTranslations as useTranslations7 } from "next-intl";
711
- import { getUserName as getUserName2 } from "@pelatform/starter.utils";
712
- import { cn as cn9 } from "pelatform-ui";
713
- import { Skeleton as Skeleton5 } from "pelatform-ui/default";
714
- import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
715
- function UserView({ className, classNames, isPending, size, user }) {
716
- const t = useTranslations7();
717
- return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-2", className, classNames?.base), children: [
718
- /* @__PURE__ */ jsx12(
719
- UserAvatar,
720
- {
721
- className: cn9(size !== "sm" && "my-0.5"),
722
- classNames: classNames?.avatar,
723
- isPending,
724
- size,
725
- user
726
- }
727
- ),
728
- /* @__PURE__ */ jsx12("div", { className: cn9("grid flex-1 text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
729
- /* @__PURE__ */ jsx12(
730
- Skeleton5,
731
- {
732
- className: cn9(
733
- "max-w-full",
734
- size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
735
- classNames?.title,
736
- classNames?.skeleton
737
- )
738
- }
739
- ),
740
- size !== "sm" && /* @__PURE__ */ jsx12(
741
- Skeleton5,
742
- {
743
- className: cn9(
744
- "mt-1.5 max-w-full",
745
- size === "lg" ? "h-3.5 w-40" : "h-3 w-32",
746
- classNames?.subtitle,
747
- classNames?.skeleton
748
- )
749
- }
750
- )
751
- ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
752
- /* @__PURE__ */ jsx12(
753
- "span",
754
- {
755
- className: cn9(
756
- "truncate font-semibold",
757
- size === "lg" ? "text-base" : "text-sm",
758
- classNames?.title
759
- ),
760
- children: getUserName2(user) || t("ui.navigation.user")
761
- }
762
- ),
763
- !user?.isAnonymous && size !== "sm" && (user?.name || user?.username) && /* @__PURE__ */ jsx12(
764
- "span",
765
- {
766
- className: cn9(
767
- "truncate opacity-70",
768
- size === "lg" ? "text-sm" : "text-xs",
769
- classNames?.subtitle
770
- ),
771
- children: user?.email
772
- }
773
- )
774
- ] }) })
775
- ] });
776
- }
777
- function ApiKeyView({ className, classNames, apiKey }) {
778
- const t = useTranslations7();
779
- const locale = useLocale2();
780
- const formatExpiration = () => {
781
- if (!apiKey.expiresAt) return t("common.time.neverExpires");
782
- const expiresDate = new Date(apiKey.expiresAt);
783
- return `${t("common.time.expires")} ${expiresDate.toLocaleDateString(locale ?? "en", {
784
- month: "short",
785
- day: "numeric",
786
- year: "numeric"
787
- })}`;
788
- };
789
- return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-3 truncate", className, classNames?.base), children: [
790
- /* @__PURE__ */ jsx12(KeyRoundIcon, { className: cn9("size-4 shrink-0", classNames?.icon) }),
791
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col truncate text-start", children: [
792
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
793
- /* @__PURE__ */ jsx12("span", { className: "truncate font-semibold text-sm", children: apiKey.name }),
794
- /* @__PURE__ */ jsxs11("span", { className: "flex-1 truncate text-muted-foreground text-sm", children: [
795
- apiKey.start,
796
- "******"
797
- ] })
798
- ] }),
799
- /* @__PURE__ */ jsx12("div", { className: "truncate text-muted-foreground text-xs", children: formatExpiration() })
800
- ] })
801
- ] });
802
- }
803
- function WorkspaceView({ className, classNames, isPending, size, workspace }) {
804
- const t = useTranslations7();
805
- return /* @__PURE__ */ jsxs11("div", { className: cn9("flex items-center gap-2 truncate", className, classNames?.base), children: [
806
- /* @__PURE__ */ jsx12(
807
- WorkspaceLogo,
808
- {
809
- className: cn9(size !== "sm" && "my-0.5"),
810
- classNames: classNames?.avatar,
811
- isPending,
812
- workspace,
813
- size
814
- }
815
- ),
816
- /* @__PURE__ */ jsx12("div", { className: cn9("flex flex-col truncate text-start leading-tight", classNames?.content), children: isPending ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
817
- /* @__PURE__ */ jsx12(
818
- Skeleton5,
819
- {
820
- className: cn9(
821
- "max-w-full",
822
- size === "lg" ? "h-4.5 w-32" : "h-3.5 w-24",
823
- classNames?.title,
824
- classNames?.skeleton
825
- )
826
- }
827
- ),
828
- size !== "sm" && /* @__PURE__ */ jsx12(
829
- Skeleton5,
830
- {
831
- className: cn9(
832
- "mt-1.5 max-w-full",
833
- size === "lg" ? "h-3.5 w-24" : "h-3 w-16",
834
- classNames?.subtitle,
835
- classNames?.skeleton
836
- )
837
- }
838
- )
839
- ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
840
- /* @__PURE__ */ jsx12(
841
- "span",
842
- {
843
- className: cn9(
844
- "truncate font-semibold",
845
- size === "lg" ? "text-base" : "text-sm",
846
- classNames?.title
847
- ),
848
- children: workspace?.name || t("ui.navigation.workspace")
849
- }
850
- ),
851
- size !== "sm" && workspace?.slug && /* @__PURE__ */ jsx12(
852
- "span",
853
- {
854
- className: cn9(
855
- "truncate opacity-70",
856
- size === "lg" ? "text-sm" : "text-xs",
857
- classNames?.subtitle
858
- ),
859
- children: workspace.slug
860
- }
861
- )
862
- ] }) })
863
- ] });
864
- }
865
-
866
- // src/components/user-menu.tsx
867
- import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
868
- function UserMenu({ hiddenSwitcher = false }) {
869
- const { features, path } = useConfig3();
870
- const router = useRouter2();
871
- const t = useTranslations8();
872
- const { isPending: sessionPending, user } = useSession2();
873
- const { setActiveSessionAsync } = useSetActiveSession();
874
- const { data: deviceSessions, isPending: deviceSessionsPending } = useListDeviceSessions({
875
- enabled: features.multiSession
876
- });
877
- const [activeSessionPending, setActiveSessionPending] = useState2(false);
878
- const isPending = sessionPending || activeSessionPending;
879
- const switchAccount = useCallback(
880
- async (sessionToken) => {
881
- setActiveSessionPending(true);
882
- try {
883
- await setActiveSessionAsync({ sessionToken });
884
- router.refresh();
885
- setActiveSessionPending(false);
886
- } catch (error) {
887
- console.error("Error switching account:", error);
888
- setActiveSessionPending(false);
889
- }
890
- },
891
- [router, setActiveSessionAsync]
892
- );
893
- useEffect(() => {
894
- if (!features.multiSession) return;
895
- setActiveSessionPending(false);
896
- }, [features.multiSession, user?.id]);
897
- const userEmail = user?.email || "user@example.com";
898
- const userName = getUserName3(user);
899
- const userAvatar = user?.image || void 0;
900
- const userRole = user?.role || "user";
901
- return /* @__PURE__ */ jsxs12(DropdownMenu, { children: [
902
- /* @__PURE__ */ jsx13(DropdownMenuTrigger, { className: "focus:outline-none focus:ring-0", children: isPending ? /* @__PURE__ */ jsx13(Skeleton6, { className: "size-8 shrink-0 rounded-full" }) : /* @__PURE__ */ jsx13(UserAvatar2, { className: "size-8", indicator: true, src: userAvatar, alt: userName }) }),
903
- /* @__PURE__ */ jsxs12(DropdownMenuContent, { className: "w-56", side: "bottom", align: "end", sideOffset: 11, children: [
904
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3 px-3 py-2", children: [
905
- /* @__PURE__ */ jsx13(UserAvatar2, { src: userAvatar, alt: userName }),
906
- /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
907
- /* @__PURE__ */ jsx13("span", { className: "truncate font-semibold text-foreground text-sm", children: userName }),
908
- /* @__PURE__ */ jsx13("span", { className: "block w-full truncate text-muted-foreground text-xs", children: userEmail }),
909
- /* @__PURE__ */ jsx13(Badge, { variant: "success", appearance: "outline", size: "sm", className: "mt-1", children: userRole.toUpperCase() })
910
- ] })
911
- ] }),
912
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
913
- /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.account.SETTINGS, children: [
914
- /* @__PURE__ */ jsx13(Settings, {}),
915
- /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.preferences") })
916
- ] }) }),
917
- /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.account.SECURITY, children: [
918
- /* @__PURE__ */ jsx13(Shield, {}),
919
- /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.security") })
920
- ] }) }),
921
- "admin" === userRole && /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.admin.OVERVIEW, children: [
922
- /* @__PURE__ */ jsx13(UserStar, {}),
923
- /* @__PURE__ */ jsx13("span", { children: "Admin Dashboard" })
924
- ] }) }),
925
- !hiddenSwitcher && /* @__PURE__ */ jsxs12(Fragment6, { children: [
926
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
927
- /* @__PURE__ */ jsx13(
928
- ModeSwitcher,
929
- {
930
- type: "sub-dropdown",
931
- label: {
932
- system: t("ui.common.system"),
933
- dark: t("ui.common.dark"),
934
- light: t("ui.common.light")
935
- }
936
- }
937
- ),
938
- /* @__PURE__ */ jsx13(LanguageSwitcher, { type: "sub-dropdown" })
939
- ] }),
940
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
941
- /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.auth.SIGN_OUT, children: [
942
- /* @__PURE__ */ jsx13(LogOut, {}),
943
- /* @__PURE__ */ jsx13("span", { children: t("ui.navigation.signOut") })
944
- ] }) }),
945
- user && features.multiSession && /* @__PURE__ */ jsxs12(Fragment6, { children: [
946
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {}),
947
- !deviceSessions && deviceSessionsPending && /* @__PURE__ */ jsxs12(Fragment6, { children: [
948
- /* @__PURE__ */ jsx13(DropdownMenuItem, { disabled: true, children: /* @__PURE__ */ jsx13(UserView, { isPending: true }) }),
949
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {})
950
- ] }),
951
- deviceSessions?.filter((sessionData) => sessionData.user.id !== user?.id).map(({ session, user: multiUser }) => /* @__PURE__ */ jsxs12(Fragment5, { children: [
952
- /* @__PURE__ */ jsxs12(DropdownMenuItem, { onClick: () => switchAccount(session.token), children: [
953
- /* @__PURE__ */ jsx13(UserAvatar2, { src: multiUser?.image || void 0, alt: getUserName3(multiUser) }),
954
- /* @__PURE__ */ jsxs12("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
955
- /* @__PURE__ */ jsx13("span", { className: "truncate font-semibold text-foreground text-xs", children: getUserName3(multiUser) }),
956
- /* @__PURE__ */ jsx13("span", { className: "block w-full truncate text-muted-foreground text-xs", children: multiUser?.email })
957
- ] })
958
- ] }),
959
- /* @__PURE__ */ jsx13(DropdownMenuSeparator, {})
960
- ] }, session.id)),
961
- /* @__PURE__ */ jsx13(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs12(Link4, { href: path.auth.SIGN_IN, children: [
962
- /* @__PURE__ */ jsx13(PlusCircleIcon, {}),
963
- t("common.actions.addAccount")
964
- ] }) })
965
- ] })
966
- ] })
967
- ] });
968
- }
969
1595
  export {
970
1596
  ApiKeyView,
1597
+ AuthLayout,
971
1598
  CardActionComponent,
972
1599
  CardComponent,
973
1600
  CardFooterComponent,
974
1601
  CardHeaderComponent,
1602
+ ConfigProvider,
975
1603
  DialogComponent,
976
1604
  DialogFooterComponent,
977
1605
  DisplayIdCard,
978
1606
  EmptyState,
1607
+ Header,
1608
+ HeaderLeft,
1609
+ HeaderRight,
1610
+ HeaderSidebarMobile,
979
1611
  LanguageSwitcher,
1612
+ LayoutLoader,
1613
+ LayoutProvider,
1614
+ LayoutWrapper,
980
1615
  Logo as LogoDefault,
981
1616
  LogoWithHref,
982
1617
  LogoWithName,
983
1618
  OTPInputGroup,
984
1619
  PasswordInput,
1620
+ SharedProviders,
1621
+ Sidebar,
1622
+ SidebarContent,
1623
+ SidebarContentMenu,
1624
+ SidebarHeaderBack,
985
1625
  SignedInHint,
1626
+ SiteFooter,
1627
+ SiteHeader,
1628
+ SiteHeaderSecondary,
986
1629
  SkeletonInputComponent,
987
1630
  SkeletonViewComponent,
1631
+ Toolbar,
988
1632
  UserAvatar,
989
1633
  UserMenu,
990
1634
  UserView,