@yimingliao/cms 0.0.94 → 0.0.95

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.
@@ -1,12 +1,14 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import { useState, useRef, useCallback, useEffect } from 'react';
4
+ import { usePathname } from 'next/navigation';
4
5
  import { UAParser } from 'ua-parser-js';
5
6
  import { Slot } from '@radix-ui/react-slot';
6
7
  import { cva } from 'class-variance-authority';
7
8
  import { jsx } from 'react/jsx-runtime';
8
9
  import { Loader2Icon } from 'lucide-react';
9
10
  import * as LabelPrimitive from '@radix-ui/react-label';
11
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
10
12
 
11
13
  // src/client/applications/ui/utils.ts
12
14
  var cn = (...inputs) => {
@@ -42,6 +44,17 @@ var useCountdown = (initialTime) => {
42
44
  }, [isCounting]);
43
45
  return { timeLeft, isCounting, startCountdown };
44
46
  };
47
+ var useParentPathname = () => {
48
+ const pathname = usePathname();
49
+ if (pathname === "/") return "/";
50
+ const index = pathname.lastIndexOf("/");
51
+ return index <= 0 ? "/" : pathname.slice(0, index);
52
+ };
53
+
54
+ // src/client/applications/ui/is-confirm.ts
55
+ var isConfirm = (t, key = "ui.dialog.confirm.text") => {
56
+ return confirm(t(key));
57
+ };
45
58
  function useDeviceInfo() {
46
59
  const [deviceInfo, setDeviceInfo] = useState(null);
47
60
  useEffect(() => {
@@ -384,5 +397,25 @@ function Label({ className, ...props }) {
384
397
  }
385
398
  );
386
399
  }
400
+ function Separator({
401
+ className,
402
+ orientation = "horizontal",
403
+ decorative = true,
404
+ ...props
405
+ }) {
406
+ return /* @__PURE__ */ jsx(
407
+ SeparatorPrimitive.Root,
408
+ {
409
+ "data-slot": "separator",
410
+ decorative,
411
+ orientation,
412
+ className: cn(
413
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
414
+ className
415
+ ),
416
+ ...props
417
+ }
418
+ );
419
+ }
387
420
 
388
- export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Spinner, Textarea, cn, useCountdown, useDeviceInfo };
421
+ export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Separator, Spinner, Textarea, cn, isConfirm, useCountdown, useDeviceInfo, useParentPathname };
@@ -6,9 +6,9 @@ import * as _tanstack_query_core from '@tanstack/query-core';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
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
8
  import * as React$1 from 'react';
9
- import { ComponentProps, ReactNode, HTMLAttributes } from 'react';
10
- import { L as LabelProps, B as ButtonProps$1 } from '../label-BF4qxS03.js';
9
+ import { ReactNode, ComponentProps, HTMLAttributes } from 'react';
11
10
  import { LucideIcon } from 'lucide-react';
11
+ import { B as ButtonProps$1, L as LabelProps } from '../label-BF4qxS03.js';
12
12
  import { ClassValue } from 'clsx';
13
13
  import 'zod';
14
14
  import 'zod/v4/core';
@@ -26,18 +26,18 @@ import 'class-variance-authority';
26
26
  import '@radix-ui/react-label';
27
27
 
28
28
  interface UIStates {
29
- isLoading?: boolean;
30
- isDisabled?: boolean;
31
- isError?: boolean;
29
+ isLoading?: boolean | undefined;
30
+ isDisabled?: boolean | undefined;
31
+ isError?: boolean | undefined;
32
32
  }
33
33
  interface FormContext<T> {
34
- formData?: T;
35
- setFormData?: React$1.Dispatch<React$1.SetStateAction<T>>;
34
+ formData?: T | undefined;
35
+ setFormData?: React$1.Dispatch<React$1.SetStateAction<T>> | undefined;
36
36
  }
37
37
  interface FieldContext {
38
- fieldName?: string;
39
- translations?: Translation[];
40
- errors?: string[];
38
+ fieldName?: string | undefined;
39
+ translations?: Translation[] | undefined;
40
+ errors?: string[] | undefined;
41
41
  }
42
42
  interface FormFieldController<T = Record<string, unknown>> extends UIStates, FormContext<T>, FieldContext {
43
43
  }
@@ -349,6 +349,52 @@ declare function createAdminInitializer({ useAdmin, useQuery, verifyAction, }: {
349
349
  verifyAction: ReturnType<typeof createVerifyAction>;
350
350
  }): () => null;
351
351
 
352
+ interface PageHeaderTitleProps {
353
+ icon?: LucideIcon;
354
+ title?: ReactNode;
355
+ subtitle?: ReactNode;
356
+ children?: ReactNode;
357
+ leftChildren?: ReactNode;
358
+ className?: string;
359
+ }
360
+
361
+ type Variant = "default" | "index" | "create" | "show" | "edit" | "batch" | "batch-create" | "trash";
362
+
363
+ interface ButtonProps extends ButtonProps$1, UIStates {
364
+ icon?: LucideIcon | undefined;
365
+ href?: string | undefined;
366
+ openNewTab?: boolean | undefined;
367
+ }
368
+ declare function Button({ icon, href, openNewTab, isDisabled, isLoading, children, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
369
+
370
+ interface InputProps<T = Record<string, unknown>> extends ComponentProps<"input">, FormFieldController<T> {
371
+ }
372
+ declare function Input<T>({ fieldName, setFormData, isLoading, isDisabled, isError, children, ...props }: InputProps<T>): react_jsx_runtime.JSX.Element;
373
+
374
+ interface PageHeaderProps {
375
+ titleProps?: PageHeaderTitleProps;
376
+ leftChildren?: ReactNode;
377
+ rightChildren?: ReactNode;
378
+ variant?: Variant;
379
+ returnButtonProps?: ButtonProps;
380
+ createButtonProps?: ButtonProps;
381
+ createCategoryButtonProps?: ButtonProps;
382
+ editButtonProps?: ButtonProps;
383
+ showButtonProps?: ButtonProps;
384
+ settingButtonProps?: ButtonProps;
385
+ batchButtonProps?: ButtonProps;
386
+ destroyButtonProps?: ButtonProps;
387
+ restoreButtonProps?: ButtonProps;
388
+ isLocked?: boolean;
389
+ isDisabled?: boolean;
390
+ isNotFound?: boolean;
391
+ batchCreateButtonHref?: string;
392
+ selectAllFn?: () => void;
393
+ cancelAllFn?: () => void;
394
+ showTopicSettingButton?: boolean;
395
+ }
396
+ declare function PageHeader(props: PageHeaderProps): react_jsx_runtime.JSX.Element;
397
+
352
398
  declare function Form({ onSubmit, className, ...props }: ComponentProps<"form">): react_jsx_runtime.JSX.Element;
353
399
 
354
400
  interface FieldProps extends LabelProps {
@@ -367,17 +413,6 @@ interface FieldBodyProps extends HTMLAttributes<HTMLDivElement>, UIStates {
367
413
  }
368
414
  declare function FieldBody({ isLoading, isDisabled, isEmpty, className, backgroundClassName, childrenClassName, children, ...props }: FieldBodyProps): react_jsx_runtime.JSX.Element;
369
415
 
370
- interface ButtonProps extends ButtonProps$1, UIStates {
371
- icon?: LucideIcon;
372
- href?: string;
373
- openNewTab?: boolean;
374
- }
375
- declare function Button({ icon, href, openNewTab, isDisabled, isLoading, children, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
376
-
377
- interface InputProps<T = Record<string, unknown>> extends ComponentProps<"input">, FormFieldController<T> {
378
- }
379
- declare function Input<T>({ fieldName, setFormData, isLoading, isDisabled, isError, children, ...props }: InputProps<T>): react_jsx_runtime.JSX.Element;
380
-
381
416
  declare function PasswordInput<T>({ ...props }: InputProps<T>): react_jsx_runtime.JSX.Element;
382
417
 
383
418
  /**
@@ -456,4 +491,4 @@ declare const cn: (...inputs: ClassValue[]) => string;
456
491
 
457
492
  declare function useDeviceInfo(): DeviceInfo | null;
458
493
 
459
- export { AdminProvider, Button, type ButtonProps, Field, FieldBody, Form, Input, type InputProps, PasswordInput, type ShowToastOption, cn, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin, useDeviceInfo };
494
+ export { AdminProvider, Button, type ButtonProps, Field, FieldBody, Form, Input, type InputProps, PageHeader, PasswordInput, type ShowToastOption, cn, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin, useDeviceInfo };
@@ -1,12 +1,12 @@
1
- import { cn, Label, Spinner, Button, InputGroup, InputGroupAddon, InputGroupInput, InputGroupButton, useDeviceInfo, Card, CardHeader, CardTitle, CardContent, useCountdown, CardDescription } from '../chunk-BVWT2DIB.js';
2
- export { cn, useDeviceInfo } from '../chunk-BVWT2DIB.js';
1
+ import { Button, Spinner, InputGroup, InputGroupAddon, InputGroupInput, cn, Separator, Label, InputGroupButton, useDeviceInfo, Card, CardHeader, CardTitle, CardContent, useCountdown, CardDescription, useParentPathname, isConfirm } from '../chunk-FLKUBNE4.js';
2
+ export { cn, useDeviceInfo } from '../chunk-FLKUBNE4.js';
3
3
  import { ensureArray } from '../chunk-OAENV763.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 } from 'react';
8
- import { Asterisk, Eye, EyeOff, Mail } from 'lucide-react';
9
8
  import { useTranslator } from 'intor/react';
9
+ import { Files, Asterisk, Eye, EyeOff, Mail, Trash2, CopyCheck, CopyX, FileSymlink, FileX, FilePlus, FilePen, File, FileStack, FolderSearch, Lock, FolderCog, FileSpreadsheet, Undo2 } from 'lucide-react';
10
10
  import { useRouter, useSearchParams } from 'next/navigation';
11
11
  import Link from 'next/link';
12
12
 
@@ -240,6 +240,362 @@ function createAdminInitializer({
240
240
  return null;
241
241
  };
242
242
  }
243
+
244
+ // src/client/interfaces/styles/constants.ts
245
+ var PAGE_HEADER_HEIGHT = 56;
246
+ function PageHeaderTitle({
247
+ icon,
248
+ title,
249
+ subtitle,
250
+ children,
251
+ leftChildren,
252
+ className
253
+ }) {
254
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3", className), children: [
255
+ leftChildren,
256
+ icon && createElement(icon),
257
+ /* @__PURE__ */ jsxs("div", { className: "flex-center w-fit gap-3 whitespace-nowrap", children: [
258
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: subtitle }),
259
+ /* @__PURE__ */ jsx("p", { className: "scroll-m-20 text-xl font-semibold tracking-tight", children: title })
260
+ ] }),
261
+ children
262
+ ] });
263
+ }
264
+ function Button2({
265
+ icon,
266
+ href,
267
+ openNewTab = false,
268
+ // ui states
269
+ isDisabled = false,
270
+ isLoading = false,
271
+ // base
272
+ children,
273
+ ...props
274
+ }) {
275
+ const router = useRouter();
276
+ const handleClick = () => {
277
+ if (!href) return;
278
+ if (openNewTab) {
279
+ window.open(href, "_blank");
280
+ } else {
281
+ router.push(href);
282
+ }
283
+ };
284
+ return /* @__PURE__ */ jsx(
285
+ Button,
286
+ {
287
+ type: props.type ?? "button",
288
+ disabled: isDisabled || isLoading,
289
+ onClick: props.onClick ?? handleClick,
290
+ ...props,
291
+ children: isLoading ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
292
+ icon && createElement(icon),
293
+ children
294
+ ] })
295
+ }
296
+ );
297
+ }
298
+ function Input({
299
+ // form context
300
+ fieldName,
301
+ setFormData,
302
+ // ui states
303
+ isLoading = false,
304
+ isDisabled = false,
305
+ isError = false,
306
+ // base
307
+ children,
308
+ ...props
309
+ }) {
310
+ return /* @__PURE__ */ jsxs(InputGroup, { "data-disabled": isDisabled || isLoading, children: [
311
+ isLoading ? /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Spinner, {}) }) : /* @__PURE__ */ jsx(
312
+ InputGroupInput,
313
+ {
314
+ disabled: isDisabled || isLoading,
315
+ "aria-invalid": isError,
316
+ onChange: (e) => {
317
+ if (!setFormData || !fieldName) return;
318
+ setFormData((p) => ({ ...p, [fieldName]: e.target.value }));
319
+ },
320
+ ...props
321
+ }
322
+ ),
323
+ children
324
+ ] });
325
+ }
326
+ function ReturnButton({
327
+ icon,
328
+ useIcon = true,
329
+ // use in create/edit page
330
+ useConfirm = false,
331
+ // navigation
332
+ href,
333
+ replace = false,
334
+ pushToParent = false,
335
+ replaceParent = false,
336
+ // base
337
+ className,
338
+ children,
339
+ ...props
340
+ }) {
341
+ const { t } = useTranslator();
342
+ const router = useRouter();
343
+ const parentPath = useParentPathname();
344
+ const handelClick = () => {
345
+ if (useConfirm) {
346
+ if (!isConfirm(t)) return;
347
+ }
348
+ if (href) {
349
+ return replace ? router.replace(href) : router.push(href);
350
+ }
351
+ if (replaceParent) {
352
+ return router.replace(parentPath);
353
+ }
354
+ if (pushToParent) {
355
+ return router.push(parentPath);
356
+ }
357
+ router.back();
358
+ };
359
+ return /* @__PURE__ */ jsx(
360
+ Button2,
361
+ {
362
+ variant: "outline",
363
+ size: "sm",
364
+ icon: useIcon ? icon || Undo2 : void 0,
365
+ onClick: handelClick,
366
+ className,
367
+ ...props,
368
+ children: children ?? t("ui.button.return.text")
369
+ }
370
+ );
371
+ }
372
+ function createIndexPreset(ctx) {
373
+ const { props, t } = ctx;
374
+ return {
375
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
376
+ titleProps: {
377
+ icon: Files,
378
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
379
+ props.settingButtonProps && props.showTopicSettingButton && /* @__PURE__ */ jsx(
380
+ Button2,
381
+ {
382
+ ...props.settingButtonProps,
383
+ variant: "outline",
384
+ icon: FolderCog,
385
+ isDisabled: props.settingButtonProps.isDisabled ?? props.isDisabled,
386
+ children: `${t("ui.button.setting.text")} ${t("resources.topic.text")}`
387
+ }
388
+ ),
389
+ props.createCategoryButtonProps && /* @__PURE__ */ jsx(
390
+ Button2,
391
+ {
392
+ ...props.createCategoryButtonProps,
393
+ variant: "success",
394
+ icon: FileSpreadsheet,
395
+ isDisabled: props.createCategoryButtonProps.isDisabled ?? props.isDisabled,
396
+ children: t("ui.button.create.text")
397
+ }
398
+ ),
399
+ props.createButtonProps && /* @__PURE__ */ jsx(
400
+ Button2,
401
+ {
402
+ variant: "success",
403
+ icon: FilePlus,
404
+ ...props.createButtonProps,
405
+ children: t("ui.button.create.text")
406
+ }
407
+ )
408
+ ] })
409
+ },
410
+ right: props.batchButtonProps && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Button2, { variant: "outline", icon: FileStack, ...props.batchButtonProps, children: /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("ui.button.batch.text") }) }) })
411
+ };
412
+ }
413
+ function createBatchPreset(ctx) {
414
+ const { props, t } = ctx;
415
+ return {
416
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps, children: t("ui.button.exit-batch-mode.text") }) }),
417
+ titleProps: {
418
+ icon: FilePen,
419
+ subtitle: t("ui.page-header.batch.subtitle.text"),
420
+ children: /* @__PURE__ */ jsx(
421
+ Button2,
422
+ {
423
+ variant: "success",
424
+ href: props.batchCreateButtonHref,
425
+ icon: FilePlus,
426
+ children: t("ui.button.batch-create.text")
427
+ }
428
+ )
429
+ },
430
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
431
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.selectAllFn, children: /* @__PURE__ */ jsx(CopyCheck, {}) }),
432
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.cancelAllFn, children: /* @__PURE__ */ jsx(CopyX, {}) }),
433
+ /* @__PURE__ */ jsx(
434
+ Button2,
435
+ {
436
+ ...props.destroyButtonProps,
437
+ variant: "destructive",
438
+ icon: FileX,
439
+ children: t("ui.button.destroy.text")
440
+ }
441
+ )
442
+ ] })
443
+ };
444
+ }
445
+ function createBatchCreatePreset(ctx) {
446
+ const { props, t } = ctx;
447
+ return {
448
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
449
+ titleProps: {
450
+ icon: FilePlus,
451
+ subtitle: t("ui.page-header.batch-create.subtitle.text")
452
+ }
453
+ };
454
+ }
455
+ function createCreatePreset(ctx) {
456
+ const { props, t } = ctx;
457
+ return {
458
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
459
+ titleProps: {
460
+ icon: FilePlus,
461
+ subtitle: t("ui.page-header.create.subtitle.text")
462
+ }
463
+ };
464
+ }
465
+ function createEditPreset(ctx) {
466
+ const { props, t } = ctx;
467
+ return {
468
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
469
+ titleProps: {
470
+ icon: FilePen,
471
+ subtitle: t("ui.page-header.edit.subtitle.text")
472
+ }
473
+ };
474
+ }
475
+ function createShowPreset(ctx) {
476
+ const { props, t } = ctx;
477
+ return {
478
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
479
+ titleProps: {
480
+ icon: File,
481
+ children: !props.isNotFound && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
482
+ props.showButtonProps && /* @__PURE__ */ jsx(
483
+ Button2,
484
+ {
485
+ ...props.showButtonProps,
486
+ variant: "outline",
487
+ icon: FolderSearch,
488
+ isDisabled: props.showButtonProps.isDisabled || props.isDisabled,
489
+ children: `${t("ui.button.show.text")} ${t("resources.related.text")}`
490
+ }
491
+ ),
492
+ props.editButtonProps && /* @__PURE__ */ jsx(
493
+ Button2,
494
+ {
495
+ ...props.editButtonProps,
496
+ variant: "warning",
497
+ icon: FilePen,
498
+ isDisabled: props.editButtonProps.isDisabled || props.isDisabled,
499
+ children: t("ui.button.edit.text")
500
+ }
501
+ ),
502
+ props.destroyButtonProps && /* @__PURE__ */ jsx(
503
+ Button2,
504
+ {
505
+ ...props.destroyButtonProps,
506
+ variant: "destructive",
507
+ icon: FileX,
508
+ isDisabled: props.destroyButtonProps.isDisabled || props.isDisabled,
509
+ children: t("ui.button.destroy.text")
510
+ }
511
+ ),
512
+ /* @__PURE__ */ jsx(
513
+ Lock,
514
+ {
515
+ className: cn(
516
+ props.isLocked && !props.isDisabled ? "opacity-100" : "opacity-0"
517
+ )
518
+ }
519
+ )
520
+ ] })
521
+ },
522
+ right: props.batchButtonProps && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Button2, { variant: "outline", icon: FileStack, ...props.batchButtonProps, children: /* @__PURE__ */ jsx("span", { className: "text-sm", children: t("ui.button.batch.text") }) }) })
523
+ };
524
+ }
525
+ function createTrashPreset(ctx) {
526
+ const { props, t } = ctx;
527
+ return {
528
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
529
+ titleProps: {
530
+ icon: Trash2,
531
+ title: t("main.trash.text")
532
+ },
533
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
534
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.selectAllFn, children: /* @__PURE__ */ jsx(CopyCheck, {}) }),
535
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.cancelAllFn, children: /* @__PURE__ */ jsx(CopyX, {}) }),
536
+ /* @__PURE__ */ jsx(
537
+ Button2,
538
+ {
539
+ ...props.restoreButtonProps,
540
+ variant: "success",
541
+ icon: FileSymlink,
542
+ children: t("ui.button.restore.text")
543
+ }
544
+ ),
545
+ /* @__PURE__ */ jsx(
546
+ Button2,
547
+ {
548
+ ...props.destroyButtonProps,
549
+ variant: "destructive",
550
+ icon: FileX,
551
+ children: t("ui.button.destroy.text")
552
+ }
553
+ )
554
+ ] })
555
+ };
556
+ }
557
+ var PRESET_BUILDERS = {
558
+ default: () => ({ titleProps: { icon: Files } }),
559
+ index: createIndexPreset,
560
+ create: createCreatePreset,
561
+ show: createShowPreset,
562
+ edit: createEditPreset,
563
+ batch: createBatchPreset,
564
+ "batch-create": createBatchCreatePreset,
565
+ trash: createTrashPreset
566
+ };
567
+ function PageHeader(props) {
568
+ const { t } = useTranslator();
569
+ const variant = props.variant ?? "default";
570
+ const isDefault = variant === "default";
571
+ const preset = PRESET_BUILDERS[variant]({ props, t });
572
+ const left = props.leftChildren ?? preset.left;
573
+ const resolvedTitleProps = { ...preset.titleProps, ...props.titleProps };
574
+ const right = props.rightChildren ?? preset.right;
575
+ return /* @__PURE__ */ jsxs("div", { style: { height: PAGE_HEADER_HEIGHT }, children: [
576
+ /* @__PURE__ */ jsxs(
577
+ "div",
578
+ {
579
+ className: cn(
580
+ "relative h-full px-6",
581
+ "flex items-center justify-between gap-3"
582
+ ),
583
+ children: [
584
+ !isDefault && left && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: left }),
585
+ /* @__PURE__ */ jsx(
586
+ PageHeaderTitle,
587
+ {
588
+ className: cn(!isDefault && "absolute left-1/2 -translate-x-1/2"),
589
+ ...resolvedTitleProps
590
+ }
591
+ ),
592
+ right && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-3", children: right })
593
+ ]
594
+ }
595
+ ),
596
+ /* @__PURE__ */ jsx(Separator, {})
597
+ ] });
598
+ }
243
599
  function Form({
244
600
  onSubmit,
245
601
  className,
@@ -327,68 +683,6 @@ function FieldBody({
327
683
  }
328
684
  );
329
685
  }
330
- function Button2({
331
- icon,
332
- href,
333
- openNewTab = false,
334
- // ui states
335
- isDisabled = false,
336
- isLoading = false,
337
- // base
338
- children,
339
- ...props
340
- }) {
341
- const router = useRouter();
342
- const handleClick = () => {
343
- if (!href) return;
344
- if (openNewTab) {
345
- window.open(href, "_blank");
346
- } else {
347
- router.push(href);
348
- }
349
- };
350
- return /* @__PURE__ */ jsx(
351
- Button,
352
- {
353
- type: props.type ?? "button",
354
- disabled: isDisabled || isLoading,
355
- onClick: props.onClick ?? handleClick,
356
- ...props,
357
- children: isLoading ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
358
- icon && createElement(icon),
359
- children
360
- ] })
361
- }
362
- );
363
- }
364
- function Input({
365
- // form context
366
- fieldName,
367
- setFormData,
368
- // ui states
369
- isLoading = false,
370
- isDisabled = false,
371
- isError = false,
372
- // base
373
- children,
374
- ...props
375
- }) {
376
- return /* @__PURE__ */ jsxs(InputGroup, { "data-disabled": isDisabled || isLoading, children: [
377
- isLoading ? /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Spinner, {}) }) : /* @__PURE__ */ jsx(
378
- InputGroupInput,
379
- {
380
- disabled: isDisabled || isLoading,
381
- "aria-invalid": isError,
382
- onChange: (e) => {
383
- if (!setFormData || !fieldName) return;
384
- setFormData((p) => ({ ...p, [fieldName]: e.target.value }));
385
- },
386
- ...props
387
- }
388
- ),
389
- children
390
- ] });
391
- }
392
686
  function PasswordInput({ ...props }) {
393
687
  const [showPassword, setShowPassword] = useState(false);
394
688
  return /* @__PURE__ */ jsx(Input, { type: showPassword ? "text" : "password", ...props, children: /* @__PURE__ */ jsx(InputGroupAddon, { align: "inline-end", children: /* @__PURE__ */ jsx(
@@ -879,4 +1173,4 @@ function createChangePasswordPage({
879
1173
  };
880
1174
  }
881
1175
 
882
- export { AdminProvider, Button2 as Button, Field, FieldBody, Form, Input, PasswordInput, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin };
1176
+ export { AdminProvider, Button2 as Button, Field, FieldBody, Form, Input, PageHeader, PasswordInput, createAdminInitializer, createChangePasswordPage, createEmailUnverifiedPage, createForgotPasswordPage, createRequestInterceptor, createResetPasswordPage, createResponseInterceptor, createSignInPage, createSmartFetch, createUseCommand, createUseQuery, createVerifyEmailPage, handleToast, useAdmin };
@@ -5,6 +5,7 @@ import * as React from 'react';
5
5
  import { ComponentProps } from 'react';
6
6
  import * as class_variance_authority_types from 'class-variance-authority/types';
7
7
  import { VariantProps } from 'class-variance-authority';
8
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
8
9
  import '@radix-ui/react-label';
9
10
 
10
11
  declare function Card({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
@@ -34,4 +35,6 @@ declare function Spinner({ className, ...props }: ComponentProps<"svg">): react_
34
35
 
35
36
  declare function Textarea({ className, ...props }: React.ComponentProps<"textarea">): react_jsx_runtime.JSX.Element;
36
37
 
37
- export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Spinner, Textarea };
38
+ declare function Separator({ className, orientation, decorative, ...props }: React.ComponentProps<typeof SeparatorPrimitive.Root>): react_jsx_runtime.JSX.Element;
39
+
40
+ export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Separator, Spinner, Textarea };
@@ -1 +1 @@
1
- export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Spinner, Textarea } from '../../chunk-BVWT2DIB.js';
1
+ export { Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Label, Separator, Spinner, Textarea } from '../../chunk-FLKUBNE4.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yimingliao/cms",
3
- "version": "0.0.94",
3
+ "version": "0.0.95",
4
4
  "author": "Yiming Liao",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,6 +50,7 @@
50
50
  "dependencies": {
51
51
  "@keyv/redis": "^5.1.6",
52
52
  "@radix-ui/react-label": "^2.1.8",
53
+ "@radix-ui/react-separator": "^1.1.8",
53
54
  "@radix-ui/react-slot": "^1.2.4",
54
55
  "argon2": "^0.44.0",
55
56
  "class-variance-authority": "^0.7.1",