@btst/plugin-cms 1.0.0 → 1.2.0-beta.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/dist/api/getters.cjs +37 -25
- package/dist/api/getters.mjs +37 -25
- package/dist/api/index.cjs +1 -0
- package/dist/api/index.d.cts +17 -8
- package/dist/api/index.d.mts +17 -8
- package/dist/api/index.d.ts +17 -8
- package/dist/api/index.mjs +1 -1
- package/dist/api/mutations.cjs +46 -19
- package/dist/api/mutations.mjs +46 -20
- package/dist/api/operations.cjs +586 -177
- package/dist/api/operations.mjs +585 -178
- package/dist/api/plugin.cjs +56 -7
- package/dist/api/plugin.mjs +57 -8
- package/dist/api/publication.cjs +8 -0
- package/dist/api/publication.mjs +6 -0
- package/dist/client/components/forms/content-form.cjs +107 -1
- package/dist/client/components/forms/content-form.mjs +108 -2
- package/dist/client/components/pages/content-editor-page.internal.cjs +23 -5
- package/dist/client/components/pages/content-editor-page.internal.mjs +23 -5
- package/dist/client/components/pages/content-list-page.internal.cjs +3 -0
- package/dist/client/components/pages/content-list-page.internal.mjs +3 -0
- package/dist/client/components/pages/dashboard-page.internal.cjs +10 -30
- package/dist/client/components/pages/dashboard-page.internal.mjs +10 -30
- package/dist/client/components/revision-history.cjs +161 -0
- package/dist/client/components/revision-history.mjs +159 -0
- package/dist/client/components/shared/content-type-card.cjs +56 -0
- package/dist/client/components/shared/content-type-card.mjs +54 -0
- package/dist/client/components/shared/empty-state.cjs +18 -1
- package/dist/client/components/shared/empty-state.mjs +19 -2
- package/dist/client/hooks/cms-hooks.cjs +18 -2
- package/dist/client/hooks/cms-hooks.mjs +17 -3
- package/dist/client/hooks/index.cjs +2 -0
- package/dist/client/hooks/index.d.cts +306 -2
- package/dist/client/hooks/index.d.mts +306 -2
- package/dist/client/hooks/index.d.ts +306 -2
- package/dist/client/hooks/index.mjs +1 -1
- package/dist/client/index.d.cts +55 -2
- package/dist/client/index.d.mts +55 -2
- package/dist/client/index.d.ts +55 -2
- package/dist/db.cjs +25 -0
- package/dist/db.mjs +25 -0
- package/dist/permissions.cjs +2 -0
- package/dist/permissions.d.cts +1 -0
- package/dist/permissions.d.mts +1 -0
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.mjs +2 -0
- package/dist/query-keys.cjs +31 -1
- package/dist/query-keys.d.cts +1 -1
- package/dist/query-keys.d.mts +1 -1
- package/dist/query-keys.d.ts +1 -1
- package/dist/query-keys.mjs +31 -1
- package/dist/shared/{plugin-cms.W4Le8D91.d.mts → plugin-cms.DAAUZ41w.d.mts} +377 -144
- package/dist/shared/{plugin-cms.c-GeWvTf.d.cts → plugin-cms.DJ_293QU.d.cts} +377 -144
- package/dist/shared/{plugin-cms.DQLAoogy.d.ts → plugin-cms.DlUSv7wz.d.ts} +377 -144
- package/dist/types.d.cts +38 -2
- package/dist/types.d.mts +38 -2
- package/dist/types.d.ts +38 -2
- package/dist/ui/src/components/auto-form/config.cjs +2 -0
- package/dist/ui/src/components/auto-form/config.mjs +2 -0
- package/dist/ui/src/components/auto-form/fields/file.cjs +68 -0
- package/dist/ui/src/components/auto-form/fields/file.mjs +63 -0
- package/dist/ui/src/components/auto-form/fields/object.cjs +9 -2
- package/dist/ui/src/components/auto-form/fields/object.mjs +9 -2
- package/dist/ui/src/components/auto-form/helpers.cjs +9 -0
- package/dist/ui/src/components/auto-form/helpers.mjs +9 -0
- package/dist/ui/src/components/auto-form/index.cjs +29 -4
- package/dist/ui/src/components/auto-form/index.mjs +31 -6
- package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +34 -29
- package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +35 -30
- package/dist/ui/src/components/sheet.cjs +126 -0
- package/dist/ui/src/components/sheet.mjs +105 -0
- package/dist/ui/src/lib/form-visibility.cjs +20 -0
- package/dist/ui/src/lib/form-visibility.mjs +18 -0
- package/dist/ui/src/lib/schema-converter.cjs +101 -0
- package/dist/ui/src/lib/schema-converter.mjs +100 -1
- package/package.json +5 -4
|
@@ -8,6 +8,7 @@ import { orderCMSContentTypes } from '../../overrides.mjs';
|
|
|
8
8
|
import { CMS_PLUGIN_ID } from '../../constants.mjs';
|
|
9
9
|
import { ContentForm } from '../forms/content-form.mjs';
|
|
10
10
|
import { InverseRelationsPanel } from '../inverse-relations-panel.mjs';
|
|
11
|
+
import { RevisionHistory } from '../revision-history.mjs';
|
|
11
12
|
import { EmptyState } from '../shared/empty-state.mjs';
|
|
12
13
|
import { PageWrapper } from '../shared/page-wrapper.mjs';
|
|
13
14
|
import { EditorSkeleton } from '../loading/editor-skeleton.mjs';
|
|
@@ -85,6 +86,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
85
86
|
);
|
|
86
87
|
const contentType = contentTypes.find((ct) => ct.slug === typeSlug);
|
|
87
88
|
const isEditing = !!id;
|
|
89
|
+
const [restoreCount, setRestoreCount] = useState(0);
|
|
88
90
|
const { item, isLoading: isLoadingItem } = useContentItem(typeSlug, id ?? "");
|
|
89
91
|
const resourceForm = useContentItemForm({
|
|
90
92
|
action: isEditing ? "edit" : "create",
|
|
@@ -93,12 +95,17 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
93
95
|
toCreateVars: (values) => ({
|
|
94
96
|
typeSlug,
|
|
95
97
|
slug: values.slug,
|
|
96
|
-
data: values.data
|
|
98
|
+
data: values.data,
|
|
99
|
+
publishAt: values.publishAt
|
|
97
100
|
}),
|
|
98
101
|
toUpdateVars: (values) => ({
|
|
99
102
|
typeSlug,
|
|
100
103
|
id: id ?? "",
|
|
101
|
-
data: {
|
|
104
|
+
data: {
|
|
105
|
+
slug: values.slug,
|
|
106
|
+
data: values.data,
|
|
107
|
+
publishAt: values.publishAt
|
|
108
|
+
}
|
|
102
109
|
}),
|
|
103
110
|
onSuccess: () => {
|
|
104
111
|
void navigate?.(joinBasePath(basePath, `/cms/${typeSlug}`));
|
|
@@ -108,6 +115,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
108
115
|
return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx(
|
|
109
116
|
EmptyState,
|
|
110
117
|
{
|
|
118
|
+
page: id ? "editContent" : "newContent",
|
|
111
119
|
title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
|
|
112
120
|
description: localization?.CMS_ERROR_TYPE_NOT_FOUND_DESCRIPTION ?? t("cms.common.typeNotFoundDescription", "Content type not found")
|
|
113
121
|
}
|
|
@@ -120,6 +128,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
120
128
|
return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx(
|
|
121
129
|
EmptyState,
|
|
122
130
|
{
|
|
131
|
+
page: id ? "editContent" : "newContent",
|
|
123
132
|
title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
|
|
124
133
|
description: localization?.CMS_ERROR_ITEM_NOT_FOUND_DESCRIPTION ?? t("cms.common.itemNotFoundDescription", "Content item not found")
|
|
125
134
|
}
|
|
@@ -131,7 +140,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
131
140
|
const hasFieldErrors = Object.keys(resourceForm.fieldErrors).length > 0;
|
|
132
141
|
const title = isEditing ? (localization?.CMS_EDITOR_TITLE_EDIT ?? t("cms.editor.titleEdit", "Edit {typeName}")).replace("{typeName}", contentType.name) : (localization?.CMS_EDITOR_TITLE_NEW ?? t("cms.editor.titleNew", "New {typeName}")).replace("{typeName}", contentType.name);
|
|
133
142
|
return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-editor-page", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-2xl space-y-6", children: [
|
|
134
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
143
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-4", children: [
|
|
135
144
|
/* @__PURE__ */ jsx(
|
|
136
145
|
Button,
|
|
137
146
|
{
|
|
@@ -141,7 +150,15 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
141
150
|
children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" })
|
|
142
151
|
}
|
|
143
152
|
),
|
|
144
|
-
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title })
|
|
153
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
154
|
+
isEditing && id && /* @__PURE__ */ jsx(
|
|
155
|
+
RevisionHistory,
|
|
156
|
+
{
|
|
157
|
+
typeSlug,
|
|
158
|
+
itemId: id,
|
|
159
|
+
onRestored: () => setRestoreCount((count) => count + 1)
|
|
160
|
+
}
|
|
161
|
+
)
|
|
145
162
|
] }),
|
|
146
163
|
/* @__PURE__ */ jsx(
|
|
147
164
|
ContentForm,
|
|
@@ -152,6 +169,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
152
169
|
JSON.parse(contentType.jsonSchema)
|
|
153
170
|
) : void 0,
|
|
154
171
|
initialSlug: item?.slug,
|
|
172
|
+
initialPublishAt: item?.publishAt,
|
|
155
173
|
isEditing,
|
|
156
174
|
onSubmit: handleSubmit,
|
|
157
175
|
onCancel: () => void navigate?.(joinBasePath(basePath, `/cms/${typeSlug}`)),
|
|
@@ -159,7 +177,7 @@ function ContentEditorPage({ typeSlug, id }) {
|
|
|
159
177
|
errorMessage: hasFieldErrors ? void 0 : resourceForm.error?.message,
|
|
160
178
|
isSubmitting: resourceForm.isSubmitting
|
|
161
179
|
},
|
|
162
|
-
isEditing ? `edit-${id}` : "create"
|
|
180
|
+
isEditing ? `edit-${id}-${restoreCount}` : "create"
|
|
163
181
|
),
|
|
164
182
|
isEditing && id && /* @__PURE__ */ jsx(InverseRelationsPanel, { contentTypeSlug: typeSlug, itemId: id })
|
|
165
183
|
] }) });
|
|
@@ -99,6 +99,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
99
99
|
return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-list-page", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full max-w-5xl", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
100
100
|
emptyState.EmptyState,
|
|
101
101
|
{
|
|
102
|
+
page: "contentList",
|
|
102
103
|
title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
|
|
103
104
|
description: localization?.CMS_ERROR_TYPE_NOT_FOUND_DESCRIPTION ?? t("cms.common.typeNotFoundDescription", "Content type not found")
|
|
104
105
|
}
|
|
@@ -157,6 +158,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
157
158
|
items.length === 0 ? isSearchLoading ? null : hasSearch ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
158
159
|
emptyState.EmptyState,
|
|
159
160
|
{
|
|
161
|
+
page: "contentList",
|
|
160
162
|
title: localization?.CMS_LIST_SEARCH_EMPTY ?? t("cms.list.searchEmpty", "No items match your search"),
|
|
161
163
|
description: localization?.CMS_LIST_SEARCH_EMPTY_DESCRIPTION ?? t(
|
|
162
164
|
"cms.list.searchEmptyDescription",
|
|
@@ -166,6 +168,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
166
168
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
167
169
|
emptyState.EmptyState,
|
|
168
170
|
{
|
|
171
|
+
page: "contentList",
|
|
169
172
|
title: localization?.CMS_LIST_EMPTY ?? t("cms.list.empty", "No items yet"),
|
|
170
173
|
description: localization?.CMS_LIST_EMPTY_DESCRIPTION ?? t(
|
|
171
174
|
"cms.list.emptyDescription",
|
|
@@ -97,6 +97,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
97
97
|
return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-list-page", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-5xl", children: /* @__PURE__ */ jsx(
|
|
98
98
|
EmptyState,
|
|
99
99
|
{
|
|
100
|
+
page: "contentList",
|
|
100
101
|
title: localization?.CMS_ERROR_NOT_FOUND ?? t("cms.common.notFound", "Not found"),
|
|
101
102
|
description: localization?.CMS_ERROR_TYPE_NOT_FOUND_DESCRIPTION ?? t("cms.common.typeNotFoundDescription", "Content type not found")
|
|
102
103
|
}
|
|
@@ -155,6 +156,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
155
156
|
items.length === 0 ? isSearchLoading ? null : hasSearch ? /* @__PURE__ */ jsx(
|
|
156
157
|
EmptyState,
|
|
157
158
|
{
|
|
159
|
+
page: "contentList",
|
|
158
160
|
title: localization?.CMS_LIST_SEARCH_EMPTY ?? t("cms.list.searchEmpty", "No items match your search"),
|
|
159
161
|
description: localization?.CMS_LIST_SEARCH_EMPTY_DESCRIPTION ?? t(
|
|
160
162
|
"cms.list.searchEmptyDescription",
|
|
@@ -164,6 +166,7 @@ function ContentListPage({ typeSlug }) {
|
|
|
164
166
|
) : /* @__PURE__ */ jsx(
|
|
165
167
|
EmptyState,
|
|
166
168
|
{
|
|
169
|
+
page: "contentList",
|
|
167
170
|
title: localization?.CMS_LIST_EMPTY ?? t("cms.list.empty", "No items yet"),
|
|
168
171
|
description: localization?.CMS_LIST_EMPTY_DESCRIPTION ?? t(
|
|
169
172
|
"cms.list.emptyDescription",
|
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
const lucideReact = require('lucide-react');
|
|
6
|
-
const card = require('../../../ui/src/components/card.cjs');
|
|
7
5
|
const context = require('@btst/stack/context');
|
|
8
6
|
const overrides = require('../../overrides.cjs');
|
|
9
7
|
const constants = require('../../constants.cjs');
|
|
10
8
|
const emptyState = require('../shared/empty-state.cjs');
|
|
11
9
|
const pageWrapper = require('../shared/page-wrapper.cjs');
|
|
12
10
|
const useRouteLifecycle = require('../../../ui/src/hooks/use-route-lifecycle.cjs');
|
|
13
|
-
const
|
|
11
|
+
const contentTypeCard = require('../shared/content-type-card.cjs');
|
|
14
12
|
const cmsHooks = require('../../hooks/cms-hooks.cjs');
|
|
15
13
|
|
|
16
14
|
function DashboardPage() {
|
|
@@ -44,6 +42,7 @@ function DashboardPage() {
|
|
|
44
42
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45
43
|
emptyState.EmptyState,
|
|
46
44
|
{
|
|
45
|
+
page: "dashboard",
|
|
47
46
|
title: localization?.CMS_DASHBOARD_NO_TYPES ?? t("cms.dashboard.noTypes", "No content types configured"),
|
|
48
47
|
description: localization?.CMS_DASHBOARD_NO_TYPES_DESCRIPTION ?? t(
|
|
49
48
|
"cms.dashboard.noTypesDescription",
|
|
@@ -65,34 +64,15 @@ function DashboardPage() {
|
|
|
65
64
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
66
65
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: subtitle })
|
|
67
66
|
] }),
|
|
68
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: contentTypes.map((ct) => /* @__PURE__ */ jsxRuntime.
|
|
69
|
-
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: contentTypes.map((ct) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
+
contentTypeCard.ContentTypeCard,
|
|
70
69
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/* @__PURE__ */ jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
78
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
79
|
-
card.CardTitle,
|
|
80
|
-
{
|
|
81
|
-
className: utils.cn(
|
|
82
|
-
"text-lg font-medium",
|
|
83
|
-
classNames?.contentTypeTitle
|
|
84
|
-
),
|
|
85
|
-
children: ct.name
|
|
86
|
-
}
|
|
87
|
-
),
|
|
88
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-5 w-5 text-muted-foreground" })
|
|
89
|
-
] }),
|
|
90
|
-
/* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { children: [
|
|
91
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold", children: ct.itemCount }),
|
|
92
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: formatItemCount(ct.itemCount) }),
|
|
93
|
-
ct.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2 line-clamp-2", children: ct.description })
|
|
94
|
-
] })
|
|
95
|
-
]
|
|
70
|
+
page: "dashboard",
|
|
71
|
+
contentType: ct,
|
|
72
|
+
itemCountLabel: formatItemCount(ct.itemCount),
|
|
73
|
+
className: classNames?.contentTypeCard,
|
|
74
|
+
titleClassName: classNames?.contentTypeTitle,
|
|
75
|
+
onOpen: () => void navigate?.(context.joinBasePath(basePath, `/cms/${ct.slug}`))
|
|
96
76
|
},
|
|
97
77
|
ct.id
|
|
98
78
|
)) })
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { FileText } from 'lucide-react';
|
|
4
|
-
import { Card, CardHeader, CardTitle, CardContent } from '../../../ui/src/components/card.mjs';
|
|
5
3
|
import { useTranslate, usePluginOverrides, useStack, joinBasePath } from '@btst/stack/context';
|
|
6
4
|
import { orderCMSContentTypes } from '../../overrides.mjs';
|
|
7
5
|
import { CMS_PLUGIN_ID } from '../../constants.mjs';
|
|
8
6
|
import { EmptyState } from '../shared/empty-state.mjs';
|
|
9
7
|
import { PageWrapper } from '../shared/page-wrapper.mjs';
|
|
10
8
|
import { useRouteLifecycle } from '../../../ui/src/hooks/use-route-lifecycle.mjs';
|
|
11
|
-
import {
|
|
9
|
+
import { ContentTypeCard } from '../shared/content-type-card.mjs';
|
|
12
10
|
import { useSuspenseContentTypes } from '../../hooks/cms-hooks.mjs';
|
|
13
11
|
|
|
14
12
|
function DashboardPage() {
|
|
@@ -42,6 +40,7 @@ function DashboardPage() {
|
|
|
42
40
|
/* @__PURE__ */ jsx(
|
|
43
41
|
EmptyState,
|
|
44
42
|
{
|
|
43
|
+
page: "dashboard",
|
|
45
44
|
title: localization?.CMS_DASHBOARD_NO_TYPES ?? t("cms.dashboard.noTypes", "No content types configured"),
|
|
46
45
|
description: localization?.CMS_DASHBOARD_NO_TYPES_DESCRIPTION ?? t(
|
|
47
46
|
"cms.dashboard.noTypesDescription",
|
|
@@ -63,34 +62,15 @@ function DashboardPage() {
|
|
|
63
62
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold tracking-tight", children: title }),
|
|
64
63
|
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: subtitle })
|
|
65
64
|
] }),
|
|
66
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: contentTypes.map((ct) => /* @__PURE__ */
|
|
67
|
-
|
|
65
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: contentTypes.map((ct) => /* @__PURE__ */ jsx(
|
|
66
|
+
ContentTypeCard,
|
|
68
67
|
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/* @__PURE__ */ jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
76
|
-
/* @__PURE__ */ jsx(
|
|
77
|
-
CardTitle,
|
|
78
|
-
{
|
|
79
|
-
className: cn(
|
|
80
|
-
"text-lg font-medium",
|
|
81
|
-
classNames?.contentTypeTitle
|
|
82
|
-
),
|
|
83
|
-
children: ct.name
|
|
84
|
-
}
|
|
85
|
-
),
|
|
86
|
-
/* @__PURE__ */ jsx(FileText, { className: "h-5 w-5 text-muted-foreground" })
|
|
87
|
-
] }),
|
|
88
|
-
/* @__PURE__ */ jsxs(CardContent, { children: [
|
|
89
|
-
/* @__PURE__ */ jsx("div", { className: "text-2xl font-bold", children: ct.itemCount }),
|
|
90
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: formatItemCount(ct.itemCount) }),
|
|
91
|
-
ct.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-2 line-clamp-2", children: ct.description })
|
|
92
|
-
] })
|
|
93
|
-
]
|
|
68
|
+
page: "dashboard",
|
|
69
|
+
contentType: ct,
|
|
70
|
+
itemCountLabel: formatItemCount(ct.itemCount),
|
|
71
|
+
className: classNames?.contentTypeCard,
|
|
72
|
+
titleClassName: classNames?.contentTypeTitle,
|
|
73
|
+
onOpen: () => void navigate?.(joinBasePath(basePath, `/cms/${ct.slug}`))
|
|
94
74
|
},
|
|
95
75
|
ct.id
|
|
96
76
|
)) })
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
const React = require('react');
|
|
6
|
+
const button = require('../../ui/src/components/button.cjs');
|
|
7
|
+
const sheet = require('../../ui/src/components/sheet.cjs');
|
|
8
|
+
const alertDialog = require('../../ui/src/components/alert-dialog.cjs');
|
|
9
|
+
const context = require('@btst/stack/context');
|
|
10
|
+
const cmsHooks = require('../hooks/cms-hooks.cjs');
|
|
11
|
+
|
|
12
|
+
function RevisionHistory({
|
|
13
|
+
typeSlug,
|
|
14
|
+
itemId,
|
|
15
|
+
onRestored
|
|
16
|
+
}) {
|
|
17
|
+
const t = context.useTranslate();
|
|
18
|
+
const [open, setOpen] = React.useState(false);
|
|
19
|
+
const [selected, setSelected] = React.useState(
|
|
20
|
+
null
|
|
21
|
+
);
|
|
22
|
+
const [restoreError, setRestoreError] = React.useState(null);
|
|
23
|
+
const history = cmsHooks.useContentRevisions(typeSlug, itemId, open);
|
|
24
|
+
const restore = cmsHooks.useRestoreContentRevision();
|
|
25
|
+
const restoreSelected = async () => {
|
|
26
|
+
if (!selected) return;
|
|
27
|
+
setRestoreError(null);
|
|
28
|
+
try {
|
|
29
|
+
await restore.mutateAsync({
|
|
30
|
+
typeSlug,
|
|
31
|
+
id: itemId,
|
|
32
|
+
revisionId: selected.id
|
|
33
|
+
});
|
|
34
|
+
onRestored();
|
|
35
|
+
setSelected(null);
|
|
36
|
+
setOpen(false);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
setRestoreError(
|
|
39
|
+
error instanceof Error ? error.message : t("cms.revisions.restoreError", "Could not restore revision")
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(sheet.Sheet, { open, onOpenChange: setOpen, children: [
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(sheet.SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(button.Button, { variant: "outline", children: t("cms.revisions.title", "Revision history") }) }),
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsxs(sheet.SheetContent, { className: "w-full overflow-y-auto sm:max-w-lg", children: [
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsxs(sheet.SheetHeader, { children: [
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx(sheet.SheetTitle, { children: t("cms.revisions.title", "Revision history") }),
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx(sheet.SheetDescription, { children: t(
|
|
49
|
+
"cms.revisions.description",
|
|
50
|
+
"Inspect saved versions. Restoring a version replaces the editor state and creates a new revision."
|
|
51
|
+
) })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 px-4 pb-6", children: [
|
|
54
|
+
history.isLoading && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: t("cms.revisions.loading", "Loading revisions...") }),
|
|
55
|
+
history.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: "space-y-2", children: [
|
|
56
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive", children: history.error.message }),
|
|
57
|
+
/* @__PURE__ */ jsxRuntime.jsx(button.Button, { variant: "outline", onClick: () => void history.refetch(), children: t("cms.revisions.retry", "Retry") })
|
|
58
|
+
] }),
|
|
59
|
+
!history.isLoading && !history.error && history.revisions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: t(
|
|
60
|
+
"cms.revisions.empty",
|
|
61
|
+
"No revisions yet. Saving this entry will create its first revision."
|
|
62
|
+
) }),
|
|
63
|
+
history.revisions.map((revision) => /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "rounded-md border p-3", children: [
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "cursor-pointer space-y-1 break-words", children: [
|
|
65
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: t("cms.revisions.version", "Version {version}").replace(
|
|
66
|
+
"{version}",
|
|
67
|
+
String(revision.version)
|
|
68
|
+
) }),
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-sm text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: revision.createdAt, children: new Date(revision.createdAt).toLocaleString() }) }),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "block text-sm text-muted-foreground", children: [
|
|
71
|
+
t("cms.revisions.author", "Author"),
|
|
72
|
+
":",
|
|
73
|
+
" ",
|
|
74
|
+
revision.authorId ?? t("cms.revisions.system", "System")
|
|
75
|
+
] })
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 space-y-3 text-sm", children: [
|
|
78
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "break-words", children: [
|
|
79
|
+
t("cms.common.slugLabel", "Slug"),
|
|
80
|
+
": ",
|
|
81
|
+
revision.slug
|
|
82
|
+
] }),
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
84
|
+
t("cms.editor.publishAt", "Publish at"),
|
|
85
|
+
":",
|
|
86
|
+
" ",
|
|
87
|
+
revision.publishAt ? new Date(revision.publishAt).toLocaleString() : t("cms.revisions.unscheduled", "Not scheduled")
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
90
|
+
"pre",
|
|
91
|
+
{
|
|
92
|
+
className: "max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs",
|
|
93
|
+
"aria-label": t("cms.revisions.snapshot", "Field snapshot"),
|
|
94
|
+
children: JSON.stringify(JSON.parse(revision.data), null, 2)
|
|
95
|
+
}
|
|
96
|
+
),
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
98
|
+
button.Button,
|
|
99
|
+
{
|
|
100
|
+
variant: "outline",
|
|
101
|
+
disabled: restore.isPending,
|
|
102
|
+
onClick: () => {
|
|
103
|
+
setRestoreError(null);
|
|
104
|
+
setSelected(revision);
|
|
105
|
+
},
|
|
106
|
+
children: t("cms.revisions.restore", "Restore this version")
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
] })
|
|
110
|
+
] }, revision.id)),
|
|
111
|
+
history.hasNextPage && /* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
+
button.Button,
|
|
113
|
+
{
|
|
114
|
+
variant: "outline",
|
|
115
|
+
disabled: history.isFetchingNextPage,
|
|
116
|
+
onClick: () => void history.fetchNextPage(),
|
|
117
|
+
children: t("cms.revisions.loadMore", "Load older revisions")
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
] })
|
|
121
|
+
] }),
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
123
|
+
alertDialog.AlertDialog,
|
|
124
|
+
{
|
|
125
|
+
open: !!selected,
|
|
126
|
+
onOpenChange: (value) => {
|
|
127
|
+
if (!value && !restore.isPending) setSelected(null);
|
|
128
|
+
},
|
|
129
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogContent, { children: [
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogHeader, { children: [
|
|
131
|
+
/* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogTitle, { children: t(
|
|
132
|
+
"cms.revisions.confirmTitle",
|
|
133
|
+
"Restore version {version}?"
|
|
134
|
+
).replace("{version}", String(selected?.version ?? "")) }),
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogDescription, { children: t(
|
|
136
|
+
"cms.revisions.confirmDescription",
|
|
137
|
+
"This replaces the active entry, including its slug and schedule. Unsaved editor changes will be discarded. Existing revisions are kept."
|
|
138
|
+
) })
|
|
139
|
+
] }),
|
|
140
|
+
restoreError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive", children: restoreError }),
|
|
141
|
+
/* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogFooter, { children: [
|
|
142
|
+
/* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogCancel, { disabled: restore.isPending, children: t("cms.common.cancel", "Cancel") }),
|
|
143
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
144
|
+
alertDialog.AlertDialogAction,
|
|
145
|
+
{
|
|
146
|
+
disabled: restore.isPending,
|
|
147
|
+
onClick: (event) => {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
void restoreSelected();
|
|
150
|
+
},
|
|
151
|
+
children: restore.isPending ? t("cms.revisions.restoring", "Restoring...") : t("cms.revisions.confirm", "Restore version")
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
] })
|
|
155
|
+
] })
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
] });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
exports.RevisionHistory = RevisionHistory;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Button } from '../../ui/src/components/button.mjs';
|
|
5
|
+
import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '../../ui/src/components/sheet.mjs';
|
|
6
|
+
import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from '../../ui/src/components/alert-dialog.mjs';
|
|
7
|
+
import { useTranslate } from '@btst/stack/context';
|
|
8
|
+
import { useContentRevisions, useRestoreContentRevision } from '../hooks/cms-hooks.mjs';
|
|
9
|
+
|
|
10
|
+
function RevisionHistory({
|
|
11
|
+
typeSlug,
|
|
12
|
+
itemId,
|
|
13
|
+
onRestored
|
|
14
|
+
}) {
|
|
15
|
+
const t = useTranslate();
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
17
|
+
const [selected, setSelected] = useState(
|
|
18
|
+
null
|
|
19
|
+
);
|
|
20
|
+
const [restoreError, setRestoreError] = useState(null);
|
|
21
|
+
const history = useContentRevisions(typeSlug, itemId, open);
|
|
22
|
+
const restore = useRestoreContentRevision();
|
|
23
|
+
const restoreSelected = async () => {
|
|
24
|
+
if (!selected) return;
|
|
25
|
+
setRestoreError(null);
|
|
26
|
+
try {
|
|
27
|
+
await restore.mutateAsync({
|
|
28
|
+
typeSlug,
|
|
29
|
+
id: itemId,
|
|
30
|
+
revisionId: selected.id
|
|
31
|
+
});
|
|
32
|
+
onRestored();
|
|
33
|
+
setSelected(null);
|
|
34
|
+
setOpen(false);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
setRestoreError(
|
|
37
|
+
error instanceof Error ? error.message : t("cms.revisions.restoreError", "Could not restore revision")
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
|
|
42
|
+
/* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", children: t("cms.revisions.title", "Revision history") }) }),
|
|
43
|
+
/* @__PURE__ */ jsxs(SheetContent, { className: "w-full overflow-y-auto sm:max-w-lg", children: [
|
|
44
|
+
/* @__PURE__ */ jsxs(SheetHeader, { children: [
|
|
45
|
+
/* @__PURE__ */ jsx(SheetTitle, { children: t("cms.revisions.title", "Revision history") }),
|
|
46
|
+
/* @__PURE__ */ jsx(SheetDescription, { children: t(
|
|
47
|
+
"cms.revisions.description",
|
|
48
|
+
"Inspect saved versions. Restoring a version replaces the editor state and creates a new revision."
|
|
49
|
+
) })
|
|
50
|
+
] }),
|
|
51
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 px-4 pb-6", children: [
|
|
52
|
+
history.isLoading && /* @__PURE__ */ jsx("p", { role: "status", children: t("cms.revisions.loading", "Loading revisions...") }),
|
|
53
|
+
history.error && /* @__PURE__ */ jsxs("div", { role: "alert", className: "space-y-2", children: [
|
|
54
|
+
/* @__PURE__ */ jsx("p", { className: "text-destructive", children: history.error.message }),
|
|
55
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => void history.refetch(), children: t("cms.revisions.retry", "Retry") })
|
|
56
|
+
] }),
|
|
57
|
+
!history.isLoading && !history.error && history.revisions.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t(
|
|
58
|
+
"cms.revisions.empty",
|
|
59
|
+
"No revisions yet. Saving this entry will create its first revision."
|
|
60
|
+
) }),
|
|
61
|
+
history.revisions.map((revision) => /* @__PURE__ */ jsxs("details", { className: "rounded-md border p-3", children: [
|
|
62
|
+
/* @__PURE__ */ jsxs("summary", { className: "cursor-pointer space-y-1 break-words", children: [
|
|
63
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: t("cms.revisions.version", "Version {version}").replace(
|
|
64
|
+
"{version}",
|
|
65
|
+
String(revision.version)
|
|
66
|
+
) }),
|
|
67
|
+
/* @__PURE__ */ jsx("span", { className: "block text-sm text-muted-foreground", children: /* @__PURE__ */ jsx("time", { dateTime: revision.createdAt, children: new Date(revision.createdAt).toLocaleString() }) }),
|
|
68
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-sm text-muted-foreground", children: [
|
|
69
|
+
t("cms.revisions.author", "Author"),
|
|
70
|
+
":",
|
|
71
|
+
" ",
|
|
72
|
+
revision.authorId ?? t("cms.revisions.system", "System")
|
|
73
|
+
] })
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-3 text-sm", children: [
|
|
76
|
+
/* @__PURE__ */ jsxs("p", { className: "break-words", children: [
|
|
77
|
+
t("cms.common.slugLabel", "Slug"),
|
|
78
|
+
": ",
|
|
79
|
+
revision.slug
|
|
80
|
+
] }),
|
|
81
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
82
|
+
t("cms.editor.publishAt", "Publish at"),
|
|
83
|
+
":",
|
|
84
|
+
" ",
|
|
85
|
+
revision.publishAt ? new Date(revision.publishAt).toLocaleString() : t("cms.revisions.unscheduled", "Not scheduled")
|
|
86
|
+
] }),
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
"pre",
|
|
89
|
+
{
|
|
90
|
+
className: "max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs",
|
|
91
|
+
"aria-label": t("cms.revisions.snapshot", "Field snapshot"),
|
|
92
|
+
children: JSON.stringify(JSON.parse(revision.data), null, 2)
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
Button,
|
|
97
|
+
{
|
|
98
|
+
variant: "outline",
|
|
99
|
+
disabled: restore.isPending,
|
|
100
|
+
onClick: () => {
|
|
101
|
+
setRestoreError(null);
|
|
102
|
+
setSelected(revision);
|
|
103
|
+
},
|
|
104
|
+
children: t("cms.revisions.restore", "Restore this version")
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
] })
|
|
108
|
+
] }, revision.id)),
|
|
109
|
+
history.hasNextPage && /* @__PURE__ */ jsx(
|
|
110
|
+
Button,
|
|
111
|
+
{
|
|
112
|
+
variant: "outline",
|
|
113
|
+
disabled: history.isFetchingNextPage,
|
|
114
|
+
onClick: () => void history.fetchNextPage(),
|
|
115
|
+
children: t("cms.revisions.loadMore", "Load older revisions")
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
] })
|
|
119
|
+
] }),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
AlertDialog,
|
|
122
|
+
{
|
|
123
|
+
open: !!selected,
|
|
124
|
+
onOpenChange: (value) => {
|
|
125
|
+
if (!value && !restore.isPending) setSelected(null);
|
|
126
|
+
},
|
|
127
|
+
children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
|
|
128
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
|
|
129
|
+
/* @__PURE__ */ jsx(AlertDialogTitle, { children: t(
|
|
130
|
+
"cms.revisions.confirmTitle",
|
|
131
|
+
"Restore version {version}?"
|
|
132
|
+
).replace("{version}", String(selected?.version ?? "")) }),
|
|
133
|
+
/* @__PURE__ */ jsx(AlertDialogDescription, { children: t(
|
|
134
|
+
"cms.revisions.confirmDescription",
|
|
135
|
+
"This replaces the active entry, including its slug and schedule. Unsaved editor changes will be discarded. Existing revisions are kept."
|
|
136
|
+
) })
|
|
137
|
+
] }),
|
|
138
|
+
restoreError && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: restoreError }),
|
|
139
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
|
|
140
|
+
/* @__PURE__ */ jsx(AlertDialogCancel, { disabled: restore.isPending, children: t("cms.common.cancel", "Cancel") }),
|
|
141
|
+
/* @__PURE__ */ jsx(
|
|
142
|
+
AlertDialogAction,
|
|
143
|
+
{
|
|
144
|
+
disabled: restore.isPending,
|
|
145
|
+
onClick: (event) => {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
void restoreSelected();
|
|
148
|
+
},
|
|
149
|
+
children: restore.isPending ? t("cms.revisions.restoring", "Restoring...") : t("cms.revisions.confirm", "Restore version")
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
] })
|
|
153
|
+
] })
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
] });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export { RevisionHistory };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
const lucideReact = require('lucide-react');
|
|
6
|
+
const card = require('../../../ui/src/components/card.cjs');
|
|
7
|
+
const context = require('@btst/stack/context');
|
|
8
|
+
const constants = require('../../constants.cjs');
|
|
9
|
+
const utils = require('../../../utils.cjs');
|
|
10
|
+
|
|
11
|
+
function ContentTypeCard({
|
|
12
|
+
page,
|
|
13
|
+
...props
|
|
14
|
+
}) {
|
|
15
|
+
if (!page) return /* @__PURE__ */ jsxRuntime.jsx(DefaultContentTypeCard, { ...props });
|
|
16
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ScopedContentTypeCard, { page, ...props });
|
|
17
|
+
}
|
|
18
|
+
function ScopedContentTypeCard({
|
|
19
|
+
page,
|
|
20
|
+
...props
|
|
21
|
+
}) {
|
|
22
|
+
const { pageOverrides } = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
|
|
23
|
+
const TypeCard = (page ? pageOverrides?.[page]?.ContentTypeCard : void 0) ?? DefaultContentTypeCard;
|
|
24
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TypeCard, { ...props });
|
|
25
|
+
}
|
|
26
|
+
function DefaultContentTypeCard({
|
|
27
|
+
contentType,
|
|
28
|
+
itemCountLabel,
|
|
29
|
+
onOpen,
|
|
30
|
+
className,
|
|
31
|
+
titleClassName
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
34
|
+
card.Card,
|
|
35
|
+
{
|
|
36
|
+
className: utils.cn(
|
|
37
|
+
"hover:border-primary/50 transition-colors cursor-pointer",
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
onClick: onOpen,
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
43
|
+
/* @__PURE__ */ jsxRuntime.jsx(card.CardTitle, { className: utils.cn("text-lg font-medium", titleClassName), children: contentType.name }),
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "h-5 w-5 text-muted-foreground" })
|
|
45
|
+
] }),
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { children: [
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold", children: contentType.itemCount }),
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: itemCountLabel }),
|
|
49
|
+
contentType.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2 line-clamp-2", children: contentType.description })
|
|
50
|
+
] })
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.ContentTypeCard = ContentTypeCard;
|