@yimingliao/cms 0.0.106 → 0.0.108

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.
@@ -491,6 +491,13 @@ function formatDateTime(input) {
491
491
  return dateTimeFormatter.format(date);
492
492
  }
493
493
 
494
+ // src/shared/utils/join-url.ts
495
+ function joinUrl(...parts) {
496
+ return parts.filter(Boolean).map(
497
+ (part, i) => i === 0 ? part.replace(/\/+$/, "") : part.replace(/^\/+|\/+$/g, "")
498
+ ).join("/");
499
+ }
500
+
494
501
  // src/shared/units.ts
495
502
  var SIZE = {
496
503
  BYTE: 1,
@@ -501,4 +508,4 @@ var SIZE = {
501
508
  PB: 1024 ** 5
502
509
  };
503
510
 
504
- export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, ensureArray, findTranslation, formatDateTime, formatFileSize, getMediaInfo, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
511
+ export { FILE_TYPES, OG_TYPE_ARRAY, SIZE, TWITTER_CARD_ARRAY, classifyFileType, createBuildArticleMetadata, createBuildTranslations, createBuildWebsiteMetadata, datetimeToDb, datetimeToUi, ensureArray, findTranslation, formatDateTime, formatFileSize, getMediaInfo, joinUrl, jsonArrayToDb, jsonArrayToUi, mimeToExtension, result, serializeJsonLd };
@@ -4,11 +4,13 @@ import * as _tanstack_react_query from '@tanstack/react-query';
4
4
  import { QueryClient, UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';
5
5
  import * as _tanstack_query_core from '@tanstack/query-core';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
- import { c as createVerifyAction, a as createSignInAction, b as createVerifyEmailAction, d as createEmailUnverifiedAction, e as createForgotPasswordAction, f as createResetPasswordAction, g as createChangePasswordAction } from '../create-reset-password-action-D6aTuuqO.js';
8
- import { U as UIStates, F as FormData, a as FormFieldController } from '../types-BUmWwzpD.js';
7
+ import { ThemeProvider as ThemeProvider$1 } from 'next-themes';
8
+ import * as React$1 from 'react';
9
+ import { HTMLAttributes, ReactNode, ComponentProps, InputHTMLAttributes, Dispatch, SetStateAction } from 'react';
10
+ import { c as createVerifyAction, a as createSignOutAction, b as createSignInAction, d as createVerifyEmailAction, e as createEmailUnverifiedAction, f as createForgotPasswordAction, g as createResetPasswordAction, h as createChangePasswordAction } from '../create-reset-password-action-C-B3uh5m.js';
9
11
  import { LucideIcon } from 'lucide-react';
10
- import { B as ButtonProps$1, L as LabelProps } from '../label-BF4qxS03.js';
11
- import { ReactNode, ComponentProps, HTMLAttributes, InputHTMLAttributes, Dispatch, SetStateAction } from 'react';
12
+ import { S as Sidebar, B as ButtonProps$1, L as LabelProps } from '../sidebar-Dei7UxR1.js';
13
+ import { U as UIStates, F as FormData, a as FormFieldController } from '../types-BUmWwzpD.js';
12
14
  import { ClassValue } from 'clsx';
13
15
  import 'zod';
14
16
  import 'zod/v4/core';
@@ -21,9 +23,11 @@ import '@prisma/client';
21
23
  import 'nodemailer';
22
24
  import 'intor';
23
25
  import 'keyv';
26
+ import '@radix-ui/react-label';
24
27
  import 'class-variance-authority/types';
25
28
  import 'class-variance-authority';
26
- import '@radix-ui/react-label';
29
+ import '@radix-ui/react-separator';
30
+ import '@radix-ui/react-tooltip';
27
31
 
28
32
  interface FetchContext {
29
33
  input: string;
@@ -326,12 +330,54 @@ declare function AdminProvider({ children }: {
326
330
  }): react_jsx_runtime.JSX.Element;
327
331
  declare function useAdmin(): AdminContextValue;
328
332
 
333
+ declare function ThemeProvider({ children, ...props }: React$1.ComponentProps<typeof ThemeProvider$1>): react_jsx_runtime.JSX.Element;
334
+
329
335
  declare function createAdminInitializer({ useAdmin, useQuery, verifyAction, }: {
330
336
  useAdmin: () => AdminContextValue;
331
337
  useQuery: ReturnType<typeof createUseQuery>;
332
338
  verifyAction: ReturnType<typeof createVerifyAction>;
333
339
  }): () => null;
334
340
 
341
+ interface ContentContainerProps extends HTMLAttributes<HTMLDivElement> {
342
+ children?: ReactNode;
343
+ isNotFound?: boolean;
344
+ isFixHeight?: boolean;
345
+ }
346
+ declare function ContentContainer({ className, children, isNotFound, isFixHeight, ...props }: ContentContainerProps): react_jsx_runtime.JSX.Element;
347
+
348
+ declare function ContentSkeleton(): react_jsx_runtime.JSX.Element;
349
+
350
+ interface NavItem {
351
+ icon?: LucideIcon;
352
+ title?: string;
353
+ url?: string;
354
+ isSeparator?: boolean;
355
+ items?: NavItem[];
356
+ }
357
+ declare function NavMain({ items }: {
358
+ items: NavItem[];
359
+ }): react_jsx_runtime.JSX.Element;
360
+
361
+ declare function SidebarSkeleton({ ...props }: React$1.ComponentProps<typeof Sidebar>): react_jsx_runtime.JSX.Element;
362
+
363
+ declare function createNavbar({ webUrl, storageUrl, I18nSelector, SignOutButton, }: {
364
+ webUrl: string;
365
+ storageUrl: string;
366
+ I18nSelector: ReactNode;
367
+ SignOutButton: ReactNode;
368
+ }): () => react_jsx_runtime.JSX.Element;
369
+
370
+ declare function createI18nSelector({ enabled, locales, localeDisplay, }: {
371
+ enabled: boolean;
372
+ locales: string[];
373
+ localeDisplay: Record<string, string>;
374
+ }): () => react_jsx_runtime.JSX.Element | null;
375
+
376
+ declare function createSignOutButton(): ({ useCommand, signOutAction, }: {
377
+ useCommand: ReturnType<typeof createUseCommand>;
378
+ signOutAction: ReturnType<typeof createSignOutAction>;
379
+ }) => react_jsx_runtime.JSX.Element;
380
+
335
381
  interface PageHeaderTitleProps {
336
382
  icon?: LucideIcon;
337
383
  title?: ReactNode;
@@ -542,4 +588,4 @@ declare const cn: (...inputs: ClassValue[]) => string;
542
588
 
543
589
  declare function useDeviceInfo(): DeviceInfo | null;
544
590
 
545
- export { AdminProvider, ArrayInput, Button, type ButtonProps, Checkbox, ControlFields, type ControlMeta, Field, FieldBody, FieldsContainer, Form, IndexField, Input, type InputProps, MainFields, PageHeader, PasswordInput, ReturnButton, SearchInput, type ShowToastOption, SideFields, SlugField, Textarea, cn, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin, useDeviceInfo };
591
+ export { AdminProvider, ArrayInput, Button, type ButtonProps, Checkbox, ContentContainer, ContentSkeleton, ControlFields, type ControlMeta, Field, FieldBody, FieldsContainer, Form, IndexField, Input, type InputProps, MainFields, type NavItem, NavMain, PageHeader, PasswordInput, ReturnButton, SearchInput, type ShowToastOption, SideFields, SidebarSkeleton, SlugField, Textarea, ThemeProvider, cn, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createI18nSelector, createNavbar, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSignOutButton, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin, useDeviceInfo };
@@ -1,14 +1,16 @@
1
- import { Button, Spinner, useParentPathname, cn, Separator, Label, InputGroup, InputGroupAddon, InputGroupInput, InputGroupButton, Textarea, Card, useDeviceInfo, CardHeader, CardTitle, CardContent, useCountdown, CardDescription, isConfirm } from '../chunk-FLKUBNE4.js';
2
- export { cn, useDeviceInfo } from '../chunk-FLKUBNE4.js';
3
- import { ensureArray } from '../chunk-OAENV763.js';
1
+ import { cn, useSidebar, SidebarMenuSkeleton, SidebarInset, SIDEBAR_WIDTH, Skeleton, SidebarGroup, SidebarMenu, Collapsible, SidebarMenuItem, SidebarMenuButton, Separator, CollapsibleTrigger, SidebarMenuAction, CollapsibleContent, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton, Sidebar, Button, Spinner, useParentPathname, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, PAGE_HEADER_HEIGHT, Label, FORM_MIDDLE_GAP_WIDTH, FORM_SIDE_FIELDS_WIDTH, InputGroup, InputGroupAddon, InputGroupInput, InputGroupButton, Textarea, Card, useDeviceInfo, CardHeader, CardTitle, CardContent, useCountdown, CardDescription, NAVBAR_HEIGHT, isConfirm, Avatar, AvatarImage, AvatarFallback, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup } from '../chunk-Q654SMCX.js';
2
+ export { cn, useDeviceInfo } from '../chunk-Q654SMCX.js';
3
+ import { ensureArray, findTranslation, joinUrl } from '../chunk-VSV6SQWC.js';
4
4
  import { toast } from 'sonner';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { useMutation, useQuery } from '@tanstack/react-query';
7
7
  import { createContext, useState, useContext, useEffect, createElement, useRef } from 'react';
8
+ import { ThemeProvider as ThemeProvider$1, useTheme } from 'next-themes';
8
9
  import { useTranslator } from 'intor/react';
9
- import { Undo2, Files, Asterisk, Eye, EyeOff, CircleX, CirclePlus, Search, Mail, Trash2, CopyCheck, CopyX, FileSymlink, FileX, FilePlus, FilePen, File, FileStack, FolderSearch, Lock, FolderCog, FileSpreadsheet, Archive, Binary, MapPinCheckInside, Star, House, CircleMinus } from 'lucide-react';
10
- import { useRouter, useSearchParams } from 'next/navigation';
10
+ import { ChevronRight, Undo2, SidebarIcon, House, SquareArrowOutUpRight, Languages, LogOut, Files, Asterisk, Eye, EyeOff, CircleX, CirclePlus, Search, Mail, Sun, Moon, TvMinimal, UserCircle, ChevronsUpDown, PenLine, Trash2, CopyCheck, CopyX, FileSymlink, FileX, FilePlus, FilePen, File, FileStack, FolderSearch, Lock, FolderCog, FileSpreadsheet, Archive, Binary, MapPinCheckInside, Star, CircleMinus } from 'lucide-react';
11
11
  import Link from 'next/link';
12
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation';
13
+ import { Link as Link$1 } from 'intor/next';
12
14
 
13
15
  // src/client/infrastructure/fetch/smart-fetch.ts
14
16
  function createSmartFetch({
@@ -217,6 +219,22 @@ function useAdmin() {
217
219
  if (!ctx) throw new Error("useAdmin must be used within AdminProvider");
218
220
  return ctx;
219
221
  }
222
+ function ThemeProvider({
223
+ children,
224
+ ...props
225
+ }) {
226
+ return /* @__PURE__ */ jsx(
227
+ ThemeProvider$1,
228
+ {
229
+ attribute: "class",
230
+ defaultTheme: "system",
231
+ enableSystem: true,
232
+ disableTransitionOnChange: true,
233
+ ...props,
234
+ children
235
+ }
236
+ );
237
+ }
220
238
  function createAdminInitializer({
221
239
  useAdmin: useAdmin2,
222
240
  useQuery,
@@ -240,29 +258,205 @@ function createAdminInitializer({
240
258
  return null;
241
259
  };
242
260
  }
243
-
244
- // src/client/interfaces/styles/constants.ts
245
- var PAGE_HEADER_HEIGHT = 56;
246
- var FORM_SIDE_FIELDS_WIDTH = 320;
247
- var FORM_MIDDLE_GAP_WIDTH = 24;
248
- function PageHeaderTitle({
249
- icon,
250
- title,
251
- subtitle,
261
+ function ContentContainer({
262
+ className = "",
252
263
  children,
253
- leftChildren,
254
- className
264
+ isNotFound = false,
265
+ isFixHeight,
266
+ ...props
255
267
  }) {
256
- return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", className), children: [
257
- leftChildren,
258
- icon && createElement(icon),
259
- /* @__PURE__ */ jsxs("div", { className: "flex-center w-fit gap-3 whitespace-nowrap", children: [
260
- subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: subtitle }),
261
- /* @__PURE__ */ jsx("p", { className: "scroll-m-20 text-xl font-semibold tracking-tight", children: title })
262
- ] }),
263
- children
268
+ const { t } = useTranslator();
269
+ const ABOVE_HEIGHT = NAVBAR_HEIGHT + PAGE_HEADER_HEIGHT;
270
+ return /* @__PURE__ */ jsx(
271
+ "div",
272
+ {
273
+ style: {
274
+ height: isFixHeight ? `calc(100vh - ${ABOVE_HEIGHT}px)` : "auto"
275
+ },
276
+ className: cn(
277
+ className,
278
+ "relative",
279
+ "flex flex-col gap-4",
280
+ "px-6 pt-6",
281
+ isFixHeight ? "pb-6" : "flex-1 pb-64"
282
+ ),
283
+ ...props,
284
+ children: isNotFound ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t("ui.no-data.text") }) : children
285
+ }
286
+ );
287
+ }
288
+ function ContentSkeleton() {
289
+ const { open } = useSidebar();
290
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1", children: [
291
+ /* @__PURE__ */ jsx(SidebarMenuSkeleton, {}),
292
+ /* @__PURE__ */ jsx(
293
+ SidebarInset,
294
+ {
295
+ style: { width: open ? `calc(100% - ${SIDEBAR_WIDTH})` : "100%" },
296
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-6", children: [
297
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-96" }),
298
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-72" }),
299
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-64" })
300
+ ] })
301
+ }
302
+ )
264
303
  ] });
265
304
  }
305
+ var getMainPath = (path) => "/" + path.split("/").slice(3).filter(Boolean).join("/");
306
+ var toSegments = (path) => path.split("/").filter(Boolean);
307
+ var isSegmentMatch = (current, target) => {
308
+ const currentSeg = toSegments(current);
309
+ const targetSeg = toSegments(target);
310
+ if (targetSeg.length > currentSeg.length) return false;
311
+ return targetSeg.every((seg, i) => currentSeg[i] === seg);
312
+ };
313
+ function NavMain({ items }) {
314
+ const pathname = usePathname();
315
+ const [openItems, setOpenItems] = useState([]);
316
+ const toggleItem = (title, open) => {
317
+ setOpenItems(
318
+ (prev) => open ? [...prev, title] : prev.filter((t) => t !== title)
319
+ );
320
+ };
321
+ const parsedPathname = getMainPath(pathname);
322
+ useEffect(() => {
323
+ const matched = items.filter(
324
+ (item) => item.url ? isSegmentMatch(parsedPathname, getMainPath(item.url)) : false
325
+ ).map((item) => item.title || "");
326
+ queueMicrotask(() => setOpenItems(matched));
327
+ }, [parsedPathname, items]);
328
+ return /* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: items.map((item, index) => {
329
+ const isOpen = openItems.includes(item.title || "");
330
+ const parsedUrl = getMainPath(item.url || "");
331
+ const isCurrentPath = item.url ? isSegmentMatch(parsedPathname, parsedUrl) : false;
332
+ return /* @__PURE__ */ jsx(
333
+ Collapsible,
334
+ {
335
+ asChild: true,
336
+ open: isOpen,
337
+ onOpenChange: (open) => toggleItem(item.title || "", open),
338
+ children: /* @__PURE__ */ jsxs(SidebarMenuItem, { className: "[&>button]:top-2 [&>button]:size-6", children: [
339
+ !item.isSeparator ? /* @__PURE__ */ jsx(
340
+ SidebarMenuButton,
341
+ {
342
+ asChild: true,
343
+ size: "md",
344
+ isActive: isCurrentPath,
345
+ children: /* @__PURE__ */ jsxs(Link, { href: item.url || "", children: [
346
+ item.icon && /* @__PURE__ */ jsx(item.icon, {}),
347
+ /* @__PURE__ */ jsx("span", { children: item.title })
348
+ ] })
349
+ }
350
+ ) : /* @__PURE__ */ jsx(Separator, {}),
351
+ item.items?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
352
+ /* @__PURE__ */ jsx(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(SidebarMenuAction, { className: "data-[state=open]:rotate-90", children: [
353
+ /* @__PURE__ */ jsx(ChevronRight, {}),
354
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Toggle" })
355
+ ] }) }),
356
+ /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(SidebarMenuSub, { children: item.items?.map((subItem, index2) => {
357
+ const parsedPathname2 = getMainPath(pathname);
358
+ const parsedUrl2 = getMainPath(subItem.url || "");
359
+ const isCurrentPath2 = subItem.url ? isSegmentMatch(parsedPathname2, parsedUrl2) : false;
360
+ return /* @__PURE__ */ jsx(SidebarMenuSubItem, { children: !subItem.isSeparator ? /* @__PURE__ */ jsx(
361
+ SidebarMenuSubButton,
362
+ {
363
+ asChild: true,
364
+ size: "lg",
365
+ isActive: isCurrentPath2,
366
+ children: /* @__PURE__ */ jsxs(Link, { href: subItem.url || "", children: [
367
+ subItem.icon && /* @__PURE__ */ jsx(subItem.icon, {}),
368
+ /* @__PURE__ */ jsx("span", { children: subItem.title })
369
+ ] })
370
+ }
371
+ ) : /* @__PURE__ */ jsx(Separator, {}) }, index2);
372
+ }) }) })
373
+ ] }) : null
374
+ ] })
375
+ },
376
+ index
377
+ );
378
+ }) }) });
379
+ }
380
+ function SidebarSkeleton({
381
+ ...props
382
+ }) {
383
+ return /* @__PURE__ */ jsx(
384
+ Sidebar,
385
+ {
386
+ className: "top-(--header-height) h-[calc(100svh-var(--header-height))]!",
387
+ ...props,
388
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 p-3", children: [
389
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
390
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
391
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
392
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
393
+ ] })
394
+ }
395
+ );
396
+ }
397
+
398
+ // src/constants/keys/auth.ts
399
+ var AUTH_KEYS = {
400
+ signIn: { key: "sign-in" },
401
+ forgotPassword: { key: "forgot-password" },
402
+ changePassword: { key: "change-password" }};
403
+
404
+ // src/constants/keys/main.ts
405
+ var MAIN_KEYS = {
406
+ dashboard: { key: "dashboard" },
407
+ cmsSettings: { key: "cms-settings" }};
408
+
409
+ // src/constants/keys/resources.ts
410
+ var RESOURCES_KEYS = {
411
+ admin: { key: "admin" }};
412
+
413
+ // src/constants/keys/index.ts
414
+ var KEYS = {
415
+ main: MAIN_KEYS,
416
+ auth: AUTH_KEYS,
417
+ resources: RESOURCES_KEYS};
418
+
419
+ // src/constants/paths/cms-path.ts
420
+ var CMS_PATH = "/cms";
421
+
422
+ // src/constants/paths/main.ts
423
+ var MAIN_PATHS = {
424
+ dashboard: {
425
+ path: `${CMS_PATH}/${KEYS.main.dashboard.key}`
426
+ },
427
+ cmsSettings: {
428
+ path: `${CMS_PATH}/${KEYS.main.dashboard.key}/${KEYS.main.cmsSettings.key}`
429
+ }};
430
+
431
+ // src/constants/paths/auth.ts
432
+ var AUTH_PATHS = {
433
+ signIn: {
434
+ path: `${CMS_PATH}/${KEYS.auth.signIn.key}`
435
+ },
436
+ forgotPassword: {
437
+ path: `${CMS_PATH}/${KEYS.auth.forgotPassword.key}`
438
+ },
439
+ changePassword: {
440
+ path: `${MAIN_PATHS.dashboard.path}/${KEYS.auth.changePassword.key}`
441
+ }
442
+ };
443
+
444
+ // src/constants/paths/resources.ts
445
+ var RESOURCES_PATHS = {
446
+ admin: {
447
+ path: `${MAIN_PATHS.cmsSettings.path}/${KEYS.resources.admin.key}`
448
+ }};
449
+
450
+ // src/constants/paths/index.ts
451
+ var PATHS = {
452
+ main: MAIN_PATHS,
453
+ auth: AUTH_PATHS,
454
+ resources: RESOURCES_PATHS
455
+ };
456
+
457
+ // src/constants/anchor.ts
458
+ var NEW_TAB_TARGET = "_blank";
459
+ var NEW_TAB_REL = "noopener noreferrer";
266
460
  function Button2({
267
461
  icon,
268
462
  href,
@@ -343,6 +537,206 @@ function ReturnButton({
343
537
  }
344
538
  );
345
539
  }
540
+ function NavUser({
541
+ storageUrl,
542
+ admin,
543
+ isLoading = false,
544
+ SignOutButton
545
+ }) {
546
+ const { t, locale } = useTranslator();
547
+ const { name } = findTranslation(admin?.translations, locale);
548
+ if (isLoading)
549
+ return /* @__PURE__ */ jsx(Button2, { variant: "outline", size: "icon", disabled: true, className: "w-64", children: /* @__PURE__ */ jsx(Spinner, {}) });
550
+ if (!admin)
551
+ return /* @__PURE__ */ jsx(Button2, { variant: "outline", size: "icon", disabled: true, className: "w-64", children: /* @__PURE__ */ jsx(UserCircle, { className: "size-4" }) });
552
+ return /* @__PURE__ */ jsx(SidebarMenu, { className: "w-64", children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
553
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
554
+ SidebarMenuButton,
555
+ {
556
+ size: "lg",
557
+ className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
558
+ disabled: isLoading,
559
+ children: [
560
+ /* @__PURE__ */ jsxs(Avatar, { className: "h-8 w-8 rounded-lg", children: [
561
+ admin.avatarImage?.key && /* @__PURE__ */ jsx(
562
+ AvatarImage,
563
+ {
564
+ src: joinUrl(storageUrl, admin.avatarImage?.key),
565
+ alt: name ?? ""
566
+ }
567
+ ),
568
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "rounded-lg" })
569
+ ] }),
570
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
571
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: name }),
572
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs", children: admin.email })
573
+ ] }),
574
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-auto size-4" })
575
+ ]
576
+ }
577
+ ) }),
578
+ /* @__PURE__ */ jsxs(
579
+ DropdownMenuContent,
580
+ {
581
+ className: "w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg",
582
+ side: "bottom",
583
+ align: "end",
584
+ sideOffset: 4,
585
+ children: [
586
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "p-0 font-normal", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-1 py-1.5 text-left text-sm", children: [
587
+ /* @__PURE__ */ jsxs(Avatar, { className: "h-8 w-8 rounded-lg", children: [
588
+ admin.avatarImage?.key && /* @__PURE__ */ jsx(
589
+ AvatarImage,
590
+ {
591
+ src: joinUrl(storageUrl, admin.avatarImage?.key),
592
+ alt: name ?? ""
593
+ }
594
+ ),
595
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "rounded-lg" })
596
+ ] }),
597
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
598
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: name }),
599
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs", children: admin.email })
600
+ ] })
601
+ ] }) }),
602
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
603
+ /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(Link, { href: PATHS.auth.changePassword.path, children: /* @__PURE__ */ jsxs(DropdownMenuItem, { children: [
604
+ /* @__PURE__ */ jsx(PenLine, {}),
605
+ t("auth.change-password.text")
606
+ ] }) }) }),
607
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
608
+ SignOutButton
609
+ ]
610
+ }
611
+ )
612
+ ] }) }) });
613
+ }
614
+ function ThemeSelector() {
615
+ const { setTheme } = useTheme();
616
+ const { t } = useTranslator();
617
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
618
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button2, { variant: "outline", size: "icon", children: [
619
+ /* @__PURE__ */ jsx(Sun, { className: "h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
620
+ /* @__PURE__ */ jsx(Moon, { className: "absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
621
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Select theme" })
622
+ ] }) }),
623
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
624
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setTheme("light"), children: [
625
+ /* @__PURE__ */ jsx(Sun, {}),
626
+ t("ui.layout.navbar.theme.light.text")
627
+ ] }),
628
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setTheme("dark"), children: [
629
+ /* @__PURE__ */ jsx(Moon, {}),
630
+ t("ui.layout.navbar.theme.dark.text")
631
+ ] }),
632
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setTheme("system"), children: [
633
+ /* @__PURE__ */ jsx(TvMinimal, {}),
634
+ t("ui.layout.navbar.theme.system.text")
635
+ ] })
636
+ ] })
637
+ ] });
638
+ }
639
+ function createNavbar({
640
+ webUrl,
641
+ storageUrl,
642
+ I18nSelector,
643
+ SignOutButton
644
+ }) {
645
+ return function Navbar() {
646
+ const { toggleSidebar } = useSidebar();
647
+ const { admin, isLoading } = useAdmin();
648
+ const { t } = useTranslator();
649
+ return /* @__PURE__ */ jsx("header", { className: "bg-background sticky top-0 z-50 flex w-full items-center border-b", children: /* @__PURE__ */ jsxs("div", { className: "flex h-(--header-height) w-full items-center gap-2 px-2", children: [
650
+ /* @__PURE__ */ jsx(
651
+ Button2,
652
+ {
653
+ className: "h-8 w-8",
654
+ variant: "ghost",
655
+ size: "icon",
656
+ onClick: toggleSidebar,
657
+ children: /* @__PURE__ */ jsx(SidebarIcon, {})
658
+ }
659
+ ),
660
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mr-2 h-4" }),
661
+ /* @__PURE__ */ jsx(Button2, { variant: "outline", asChild: true, children: /* @__PURE__ */ jsx(Link, { href: PATHS.main.dashboard.path, children: /* @__PURE__ */ jsx(House, {}) }) }),
662
+ /* @__PURE__ */ jsx(Button2, { variant: "outline", asChild: true, children: /* @__PURE__ */ jsxs(Link, { href: webUrl, target: NEW_TAB_TARGET, rel: NEW_TAB_REL, children: [
663
+ /* @__PURE__ */ jsx(SquareArrowOutUpRight, {}),
664
+ t("ui.layout.navbar.website-homepage.text")
665
+ ] }) }),
666
+ /* @__PURE__ */ jsx("div", { className: "ml-auto" }),
667
+ I18nSelector,
668
+ /* @__PURE__ */ jsx(ThemeSelector, {}),
669
+ /* @__PURE__ */ jsx(
670
+ NavUser,
671
+ {
672
+ storageUrl,
673
+ SignOutButton,
674
+ admin,
675
+ isLoading
676
+ }
677
+ )
678
+ ] }) });
679
+ };
680
+ }
681
+ function createI18nSelector({
682
+ enabled,
683
+ locales,
684
+ localeDisplay
685
+ }) {
686
+ return function I18nSelector() {
687
+ if (!enabled) return null;
688
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
689
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button2, { variant: "outline", size: "icon", children: [
690
+ /* @__PURE__ */ jsx(Languages, {}),
691
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Switch Languages" })
692
+ ] }) }),
693
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: locales.map((locale) => /* @__PURE__ */ jsx(Link$1, { locale, children: /* @__PURE__ */ jsx(DropdownMenuItem, { children: localeDisplay[locale] }) }, locale)) })
694
+ ] });
695
+ };
696
+ }
697
+ function createSignOutButton() {
698
+ return function SignOutButton({
699
+ useCommand,
700
+ signOutAction
701
+ }) {
702
+ const { t } = useTranslator();
703
+ const router = useRouter();
704
+ const { setAdmin } = useAdmin();
705
+ const { execute, isRedirecting } = useCommand(signOutAction, {
706
+ onSuccess: () => {
707
+ setAdmin(null);
708
+ router.push(PATHS.auth.signIn.path);
709
+ }
710
+ });
711
+ const handleSignOut = () => {
712
+ if (!isConfirm(t)) return;
713
+ void execute();
714
+ };
715
+ const buttonText = isRedirecting ? /* @__PURE__ */ jsx(Spinner, {}) : t("auth.sign-out.text");
716
+ return /* @__PURE__ */ jsx("button", { onClick: handleSignOut, className: "w-full", children: /* @__PURE__ */ jsxs(DropdownMenuItem, { variant: "destructive", children: [
717
+ /* @__PURE__ */ jsx(LogOut, {}),
718
+ buttonText
719
+ ] }) });
720
+ };
721
+ }
722
+ function PageHeaderTitle({
723
+ icon,
724
+ title,
725
+ subtitle,
726
+ children,
727
+ leftChildren,
728
+ className
729
+ }) {
730
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", className), children: [
731
+ leftChildren,
732
+ icon && createElement(icon),
733
+ /* @__PURE__ */ jsxs("div", { className: "flex-center w-fit gap-3 whitespace-nowrap", children: [
734
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: subtitle }),
735
+ /* @__PURE__ */ jsx("p", { className: "scroll-m-20 text-xl font-semibold tracking-tight", children: title })
736
+ ] }),
737
+ children
738
+ ] });
739
+ }
346
740
  function createIndexPreset(ctx) {
347
741
  const { props, t } = ctx;
348
742
  return {
@@ -1509,60 +1903,6 @@ function ControlFields({
1509
1903
  }
1510
1904
  ) });
1511
1905
  }
1512
-
1513
- // src/constants/keys/auth.ts
1514
- var AUTH_KEYS = {
1515
- signIn: { key: "sign-in" },
1516
- forgotPassword: { key: "forgot-password" }};
1517
-
1518
- // src/constants/keys/main.ts
1519
- var MAIN_KEYS = {
1520
- dashboard: { key: "dashboard" },
1521
- cmsSettings: { key: "cms-settings" }};
1522
-
1523
- // src/constants/keys/resources.ts
1524
- var RESOURCES_KEYS = {
1525
- admin: { key: "admin" }};
1526
-
1527
- // src/constants/keys/index.ts
1528
- var KEYS = {
1529
- main: MAIN_KEYS,
1530
- auth: AUTH_KEYS,
1531
- resources: RESOURCES_KEYS};
1532
-
1533
- // src/constants/paths/cms-path.ts
1534
- var CMS_PATH = "/cms";
1535
-
1536
- // src/constants/paths/main.ts
1537
- var MAIN_PATHS = {
1538
- dashboard: {
1539
- path: `${CMS_PATH}/${KEYS.main.dashboard.key}`
1540
- },
1541
- cmsSettings: {
1542
- path: `${CMS_PATH}/${KEYS.main.dashboard.key}/${KEYS.main.cmsSettings.key}`
1543
- }};
1544
-
1545
- // src/constants/paths/auth.ts
1546
- var AUTH_PATHS = {
1547
- signIn: {
1548
- path: `${CMS_PATH}/${KEYS.auth.signIn.key}`
1549
- },
1550
- forgotPassword: {
1551
- path: `${CMS_PATH}/${KEYS.auth.forgotPassword.key}`
1552
- }};
1553
-
1554
- // src/constants/paths/resources.ts
1555
- var RESOURCES_PATHS = {
1556
- admin: {
1557
- path: `${MAIN_PATHS.cmsSettings.path}/${KEYS.resources.admin.key}`
1558
- }};
1559
-
1560
- // src/constants/paths/index.ts
1561
- var PATHS = {
1562
- main: MAIN_PATHS,
1563
- auth: AUTH_PATHS,
1564
- resources: RESOURCES_PATHS
1565
- };
1566
1906
  function createSignInPage({
1567
1907
  useCommand,
1568
1908
  signInAction
@@ -1986,4 +2326,4 @@ function createChangePasswordPage({
1986
2326
  };
1987
2327
  }
1988
2328
 
1989
- export { AdminProvider, ArrayInput, Button2 as Button, Checkbox, ControlFields, Field, FieldBody, FieldsContainer, Form, IndexField, Input, MainFields, PageHeader, PasswordInput, ReturnButton, SearchInput, SideFields, SlugField, Textarea2 as Textarea, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin };
2329
+ export { AdminProvider, ArrayInput, Button2 as Button, Checkbox, ContentContainer, ContentSkeleton, ControlFields, Field, FieldBody, FieldsContainer, Form, IndexField, Input, MainFields, NavMain, PageHeader, PasswordInput, ReturnButton, SearchInput, SideFields, SidebarSkeleton, SlugField, Textarea2 as Textarea, ThemeProvider, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createI18nSelector, createNavbar, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSignOutButton, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin };