@btst/stack 2.5.6 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/client/components/index.d.cts +9 -9
- package/dist/client/components/index.d.mts +9 -9
- package/dist/client/components/index.d.ts +9 -9
- package/dist/components/auto-form/index.cjs +8 -0
- package/dist/components/auto-form/index.d.cts +26 -0
- package/dist/components/auto-form/index.d.mts +26 -0
- package/dist/components/auto-form/index.d.ts +26 -0
- package/dist/components/auto-form/index.mjs +1 -0
- package/dist/components/empty/index.cjs +12 -0
- package/dist/components/empty/index.d.cts +15 -0
- package/dist/components/empty/index.d.mts +15 -0
- package/dist/components/empty/index.d.ts +15 -0
- package/dist/components/empty/index.mjs +1 -0
- package/dist/components/form-builder/index.cjs +16 -0
- package/dist/components/form-builder/index.d.cts +385 -0
- package/dist/components/form-builder/index.d.mts +385 -0
- package/dist/components/form-builder/index.d.ts +385 -0
- package/dist/components/form-builder/index.mjs +4 -0
- package/dist/components/markdown/index.cjs +9 -0
- package/dist/components/markdown/index.d.cts +30 -0
- package/dist/components/markdown/index.d.mts +30 -0
- package/dist/components/markdown/index.d.ts +30 -0
- package/dist/components/markdown/index.mjs +2 -0
- package/dist/components/markdown/style.css +394 -0
- package/dist/components/minimal-tiptap/style.css +548 -0
- package/dist/components/multi-select/index.cjs +7 -0
- package/dist/components/multi-select/index.d.cts +78 -0
- package/dist/components/multi-select/index.d.mts +78 -0
- package/dist/components/multi-select/index.d.ts +78 -0
- package/dist/components/multi-select/index.mjs +1 -0
- package/dist/components/search-select/index.cjs +7 -0
- package/dist/components/search-select/index.d.cts +15 -0
- package/dist/components/search-select/index.d.mts +15 -0
- package/dist/components/search-select/index.d.ts +15 -0
- package/dist/components/search-select/index.mjs +1 -0
- package/dist/components/stepped-auto-form/index.cjs +7 -0
- package/dist/components/stepped-auto-form/index.d.cts +37 -0
- package/dist/components/stepped-auto-form/index.d.mts +37 -0
- package/dist/components/stepped-auto-form/index.d.ts +37 -0
- package/dist/components/stepped-auto-form/index.mjs +1 -0
- package/dist/components/ui-builder/style.css +552 -0
- package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.cjs +1 -1
- package/dist/node_modules/.pnpm/@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@dnd-kit/core/dist/core.esm.mjs +1 -1
- package/dist/node_modules/.pnpm/@dnd-kit_sortable@10.0.0_@dnd-kit_core@6.3.1_react-dom@19.2.0_react@19.2.0__react@19.2.0__react@19.2.0/node_modules/@dnd-kit/sortable/dist/sortable.esm.mjs +2 -2
- package/dist/node_modules/.pnpm/@floating-ui_core@1.7.3/node_modules/@floating-ui/core/dist/floating-ui.core.mjs +1 -1
- package/dist/node_modules/.pnpm/@floating-ui_dom@1.7.4/node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs +3 -3
- package/dist/node_modules/.pnpm/@floating-ui_react-dom@2.1.6_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.mjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +44 -35
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +44 -35
- package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.cjs +23 -0
- package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.mjs +21 -0
- package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor.cjs +11 -12
- package/dist/packages/stack/src/plugins/blog/client/components/forms/markdown-editor.mjs +11 -12
- package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +2 -2
- package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +2 -2
- package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.cjs +0 -3
- package/dist/packages/stack/src/plugins/blog/client/components/shared/search-input.mjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/components/shared/search-modal.cjs +0 -3
- package/dist/packages/stack/src/plugins/blog/client/components/shared/search-modal.mjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/hooks/use-debounce.cjs +22 -0
- package/dist/packages/stack/src/plugins/blog/client/hooks/use-debounce.mjs +23 -2
- package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +12 -6
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +12 -6
- package/dist/packages/stack/src/plugins/cms/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +38 -26
- package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +38 -26
- package/dist/packages/stack/src/plugins/form-builder/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/form-builder/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +32 -20
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +32 -20
- package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +6 -3
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +6 -3
- package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.cjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/page-renderer.mjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.cjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/components/shared/default-error.mjs +1 -1
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +24 -15
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +24 -15
- package/dist/packages/ui/src/components/auto-form/index.cjs +12 -2
- package/dist/packages/ui/src/components/auto-form/index.mjs +9 -2
- package/dist/packages/ui/src/components/auto-form/stepped-auto-form.cjs +2 -2
- package/dist/packages/ui/src/components/empty.cjs +28 -0
- package/dist/packages/ui/src/components/empty.mjs +27 -1
- package/dist/packages/ui/src/components/form-builder/components/index.mjs +2 -2
- package/dist/packages/ui/src/components/form-builder/edit-field-dialog.cjs +1 -1
- package/dist/packages/ui/src/components/form-builder/index.mjs +2 -2
- package/dist/packages/ui/src/components/form.mjs +1 -1
- package/dist/packages/ui/src/components/kanban.mjs +1 -1
- package/dist/packages/ui/src/components/multi-select.mjs +2 -2
- package/dist/packages/ui/src/components/search-select.cjs +13 -3
- package/dist/packages/ui/src/components/search-select.mjs +14 -4
- package/dist/packages/ui/src/components/ui-builder/internal/config-panel.cjs +1 -1
- package/dist/packages/ui/src/components/ui-builder/internal/props-panel.cjs +1 -1
- package/dist/plugins/ai-chat/client/index.d.cts +17 -4
- package/dist/plugins/ai-chat/client/index.d.mts +17 -4
- package/dist/plugins/ai-chat/client/index.d.ts +17 -4
- package/dist/plugins/blog/api/index.d.cts +2 -2
- package/dist/plugins/blog/api/index.d.mts +2 -2
- package/dist/plugins/blog/api/index.d.ts +2 -2
- package/dist/plugins/blog/client/hooks/index.cjs +3 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +7 -226
- package/dist/plugins/blog/client/hooks/index.d.mts +7 -226
- package/dist/plugins/blog/client/hooks/index.d.ts +7 -226
- package/dist/plugins/blog/client/hooks/index.mjs +1 -0
- package/dist/plugins/blog/client/index.d.cts +46 -22
- package/dist/plugins/blog/client/index.d.mts +46 -22
- package/dist/plugins/blog/client/index.d.ts +46 -22
- package/dist/plugins/blog/query-keys.d.cts +2 -2
- package/dist/plugins/blog/query-keys.d.mts +2 -2
- package/dist/plugins/blog/query-keys.d.ts +2 -2
- package/dist/plugins/cms/client/index.d.cts +36 -15
- package/dist/plugins/cms/client/index.d.mts +36 -15
- package/dist/plugins/cms/client/index.d.ts +36 -15
- package/dist/plugins/form-builder/client/components/index.d.cts +2 -2
- package/dist/plugins/form-builder/client/components/index.d.mts +2 -2
- package/dist/plugins/form-builder/client/components/index.d.ts +2 -2
- package/dist/plugins/form-builder/client/index.d.cts +33 -15
- package/dist/plugins/form-builder/client/index.d.mts +33 -15
- package/dist/plugins/form-builder/client/index.d.ts +33 -15
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/client/components/index.d.cts +5 -5
- package/dist/plugins/kanban/client/components/index.d.mts +5 -5
- package/dist/plugins/kanban/client/components/index.d.ts +5 -5
- package/dist/plugins/kanban/client/index.d.cts +25 -10
- package/dist/plugins/kanban/client/index.d.mts +25 -10
- package/dist/plugins/kanban/client/index.d.ts +25 -10
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/plugins/route-docs/client/index.d.cts +4 -4
- package/dist/plugins/route-docs/client/index.d.mts +4 -4
- package/dist/plugins/route-docs/client/index.d.ts +4 -4
- package/dist/plugins/ui-builder/client/components/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/components/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/components/index.d.ts +3 -3
- package/dist/plugins/ui-builder/client/hooks/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/hooks/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/hooks/index.d.ts +3 -3
- package/dist/plugins/ui-builder/client/index.d.cts +32 -18
- package/dist/plugins/ui-builder/client/index.d.mts +32 -18
- package/dist/plugins/ui-builder/client/index.d.ts +32 -18
- package/dist/plugins/ui-builder/index.d.cts +3 -3
- package/dist/plugins/ui-builder/index.d.mts +3 -3
- package/dist/plugins/ui-builder/index.d.ts +3 -3
- package/dist/shared/{stack.B2DwzF3r.d.ts → stack.ASwEoINr.d.ts} +1 -1
- package/dist/shared/{stack.C5ZSOJGJ.d.cts → stack.B1srlBud.d.mts} +1 -1
- package/dist/shared/stack.B8vT-Yt4.d.mts +228 -0
- package/dist/shared/stack.BAT540yW.d.ts +228 -0
- package/dist/shared/{stack.D0QupDcQ.d.ts → stack.BK9Z2dcL.d.ts} +1 -1
- package/dist/shared/stack.BwA7trxA.d.cts +228 -0
- package/dist/shared/{stack.Cl7ok_cY.d.cts → stack.CFECM0ew.d.cts} +1 -1
- package/dist/shared/stack.CZMWR72v.d.cts +10 -0
- package/dist/shared/stack.CZMWR72v.d.mts +10 -0
- package/dist/shared/stack.CZMWR72v.d.ts +10 -0
- package/dist/shared/{stack.VMmQdbsJ.d.mts → stack.DVtk5CNw.d.mts} +1 -1
- package/dist/shared/{stack.B8_74ror.d.ts → stack.DXnclTG7.d.ts} +4 -4
- package/dist/shared/{stack.C21-LFX8.d.cts → stack.DaZM10cp.d.cts} +4 -4
- package/dist/shared/{stack.Dq4qVr1F.d.mts → stack.DmpPDPxA.d.cts} +1 -1
- package/dist/shared/{stack.CL4mKxe7.d.mts → stack.cfCkioTe.d.mts} +4 -4
- package/dist/shared/stack.fdi94T4S.d.cts +291 -0
- package/dist/shared/stack.fdi94T4S.d.mts +291 -0
- package/dist/shared/stack.fdi94T4S.d.ts +291 -0
- package/package.json +115 -4
- package/src/__tests__/page-component-overrides.test.tsx +147 -0
- package/src/components/auto-form/index.ts +12 -0
- package/src/components/empty/index.ts +8 -0
- package/src/components/form-builder/index.ts +23 -0
- package/src/components/kanban/index.ts +9 -0
- package/src/components/markdown/index.ts +5 -0
- package/src/components/markdown/style.css +3 -0
- package/src/components/minimal-tiptap/index.ts +5 -0
- package/src/components/minimal-tiptap/style.css +1 -0
- package/src/components/multi-select/index.ts +5 -0
- package/src/components/search-select/index.ts +1 -0
- package/src/components/stepped-auto-form/index.ts +5 -0
- package/src/components/ui-builder/index.ts +50 -0
- package/src/components/ui-builder/style.css +5 -0
- package/src/plugins/ai-chat/client/components/shared/default-error.tsx +1 -1
- package/src/plugins/ai-chat/client/plugin.tsx +60 -32
- package/src/plugins/blog/client/components/forms/markdown-editor-with-overrides.tsx +29 -0
- package/src/plugins/blog/client/components/forms/markdown-editor.tsx +24 -21
- package/src/plugins/blog/client/components/forms/post-forms.tsx +2 -2
- package/src/plugins/blog/client/components/shared/default-error.tsx +2 -1
- package/src/plugins/blog/client/components/shared/posts-list.tsx +1 -1
- package/src/plugins/blog/client/components/shared/search-input.tsx +0 -2
- package/src/plugins/blog/client/components/shared/search-modal.tsx +0 -2
- package/src/plugins/blog/client/hooks/index.tsx +1 -0
- package/src/plugins/blog/client/plugin.tsx +41 -6
- package/src/plugins/cms/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/cms/client/plugin.tsx +65 -32
- package/src/plugins/form-builder/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/form-builder/client/plugin.tsx +56 -23
- package/src/plugins/kanban/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/kanban/client/plugin.tsx +23 -3
- package/src/plugins/ui-builder/client/components/page-renderer.tsx +5 -3
- package/src/plugins/ui-builder/client/components/shared/default-error.tsx +3 -2
- package/src/plugins/ui-builder/client/plugin.tsx +41 -15
- package/dist/shared/stack.8nldKomx.d.cts +0 -114
- package/dist/shared/stack.8nldKomx.d.mts +0 -114
- package/dist/shared/stack.8nldKomx.d.ts +0 -114
- package/dist/shared/{stack.CxNeGV2z.d.mts → stack.B8D4r97Z.d.mts} +6 -6
- package/dist/shared/{stack.BWp0hcm9.d.cts → stack.BQmuNl5p.d.cts} +3 -3
- package/dist/shared/{stack.BWp0hcm9.d.mts → stack.BQmuNl5p.d.mts} +3 -3
- package/dist/shared/{stack.BWp0hcm9.d.ts → stack.BQmuNl5p.d.ts} +3 -3
- package/dist/shared/{stack.BFcg0tDz.d.ts → stack.DgKOwl20.d.ts} +6 -6
- package/dist/shared/{stack.DSxTDZBQ.d.cts → stack.uWSqCWAb.d.cts} +6 -6
|
@@ -9,25 +9,24 @@ import { listener, listenerCtx } from "@milkdown/kit/plugin/listener";
|
|
|
9
9
|
import { Slice } from "@milkdown/kit/prose/model";
|
|
10
10
|
import { Selection } from "@milkdown/kit/prose/state";
|
|
11
11
|
import { useLayoutEffect, useRef, useState } from "react";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
|
|
13
|
+
export interface MarkdownEditorProps {
|
|
14
|
+
value?: string;
|
|
15
|
+
onChange?: (markdown: string) => void;
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Optional image upload handler. When provided, enables image upload in the editor. */
|
|
18
|
+
uploadImage?: (file: File) => Promise<string>;
|
|
19
|
+
/** Placeholder text shown when the editor is empty. */
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
export function MarkdownEditor({
|
|
17
24
|
value,
|
|
18
25
|
onChange,
|
|
19
26
|
className,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
className?: string;
|
|
24
|
-
}) {
|
|
25
|
-
const { uploadImage, localization } = usePluginOverrides<
|
|
26
|
-
BlogPluginOverrides,
|
|
27
|
-
Partial<BlogPluginOverrides>
|
|
28
|
-
>("blog", {
|
|
29
|
-
localization: BLOG_LOCALIZATION,
|
|
30
|
-
});
|
|
27
|
+
uploadImage,
|
|
28
|
+
placeholder = "Write something...",
|
|
29
|
+
}: MarkdownEditorProps) {
|
|
31
30
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
32
31
|
const crepeRef = useRef<Crepe | null>(null);
|
|
33
32
|
const isReadyRef = useRef(false);
|
|
@@ -52,14 +51,18 @@ export function MarkdownEditor({
|
|
|
52
51
|
defaultValue: initialValueRef.current,
|
|
53
52
|
featureConfigs: {
|
|
54
53
|
[CrepeFeature.Placeholder]: {
|
|
55
|
-
text:
|
|
56
|
-
},
|
|
57
|
-
[CrepeFeature.ImageBlock]: {
|
|
58
|
-
onUpload: async (file) => {
|
|
59
|
-
const url = await uploadImage(file);
|
|
60
|
-
return url;
|
|
61
|
-
},
|
|
54
|
+
text: placeholder,
|
|
62
55
|
},
|
|
56
|
+
...(uploadImage
|
|
57
|
+
? {
|
|
58
|
+
[CrepeFeature.ImageBlock]: {
|
|
59
|
+
onUpload: async (file: File) => {
|
|
60
|
+
const url = await uploadImage(file);
|
|
61
|
+
return url;
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
: {}),
|
|
63
66
|
},
|
|
64
67
|
});
|
|
65
68
|
|
|
@@ -52,8 +52,8 @@ import { z } from "zod";
|
|
|
52
52
|
import { FeaturedImageField } from "./image-field";
|
|
53
53
|
|
|
54
54
|
const MarkdownEditor = lazy(() =>
|
|
55
|
-
import("./markdown-editor").then((module) => ({
|
|
56
|
-
default: module.
|
|
55
|
+
import("./markdown-editor-with-overrides").then((module) => ({
|
|
56
|
+
default: module.MarkdownEditorWithOverrides,
|
|
57
57
|
})),
|
|
58
58
|
);
|
|
59
59
|
import { BLOG_LOCALIZATION } from "../../localization";
|
|
@@ -18,6 +18,7 @@ export function DefaultError({ error }: FallbackProps) {
|
|
|
18
18
|
const message =
|
|
19
19
|
process.env.NODE_ENV === "production"
|
|
20
20
|
? localization.BLOG_GENERIC_ERROR_MESSAGE
|
|
21
|
-
: (error
|
|
21
|
+
: ((error instanceof Error ? error.message : undefined) ??
|
|
22
|
+
localization.BLOG_GENERIC_ERROR_MESSAGE);
|
|
22
23
|
return <ErrorPlaceholder title={title} message={message} />;
|
|
23
24
|
}
|
|
@@ -2,7 +2,7 @@ import { usePluginOverrides } from "@btst/stack/context";
|
|
|
2
2
|
import type { SerializedPost } from "../../../types";
|
|
3
3
|
import { Button } from "@workspace/ui/components/button";
|
|
4
4
|
import { EmptyList } from "./empty-list";
|
|
5
|
-
import SearchInput from "./search-input";
|
|
5
|
+
import { SearchInput } from "./search-input";
|
|
6
6
|
import type { BlogPluginOverrides } from "../../overrides";
|
|
7
7
|
import { PostCard as DefaultPostCard } from "./post-card";
|
|
8
8
|
import { BLOG_LOCALIZATION } from "../../localization";
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
runClientHookWithShim,
|
|
6
6
|
} from "@btst/stack/plugins/client";
|
|
7
7
|
import { createRoute } from "@btst/yar";
|
|
8
|
+
import type { ComponentType } from "react";
|
|
8
9
|
import type { QueryClient } from "@tanstack/react-query";
|
|
9
10
|
import type { BlogApiRouter } from "../api";
|
|
10
11
|
import { createBlogQueryKeys } from "../query-keys";
|
|
@@ -84,6 +85,26 @@ export interface BlogClientConfig {
|
|
|
84
85
|
|
|
85
86
|
/** Optional headers for SSR (e.g., forwarding cookies) */
|
|
86
87
|
headers?: Headers;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Optional page component overrides.
|
|
91
|
+
* Replace any plugin page with a custom React component.
|
|
92
|
+
* The built-in component is used as the fallback when not provided.
|
|
93
|
+
*/
|
|
94
|
+
pageComponents?: {
|
|
95
|
+
/** Replaces the published posts list page */
|
|
96
|
+
posts?: ComponentType;
|
|
97
|
+
/** Replaces the drafts list page */
|
|
98
|
+
drafts?: ComponentType;
|
|
99
|
+
/** Replaces the new post page */
|
|
100
|
+
newPost?: ComponentType;
|
|
101
|
+
/** Replaces the single post page */
|
|
102
|
+
post?: ComponentType<{ slug: string }>;
|
|
103
|
+
/** Replaces the edit post page */
|
|
104
|
+
editPost?: ComponentType<{ slug: string }>;
|
|
105
|
+
/** Replaces the tag posts page */
|
|
106
|
+
tag?: ComponentType<{ tagSlug: string }>;
|
|
107
|
+
};
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
/**
|
|
@@ -700,43 +721,57 @@ export const blogClientPlugin = (config: BlogClientConfig) =>
|
|
|
700
721
|
|
|
701
722
|
routes: () => ({
|
|
702
723
|
posts: createRoute("/blog", () => {
|
|
724
|
+
const CustomPosts = config.pageComponents?.posts;
|
|
703
725
|
return {
|
|
704
|
-
PageComponent:
|
|
726
|
+
PageComponent:
|
|
727
|
+
CustomPosts ?? (() => <HomePageComponent published={true} />),
|
|
705
728
|
loader: createPostsLoader(true, config),
|
|
706
729
|
meta: createPostsListMeta(true, config),
|
|
707
730
|
};
|
|
708
731
|
}),
|
|
709
732
|
drafts: createRoute("/blog/drafts", () => {
|
|
733
|
+
const CustomDrafts = config.pageComponents?.drafts;
|
|
710
734
|
return {
|
|
711
|
-
PageComponent:
|
|
735
|
+
PageComponent:
|
|
736
|
+
CustomDrafts ?? (() => <HomePageComponent published={false} />),
|
|
712
737
|
loader: createPostsLoader(false, config),
|
|
713
738
|
meta: createPostsListMeta(false, config),
|
|
714
739
|
};
|
|
715
740
|
}),
|
|
716
741
|
newPost: createRoute("/blog/new", () => {
|
|
742
|
+
const CustomNewPost = config.pageComponents?.newPost;
|
|
717
743
|
return {
|
|
718
|
-
PageComponent: NewPostPageComponent,
|
|
744
|
+
PageComponent: CustomNewPost ?? NewPostPageComponent,
|
|
719
745
|
loader: createNewPostLoader(config),
|
|
720
746
|
meta: createNewPostMeta(config),
|
|
721
747
|
};
|
|
722
748
|
}),
|
|
723
749
|
editPost: createRoute("/blog/:slug/edit", ({ params: { slug } }) => {
|
|
750
|
+
const CustomEditPost = config.pageComponents?.editPost;
|
|
724
751
|
return {
|
|
725
|
-
PageComponent:
|
|
752
|
+
PageComponent: CustomEditPost
|
|
753
|
+
? () => <CustomEditPost slug={slug} />
|
|
754
|
+
: () => <EditPostPageComponent slug={slug} />,
|
|
726
755
|
loader: createPostLoader(slug, config, `/blog/${slug}/edit`),
|
|
727
756
|
meta: createEditPostMeta(slug, config),
|
|
728
757
|
};
|
|
729
758
|
}),
|
|
730
759
|
tag: createRoute("/blog/tag/:tagSlug", ({ params: { tagSlug } }) => {
|
|
760
|
+
const CustomTag = config.pageComponents?.tag;
|
|
731
761
|
return {
|
|
732
|
-
PageComponent:
|
|
762
|
+
PageComponent: CustomTag
|
|
763
|
+
? () => <CustomTag tagSlug={tagSlug} />
|
|
764
|
+
: () => <TagPageComponent tagSlug={tagSlug} />,
|
|
733
765
|
loader: createTagLoader(tagSlug, config),
|
|
734
766
|
meta: createTagMeta(tagSlug, config),
|
|
735
767
|
};
|
|
736
768
|
}),
|
|
737
769
|
post: createRoute("/blog/:slug", ({ params: { slug } }) => {
|
|
770
|
+
const CustomPost = config.pageComponents?.post;
|
|
738
771
|
return {
|
|
739
|
-
PageComponent:
|
|
772
|
+
PageComponent: CustomPost
|
|
773
|
+
? () => <CustomPost slug={slug} />
|
|
774
|
+
: () => <PostPageComponent slug={slug} />,
|
|
740
775
|
loader: createPostLoader(slug, config),
|
|
741
776
|
meta: createPostMeta(slug, config),
|
|
742
777
|
};
|
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
runClientHookWithShim,
|
|
7
7
|
} from "@btst/stack/plugins/client";
|
|
8
8
|
import { createRoute } from "@btst/yar";
|
|
9
|
+
import type { ComponentType } from "react";
|
|
9
10
|
import type { QueryClient } from "@tanstack/react-query";
|
|
10
11
|
import type { CMSApiRouter } from "../api";
|
|
11
12
|
import { createCMSQueryKeys } from "../query-keys";
|
|
@@ -129,6 +130,22 @@ export interface CMSClientConfig {
|
|
|
129
130
|
headers?: Headers;
|
|
130
131
|
/** Optional hooks for customizing behavior (authorization, redirects, etc.) */
|
|
131
132
|
hooks?: CMSClientHooks;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Optional page component overrides.
|
|
136
|
+
* Replace any plugin page with a custom React component.
|
|
137
|
+
* The built-in component is used as the fallback when not provided.
|
|
138
|
+
*/
|
|
139
|
+
pageComponents?: {
|
|
140
|
+
/** Replaces the CMS dashboard page */
|
|
141
|
+
dashboard?: ComponentType;
|
|
142
|
+
/** Replaces the content list page */
|
|
143
|
+
contentList?: ComponentType<{ typeSlug: string }>;
|
|
144
|
+
/** Replaces the new content editor page */
|
|
145
|
+
newContent?: ComponentType<{ typeSlug: string }>;
|
|
146
|
+
/** Replaces the edit content editor page */
|
|
147
|
+
editContent?: ComponentType<{ typeSlug: string; id: string }>;
|
|
148
|
+
};
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
/**
|
|
@@ -469,38 +486,54 @@ export const cmsClientPlugin = (config: CMSClientConfig) =>
|
|
|
469
486
|
name: "cms",
|
|
470
487
|
|
|
471
488
|
routes: () => ({
|
|
472
|
-
dashboard: createRoute("/cms", () =>
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
typeSlug={params.typeSlug}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
})
|
|
489
|
+
dashboard: createRoute("/cms", () => {
|
|
490
|
+
const CustomDashboard = config.pageComponents?.dashboard;
|
|
491
|
+
return {
|
|
492
|
+
PageComponent: CustomDashboard ?? (() => <DashboardPageComponent />),
|
|
493
|
+
loader: createDashboardLoader(config),
|
|
494
|
+
meta: createDashboardMeta(),
|
|
495
|
+
};
|
|
496
|
+
}),
|
|
497
|
+
|
|
498
|
+
contentList: createRoute("/cms/:typeSlug", ({ params }) => {
|
|
499
|
+
const CustomContentList = config.pageComponents?.contentList;
|
|
500
|
+
return {
|
|
501
|
+
PageComponent: CustomContentList
|
|
502
|
+
? () => <CustomContentList typeSlug={params.typeSlug} />
|
|
503
|
+
: () => <ContentListPageComponent typeSlug={params.typeSlug} />,
|
|
504
|
+
loader: createContentListLoader(params.typeSlug, config),
|
|
505
|
+
meta: createContentListMeta(params.typeSlug, config),
|
|
506
|
+
};
|
|
507
|
+
}),
|
|
508
|
+
|
|
509
|
+
newContent: createRoute("/cms/:typeSlug/new", ({ params }) => {
|
|
510
|
+
const CustomNewContent = config.pageComponents?.newContent;
|
|
511
|
+
return {
|
|
512
|
+
PageComponent: CustomNewContent
|
|
513
|
+
? () => <CustomNewContent typeSlug={params.typeSlug} />
|
|
514
|
+
: () => <ContentEditorPageComponent typeSlug={params.typeSlug} />,
|
|
515
|
+
loader: createContentEditorLoader(params.typeSlug, undefined, config),
|
|
516
|
+
meta: createContentEditorMeta(params.typeSlug, undefined, config),
|
|
517
|
+
};
|
|
518
|
+
}),
|
|
519
|
+
|
|
520
|
+
editContent: createRoute("/cms/:typeSlug/:id", ({ params }) => {
|
|
521
|
+
const CustomEditContent = config.pageComponents?.editContent;
|
|
522
|
+
return {
|
|
523
|
+
PageComponent: CustomEditContent
|
|
524
|
+
? () => (
|
|
525
|
+
<CustomEditContent typeSlug={params.typeSlug} id={params.id} />
|
|
526
|
+
)
|
|
527
|
+
: () => (
|
|
528
|
+
<ContentEditorPageComponent
|
|
529
|
+
typeSlug={params.typeSlug}
|
|
530
|
+
id={params.id}
|
|
531
|
+
/>
|
|
532
|
+
),
|
|
533
|
+
loader: createContentEditorLoader(params.typeSlug, params.id, config),
|
|
534
|
+
meta: createContentEditorMeta(params.typeSlug, params.id, config),
|
|
535
|
+
};
|
|
536
|
+
}),
|
|
504
537
|
}),
|
|
505
538
|
|
|
506
539
|
sitemap: async () => {
|
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
runClientHookWithShim,
|
|
8
8
|
} from "@btst/stack/plugins/client";
|
|
9
9
|
import { createRoute } from "@btst/yar";
|
|
10
|
+
import type { ComponentType } from "react";
|
|
10
11
|
import type { QueryClient } from "@tanstack/react-query";
|
|
11
12
|
import type { FormBuilderApiRouter } from "../api";
|
|
12
13
|
import { createFormBuilderQueryKeys } from "../query-keys";
|
|
@@ -126,6 +127,22 @@ export interface FormBuilderClientConfig {
|
|
|
126
127
|
headers?: Headers;
|
|
127
128
|
/** Optional hooks for customizing behavior (authorization, redirects, etc.) */
|
|
128
129
|
hooks?: FormBuilderClientHooks;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Optional page component overrides.
|
|
133
|
+
* Replace any plugin page with a custom React component.
|
|
134
|
+
* The built-in component is used as the fallback when not provided.
|
|
135
|
+
*/
|
|
136
|
+
pageComponents?: {
|
|
137
|
+
/** Replaces the form list page */
|
|
138
|
+
formList?: ComponentType;
|
|
139
|
+
/** Replaces the new form page */
|
|
140
|
+
newForm?: ComponentType;
|
|
141
|
+
/** Replaces the form editor page */
|
|
142
|
+
editForm?: ComponentType<{ id: string }>;
|
|
143
|
+
/** Replaces the form submissions page */
|
|
144
|
+
submissions?: ComponentType<{ formId: string }>;
|
|
145
|
+
};
|
|
129
146
|
}
|
|
130
147
|
|
|
131
148
|
/**
|
|
@@ -476,29 +493,45 @@ export const formBuilderClientPlugin = (config: FormBuilderClientConfig) =>
|
|
|
476
493
|
name: "form-builder",
|
|
477
494
|
|
|
478
495
|
routes: () => ({
|
|
479
|
-
formList: createRoute("/forms", () =>
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
496
|
+
formList: createRoute("/forms", () => {
|
|
497
|
+
const CustomFormList = config.pageComponents?.formList;
|
|
498
|
+
return {
|
|
499
|
+
PageComponent: CustomFormList ?? (() => <FormListPageComponent />),
|
|
500
|
+
loader: createFormListLoader(config),
|
|
501
|
+
meta: createFormListMeta(),
|
|
502
|
+
};
|
|
503
|
+
}),
|
|
504
|
+
|
|
505
|
+
newForm: createRoute("/forms/new", () => {
|
|
506
|
+
const CustomNewForm = config.pageComponents?.newForm;
|
|
507
|
+
return {
|
|
508
|
+
PageComponent: CustomNewForm ?? (() => <FormBuilderPageComponent />),
|
|
509
|
+
loader: createFormBuilderLoader(undefined, config),
|
|
510
|
+
meta: createFormBuilderMeta(undefined, config),
|
|
511
|
+
};
|
|
512
|
+
}),
|
|
513
|
+
|
|
514
|
+
editForm: createRoute("/forms/:id/edit", ({ params }) => {
|
|
515
|
+
const CustomEditForm = config.pageComponents?.editForm;
|
|
516
|
+
return {
|
|
517
|
+
PageComponent: CustomEditForm
|
|
518
|
+
? () => <CustomEditForm id={params.id} />
|
|
519
|
+
: () => <FormBuilderPageComponent id={params.id} />,
|
|
520
|
+
loader: createFormBuilderLoader(params.id, config),
|
|
521
|
+
meta: createFormBuilderMeta(params.id, config),
|
|
522
|
+
};
|
|
523
|
+
}),
|
|
524
|
+
|
|
525
|
+
submissions: createRoute("/forms/:id/submissions", ({ params }) => {
|
|
526
|
+
const CustomSubmissions = config.pageComponents?.submissions;
|
|
527
|
+
return {
|
|
528
|
+
PageComponent: CustomSubmissions
|
|
529
|
+
? () => <CustomSubmissions formId={params.id} />
|
|
530
|
+
: () => <SubmissionsPageComponent formId={params.id} />,
|
|
531
|
+
loader: createSubmissionsLoader(params.id, config),
|
|
532
|
+
meta: createSubmissionsMeta(params.id, config),
|
|
533
|
+
};
|
|
534
|
+
}),
|
|
502
535
|
}),
|
|
503
536
|
|
|
504
537
|
sitemap: async () => {
|
|
@@ -4,7 +4,7 @@ import { AlertCircle, RefreshCw } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error?:
|
|
7
|
+
error?: unknown;
|
|
8
8
|
reset?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -19,7 +19,8 @@ export function DefaultError({ error, reset }: DefaultErrorProps) {
|
|
|
19
19
|
</div>
|
|
20
20
|
<h3 className="text-lg font-semibold mb-2">Something went wrong</h3>
|
|
21
21
|
<p className="text-muted-foreground max-w-md mb-4">
|
|
22
|
-
{error
|
|
22
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
23
|
+
"An unexpected error occurred. Please try again."}
|
|
23
24
|
</p>
|
|
24
25
|
{reset && (
|
|
25
26
|
<Button onClick={reset} variant="outline">
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
runClientHookWithShim,
|
|
6
6
|
} from "@btst/stack/plugins/client";
|
|
7
7
|
import { createRoute } from "@btst/yar";
|
|
8
|
+
import type { ComponentType } from "react";
|
|
8
9
|
import type { QueryClient } from "@tanstack/react-query";
|
|
9
10
|
import type { KanbanApiRouter } from "../api";
|
|
10
11
|
import { createKanbanQueryKeys } from "../query-keys";
|
|
@@ -79,6 +80,20 @@ export interface KanbanClientConfig {
|
|
|
79
80
|
|
|
80
81
|
/** Optional headers for SSR (e.g., forwarding cookies) */
|
|
81
82
|
headers?: Headers;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Optional page component overrides.
|
|
86
|
+
* Replace any plugin page with a custom React component.
|
|
87
|
+
* The built-in component is used as the fallback when not provided.
|
|
88
|
+
*/
|
|
89
|
+
pageComponents?: {
|
|
90
|
+
/** Replaces the boards list page */
|
|
91
|
+
boards?: ComponentType;
|
|
92
|
+
/** Replaces the new board page */
|
|
93
|
+
newBoard?: ComponentType;
|
|
94
|
+
/** Replaces the board detail page */
|
|
95
|
+
board?: ComponentType<{ boardId: string }>;
|
|
96
|
+
};
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
/**
|
|
@@ -407,22 +422,27 @@ export const kanbanClientPlugin = (config: KanbanClientConfig) =>
|
|
|
407
422
|
|
|
408
423
|
routes: () => ({
|
|
409
424
|
boards: createRoute("/kanban", () => {
|
|
425
|
+
const CustomBoards = config.pageComponents?.boards;
|
|
410
426
|
return {
|
|
411
|
-
PageComponent: () => <BoardsListPageComponent
|
|
427
|
+
PageComponent: CustomBoards ?? (() => <BoardsListPageComponent />),
|
|
412
428
|
loader: createBoardsLoader(config),
|
|
413
429
|
meta: createBoardsListMeta(config),
|
|
414
430
|
};
|
|
415
431
|
}),
|
|
416
432
|
newBoard: createRoute("/kanban/new", () => {
|
|
433
|
+
const CustomNewBoard = config.pageComponents?.newBoard;
|
|
417
434
|
return {
|
|
418
|
-
PageComponent: NewBoardPageComponent,
|
|
435
|
+
PageComponent: CustomNewBoard ?? NewBoardPageComponent,
|
|
419
436
|
loader: createNewBoardLoader(config),
|
|
420
437
|
meta: createNewBoardMeta(config),
|
|
421
438
|
};
|
|
422
439
|
}),
|
|
423
440
|
board: createRoute("/kanban/:boardId", ({ params: { boardId } }) => {
|
|
441
|
+
const CustomBoard = config.pageComponents?.board;
|
|
424
442
|
return {
|
|
425
|
-
PageComponent:
|
|
443
|
+
PageComponent: CustomBoard
|
|
444
|
+
? () => <CustomBoard boardId={boardId} />
|
|
445
|
+
: () => <BoardPageComponent boardId={boardId} />,
|
|
426
446
|
loader: createBoardLoader(boardId, config),
|
|
427
447
|
meta: createBoardMeta(boardId, config),
|
|
428
448
|
};
|
|
@@ -29,13 +29,15 @@ function DefaultLoadingComponent(): ReactNode {
|
|
|
29
29
|
/**
|
|
30
30
|
* Default error component for PageRenderer
|
|
31
31
|
*/
|
|
32
|
-
function DefaultErrorComponent({ error }: { error:
|
|
32
|
+
function DefaultErrorComponent({ error }: { error: unknown }): ReactNode {
|
|
33
33
|
return (
|
|
34
34
|
<div className="flex flex-col items-center justify-center min-h-[200px] p-4">
|
|
35
35
|
<div className="text-destructive font-medium">
|
|
36
36
|
{uiBuilderLocalization.pageRenderer.error}
|
|
37
37
|
</div>
|
|
38
|
-
<div className="text-sm text-muted-foreground mt-2">
|
|
38
|
+
<div className="text-sm text-muted-foreground mt-2">
|
|
39
|
+
{error instanceof Error ? error.message : String(error)}
|
|
40
|
+
</div>
|
|
39
41
|
</div>
|
|
40
42
|
);
|
|
41
43
|
}
|
|
@@ -65,7 +67,7 @@ export interface PageRendererProps {
|
|
|
65
67
|
/** Custom loading component */
|
|
66
68
|
LoadingComponent?: ComponentType;
|
|
67
69
|
/** Custom error component */
|
|
68
|
-
ErrorComponent?: ComponentType<{ error:
|
|
70
|
+
ErrorComponent?: ComponentType<{ error: unknown }>;
|
|
69
71
|
/** Custom not found component */
|
|
70
72
|
NotFoundComponent?: ComponentType;
|
|
71
73
|
/** Additional className for the container */
|
|
@@ -4,7 +4,7 @@ import { AlertCircle } from "lucide-react";
|
|
|
4
4
|
import { Button } from "@workspace/ui/components/button";
|
|
5
5
|
|
|
6
6
|
interface DefaultErrorProps {
|
|
7
|
-
error:
|
|
7
|
+
error: unknown;
|
|
8
8
|
resetErrorBoundary?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -18,7 +18,8 @@ export function DefaultError({ error, resetErrorBoundary }: DefaultErrorProps) {
|
|
|
18
18
|
Something went wrong
|
|
19
19
|
</h3>
|
|
20
20
|
<p className="text-sm text-muted-foreground mb-4 max-w-sm">
|
|
21
|
-
{error
|
|
21
|
+
{(error instanceof Error ? error.message : undefined) ||
|
|
22
|
+
"An unexpected error occurred"}
|
|
22
23
|
</p>
|
|
23
24
|
{resetErrorBoundary && (
|
|
24
25
|
<Button variant="outline" onClick={resetErrorBoundary}>
|