@pelatform/starter.shared 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +138 -6
  2. package/dist/index.js +1305 -666
  3. package/package.json +6 -4
package/dist/index.js CHANGED
@@ -1,10 +1,1133 @@
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 }) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
598
+ /* @__PURE__ */ jsxs7(DropdownMenuItem, { onClick: () => switchAccount(session.token), children: [
599
+ /* @__PURE__ */ jsx9(UserAvatar2, { src: multiUser?.image || void 0, alt: getUserName3(multiUser) }),
600
+ /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 flex-col items-start", children: [
601
+ /* @__PURE__ */ jsx9("span", { className: "truncate font-semibold text-foreground text-xs", children: getUserName3(multiUser) }),
602
+ /* @__PURE__ */ jsx9("span", { className: "block w-full truncate text-muted-foreground text-xs", children: multiUser?.email })
603
+ ] })
604
+ ] }),
605
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {})
606
+ ] }, session.id)),
607
+ /* @__PURE__ */ jsx9(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs7(Link4, { href: path.auth.SIGN_IN, children: [
608
+ /* @__PURE__ */ jsx9(PlusCircleIcon, {}),
609
+ t("common.actions.addAccount")
610
+ ] }) })
611
+ ] })
612
+ ] })
613
+ ] });
614
+ }
615
+
616
+ // src/components/layouts/header.tsx
617
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
618
+ function Header({ children }) {
619
+ 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 }) });
620
+ }
621
+ function HeaderLeft() {
622
+ const { logoHeader, sidebarToggle } = useLayout();
623
+ 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: [
624
+ logoHeader,
625
+ /* @__PURE__ */ jsx10(
626
+ Button2,
627
+ {
628
+ mode: "icon",
629
+ variant: "ghost",
630
+ onClick: sidebarToggle,
631
+ className: "hidden text-muted-foreground hover:text-foreground lg:inline-flex",
632
+ children: /* @__PURE__ */ jsx10(PanelRight, { className: "-rotate-180 in-data-[sidebar-open=false]:rotate-0 opacity-100" })
633
+ }
634
+ )
635
+ ] }) });
636
+ }
637
+ function HeaderRight({ sidebar, button }) {
638
+ const { isMobile } = useLayout();
639
+ return /* @__PURE__ */ jsxs8("nav", { className: "flex items-center gap-1.5 lg:gap-2.5", children: [
640
+ button,
641
+ isMobile && sidebar,
642
+ /* @__PURE__ */ jsx10(UserMenu, {})
643
+ ] });
644
+ }
645
+ function HeaderSidebarMobile({ children }) {
646
+ const pathname = usePathname2();
647
+ const [isSheetOpen, setIsSheetOpen] = useState2(false);
648
+ useEffect2(() => {
649
+ setIsSheetOpen(false);
650
+ }, [pathname]);
651
+ return /* @__PURE__ */ jsxs8(Sheet, { open: isSheetOpen, onOpenChange: setIsSheetOpen, children: [
652
+ /* @__PURE__ */ jsx10(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(Button2, { variant: "ghost", mode: "icon", size: "icon", children: /* @__PURE__ */ jsx10(Menu, { className: "size-4" }) }) }),
653
+ /* @__PURE__ */ jsxs8(SheetContent, { className: "w-(--sidebar-width) gap-0 p-0", side: "left", close: false, children: [
654
+ /* @__PURE__ */ jsxs8(SheetHeader, { className: "hidden space-y-0 p-0", children: [
655
+ /* @__PURE__ */ jsx10(SheetTitle, { className: "sr-only", children: "Navigation menu" }),
656
+ /* @__PURE__ */ jsx10(SheetDescription, { className: "sr-only", children: "NavigatSheet Description" })
657
+ ] }),
658
+ /* @__PURE__ */ jsx10(SheetBody, { className: "flex grow flex-col p-0", children })
659
+ ] })
660
+ ] });
661
+ }
662
+
663
+ // src/components/layouts/sidebar.tsx
664
+ import { useCallback as useCallback2, useMemo } from "react";
665
+ import Link5 from "next/link";
666
+ import { usePathname as usePathname3 } from "next/navigation";
667
+ import { useTranslations as useTranslations8 } from "next-intl";
668
+ import { useLayout as useLayout2 } from "@pelatform/starter.hook";
669
+ import { BackLink } from "pelatform-ui/components";
670
+ import {
671
+ AccordionMenu,
672
+ AccordionMenuGroup,
673
+ AccordionMenuIndicator,
674
+ AccordionMenuItem,
675
+ AccordionMenuLabel,
676
+ AccordionMenuSub,
677
+ AccordionMenuSubContent,
678
+ AccordionMenuSubTrigger,
679
+ Badge as Badge2,
680
+ ScrollArea
681
+ } from "pelatform-ui/default";
682
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
683
+ function Sidebar({ children }) {
684
+ const { isMobile } = useLayout2();
685
+ if (isMobile) {
686
+ return null;
687
+ }
688
+ 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: [
689
+ children,
690
+ /* @__PURE__ */ jsx11("div", {})
691
+ ] });
692
+ }
693
+ function SidebarHeaderBack({
694
+ linkHref = "/",
695
+ admin = false
696
+ }) {
697
+ const t = useTranslations8();
698
+ 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") }) });
699
+ }
700
+ function SidebarContent({ children }) {
701
+ 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 });
702
+ }
703
+ function SidebarContentMenu({
704
+ menu,
705
+ type = "default"
706
+ }) {
707
+ const pathname = usePathname3();
708
+ const normalize = useCallback2((p) => {
709
+ if (!p) return "/";
710
+ if (p !== "/" && p.endsWith("/")) return p.replace(/\/+$/, "");
711
+ return p;
712
+ }, []);
713
+ const current = useMemo(() => normalize(pathname), [pathname, normalize]);
714
+ const allPaths = useMemo(
715
+ () => menu.flatMap(
716
+ (g) => (g.children ?? []).map((c) => c.path).filter((p) => !!p && p !== "#")
717
+ ),
718
+ [menu]
719
+ );
720
+ const activePath = useMemo(() => {
721
+ const candidates = allPaths.map(normalize);
722
+ let best = "";
723
+ for (const p of candidates) {
724
+ if (p === "/") {
725
+ if (current === "/") {
726
+ best = "/";
727
+ }
728
+ continue;
729
+ }
730
+ if (current === p || current.startsWith(`${p}/`)) {
731
+ if (p.length > best.length) {
732
+ best = p;
733
+ }
734
+ }
735
+ }
736
+ return best;
737
+ }, [allPaths, current, normalize]);
738
+ const matchPath = useCallback2(
739
+ (path) => normalize(path) === activePath,
740
+ [activePath, normalize]
741
+ );
742
+ if (type === "toggle") {
743
+ return /* @__PURE__ */ jsx11(
744
+ AccordionMenu,
745
+ {
746
+ type: "single",
747
+ selectedValue: "menu-trigger",
748
+ defaultValue: "menu-trigger",
749
+ matchPath,
750
+ collapsible: true,
751
+ className: "space-y-7.5 px-2.5",
752
+ classNames: {
753
+ 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",
754
+ subTrigger: "text-xs font-normal text-muted-foreground hover:bg-transparent",
755
+ subContent: "ps-0"
756
+ },
757
+ children: menu.map((item, index) => /* @__PURE__ */ jsxs9(AccordionMenuSub, { value: item.title || "menu", children: [
758
+ /* @__PURE__ */ jsxs9(AccordionMenuSubTrigger, { value: "menu-trigger", children: [
759
+ /* @__PURE__ */ jsx11("span", { children: item.title }),
760
+ /* @__PURE__ */ jsx11(AccordionMenuIndicator, {})
761
+ ] }),
762
+ /* @__PURE__ */ jsx11(AccordionMenuSubContent, { type: "single", collapsible: true, parentValue: "menu-trigger", children: item.children?.map((child, idx) => {
763
+ const content = /* @__PURE__ */ jsxs9(Fragment4, { children: [
764
+ child.icon && /* @__PURE__ */ jsx11(child.icon, {}),
765
+ /* @__PURE__ */ jsx11("span", { children: child.title }),
766
+ child.badge && /* @__PURE__ */ jsx11(
767
+ Badge2,
768
+ {
769
+ size: "sm",
770
+ variant: child.badgeVariant ?? "destructive",
771
+ appearance: "light",
772
+ children: child.badge
773
+ }
774
+ )
775
+ ] });
776
+ if (child.external && child.path) {
777
+ return /* @__PURE__ */ jsx11(
778
+ Link5,
779
+ {
780
+ href: child.path,
781
+ target: "_blank",
782
+ rel: "noopener noreferrer",
783
+ 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",
784
+ children: content
785
+ },
786
+ child.path || `ext-${idx}`
787
+ );
788
+ }
789
+ return /* @__PURE__ */ jsx11(AccordionMenuItem, { value: child.path || "#", children: /* @__PURE__ */ jsx11(Link5, { href: child.path || "#", children: content }) }, idx);
790
+ }) })
791
+ ] }, index))
792
+ }
793
+ );
794
+ }
795
+ return /* @__PURE__ */ jsx11(
796
+ AccordionMenu,
797
+ {
798
+ type: "multiple",
799
+ selectedValue: pathname,
800
+ matchPath,
801
+ className: "space-y-7.5 px-2.5",
802
+ classNames: {
803
+ label: "text-xs font-normal text-muted-foreground mb-2",
804
+ 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",
805
+ group: ""
806
+ },
807
+ children: menu.map((item, index) => {
808
+ return /* @__PURE__ */ jsxs9(AccordionMenuGroup, { children: [
809
+ /* @__PURE__ */ jsx11(AccordionMenuLabel, { children: item.title }),
810
+ item.children?.map((child, idx) => {
811
+ const content = /* @__PURE__ */ jsxs9(Fragment4, { children: [
812
+ child.icon && /* @__PURE__ */ jsx11(child.icon, {}),
813
+ /* @__PURE__ */ jsx11("span", { children: child.title }),
814
+ child.badge && /* @__PURE__ */ jsx11(
815
+ Badge2,
816
+ {
817
+ size: "sm",
818
+ variant: child.badgeVariant ?? "destructive",
819
+ appearance: "light",
820
+ children: child.badge
821
+ }
822
+ )
823
+ ] });
824
+ if (child.external && child.path) {
825
+ return /* @__PURE__ */ jsx11(
826
+ Link5,
827
+ {
828
+ href: child.path,
829
+ target: "_blank",
830
+ rel: "noopener noreferrer",
831
+ 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",
832
+ children: content
833
+ },
834
+ child.path || `ext-${idx}`
835
+ );
836
+ }
837
+ return /* @__PURE__ */ jsx11(AccordionMenuItem, { value: child.path || "#", children: /* @__PURE__ */ jsx11(Link5, { href: child.path || "#", children: content }) }, idx);
838
+ })
839
+ ] }, index);
840
+ })
841
+ }
842
+ );
843
+ }
844
+
845
+ // src/components/layouts/site-footer.tsx
846
+ import Link6 from "next/link";
847
+ import { useTranslations as useTranslations9 } from "next-intl";
848
+ import { useConfig as useConfig5 } from "@pelatform/starter.hook";
849
+ import { cn as cn5 } from "pelatform-ui";
850
+ import { SiteFooter as UISiteFooter } from "pelatform-ui/components";
851
+ import { Button as Button3 } from "pelatform-ui/default";
852
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
853
+ function SiteFooter({ disableProjectBy = false }) {
854
+ const { app } = useConfig5();
855
+ const t = useTranslations9();
856
+ return /* @__PURE__ */ jsxs10(UISiteFooter, { className: cn5("*:gap-2! *:py-0!", disableProjectBy ? "*:justify-center!" : ""), children: [
857
+ /* @__PURE__ */ jsxs10("div", { className: "text-balance text-center text-muted-foreground text-sm leading-loose md:text-left", children: [
858
+ "\xA9 ",
859
+ (/* @__PURE__ */ new Date()).getFullYear(),
860
+ " ",
861
+ app.name,
862
+ ". ",
863
+ t("ui.common.copyright")
864
+ ] }),
865
+ !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: [
866
+ /* @__PURE__ */ jsx12("span", { className: "text-muted-foreground", children: t("ui.common.projectBy") }),
867
+ " ",
868
+ /* @__PURE__ */ jsx12(Button3, { mode: "link", underline: "dashed", children: /* @__PURE__ */ jsx12(
869
+ Link6,
870
+ {
871
+ href: "https://pelatform.com",
872
+ target: "_blank",
873
+ className: "font-medium text-foreground",
874
+ children: "Pelatform"
875
+ }
876
+ ) })
877
+ ] }) })
878
+ ] });
879
+ }
880
+
881
+ // src/components/layouts/site-header.tsx
882
+ import { useState as useState3 } from "react";
883
+ import Link7 from "next/link";
884
+ import { usePathname as usePathname4, useRouter as useRouter3 } from "next/navigation";
885
+ import { useTranslations as useTranslations10 } from "next-intl";
886
+ import { useConfig as useConfig6, useSession as useSession4 } from "@pelatform/starter.hook";
887
+ import {
888
+ MainNav,
889
+ MobileNav,
890
+ MobileNavItemRenderer,
891
+ ModeSwitcher as ModeSwitcher3,
892
+ SiteHeader as UISiteHeader
893
+ } from "pelatform-ui/components";
894
+ import { Button as Button4, Separator } from "pelatform-ui/default";
895
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
896
+ function SiteHeader({
897
+ menu,
898
+ logo = /* @__PURE__ */ jsx13(LogoWithHref, { href: "/home" })
899
+ }) {
900
+ const { path } = useConfig6();
901
+ const pathname = usePathname4();
902
+ const router = useRouter3();
903
+ const t = useTranslations10();
904
+ const { isPending, session, user } = useSession4();
905
+ const [, setMobileNavOpen] = useState3(false);
906
+ const isAuthenticated = !isPending && session && user;
907
+ return /* @__PURE__ */ jsxs11(UISiteHeader, { className: "backdrop-blur-none supports-backdrop-filter:bg-background", children: [
908
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4.5", children: [
909
+ logo,
910
+ /* @__PURE__ */ jsx13(MainNav, { Link: Link7, pathname, items: menu })
911
+ ] }),
912
+ /* @__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: [
913
+ /* @__PURE__ */ jsx13(ModeSwitcher3, {}),
914
+ /* @__PURE__ */ jsx13(LanguageSwitcher, {}),
915
+ /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "mx-3 h-5 max-lg:hidden" }),
916
+ /* @__PURE__ */ jsx13(MobileNav, { children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col space-y-3", children: [
917
+ menu?.map(
918
+ (item, navIndex) => item.href || item.children ? /* @__PURE__ */ jsx13(
919
+ MobileNavItemRenderer,
920
+ {
921
+ item,
922
+ Link: Link7,
923
+ pathname,
924
+ level: 1,
925
+ onOpenChange: setMobileNavOpen
926
+ },
927
+ `nav-${navIndex}-${item.href}`
928
+ ) : null
929
+ ),
930
+ /* @__PURE__ */ jsx13("div", { className: "border-t pt-3", children: isAuthenticated ? /* @__PURE__ */ jsx13(
931
+ Button4,
932
+ {
933
+ variant: "outline",
934
+ size: "sm",
935
+ className: "w-full",
936
+ onClick: () => router.push(path.auth.SIGN_OUT),
937
+ children: t("ui.navigation.signOut")
938
+ }
939
+ ) : /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "w-full", children: /* @__PURE__ */ jsx13(Link7, { href: path.auth.SIGN_IN, children: t("ui.navigation.signIn") }) }) })
940
+ ] }) }),
941
+ 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") }) })
942
+ ] }) })
943
+ ] });
944
+ }
945
+ function SiteHeaderSecondary({
946
+ menu,
947
+ logo = /* @__PURE__ */ jsx13(LogoWithHref, { href: "/home" }),
948
+ loginLink
949
+ }) {
950
+ const pathname = usePathname4();
951
+ const t = useTranslations10();
952
+ const [, setMobileNavOpen] = useState3(false);
953
+ return /* @__PURE__ */ jsxs11(UISiteHeader, { className: "backdrop-blur-none supports-backdrop-filter:bg-background", children: [
954
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4.5", children: [
955
+ logo,
956
+ /* @__PURE__ */ jsx13(MainNav, { Link: Link7, pathname, items: menu })
957
+ ] }),
958
+ /* @__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: [
959
+ /* @__PURE__ */ jsx13(ModeSwitcher3, {}),
960
+ /* @__PURE__ */ jsx13(LanguageSwitcher, {}),
961
+ /* @__PURE__ */ jsx13(Separator, { orientation: "vertical", className: "mx-3 h-5 max-lg:hidden" }),
962
+ /* @__PURE__ */ jsx13(MobileNav, { children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col space-y-3", children: [
963
+ menu?.map(
964
+ (item, navIndex) => item.href || item.children ? /* @__PURE__ */ jsx13(
965
+ MobileNavItemRenderer,
966
+ {
967
+ item,
968
+ Link: Link7,
969
+ pathname,
970
+ level: 1,
971
+ onOpenChange: setMobileNavOpen
972
+ },
973
+ `nav-${navIndex}-${item.href}`
974
+ ) : null
975
+ ),
976
+ 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") }) }) })
977
+ ] }) }),
978
+ loginLink && /* @__PURE__ */ jsx13(Button4, { variant: "secondary", size: "sm", className: "hidden md:flex", children: /* @__PURE__ */ jsx13(Link7, { href: loginLink, children: t("ui.navigation.signIn") }) })
979
+ ] }) })
980
+ ] });
981
+ }
982
+
983
+ // src/components/providers/layout.tsx
984
+ import { useEffect as useEffect3, useState as useState4 } from "react";
985
+ import { LayoutContext } from "@pelatform/starter.hook";
986
+ import { cn as cn6 } from "pelatform-ui";
987
+ import { useIsMobile } from "pelatform-ui/hooks";
988
+ import { jsx as jsx14 } from "react/jsx-runtime";
989
+ var SIDEBAR_WIDTH = "240px";
990
+ var HEADER_HEIGHT = "54px";
991
+ var SIDEBAR_WIDTH_MOBILE = "240px";
992
+ var HEADER_HEIGHT_MOBILE = "54px";
993
+ function LayoutProvider({
994
+ children,
995
+ style: customStyle,
996
+ bodyClassName = "",
997
+ className = "",
998
+ logoHeader = /* @__PURE__ */ jsx14(LogoWithHref, {})
999
+ }) {
1000
+ const isMobile = useIsMobile();
1001
+ const [isSidebarOpen, setIsSidebarOpen] = useState4(true);
1002
+ const defaultStyle = {
1003
+ "--sidebar-width": SIDEBAR_WIDTH,
1004
+ "--header-height": HEADER_HEIGHT,
1005
+ "--sidebar-width-mobile": SIDEBAR_WIDTH_MOBILE,
1006
+ "--header-height-mobile": HEADER_HEIGHT_MOBILE
1007
+ };
1008
+ const style = {
1009
+ ...defaultStyle,
1010
+ ...customStyle
1011
+ };
1012
+ const sidebarToggle = () => setIsSidebarOpen((open) => !open);
1013
+ useEffect3(() => {
1014
+ if (bodyClassName) {
1015
+ const body = document.body;
1016
+ const existingClasses = body.className;
1017
+ body.className = `${existingClasses} ${bodyClassName}`.trim();
1018
+ return () => {
1019
+ body.className = existingClasses;
1020
+ };
1021
+ }
1022
+ }, [bodyClassName]);
1023
+ return /* @__PURE__ */ jsx14(
1024
+ LayoutContext.Provider,
1025
+ {
1026
+ value: {
1027
+ bodyClassName,
1028
+ style,
1029
+ isMobile,
1030
+ isSidebarOpen,
1031
+ sidebarToggle,
1032
+ logoHeader
1033
+ },
1034
+ children: /* @__PURE__ */ jsx14(
1035
+ "div",
1036
+ {
1037
+ "data-slot": "layout-wrapper",
1038
+ className: cn6("flex grow", className),
1039
+ "data-sidebar-open": isSidebarOpen,
1040
+ style,
1041
+ children
1042
+ }
1043
+ )
1044
+ }
1045
+ );
1046
+ }
1047
+
1048
+ // src/components/layouts/wrapper.tsx
1049
+ import { Fragment as Fragment5, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1050
+ function LayoutWrapper({
1051
+ children,
1052
+ sidebarHeader,
1053
+ sidebarMenu,
1054
+ logoHeader
1055
+ }) {
1056
+ const sidebarContent = /* @__PURE__ */ jsxs12(Fragment5, { children: [
1057
+ sidebarHeader,
1058
+ /* @__PURE__ */ jsx15(SidebarContent, { children: sidebarMenu })
1059
+ ] });
1060
+ return /* @__PURE__ */ jsxs12(LayoutProvider, { logoHeader, children: [
1061
+ /* @__PURE__ */ jsxs12(Header, { children: [
1062
+ /* @__PURE__ */ jsx15(HeaderLeft, {}),
1063
+ /* @__PURE__ */ jsx15(HeaderRight, { sidebar: /* @__PURE__ */ jsx15(HeaderSidebarMobile, { children: sidebarContent }) })
1064
+ ] }),
1065
+ /* @__PURE__ */ jsxs12("div", { className: "flex grow pt-(--header-height-mobile) lg:pt-(--header-height)", children: [
1066
+ /* @__PURE__ */ jsx15(Sidebar, { children: sidebarContent }),
1067
+ /* @__PURE__ */ jsx15("main", { className: "grow transition-all duration-300 lg:in-data-[sidebar-open=false]:ps-0 lg:ps-(--sidebar-width)", children })
1068
+ ] })
1069
+ ] });
1070
+ }
1071
+
1072
+ // src/components/providers/config.tsx
1073
+ import { useMemo as useMemo2 } from "react";
1074
+ import { defaultConfig, mergeConfig } from "@pelatform/starter.config";
1075
+ import {
1076
+ ConfigContext,
1077
+ defaultAuthQueryOptions,
1078
+ QueryContext
1079
+ } from "@pelatform/starter.hook";
1080
+ import { jsx as jsx16 } from "react/jsx-runtime";
1081
+ function ConfigProvider({ config, authClient, children, ...props }) {
1082
+ const mergedConfig = useMemo2(() => {
1083
+ return mergeConfig(defaultConfig, config);
1084
+ }, [config]);
1085
+ const configWithAuth = {
1086
+ ...mergedConfig,
1087
+ authClient
1088
+ };
1089
+ return /* @__PURE__ */ jsx16(
1090
+ QueryContext.Provider,
1091
+ {
1092
+ value: {
1093
+ ...defaultAuthQueryOptions,
1094
+ ...props
1095
+ },
1096
+ children: /* @__PURE__ */ jsx16(ConfigContext.Provider, { value: configWithAuth, children })
1097
+ }
1098
+ );
1099
+ }
1100
+
1101
+ // src/components/providers/shared.tsx
1102
+ import { Suspense as Suspense2 } from "react";
1103
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
1104
+ import { NextIntlClientProvider } from "next-intl";
1105
+ import { useConfig as useConfig7 } from "@pelatform/starter.hook";
1106
+ import { QueryProvider, ThemeProvider } from "pelatform-ui/components";
1107
+ import { Toaster as Sonner } from "pelatform-ui/default";
1108
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1109
+ function SharedProviders({
1110
+ children,
1111
+ locale,
1112
+ messages,
1113
+ timeZone = "Asia/Jakarta",
1114
+ sonnerPosition = "top-center"
1115
+ }) {
1116
+ const config = useConfig7();
1117
+ return /* @__PURE__ */ jsxs13(QueryProvider, { children: [
1118
+ /* @__PURE__ */ jsx17(ThemeProvider, { defaultTheme: config.ui.defaultTheme, children: /* @__PURE__ */ jsx17(NextIntlClientProvider, { locale, messages, timeZone, children: /* @__PURE__ */ jsxs13(Suspense2, { children: [
1119
+ children,
1120
+ /* @__PURE__ */ jsx17(Sonner, { position: sonnerPosition })
1121
+ ] }) }) }),
1122
+ /* @__PURE__ */ jsx17(ReactQueryDevtools, { initialIsOpen: false })
1123
+ ] });
1124
+ }
1125
+
3
1126
  // src/components/utils/card.tsx
4
1127
  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";
1128
+ import { cn as cn7 } from "pelatform-ui";
1129
+ import { Button as Button5, Card, CardContent, CardFooter, Skeleton as Skeleton4, Spinner } from "pelatform-ui/default";
1130
+ import { Fragment as Fragment6, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
8
1131
  function CardComponent({
9
1132
  children,
10
1133
  className,
@@ -20,10 +1143,10 @@ function CardComponent({
20
1143
  isSubmitting,
21
1144
  ...props
22
1145
  }) {
23
- return /* @__PURE__ */ jsxs(
1146
+ return /* @__PURE__ */ jsxs14(
24
1147
  Card,
25
1148
  {
26
- className: cn(
1149
+ className: cn7(
27
1150
  "w-full overflow-hidden",
28
1151
  isDestructive && "border-destructive/70",
29
1152
  className,
@@ -31,8 +1154,8 @@ function CardComponent({
31
1154
  ),
32
1155
  ...props,
33
1156
  children: [
34
- /* @__PURE__ */ jsxs(CardContent, { className: cn("space-y-6 p-5 sm:p-10", classNames?.content), children: [
35
- /* @__PURE__ */ jsx(
1157
+ /* @__PURE__ */ jsxs14(CardContent, { className: cn7("space-y-6 p-5 sm:p-10", classNames?.content), children: [
1158
+ /* @__PURE__ */ jsx18(
36
1159
  CardHeaderComponent,
37
1160
  {
38
1161
  classNames,
@@ -43,7 +1166,7 @@ function CardComponent({
43
1166
  ),
44
1167
  children
45
1168
  ] }),
46
- /* @__PURE__ */ jsx(
1169
+ /* @__PURE__ */ jsx18(
47
1170
  CardFooterComponent,
48
1171
  {
49
1172
  classNames,
@@ -67,12 +1190,12 @@ function CardHeaderComponent({
67
1190
  description,
68
1191
  isPending
69
1192
  }) {
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 })
1193
+ return /* @__PURE__ */ jsx18("div", { className: cn7("flex flex-col space-y-2", className, classNames?.header), children: isPending ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1194
+ /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-7 w-1/3", classNames?.skeleton) }),
1195
+ description && /* @__PURE__ */ jsx18(Skeleton4, { className: cn7("h-5 w-2/3", classNames?.skeleton) })
1196
+ ] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
1197
+ /* @__PURE__ */ jsx18("h2", { className: cn7("font-medium text-xl", classNames?.title), children: title }),
1198
+ description && /* @__PURE__ */ jsx18("p", { className: cn7("text-muted-foreground text-sm", classNames?.description), children: description })
76
1199
  ] }) });
77
1200
  }
78
1201
  function CardFooterComponent({
@@ -86,40 +1209,40 @@ function CardFooterComponent({
86
1209
  isPending,
87
1210
  isSubmitting
88
1211
  }) {
89
- return /* @__PURE__ */ jsx(
1212
+ return /* @__PURE__ */ jsx18(
90
1213
  CardFooter,
91
1214
  {
92
- className: cn(
1215
+ className: cn7(
93
1216
  "flex items-center justify-between space-x-4 bg-muted p-3 sm:px-10",
94
1217
  isDestructive && "border-destructive/70",
95
1218
  className,
96
1219
  classNames?.footer
97
1220
  ),
98
- children: isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
99
- instructions && /* @__PURE__ */ jsx(
100
- Skeleton,
1221
+ children: isPending ? /* @__PURE__ */ jsxs14(Fragment6, { children: [
1222
+ instructions && /* @__PURE__ */ jsx18(
1223
+ Skeleton4,
101
1224
  {
102
- className: cn(
1225
+ className: cn7(
103
1226
  "h-4 w-48 max-w-full bg-muted-foreground/10 md:h-5 md:w-60",
104
1227
  classNames?.skeleton
105
1228
  )
106
1229
  }
107
1230
  ),
108
- actionLabel && /* @__PURE__ */ jsx(
109
- Skeleton,
1231
+ actionLabel && /* @__PURE__ */ jsx18(
1232
+ Skeleton4,
110
1233
  {
111
- className: cn("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
1234
+ className: cn7("h-8 w-20 bg-muted-foreground/10 md:ms-auto", classNames?.skeleton)
112
1235
  }
113
1236
  )
114
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
115
- instructions && /* @__PURE__ */ jsx(
1237
+ ] }) : /* @__PURE__ */ jsxs14(Fragment6, { children: [
1238
+ instructions && /* @__PURE__ */ jsx18(
116
1239
  "div",
117
1240
  {
118
- className: cn("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
1241
+ className: cn7("text-muted-foreground text-xs md:text-sm", classNames?.instructions),
119
1242
  children: instructions
120
1243
  }
121
1244
  ),
122
- actionLabel && /* @__PURE__ */ jsx(
1245
+ actionLabel && /* @__PURE__ */ jsx18(
123
1246
  CardActionComponent,
124
1247
  {
125
1248
  classNames,
@@ -147,13 +1270,13 @@ function CardActionComponent({
147
1270
  const formState = useFormState();
148
1271
  isSubmitting = formState.isSubmitting;
149
1272
  }
150
- return /* @__PURE__ */ jsxs(
151
- Button,
1273
+ return /* @__PURE__ */ jsxs14(
1274
+ Button5,
152
1275
  {
153
1276
  type: onClick ? "button" : "submit",
154
1277
  variant: isDestructive ? "destructive" : "primary",
155
1278
  size: "sm",
156
- className: cn(
1279
+ className: cn7(
157
1280
  "ms-auto",
158
1281
  isSubmitting || disabled ? "pointer-events-auto! cursor-not-allowed" : "",
159
1282
  classNames?.button,
@@ -163,7 +1286,7 @@ function CardActionComponent({
163
1286
  disabled: isSubmitting || disabled,
164
1287
  ...props,
165
1288
  children: [
166
- isSubmitting && /* @__PURE__ */ jsx(Spinner, {}),
1289
+ isSubmitting && /* @__PURE__ */ jsx18(Spinner, {}),
167
1290
  actionLabel
168
1291
  ]
169
1292
  }
@@ -171,10 +1294,10 @@ function CardActionComponent({
171
1294
  }
172
1295
 
173
1296
  // src/components/utils/dialog.tsx
174
- import { useTranslations } from "next-intl";
175
- import { cn as cn2 } from "pelatform-ui";
1297
+ import { useTranslations as useTranslations11 } from "next-intl";
1298
+ import { cn as cn8 } from "pelatform-ui";
176
1299
  import {
177
- Button as Button2,
1300
+ Button as Button6,
178
1301
  Dialog,
179
1302
  DialogContent,
180
1303
  DialogDescription,
@@ -182,7 +1305,7 @@ import {
182
1305
  DialogHeader,
183
1306
  DialogTitle
184
1307
  } from "pelatform-ui/default";
185
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1308
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
186
1309
  function DialogComponent({
187
1310
  children,
188
1311
  classNames,
@@ -195,18 +1318,18 @@ function DialogComponent({
195
1318
  button,
196
1319
  ...props
197
1320
  }) {
198
- return /* @__PURE__ */ jsx2(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs2(
1321
+ return /* @__PURE__ */ jsx19(Dialog, { onOpenChange, ...props, children: /* @__PURE__ */ jsxs15(
199
1322
  DialogContent,
200
1323
  {
201
1324
  onOpenAutoFocus: (e) => e.preventDefault(),
202
1325
  className: classNames?.dialog?.content,
203
1326
  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 })
1327
+ /* @__PURE__ */ jsxs15(DialogHeader, { className: cn8("space-y-2", classNames?.header), children: [
1328
+ /* @__PURE__ */ jsx19(DialogTitle, { className: classNames?.title, children: title }),
1329
+ description && /* @__PURE__ */ jsx19(DialogDescription, { className: classNames?.description, children: description })
207
1330
  ] }),
208
1331
  children,
209
- !disableFooter && /* @__PURE__ */ jsx2(
1332
+ !disableFooter && /* @__PURE__ */ jsx19(
210
1333
  DialogFooterComponent,
211
1334
  {
212
1335
  classNames,
@@ -228,14 +1351,14 @@ function DialogFooterComponent({
228
1351
  cancelButtonDisabled,
229
1352
  button
230
1353
  }) {
231
- const t = useTranslations();
232
- return /* @__PURE__ */ jsxs2(DialogFooter, { className: cn2(className, classNames?.dialog?.footer), children: [
233
- cancelButton && /* @__PURE__ */ jsx2(
234
- Button2,
1354
+ const t = useTranslations11();
1355
+ return /* @__PURE__ */ jsxs15(DialogFooter, { className: cn8(className, classNames?.dialog?.footer), children: [
1356
+ cancelButton && /* @__PURE__ */ jsx19(
1357
+ Button6,
235
1358
  {
236
1359
  type: "button",
237
1360
  variant: "secondary",
238
- className: cn2(classNames?.button, classNames?.secondaryButton),
1361
+ className: cn8(classNames?.button, classNames?.secondaryButton),
239
1362
  onClick: () => onOpenChange?.(false),
240
1363
  disabled: cancelButtonDisabled,
241
1364
  children: t("common.actions.cancel")
@@ -246,154 +1369,41 @@ function DialogFooterComponent({
246
1369
  }
247
1370
 
248
1371
  // 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";
1372
+ import { cn as cn9 } from "pelatform-ui";
1373
+ import { Card as Card2, Skeleton as Skeleton5 } from "pelatform-ui/default";
1374
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
252
1375
  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) }) })
1376
+ return /* @__PURE__ */ jsxs16(Card2, { className: cn9("flex-row items-center gap-3 px-4 py-3", classNames?.cell), children: [
1377
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
1378
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("size-5 rounded-full", classNames?.skeleton) }),
1379
+ /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }) })
257
1380
  ] }),
258
- /* @__PURE__ */ jsx3(Skeleton2, { className: cn3("ms-auto size-8 w-16", classNames?.skeleton) })
1381
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("ms-auto size-8 w-16", classNames?.skeleton) })
259
1382
  ] });
260
1383
  }
261
1384
  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) })
1385
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
1386
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-4 w-32", classNames?.skeleton) }),
1387
+ /* @__PURE__ */ jsx20(Skeleton5, { className: cn9("h-9 w-full", classNames?.skeleton) })
265
1388
  ] });
266
1389
  }
267
1390
 
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
1391
  // src/components/display-id.tsx
382
1392
  import { useRef } from "react";
383
1393
  import { CheckIcon, CopyIcon } from "lucide-react";
384
- import { useTranslations as useTranslations3 } from "next-intl";
385
- import { cn as cn5 } from "pelatform-ui";
1394
+ import { useTranslations as useTranslations12 } from "next-intl";
1395
+ import { cn as cn10 } from "pelatform-ui";
386
1396
  import {
387
- Button as Button3,
1397
+ Button as Button7,
388
1398
  Input,
389
- Skeleton as Skeleton4,
1399
+ Skeleton as Skeleton6,
390
1400
  Tooltip,
391
1401
  TooltipContent,
392
1402
  TooltipProvider,
393
1403
  TooltipTrigger
394
1404
  } from "pelatform-ui/default";
395
1405
  import { useCopyToClipboard } from "pelatform-ui/hooks";
396
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1406
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
397
1407
  function DisplayIdCard({
398
1408
  className,
399
1409
  classNames,
@@ -403,7 +1413,7 @@ function DisplayIdCard({
403
1413
  description,
404
1414
  ...props
405
1415
  }) {
406
- const t = useTranslations3();
1416
+ const t = useTranslations12();
407
1417
  const { copy, copied } = useCopyToClipboard();
408
1418
  const inputRef = useRef(null);
409
1419
  const handleCopy = () => {
@@ -411,209 +1421,125 @@ function DisplayIdCard({
411
1421
  copy(inputRef.current.value);
412
1422
  }
413
1423
  };
414
- return /* @__PURE__ */ jsx5(
1424
+ return /* @__PURE__ */ jsx21(
415
1425
  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
1426
+ {
1427
+ className,
1428
+ classNames,
1429
+ title,
1430
+ description,
1431
+ isPending,
1432
+ ...props,
1433
+ children: isPending ? /* @__PURE__ */ jsx21(Skeleton6, { className: cn10("h-11.5 w-full max-w-md", classNames?.skeleton) }) : /* @__PURE__ */ jsxs17(
1434
+ "div",
1435
+ {
1436
+ className: cn10(
1437
+ "flex w-full max-w-md items-center justify-between rounded-md border p-2",
1438
+ classNames?.grid
1439
+ ),
1440
+ children: [
1441
+ /* @__PURE__ */ jsx21(Input, { value: id, ref: inputRef, disabled: true, className: "border-none! bg-transparent!" }),
1442
+ /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs17(Tooltip, { children: [
1443
+ /* @__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 }) }) }),
1444
+ /* @__PURE__ */ jsx21(TooltipContent, { className: "px-2 py-1 text-xs", children: t("common.actions.copy") })
1445
+ ] }) })
1446
+ ]
1447
+ }
1448
+ )
539
1449
  }
540
1450
  );
541
1451
  }
542
1452
 
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 })
1453
+ // src/components/empty-state.tsx
1454
+ import Link8 from "next/link";
1455
+ import { useTranslations as useTranslations13 } from "next-intl";
1456
+ import { cn as cn11 } from "pelatform-ui";
1457
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
1458
+ function EmptyState({
1459
+ className,
1460
+ icon: Icon,
1461
+ title,
1462
+ description,
1463
+ learnMore,
1464
+ learnMoreText,
1465
+ children
1466
+ }) {
1467
+ const t = useTranslations13();
1468
+ return /* @__PURE__ */ jsxs18("div", { className: cn11("flex flex-col items-center justify-center gap-y-4", className), children: [
1469
+ 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" }) }),
1470
+ /* @__PURE__ */ jsx22("p", { className: "text-center font-medium text-base text-foreground", children: title }),
1471
+ description && /* @__PURE__ */ jsxs18("p", { className: "max-w-sm text-balance text-center text-muted-foreground text-sm", children: [
1472
+ description,
1473
+ " ",
1474
+ learnMore && /* @__PURE__ */ jsxs18(
1475
+ Link8,
1476
+ {
1477
+ href: learnMore,
1478
+ className: "text-foreground underline underline-offset-2 transition-colors hover:text-primary",
1479
+ children: [
1480
+ learnMoreText ?? t("ui.common.learnMore"),
1481
+ " \u2197"
1482
+ ]
1483
+ }
1484
+ )
1485
+ ] }),
1486
+ children
561
1487
  ] });
562
1488
  }
563
1489
 
564
1490
  // src/components/otp-input-group.tsx
565
1491
  import { InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "pelatform-ui/default";
566
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1492
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
567
1493
  function OTPInputGroup({ otpSeparators = 0 }) {
568
1494
  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 })
1495
+ return /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1496
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1497
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 }),
1498
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 }),
1499
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 }),
1500
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1501
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
576
1502
  ] });
577
1503
  }
578
1504
  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 })
1505
+ return /* @__PURE__ */ jsxs19(Fragment7, { children: [
1506
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1507
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1508
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 }),
1509
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 })
584
1510
  ] }),
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 })
1511
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1512
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1513
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 }),
1514
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1515
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
590
1516
  ] })
591
1517
  ] });
592
1518
  }
593
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
594
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
595
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 0 }),
596
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 1 })
1519
+ return /* @__PURE__ */ jsxs19(Fragment7, { children: [
1520
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1521
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 0 }),
1522
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 1 })
597
1523
  ] }),
598
- /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
599
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
600
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 2 }),
601
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 3 })
1524
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1525
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1526
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 2 }),
1527
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 3 })
602
1528
  ] }),
603
- /* @__PURE__ */ jsx9(InputOTPSeparator, {}),
604
- /* @__PURE__ */ jsxs8(InputOTPGroup, { children: [
605
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 4 }),
606
- /* @__PURE__ */ jsx9(InputOTPSlot, { index: 5 })
1529
+ /* @__PURE__ */ jsx23(InputOTPSeparator, {}),
1530
+ /* @__PURE__ */ jsxs19(InputOTPGroup, { children: [
1531
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 4 }),
1532
+ /* @__PURE__ */ jsx23(InputOTPSlot, { index: 5 })
607
1533
  ] })
608
1534
  ] });
609
1535
  }
610
1536
 
611
1537
  // src/components/password-input.tsx
612
- import { useState } from "react";
1538
+ import { useState as useState5 } from "react";
613
1539
  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";
1540
+ import { cn as cn12 } from "pelatform-ui";
1541
+ import { Button as Button8, Input as Input2 } from "pelatform-ui/default";
1542
+ import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
617
1543
  function PasswordInput({
618
1544
  className,
619
1545
  variant,
@@ -621,15 +1547,15 @@ function PasswordInput({
621
1547
  onChange,
622
1548
  ...props
623
1549
  }) {
624
- const [disabled, setDisabled] = useState(true);
625
- const [isVisible, setIsVisible] = useState(false);
626
- return /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
627
- /* @__PURE__ */ jsx10(
1550
+ const [disabled, setDisabled] = useState5(true);
1551
+ const [isVisible, setIsVisible] = useState5(false);
1552
+ return /* @__PURE__ */ jsxs20("div", { className: "relative", children: [
1553
+ /* @__PURE__ */ jsx24(
628
1554
  Input2,
629
1555
  {
630
1556
  type: isVisible && enableToggle ? "text" : "password",
631
1557
  variant,
632
- className: cn8(enableToggle && "pe-10", className),
1558
+ className: cn12(enableToggle && "pe-10", className),
633
1559
  ...props,
634
1560
  onChange: (event) => {
635
1561
  setDisabled(!event.target.value);
@@ -637,9 +1563,9 @@ function PasswordInput({
637
1563
  }
638
1564
  }
639
1565
  ),
640
- enableToggle && /* @__PURE__ */ jsxs9(Fragment3, { children: [
641
- /* @__PURE__ */ jsx10(
642
- Button4,
1566
+ enableToggle && /* @__PURE__ */ jsxs20(Fragment8, { children: [
1567
+ /* @__PURE__ */ jsx24(
1568
+ Button8,
643
1569
  {
644
1570
  type: "button",
645
1571
  variant: "ghost",
@@ -647,10 +1573,10 @@ function PasswordInput({
647
1573
  className: "absolute end-0 top-0 bg-transparent!",
648
1574
  onClick: () => setIsVisible(!isVisible),
649
1575
  disabled,
650
- children: isVisible ? /* @__PURE__ */ jsx10(EyeIcon, {}) : /* @__PURE__ */ jsx10(EyeOffIcon, {})
1576
+ children: isVisible ? /* @__PURE__ */ jsx24(EyeIcon, {}) : /* @__PURE__ */ jsx24(EyeOffIcon, {})
651
1577
  }
652
1578
  ),
653
- /* @__PURE__ */ jsx10("style", { children: `
1579
+ /* @__PURE__ */ jsx24("style", { children: `
654
1580
  .hide-password-toggle::-ms-reveal,
655
1581
  .hide-password-toggle::-ms-clear {
656
1582
  visibility: hidden;
@@ -661,330 +1587,43 @@ function PasswordInput({
661
1587
  ] })
662
1588
  ] });
663
1589
  }
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
1590
  export {
970
1591
  ApiKeyView,
1592
+ AuthLayout,
971
1593
  CardActionComponent,
972
1594
  CardComponent,
973
1595
  CardFooterComponent,
974
1596
  CardHeaderComponent,
1597
+ ConfigProvider,
975
1598
  DialogComponent,
976
1599
  DialogFooterComponent,
977
1600
  DisplayIdCard,
978
1601
  EmptyState,
1602
+ Header,
1603
+ HeaderLeft,
1604
+ HeaderRight,
1605
+ HeaderSidebarMobile,
979
1606
  LanguageSwitcher,
1607
+ LayoutLoader,
1608
+ LayoutProvider,
1609
+ LayoutWrapper,
980
1610
  Logo as LogoDefault,
981
1611
  LogoWithHref,
982
1612
  LogoWithName,
983
1613
  OTPInputGroup,
984
1614
  PasswordInput,
1615
+ SharedProviders,
1616
+ Sidebar,
1617
+ SidebarContent,
1618
+ SidebarContentMenu,
1619
+ SidebarHeaderBack,
985
1620
  SignedInHint,
1621
+ SiteFooter,
1622
+ SiteHeader,
1623
+ SiteHeaderSecondary,
986
1624
  SkeletonInputComponent,
987
1625
  SkeletonViewComponent,
1626
+ Toolbar,
988
1627
  UserAvatar,
989
1628
  UserMenu,
990
1629
  UserView,