@yimingliao/cms 0.0.94 → 0.0.96

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,16 +413,11 @@ 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;
416
+ declare function FieldsContainer({ className, children, ...props }: ComponentProps<"div">): react_jsx_runtime.JSX.Element;
376
417
 
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;
418
+ declare function MainFields({ className, children, ...props }: ComponentProps<"div">): react_jsx_runtime.JSX.Element;
419
+
420
+ declare function SideFields({ className, children, ...props }: ComponentProps<"div">): react_jsx_runtime.JSX.Element;
380
421
 
381
422
  declare function PasswordInput<T>({ ...props }: InputProps<T>): react_jsx_runtime.JSX.Element;
382
423
 
@@ -456,4 +497,4 @@ declare const cn: (...inputs: ClassValue[]) => string;
456
497
 
457
498
  declare function useDeviceInfo(): DeviceInfo | null;
458
499
 
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 };
500
+ export { AdminProvider, Button, type ButtonProps, Field, FieldBody, FieldsContainer, Form, Input, type InputProps, MainFields, PageHeader, PasswordInput, type ShowToastOption, SideFields, 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,364 @@ 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
+ var FORM_SIDE_FIELDS_WIDTH = 320;
247
+ var FORM_MIDDLE_GAP_WIDTH = 24;
248
+ function PageHeaderTitle({
249
+ icon,
250
+ title,
251
+ subtitle,
252
+ children,
253
+ leftChildren,
254
+ className
255
+ }) {
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
264
+ ] });
265
+ }
266
+ function Button2({
267
+ icon,
268
+ href,
269
+ openNewTab = false,
270
+ // ui states
271
+ isDisabled = false,
272
+ isLoading = false,
273
+ // base
274
+ children,
275
+ ...props
276
+ }) {
277
+ const router = useRouter();
278
+ const handleClick = () => {
279
+ if (!href) return;
280
+ if (openNewTab) {
281
+ window.open(href, "_blank");
282
+ } else {
283
+ router.push(href);
284
+ }
285
+ };
286
+ return /* @__PURE__ */ jsx(
287
+ Button,
288
+ {
289
+ type: props.type ?? "button",
290
+ disabled: isDisabled || isLoading,
291
+ onClick: props.onClick ?? handleClick,
292
+ ...props,
293
+ children: isLoading ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
294
+ icon && createElement(icon),
295
+ children
296
+ ] })
297
+ }
298
+ );
299
+ }
300
+ function Input({
301
+ // form context
302
+ fieldName,
303
+ setFormData,
304
+ // ui states
305
+ isLoading = false,
306
+ isDisabled = false,
307
+ isError = false,
308
+ // base
309
+ children,
310
+ ...props
311
+ }) {
312
+ return /* @__PURE__ */ jsxs(InputGroup, { "data-disabled": isDisabled || isLoading, children: [
313
+ isLoading ? /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Spinner, {}) }) : /* @__PURE__ */ jsx(
314
+ InputGroupInput,
315
+ {
316
+ disabled: isDisabled || isLoading,
317
+ "aria-invalid": isError,
318
+ onChange: (e) => {
319
+ if (!setFormData || !fieldName) return;
320
+ setFormData((p) => ({ ...p, [fieldName]: e.target.value }));
321
+ },
322
+ ...props
323
+ }
324
+ ),
325
+ children
326
+ ] });
327
+ }
328
+ function ReturnButton({
329
+ icon,
330
+ useIcon = true,
331
+ // use in create/edit page
332
+ useConfirm = false,
333
+ // navigation
334
+ href,
335
+ replace = false,
336
+ pushToParent = false,
337
+ replaceParent = false,
338
+ // base
339
+ className,
340
+ children,
341
+ ...props
342
+ }) {
343
+ const { t } = useTranslator();
344
+ const router = useRouter();
345
+ const parentPath = useParentPathname();
346
+ const handelClick = () => {
347
+ if (useConfirm) {
348
+ if (!isConfirm(t)) return;
349
+ }
350
+ if (href) {
351
+ return replace ? router.replace(href) : router.push(href);
352
+ }
353
+ if (replaceParent) {
354
+ return router.replace(parentPath);
355
+ }
356
+ if (pushToParent) {
357
+ return router.push(parentPath);
358
+ }
359
+ router.back();
360
+ };
361
+ return /* @__PURE__ */ jsx(
362
+ Button2,
363
+ {
364
+ variant: "outline",
365
+ size: "sm",
366
+ icon: useIcon ? icon || Undo2 : void 0,
367
+ onClick: handelClick,
368
+ className,
369
+ ...props,
370
+ children: children ?? t("ui.button.return.text")
371
+ }
372
+ );
373
+ }
374
+ function createIndexPreset(ctx) {
375
+ const { props, t } = ctx;
376
+ return {
377
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
378
+ titleProps: {
379
+ icon: Files,
380
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
381
+ props.settingButtonProps && props.showTopicSettingButton && /* @__PURE__ */ jsx(
382
+ Button2,
383
+ {
384
+ ...props.settingButtonProps,
385
+ variant: "outline",
386
+ icon: FolderCog,
387
+ isDisabled: props.settingButtonProps.isDisabled ?? props.isDisabled,
388
+ children: `${t("ui.button.setting.text")} ${t("resources.topic.text")}`
389
+ }
390
+ ),
391
+ props.createCategoryButtonProps && /* @__PURE__ */ jsx(
392
+ Button2,
393
+ {
394
+ ...props.createCategoryButtonProps,
395
+ variant: "success",
396
+ icon: FileSpreadsheet,
397
+ isDisabled: props.createCategoryButtonProps.isDisabled ?? props.isDisabled,
398
+ children: t("ui.button.create.text")
399
+ }
400
+ ),
401
+ props.createButtonProps && /* @__PURE__ */ jsx(
402
+ Button2,
403
+ {
404
+ variant: "success",
405
+ icon: FilePlus,
406
+ ...props.createButtonProps,
407
+ children: t("ui.button.create.text")
408
+ }
409
+ )
410
+ ] })
411
+ },
412
+ 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") }) }) })
413
+ };
414
+ }
415
+ function createBatchPreset(ctx) {
416
+ const { props, t } = ctx;
417
+ return {
418
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps, children: t("ui.button.exit-batch-mode.text") }) }),
419
+ titleProps: {
420
+ icon: FilePen,
421
+ subtitle: t("ui.page-header.batch.subtitle.text"),
422
+ children: /* @__PURE__ */ jsx(
423
+ Button2,
424
+ {
425
+ variant: "success",
426
+ href: props.batchCreateButtonHref,
427
+ icon: FilePlus,
428
+ children: t("ui.button.batch-create.text")
429
+ }
430
+ )
431
+ },
432
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
433
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.selectAllFn, children: /* @__PURE__ */ jsx(CopyCheck, {}) }),
434
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.cancelAllFn, children: /* @__PURE__ */ jsx(CopyX, {}) }),
435
+ /* @__PURE__ */ jsx(
436
+ Button2,
437
+ {
438
+ ...props.destroyButtonProps,
439
+ variant: "destructive",
440
+ icon: FileX,
441
+ children: t("ui.button.destroy.text")
442
+ }
443
+ )
444
+ ] })
445
+ };
446
+ }
447
+ function createBatchCreatePreset(ctx) {
448
+ const { props, t } = ctx;
449
+ return {
450
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
451
+ titleProps: {
452
+ icon: FilePlus,
453
+ subtitle: t("ui.page-header.batch-create.subtitle.text")
454
+ }
455
+ };
456
+ }
457
+ function createCreatePreset(ctx) {
458
+ const { props, t } = ctx;
459
+ return {
460
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
461
+ titleProps: {
462
+ icon: FilePlus,
463
+ subtitle: t("ui.page-header.create.subtitle.text")
464
+ }
465
+ };
466
+ }
467
+ function createEditPreset(ctx) {
468
+ const { props, t } = ctx;
469
+ return {
470
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { useConfirm: true, replaceParent: true, ...props.returnButtonProps }) }),
471
+ titleProps: {
472
+ icon: FilePen,
473
+ subtitle: t("ui.page-header.edit.subtitle.text")
474
+ }
475
+ };
476
+ }
477
+ function createShowPreset(ctx) {
478
+ const { props, t } = ctx;
479
+ return {
480
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
481
+ titleProps: {
482
+ icon: File,
483
+ children: !props.isNotFound && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
484
+ props.showButtonProps && /* @__PURE__ */ jsx(
485
+ Button2,
486
+ {
487
+ ...props.showButtonProps,
488
+ variant: "outline",
489
+ icon: FolderSearch,
490
+ isDisabled: props.showButtonProps.isDisabled || props.isDisabled,
491
+ children: `${t("ui.button.show.text")} ${t("resources.related.text")}`
492
+ }
493
+ ),
494
+ props.editButtonProps && /* @__PURE__ */ jsx(
495
+ Button2,
496
+ {
497
+ ...props.editButtonProps,
498
+ variant: "warning",
499
+ icon: FilePen,
500
+ isDisabled: props.editButtonProps.isDisabled || props.isDisabled,
501
+ children: t("ui.button.edit.text")
502
+ }
503
+ ),
504
+ props.destroyButtonProps && /* @__PURE__ */ jsx(
505
+ Button2,
506
+ {
507
+ ...props.destroyButtonProps,
508
+ variant: "destructive",
509
+ icon: FileX,
510
+ isDisabled: props.destroyButtonProps.isDisabled || props.isDisabled,
511
+ children: t("ui.button.destroy.text")
512
+ }
513
+ ),
514
+ /* @__PURE__ */ jsx(
515
+ Lock,
516
+ {
517
+ className: cn(
518
+ props.isLocked && !props.isDisabled ? "opacity-100" : "opacity-0"
519
+ )
520
+ }
521
+ )
522
+ ] })
523
+ },
524
+ 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") }) }) })
525
+ };
526
+ }
527
+ function createTrashPreset(ctx) {
528
+ const { props, t } = ctx;
529
+ return {
530
+ left: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ReturnButton, { pushToParent: true, ...props.returnButtonProps }) }),
531
+ titleProps: {
532
+ icon: Trash2,
533
+ title: t("main.trash.text")
534
+ },
535
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
536
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.selectAllFn, children: /* @__PURE__ */ jsx(CopyCheck, {}) }),
537
+ /* @__PURE__ */ jsx(Button2, { size: "icon", variant: "outline", onClick: props.cancelAllFn, children: /* @__PURE__ */ jsx(CopyX, {}) }),
538
+ /* @__PURE__ */ jsx(
539
+ Button2,
540
+ {
541
+ ...props.restoreButtonProps,
542
+ variant: "success",
543
+ icon: FileSymlink,
544
+ children: t("ui.button.restore.text")
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsx(
548
+ Button2,
549
+ {
550
+ ...props.destroyButtonProps,
551
+ variant: "destructive",
552
+ icon: FileX,
553
+ children: t("ui.button.destroy.text")
554
+ }
555
+ )
556
+ ] })
557
+ };
558
+ }
559
+ var PRESET_BUILDERS = {
560
+ default: () => ({ titleProps: { icon: Files } }),
561
+ index: createIndexPreset,
562
+ create: createCreatePreset,
563
+ show: createShowPreset,
564
+ edit: createEditPreset,
565
+ batch: createBatchPreset,
566
+ "batch-create": createBatchCreatePreset,
567
+ trash: createTrashPreset
568
+ };
569
+ function PageHeader(props) {
570
+ const { t } = useTranslator();
571
+ const variant = props.variant ?? "default";
572
+ const isDefault = variant === "default";
573
+ const preset = PRESET_BUILDERS[variant]({ props, t });
574
+ const left = props.leftChildren ?? preset.left;
575
+ const resolvedTitleProps = { ...preset.titleProps, ...props.titleProps };
576
+ const right = props.rightChildren ?? preset.right;
577
+ return /* @__PURE__ */ jsxs("div", { style: { height: PAGE_HEADER_HEIGHT }, children: [
578
+ /* @__PURE__ */ jsxs(
579
+ "div",
580
+ {
581
+ className: cn(
582
+ "relative h-full px-6",
583
+ "flex items-center justify-between gap-3"
584
+ ),
585
+ children: [
586
+ !isDefault && left && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: left }),
587
+ /* @__PURE__ */ jsx(
588
+ PageHeaderTitle,
589
+ {
590
+ className: cn(!isDefault && "absolute left-1/2 -translate-x-1/2"),
591
+ ...resolvedTitleProps
592
+ }
593
+ ),
594
+ right && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-3", children: right })
595
+ ]
596
+ }
597
+ ),
598
+ /* @__PURE__ */ jsx(Separator, {})
599
+ ] });
600
+ }
243
601
  function Form({
244
602
  onSubmit,
245
603
  className,
@@ -327,67 +685,51 @@ function FieldBody({
327
685
  }
328
686
  );
329
687
  }
330
- function Button2({
331
- icon,
332
- href,
333
- openNewTab = false,
334
- // ui states
335
- isDisabled = false,
336
- isLoading = false,
337
- // base
688
+ function FieldsContainer({
689
+ className = "",
338
690
  children,
339
691
  ...props
340
692
  }) {
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);
693
+ return /* @__PURE__ */ jsx(
694
+ "div",
695
+ {
696
+ className: cn("relative flex w-full", className),
697
+ style: { gap: FORM_MIDDLE_GAP_WIDTH },
698
+ ...props,
699
+ children
348
700
  }
349
- };
701
+ );
702
+ }
703
+ function MainFields({
704
+ className,
705
+ children,
706
+ ...props
707
+ }) {
708
+ const sideWidth = FORM_SIDE_FIELDS_WIDTH + FORM_MIDDLE_GAP_WIDTH;
350
709
  return /* @__PURE__ */ jsx(
351
- Button,
710
+ "div",
352
711
  {
353
- type: props.type ?? "button",
354
- disabled: isDisabled || isLoading,
355
- onClick: props.onClick ?? handleClick,
712
+ className: cn("relative", "flex flex-1 flex-col gap-6", className),
713
+ style: { maxWidth: `calc(100% - ${sideWidth}px)` },
356
714
  ...props,
357
- children: isLoading ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
358
- icon && createElement(icon),
359
- children
360
- ] })
715
+ children
361
716
  }
362
717
  );
363
718
  }
364
- function Input({
365
- // form context
366
- fieldName,
367
- setFormData,
368
- // ui states
369
- isLoading = false,
370
- isDisabled = false,
371
- isError = false,
372
- // base
719
+ function SideFields({
720
+ className,
373
721
  children,
374
722
  ...props
375
723
  }) {
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
- ] });
724
+ return /* @__PURE__ */ jsx(
725
+ "div",
726
+ {
727
+ className: cn("relative", "min-h-full", className),
728
+ style: { width: `${FORM_SIDE_FIELDS_WIDTH}px` },
729
+ ...props,
730
+ children: /* @__PURE__ */ jsx("div", { className: cn("sticky top-24", "flex flex-col gap-6"), children })
731
+ }
732
+ );
391
733
  }
392
734
  function PasswordInput({ ...props }) {
393
735
  const [showPassword, setShowPassword] = useState(false);
@@ -879,4 +1221,4 @@ function createChangePasswordPage({
879
1221
  };
880
1222
  }
881
1223
 
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 };
1224
+ export { AdminProvider, Button2 as Button, Field, FieldBody, FieldsContainer, Form, Input, MainFields, PageHeader, PasswordInput, SideFields, 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.96",
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",