@questpie/admin 3.5.3 → 3.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/builder/index.d.mts +1 -1
- package/dist/client/builder/types/collection-types.d.mts +80 -5
- package/dist/client/builder/types/common.d.mts +5 -0
- package/dist/client/builder/types/field-types.d.mts +41 -1
- package/dist/client/builder/view/view.d.mts +3 -2
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/fields/boolean-field.mjs +2 -1
- package/dist/client/components/fields/date-field.mjs +2 -1
- package/dist/client/components/fields/datetime-field.mjs +2 -1
- package/dist/client/components/fields/email-field.mjs +2 -1
- package/dist/client/components/fields/field-utils.d.mts +11 -0
- package/dist/client/components/fields/field-utils.mjs +3 -1
- package/dist/client/components/fields/field-wrapper.mjs +3 -3
- package/dist/client/components/fields/number-field.mjs +2 -1
- package/dist/client/components/fields/object-field.mjs +2 -1
- package/dist/client/components/fields/relation/displays/types.mjs +3 -3
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +2 -1
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -2
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +2 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +3 -2
- package/dist/client/components/fields/rich-text-editor/index.mjs +4 -3
- package/dist/client/components/fields/select-field.mjs +2 -1
- package/dist/client/components/fields/text-field.mjs +2 -1
- package/dist/client/components/fields/textarea-field.mjs +2 -1
- package/dist/client/components/fields/time-field.mjs +2 -1
- package/dist/client/components/layout/field-layout-renderer.mjs +4 -4
- package/dist/client/components/media/media-grid.mjs +2 -1
- package/dist/client/components/primitives/asset-preview.mjs +4 -2
- package/dist/client/components/primitives/dropzone.d.mts +100 -0
- package/dist/client/components/primitives/field-select-control.mjs +2 -1
- package/dist/client/components/ui/button.d.mts +23 -0
- package/dist/client/components/ui/button.mjs +2 -2
- package/dist/client/components/ui/dropdown-menu.d.mts +49 -0
- package/dist/client/components/ui/dropdown-menu.mjs +22 -1
- package/dist/client/components/ui/popover.mjs +1 -1
- package/dist/client/components/ui/search-input.d.mts +56 -0
- package/dist/client/components/ui/select.mjs +2 -2
- package/dist/client/components/ui/sheet.d.mts +40 -0
- package/dist/client/components/ui/table.d.mts +49 -0
- package/dist/client/components/ui/table.mjs +15 -1
- package/dist/client/components/ui/tooltip.d.mts +21 -0
- package/dist/client/contexts/focus-context.d.mts +2 -2
- package/dist/client/hooks/use-admin-config.mjs +20 -1
- package/dist/client/hooks/use-autosave.mjs +91 -0
- package/dist/client/hooks/use-collection.mjs +65 -23
- package/dist/client/hooks/use-upload.d.mts +40 -0
- package/dist/client/hooks/use-upload.mjs +4 -2
- package/dist/client/i18n/hooks.d.mts +20 -0
- package/dist/client/lib/utils.d.mts +6 -0
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/runtime/provider.mjs +22 -3
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +22 -18
- package/dist/client/utils/asset-url.mjs +27 -0
- package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
- package/dist/client/views/auth/auth-layout.d.mts +3 -3
- package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/reset-password-form.d.mts +2 -2
- package/dist/client/views/auth/setup-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +4 -4
- package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +7 -0
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +3 -2
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs +3 -2
- package/dist/client/views/collection/cells/upload-cells.mjs +2 -1
- package/dist/client/views/collection/document-view.d.mts +30 -0
- package/dist/client/views/collection/document-view.mjs +377 -0
- package/dist/client/views/collection/field-context.mjs +3 -2
- package/dist/client/views/collection/field-renderer.mjs +2 -2
- package/dist/client/views/collection/form-view.mjs +14 -80
- package/dist/client/views/collection/list-view.mjs +19 -15
- package/dist/client/views/collection/table-view.mjs +1 -1
- package/dist/client/views/layout/admin-layout-provider.mjs +4 -3
- package/dist/client/views/layout/admin-layout.mjs +107 -20
- package/dist/client/views/layout/admin-router.mjs +19 -3
- package/dist/client/views/layout/admin-sidebar.mjs +50 -6
- package/dist/client/views/layout/admin-view-layout.d.mts +36 -0
- package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
- package/dist/client/views/pages/dashboard-page.d.mts +2 -2
- package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
- package/dist/client/views/pages/invite-page.d.mts +2 -2
- package/dist/client/views/pages/login-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client.d.mts +17 -2
- package/dist/client.mjs +16 -1
- package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
- package/dist/factories.d.mts +2 -2
- package/dist/factories.mjs +2 -2
- package/dist/index.d.mts +17 -3
- package/dist/index.mjs +16 -1
- package/dist/server/augmentation/actions.d.mts +5 -0
- package/dist/server/augmentation/form-layout.d.mts +5 -0
- package/dist/server/augmentation/views.d.mts +4 -1
- package/dist/server/fields/blocks.mjs +4 -1
- package/dist/server/fields/reactive-runtime.mjs +3 -0
- package/dist/server/modules/admin/.generated/module.d.mts +1 -1
- package/dist/server/modules/admin/auth-helpers.mjs +7 -1
- package/dist/server/modules/admin/block/introspection.mjs +28 -4
- package/dist/server/modules/admin/block/prefetch.d.mts +11 -0
- package/dist/server/modules/admin/block/prefetch.mjs +108 -27
- package/dist/server/modules/admin/client/.generated/module.d.mts +68 -67
- package/dist/server/modules/admin/client/.generated/module.mjs +2 -0
- package/dist/server/modules/admin/client/views/collection-document.d.mts +6 -0
- package/dist/server/modules/admin/client/views/collection-document.mjs +10 -0
- package/dist/server/modules/admin/collections/account.d.mts +46 -46
- package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -57
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +42 -42
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -50
- package/dist/server/modules/admin/collections/apikey.d.mts +79 -71
- package/dist/server/modules/admin/collections/assets.d.mts +42 -42
- package/dist/server/modules/admin/collections/session.d.mts +45 -45
- package/dist/server/modules/admin/collections/user.d.mts +66 -66
- package/dist/server/modules/admin/collections/verification.d.mts +39 -39
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +34 -4
- package/dist/server/modules/admin/factories.mjs +4 -34
- package/dist/server/modules/admin/routes/admin-config.d.mts +3 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +18 -2
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +10 -4
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/locales.mjs +1 -1
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/preview.mjs +6 -5
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/reactive.mjs +2 -2
- package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
- package/dist/server/modules/admin/routes/setup.d.mts +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin/routes/widget-data.mjs +1 -1
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
- package/dist/server/plugin.mjs +8 -3
- package/dist/server/proxy-factories.d.mts +8 -1
- package/dist/server/proxy-factories.mjs +33 -1
- package/package.json +4 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.mjs";
|
|
2
2
|
import { Button } from "../ui/button.mjs";
|
|
3
|
+
import { resolveAssetUrl } from "../../utils/asset-url.mjs";
|
|
3
4
|
import { Skeleton } from "../ui/skeleton.mjs";
|
|
4
5
|
import { Icon } from "@iconify/react";
|
|
5
6
|
import * as React from "react";
|
|
@@ -76,13 +77,14 @@ function AssetPreview({ asset, pendingFile, onRemove, onEdit, loading = false, p
|
|
|
76
77
|
const isImageType = isImage(mimeType);
|
|
77
78
|
const fileIconName = getFileIconName(mimeType);
|
|
78
79
|
const extension = getExtension(filename, mimeType);
|
|
80
|
+
const assetUrl = resolveAssetUrl(asset.url);
|
|
79
81
|
const thumbnailUrl = React.useMemo(() => {
|
|
80
82
|
if (pendingFile && isImageType) return URL.createObjectURL(pendingFile);
|
|
81
|
-
if (
|
|
83
|
+
if (assetUrl && isImageType) return assetUrl;
|
|
82
84
|
return null;
|
|
83
85
|
}, [
|
|
84
86
|
pendingFile,
|
|
85
|
-
|
|
87
|
+
assetUrl,
|
|
86
88
|
isImageType
|
|
87
89
|
]);
|
|
88
90
|
React.useEffect(() => {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as react_jsx_runtime11 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/client/components/primitives/dropzone.d.ts
|
|
5
|
+
|
|
6
|
+
interface DropzoneProps {
|
|
7
|
+
/**
|
|
8
|
+
* Called when files are dropped or selected
|
|
9
|
+
*/
|
|
10
|
+
onDrop: (files: File[]) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Accepted file types (MIME types or extensions)
|
|
13
|
+
* @example ["image/*", "application/pdf", ".doc"]
|
|
14
|
+
*/
|
|
15
|
+
accept?: string[];
|
|
16
|
+
/**
|
|
17
|
+
* Maximum file size in bytes
|
|
18
|
+
*/
|
|
19
|
+
maxSize?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Whether multiple files can be selected
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
multiple?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Disable the dropzone
|
|
27
|
+
*/
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Show loading state (e.g., during upload)
|
|
31
|
+
*/
|
|
32
|
+
loading?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Current upload progress (0-100)
|
|
35
|
+
*/
|
|
36
|
+
progress?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Visual density of the dropzone.
|
|
39
|
+
* @default "panel"
|
|
40
|
+
*/
|
|
41
|
+
variant?: "panel" | "compact";
|
|
42
|
+
/**
|
|
43
|
+
* Custom label text
|
|
44
|
+
* @default "Drop files here or click to browse"
|
|
45
|
+
*/
|
|
46
|
+
label?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Helper text shown below the label
|
|
49
|
+
*/
|
|
50
|
+
hint?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Error message to display
|
|
53
|
+
*/
|
|
54
|
+
error?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Additional className
|
|
57
|
+
*/
|
|
58
|
+
className?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Children to render inside the dropzone (custom content)
|
|
61
|
+
*/
|
|
62
|
+
children?: React.ReactNode;
|
|
63
|
+
/**
|
|
64
|
+
* Secondary action rendered inside the dropzone.
|
|
65
|
+
*/
|
|
66
|
+
action?: {
|
|
67
|
+
label: string;
|
|
68
|
+
icon?: string;
|
|
69
|
+
onClick: () => void;
|
|
70
|
+
disabled?: boolean;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Callback when validation fails
|
|
74
|
+
*/
|
|
75
|
+
onValidationError?: (errors: ValidationError[]) => void;
|
|
76
|
+
}
|
|
77
|
+
interface ValidationError {
|
|
78
|
+
file: File;
|
|
79
|
+
type: "type" | "size";
|
|
80
|
+
message: string;
|
|
81
|
+
}
|
|
82
|
+
declare function Dropzone({
|
|
83
|
+
onDrop,
|
|
84
|
+
accept,
|
|
85
|
+
maxSize,
|
|
86
|
+
multiple,
|
|
87
|
+
disabled,
|
|
88
|
+
loading,
|
|
89
|
+
progress,
|
|
90
|
+
variant,
|
|
91
|
+
label,
|
|
92
|
+
hint,
|
|
93
|
+
error,
|
|
94
|
+
className,
|
|
95
|
+
children,
|
|
96
|
+
action,
|
|
97
|
+
onValidationError
|
|
98
|
+
}: DropzoneProps): react_jsx_runtime11.JSX.Element;
|
|
99
|
+
//#endregion
|
|
100
|
+
export { Dropzone };
|
|
@@ -6,9 +6,10 @@ import { InputGroup } from "../ui/input-group.mjs";
|
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
|
|
8
8
|
//#region src/client/components/primitives/field-select-control.tsx
|
|
9
|
-
function FieldSelectTrigger({ className, hasValue, asInputGroupControl, ...props }) {
|
|
9
|
+
function FieldSelectTrigger({ className, hasValue, asInputGroupControl, static: staticPress = true, ...props }) {
|
|
10
10
|
return /* @__PURE__ */ jsx(Button, {
|
|
11
11
|
variant: "outline",
|
|
12
|
+
static: staticPress,
|
|
12
13
|
"data-slot": asInputGroupControl ? "input-group-control" : void 0,
|
|
13
14
|
className: cn("qa-field-select-control qa-select-single control-surface w-full justify-between px-3 py-2 font-normal", "hover:bg-surface-low focus-visible:border-border-strong focus-visible:ring-ring/20 aria-expanded:border-border-strong aria-expanded:ring-ring/20 focus-visible:ring-[3px] aria-expanded:ring-[3px]", !hasValue && "text-muted-foreground", asInputGroupControl && "h-full min-w-0 flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0", className),
|
|
14
15
|
...props
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import { Button } from "@base-ui/react/button";
|
|
3
|
+
import { VariantProps } from "class-variance-authority";
|
|
4
|
+
import * as class_variance_authority_types0 from "class-variance-authority/types";
|
|
5
|
+
|
|
6
|
+
//#region src/client/components/ui/button.d.ts
|
|
7
|
+
declare const buttonVariants: (props?: ({
|
|
8
|
+
variant?: "default" | "link" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
|
|
9
|
+
size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
10
|
+
} & class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
11
|
+
type ButtonProps = Button.Props & VariantProps<typeof buttonVariants> & {
|
|
12
|
+
static?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare function Button$1({
|
|
15
|
+
className,
|
|
16
|
+
type,
|
|
17
|
+
variant,
|
|
18
|
+
size,
|
|
19
|
+
static: staticPress,
|
|
20
|
+
...props
|
|
21
|
+
}: ButtonProps): react_jsx_runtime0.JSX.Element;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { Button$1 as Button };
|
|
@@ -6,7 +6,7 @@ import { Button } from "@base-ui/react/button";
|
|
|
6
6
|
import { cva } from "class-variance-authority";
|
|
7
7
|
|
|
8
8
|
//#region src/client/components/ui/button.tsx
|
|
9
|
-
const buttonVariants = cva("qa-button font-chrome group/button text-foreground focus-visible:border-border-strong focus-visible:ring-ring/20 aria-invalid:border-border-strong aria-invalid:ring-ring/20 inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--control-radius)] border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[background-color,color,border-color,box-shadow,transform,opacity] duration-150 ease-out outline-none select-none focus-visible:ring-[3px] active:
|
|
9
|
+
const buttonVariants = cva("qa-button font-chrome group/button text-foreground focus-visible:border-border-strong focus-visible:ring-ring/20 aria-invalid:border-border-strong aria-invalid:ring-ring/20 inline-flex shrink-0 cursor-pointer items-center justify-center rounded-[var(--control-radius)] border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[background-color,color,border-color,box-shadow,transform,opacity] duration-150 ease-out outline-none select-none focus-visible:ring-[3px] active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:active:translate-y-0 aria-invalid:ring-[3px] motion-reduce:active:translate-y-0 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
12
12
|
default: "bg-primary text-primary-foreground shadow-[var(--control-shadow)] hover:opacity-95",
|
|
@@ -39,7 +39,7 @@ function Button$1({ className, type = "button", variant = "default", size = "def
|
|
|
39
39
|
className: cn(buttonVariants({
|
|
40
40
|
variant,
|
|
41
41
|
size
|
|
42
|
-
}), staticPress && "active:
|
|
42
|
+
}), staticPress && "active:translate-y-0", className),
|
|
43
43
|
...props
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as react_jsx_runtime18 from "react/jsx-runtime";
|
|
3
|
+
import { Menu } from "@base-ui/react/menu";
|
|
4
|
+
|
|
5
|
+
//#region src/client/components/ui/dropdown-menu.d.ts
|
|
6
|
+
declare function DropdownMenu({
|
|
7
|
+
...props
|
|
8
|
+
}: Menu.Root.Props): react_jsx_runtime18.JSX.Element;
|
|
9
|
+
declare function DropdownMenuTrigger({
|
|
10
|
+
type,
|
|
11
|
+
...props
|
|
12
|
+
}: Menu.Trigger.Props): react_jsx_runtime18.JSX.Element;
|
|
13
|
+
declare function DropdownMenuContent({
|
|
14
|
+
align,
|
|
15
|
+
alignOffset,
|
|
16
|
+
side,
|
|
17
|
+
sideOffset,
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}: Menu.Popup.Props & Pick<Menu.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">): react_jsx_runtime18.JSX.Element;
|
|
21
|
+
declare function DropdownMenuGroup({
|
|
22
|
+
...props
|
|
23
|
+
}: Menu.Group.Props): react_jsx_runtime18.JSX.Element;
|
|
24
|
+
declare function DropdownMenuLabel({
|
|
25
|
+
className,
|
|
26
|
+
inset,
|
|
27
|
+
...props
|
|
28
|
+
}: React.ComponentProps<"div"> & {
|
|
29
|
+
inset?: boolean;
|
|
30
|
+
}): react_jsx_runtime18.JSX.Element;
|
|
31
|
+
declare function DropdownMenuItem({
|
|
32
|
+
className,
|
|
33
|
+
inset,
|
|
34
|
+
variant,
|
|
35
|
+
...props
|
|
36
|
+
}: Menu.Item.Props & {
|
|
37
|
+
inset?: boolean;
|
|
38
|
+
variant?: "default" | "destructive";
|
|
39
|
+
}): react_jsx_runtime18.JSX.Element;
|
|
40
|
+
declare function DropdownMenuSeparator({
|
|
41
|
+
className,
|
|
42
|
+
...props
|
|
43
|
+
}: Menu.Separator.Props): react_jsx_runtime18.JSX.Element;
|
|
44
|
+
declare function DropdownMenuShortcut({
|
|
45
|
+
className,
|
|
46
|
+
...props
|
|
47
|
+
}: React.ComponentProps<"span">): react_jsx_runtime18.JSX.Element;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger };
|
|
@@ -33,6 +33,20 @@ function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom"
|
|
|
33
33
|
})
|
|
34
34
|
}) });
|
|
35
35
|
}
|
|
36
|
+
function DropdownMenuGroup({ ...props }) {
|
|
37
|
+
return /* @__PURE__ */ jsx(Menu.Group, {
|
|
38
|
+
"data-slot": "dropdown-menu-group",
|
|
39
|
+
...props
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function DropdownMenuLabel({ className, inset, ...props }) {
|
|
43
|
+
return /* @__PURE__ */ jsx("div", {
|
|
44
|
+
"data-slot": "dropdown-menu-label",
|
|
45
|
+
"data-inset": inset,
|
|
46
|
+
className: cn("qa-dropdown-menu__label text-muted-foreground font-chrome chrome-meta px-2.5 py-1.5 text-xs font-medium data-[inset]:pl-8", className),
|
|
47
|
+
...props
|
|
48
|
+
});
|
|
49
|
+
}
|
|
36
50
|
function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
37
51
|
return /* @__PURE__ */ jsx(Menu.Item, {
|
|
38
52
|
"data-slot": "dropdown-menu-item",
|
|
@@ -78,6 +92,13 @@ function DropdownMenuSeparator({ className, ...props }) {
|
|
|
78
92
|
...props
|
|
79
93
|
});
|
|
80
94
|
}
|
|
95
|
+
function DropdownMenuShortcut({ className, ...props }) {
|
|
96
|
+
return /* @__PURE__ */ jsx("span", {
|
|
97
|
+
"data-slot": "dropdown-menu-shortcut",
|
|
98
|
+
className: cn("qa-dropdown-menu__shortcut text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground font-chrome chrome-meta ml-auto text-[0.625rem]", className),
|
|
99
|
+
...props
|
|
100
|
+
});
|
|
101
|
+
}
|
|
81
102
|
|
|
82
103
|
//#endregion
|
|
83
|
-
export { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
|
|
104
|
+
export { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
|
|
@@ -25,7 +25,7 @@ function PopoverContent({ className, align = "center", alignOffset = 0, side = "
|
|
|
25
25
|
className: "isolate z-50",
|
|
26
26
|
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
27
27
|
"data-slot": "popover-content",
|
|
28
|
-
className: cn("qa-popover__content floating-surface motion-floating text-popover-foreground z-50 flex min-w-48 origin-(--transform-origin) flex-col gap-4 p-2.5 text-xs outline-hidden data-ending-style:scale-[var(--motion-scale-enter)] data-ending-style:opacity-0 data-starting-style:scale-[var(--motion-scale-enter)] data-starting-style:opacity-0", className),
|
|
28
|
+
className: cn("qa-popover__content floating-surface motion-floating text-popover-foreground z-50 flex min-w-48 origin-(--transform-origin) flex-col gap-4 overflow-hidden p-2.5 text-xs outline-hidden data-ending-style:scale-[var(--motion-scale-enter)] data-ending-style:opacity-0 data-starting-style:scale-[var(--motion-scale-enter)] data-starting-style:opacity-0", className),
|
|
29
29
|
...props
|
|
30
30
|
})
|
|
31
31
|
}) });
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/client/components/ui/search-input.d.ts
|
|
4
|
+
interface SearchInputProps extends Omit<React.ComponentProps<"input">, "type"> {
|
|
5
|
+
/**
|
|
6
|
+
* Keyboard shortcut to display (e.g., "⌘K")
|
|
7
|
+
*/
|
|
8
|
+
shortcut?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Callback when clear button is clicked
|
|
11
|
+
*/
|
|
12
|
+
onClear?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Show loading spinner instead of search icon
|
|
15
|
+
*/
|
|
16
|
+
isLoading?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Additional className for the container
|
|
19
|
+
*/
|
|
20
|
+
containerClassName?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* SearchInput - Consistent search input with icon, loading state, clear button, and keyboard shortcut
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Basic usage
|
|
28
|
+
* <SearchInput
|
|
29
|
+
* value={searchTerm}
|
|
30
|
+
* onChange={(e) => setSearchTerm(e.target.value)}
|
|
31
|
+
* onClear={() => setSearchTerm("")}
|
|
32
|
+
* placeholder="Search..."
|
|
33
|
+
* />
|
|
34
|
+
*
|
|
35
|
+
* // With keyboard shortcut
|
|
36
|
+
* <SearchInput
|
|
37
|
+
* shortcut="⌘K"
|
|
38
|
+
* onClick={openSearchDialog}
|
|
39
|
+
* readOnly
|
|
40
|
+
* />
|
|
41
|
+
*
|
|
42
|
+
* // Loading state
|
|
43
|
+
* <SearchInput isLoading={isSearching} ... />
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function SearchInput({
|
|
47
|
+
shortcut,
|
|
48
|
+
onClear,
|
|
49
|
+
isLoading,
|
|
50
|
+
containerClassName,
|
|
51
|
+
className,
|
|
52
|
+
value,
|
|
53
|
+
...props
|
|
54
|
+
}: SearchInputProps): React.ReactElement;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { SearchInput };
|
|
@@ -10,7 +10,7 @@ const Select$1 = Select.Root;
|
|
|
10
10
|
function SelectGroup({ className, ...props }) {
|
|
11
11
|
return /* @__PURE__ */ jsx(Select.Group, {
|
|
12
12
|
"data-slot": "select-group",
|
|
13
|
-
className: cn("qa-select__group scroll-my-1 p-
|
|
13
|
+
className: cn("qa-select__group scroll-my-1 p-0", className),
|
|
14
14
|
...props
|
|
15
15
|
});
|
|
16
16
|
}
|
|
@@ -44,7 +44,7 @@ function SelectContent({ className, children, side = "bottom", sideOffset = 4, a
|
|
|
44
44
|
className: "isolate z-50",
|
|
45
45
|
children: /* @__PURE__ */ jsxs(Select.Popup, {
|
|
46
46
|
"data-slot": "select-content",
|
|
47
|
-
className: cn("qa-select__content floating-surface motion-floating text-popover-foreground relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto data-ending-style:scale-[var(--motion-scale-enter)] data-ending-style:opacity-0 data-starting-style:scale-[var(--motion-scale-enter)] data-starting-style:opacity-0", className),
|
|
47
|
+
className: cn("qa-select__content floating-surface motion-floating text-popover-foreground relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto p-1 data-ending-style:scale-[var(--motion-scale-enter)] data-ending-style:opacity-0 data-starting-style:scale-[var(--motion-scale-enter)] data-starting-style:opacity-0", className),
|
|
48
48
|
...props,
|
|
49
49
|
children: [
|
|
50
50
|
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as react_jsx_runtime12 from "react/jsx-runtime";
|
|
3
|
+
import { Dialog } from "@base-ui/react/dialog";
|
|
4
|
+
|
|
5
|
+
//#region src/client/components/ui/sheet.d.ts
|
|
6
|
+
declare function Sheet({
|
|
7
|
+
...props
|
|
8
|
+
}: Dialog.Root.Props): react_jsx_runtime12.JSX.Element;
|
|
9
|
+
declare function SheetContent({
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
side,
|
|
13
|
+
showCloseButton,
|
|
14
|
+
animated,
|
|
15
|
+
showOverlay,
|
|
16
|
+
...props
|
|
17
|
+
}: Dialog.Popup.Props & {
|
|
18
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
19
|
+
showCloseButton?: boolean;
|
|
20
|
+
animated?: boolean;
|
|
21
|
+
showOverlay?: boolean;
|
|
22
|
+
}): react_jsx_runtime12.JSX.Element;
|
|
23
|
+
declare function SheetHeader({
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<"div">): react_jsx_runtime12.JSX.Element;
|
|
27
|
+
declare function SheetFooter({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<"div">): react_jsx_runtime12.JSX.Element;
|
|
31
|
+
declare function SheetTitle({
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: Dialog.Title.Props): react_jsx_runtime12.JSX.Element;
|
|
35
|
+
declare function SheetDescription({
|
|
36
|
+
className,
|
|
37
|
+
...props
|
|
38
|
+
}: Dialog.Description.Props): react_jsx_runtime12.JSX.Element;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/client/components/ui/table.d.ts
|
|
5
|
+
declare function Table({
|
|
6
|
+
className,
|
|
7
|
+
...props
|
|
8
|
+
}: React.ComponentProps<"table">): react_jsx_runtime1.JSX.Element;
|
|
9
|
+
declare function TableHeader({
|
|
10
|
+
className,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<"thead">): react_jsx_runtime1.JSX.Element;
|
|
13
|
+
declare function TableBody({
|
|
14
|
+
className,
|
|
15
|
+
...props
|
|
16
|
+
}: React.ComponentProps<"tbody">): react_jsx_runtime1.JSX.Element;
|
|
17
|
+
declare function TableFooter({
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<"tfoot">): react_jsx_runtime1.JSX.Element;
|
|
21
|
+
declare const TableRow: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "ref"> & React.RefAttributes<HTMLTableRowElement>>;
|
|
22
|
+
interface TableHeadProps extends React.ComponentProps<"th"> {
|
|
23
|
+
stickyLeft?: number;
|
|
24
|
+
showStickyBorder?: boolean;
|
|
25
|
+
}
|
|
26
|
+
declare function TableHead({
|
|
27
|
+
className,
|
|
28
|
+
stickyLeft,
|
|
29
|
+
showStickyBorder,
|
|
30
|
+
style,
|
|
31
|
+
...props
|
|
32
|
+
}: TableHeadProps): react_jsx_runtime1.JSX.Element;
|
|
33
|
+
interface TableCellProps extends React.ComponentProps<"td"> {
|
|
34
|
+
stickyLeft?: number;
|
|
35
|
+
showStickyBorder?: boolean;
|
|
36
|
+
}
|
|
37
|
+
declare function TableCell({
|
|
38
|
+
className,
|
|
39
|
+
stickyLeft,
|
|
40
|
+
showStickyBorder,
|
|
41
|
+
style,
|
|
42
|
+
...props
|
|
43
|
+
}: TableCellProps): react_jsx_runtime1.JSX.Element;
|
|
44
|
+
declare function TableCaption({
|
|
45
|
+
className,
|
|
46
|
+
...props
|
|
47
|
+
}: React.ComponentProps<"caption">): react_jsx_runtime1.JSX.Element;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
|
|
@@ -28,6 +28,13 @@ function TableBody({ className, ...props }) {
|
|
|
28
28
|
...props
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
+
function TableFooter({ className, ...props }) {
|
|
32
|
+
return /* @__PURE__ */ jsx("tfoot", {
|
|
33
|
+
"data-slot": "table-footer",
|
|
34
|
+
className: cn("qa-table__footer bg-background font-medium", className),
|
|
35
|
+
...props
|
|
36
|
+
});
|
|
37
|
+
}
|
|
31
38
|
const TableRow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tr", {
|
|
32
39
|
ref,
|
|
33
40
|
"data-slot": "table-row",
|
|
@@ -61,6 +68,13 @@ function TableCell({ className, stickyLeft, showStickyBorder, style, ...props })
|
|
|
61
68
|
...props
|
|
62
69
|
});
|
|
63
70
|
}
|
|
71
|
+
function TableCaption({ className, ...props }) {
|
|
72
|
+
return /* @__PURE__ */ jsx("caption", {
|
|
73
|
+
"data-slot": "table-caption",
|
|
74
|
+
className: cn("qa-table__caption text-muted-foreground mt-4 text-xs", className),
|
|
75
|
+
...props
|
|
76
|
+
});
|
|
77
|
+
}
|
|
64
78
|
|
|
65
79
|
//#endregion
|
|
66
|
-
export { Table, TableBody, TableCell, TableHead, TableHeader, TableRow };
|
|
80
|
+
export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react_jsx_runtime8 from "react/jsx-runtime";
|
|
2
|
+
import { Tooltip } from "@base-ui/react/tooltip";
|
|
3
|
+
|
|
4
|
+
//#region src/client/components/ui/tooltip.d.ts
|
|
5
|
+
declare function Tooltip$1({
|
|
6
|
+
...props
|
|
7
|
+
}: Tooltip.Root.Props): react_jsx_runtime8.JSX.Element;
|
|
8
|
+
declare function TooltipTrigger({
|
|
9
|
+
...props
|
|
10
|
+
}: Tooltip.Trigger.Props): react_jsx_runtime8.JSX.Element;
|
|
11
|
+
declare function TooltipContent({
|
|
12
|
+
className,
|
|
13
|
+
side,
|
|
14
|
+
sideOffset,
|
|
15
|
+
align,
|
|
16
|
+
alignOffset,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}: Tooltip.Popup.Props & Pick<Tooltip.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">): react_jsx_runtime8.JSX.Element;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { Tooltip$1 as Tooltip, TooltipContent, TooltipTrigger };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime50 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/contexts/focus-context.d.ts
|
|
5
5
|
|
|
@@ -59,7 +59,7 @@ type FocusProviderProps = {
|
|
|
59
59
|
declare function FocusProvider({
|
|
60
60
|
children,
|
|
61
61
|
onFocusChange
|
|
62
|
-
}: FocusProviderProps):
|
|
62
|
+
}: FocusProviderProps): react_jsx_runtime50.JSX.Element;
|
|
63
63
|
/**
|
|
64
64
|
* Use the focus context
|
|
65
65
|
*/
|
|
@@ -11,6 +11,11 @@ const adminConfigQueryKey = [
|
|
|
11
11
|
"admin",
|
|
12
12
|
"config"
|
|
13
13
|
];
|
|
14
|
+
const publicAdminConfigQueryKey = [
|
|
15
|
+
"questpie",
|
|
16
|
+
"admin",
|
|
17
|
+
"public-config"
|
|
18
|
+
];
|
|
14
19
|
/** Query options factory for admin config — can be used for prefetching in loaders */
|
|
15
20
|
function getAdminConfigQueryOptions(client) {
|
|
16
21
|
return {
|
|
@@ -23,6 +28,20 @@ function getAdminConfigQueryOptions(client) {
|
|
|
23
28
|
gcTime: 1800 * 1e3
|
|
24
29
|
};
|
|
25
30
|
}
|
|
31
|
+
/** Query options for auth-page-safe public branding/bootstrap config. */
|
|
32
|
+
function getPublicAdminConfigQueryOptions(client) {
|
|
33
|
+
return {
|
|
34
|
+
queryKey: publicAdminConfigQueryKey,
|
|
35
|
+
queryFn: async () => {
|
|
36
|
+
if (!client || !client.routes) return {};
|
|
37
|
+
const routes = client.routes;
|
|
38
|
+
if (typeof routes.getPublicAdminConfig === "function") return routes.getPublicAdminConfig();
|
|
39
|
+
return {};
|
|
40
|
+
},
|
|
41
|
+
staleTime: 300 * 1e3,
|
|
42
|
+
gcTime: 1800 * 1e3
|
|
43
|
+
};
|
|
44
|
+
}
|
|
26
45
|
/** Standard query hook - returns loading/error states */
|
|
27
46
|
function useAdminConfig(queryOptions) {
|
|
28
47
|
return useQuery({
|
|
@@ -36,4 +55,4 @@ function useSuspenseAdminConfig() {
|
|
|
36
55
|
}
|
|
37
56
|
|
|
38
57
|
//#endregion
|
|
39
|
-
export { getAdminConfigQueryOptions, useAdminConfig, useSuspenseAdminConfig };
|
|
58
|
+
export { getAdminConfigQueryOptions, getPublicAdminConfigQueryOptions, useAdminConfig, useSuspenseAdminConfig };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useTranslation } from "../i18n/hooks.mjs";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { toast } from "sonner";
|
|
4
|
+
|
|
5
|
+
//#region src/client/hooks/use-autosave.ts
|
|
6
|
+
/**
|
|
7
|
+
* useAutosave — engine-agnostic debounced autosave for react-hook-form views.
|
|
8
|
+
*
|
|
9
|
+
* Extracted from the form view's `AutosaveManager`. The save pipeline
|
|
10
|
+
* (`runAutosave`) is unchanged — it guards on dirty/submitting, submits via the
|
|
11
|
+
* form, resets to the server result, and reports save state.
|
|
12
|
+
*
|
|
13
|
+
* The trigger is driven by `form.subscribe({ formState: { values: true } })`
|
|
14
|
+
* (the same value-subscription `PreviewPatchBridge` uses) rather than DOM
|
|
15
|
+
* `input`/`change` listeners. That makes it engine-agnostic: it catches native
|
|
16
|
+
* input edits AND programmatic `field.onChange` emissions (e.g. the TipTap
|
|
17
|
+
* rich-text field, whose contenteditable does not fire bubbling DOM events).
|
|
18
|
+
*
|
|
19
|
+
* Both the form view and the document view consume this hook so they share one
|
|
20
|
+
* autosave code path.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Wire debounced autosave onto a form. Returns the imperative `runAutosave`
|
|
24
|
+
* callback so callers can also flush manually if needed.
|
|
25
|
+
*/
|
|
26
|
+
function useAutosave({ form, id, enabled, debounce, isDirtyRef, isSubmittingRef, updateMutation, onPreviewCommit, onPreviewRefresh, onSavingChange, onSaved }) {
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
const timerRef = React.useRef(null);
|
|
29
|
+
const runAutosave = React.useCallback(async () => {
|
|
30
|
+
if (!id || !isDirtyRef.current || isSubmittingRef.current) return;
|
|
31
|
+
try {
|
|
32
|
+
onSavingChange(true);
|
|
33
|
+
await form.handleSubmit(async (data) => {
|
|
34
|
+
const result = await updateMutation.mutateAsync({
|
|
35
|
+
id,
|
|
36
|
+
data
|
|
37
|
+
});
|
|
38
|
+
form.reset(result, { keepTouched: true });
|
|
39
|
+
onPreviewCommit?.(result);
|
|
40
|
+
onPreviewRefresh?.();
|
|
41
|
+
onSaved(/* @__PURE__ */ new Date());
|
|
42
|
+
onSavingChange(false);
|
|
43
|
+
}, () => {
|
|
44
|
+
onSavingChange(false);
|
|
45
|
+
})();
|
|
46
|
+
} catch (error) {
|
|
47
|
+
onSavingChange(false);
|
|
48
|
+
console.error("Autosave failed:", error);
|
|
49
|
+
toast.error(t("error.autosaveFailed"), { description: error instanceof Error ? error.message : void 0 });
|
|
50
|
+
}
|
|
51
|
+
}, [
|
|
52
|
+
form,
|
|
53
|
+
id,
|
|
54
|
+
isDirtyRef,
|
|
55
|
+
isSubmittingRef,
|
|
56
|
+
onSaved,
|
|
57
|
+
onSavingChange,
|
|
58
|
+
onPreviewCommit,
|
|
59
|
+
onPreviewRefresh,
|
|
60
|
+
t,
|
|
61
|
+
updateMutation
|
|
62
|
+
]);
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
65
|
+
if (!enabled || !id) return;
|
|
66
|
+
const scheduleAutosave = () => {
|
|
67
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
68
|
+
timerRef.current = setTimeout(() => {
|
|
69
|
+
runAutosave();
|
|
70
|
+
}, debounce);
|
|
71
|
+
};
|
|
72
|
+
const unsubscribe = form.subscribe({
|
|
73
|
+
formState: { values: true },
|
|
74
|
+
callback: scheduleAutosave
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
unsubscribe();
|
|
78
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
79
|
+
};
|
|
80
|
+
}, [
|
|
81
|
+
debounce,
|
|
82
|
+
enabled,
|
|
83
|
+
form,
|
|
84
|
+
id,
|
|
85
|
+
runAutosave
|
|
86
|
+
]);
|
|
87
|
+
return runAutosave;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
export { useAutosave };
|