@btst/plugin-cms 0.0.0-stage → 1.0.0-beta.0

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.
Files changed (204) hide show
  1. package/LICENSE.md +17 -0
  2. package/dist/api/getters.cjs +328 -0
  3. package/dist/api/getters.mjs +314 -0
  4. package/dist/api/index.cjs +29 -0
  5. package/dist/api/index.d.cts +209 -0
  6. package/dist/api/index.d.mts +209 -0
  7. package/dist/api/index.d.ts +209 -0
  8. package/dist/api/index.mjs +7 -0
  9. package/dist/api/lifecycle-migrations.cjs +13 -0
  10. package/dist/api/lifecycle-migrations.mjs +11 -0
  11. package/dist/api/mutations.cjs +59 -0
  12. package/dist/api/mutations.mjs +57 -0
  13. package/dist/api/operations.cjs +1769 -0
  14. package/dist/api/operations.mjs +1762 -0
  15. package/dist/api/plugin.cjs +337 -0
  16. package/dist/api/plugin.mjs +331 -0
  17. package/dist/api/query-key-defs.cjs +44 -0
  18. package/dist/api/query-key-defs.mjs +39 -0
  19. package/dist/api/relations.cjs +76 -0
  20. package/dist/api/relations.mjs +70 -0
  21. package/dist/client/components/forms/content-form.cjs +286 -0
  22. package/dist/client/components/forms/content-form.mjs +284 -0
  23. package/dist/client/components/forms/file-upload.cjs +160 -0
  24. package/dist/client/components/forms/file-upload.mjs +158 -0
  25. package/dist/client/components/forms/relation-field.cjs +237 -0
  26. package/dist/client/components/forms/relation-field.mjs +235 -0
  27. package/dist/client/components/index.cjs +14 -0
  28. package/dist/client/components/index.d.cts +20 -0
  29. package/dist/client/components/index.d.mts +20 -0
  30. package/dist/client/components/index.d.ts +20 -0
  31. package/dist/client/components/index.mjs +10 -0
  32. package/dist/client/components/inverse-relations-panel.cjs +272 -0
  33. package/dist/client/components/inverse-relations-panel.mjs +270 -0
  34. package/dist/client/components/loading/dashboard-skeleton.cjs +18 -0
  35. package/dist/client/components/loading/dashboard-skeleton.mjs +16 -0
  36. package/dist/client/components/loading/editor-skeleton.cjs +32 -0
  37. package/dist/client/components/loading/editor-skeleton.mjs +30 -0
  38. package/dist/client/components/loading/list-skeleton.cjs +32 -0
  39. package/dist/client/components/loading/list-skeleton.mjs +30 -0
  40. package/dist/client/components/pages/404-page.cjs +26 -0
  41. package/dist/client/components/pages/404-page.mjs +24 -0
  42. package/dist/client/components/pages/content-editor-page.cjs +84 -0
  43. package/dist/client/components/pages/content-editor-page.internal.cjs +170 -0
  44. package/dist/client/components/pages/content-editor-page.internal.mjs +168 -0
  45. package/dist/client/components/pages/content-editor-page.mjs +82 -0
  46. package/dist/client/components/pages/content-list-page.cjs +49 -0
  47. package/dist/client/components/pages/content-list-page.internal.cjs +334 -0
  48. package/dist/client/components/pages/content-list-page.internal.mjs +332 -0
  49. package/dist/client/components/pages/content-list-page.mjs +47 -0
  50. package/dist/client/components/pages/dashboard-page.cjs +42 -0
  51. package/dist/client/components/pages/dashboard-page.internal.cjs +102 -0
  52. package/dist/client/components/pages/dashboard-page.internal.mjs +100 -0
  53. package/dist/client/components/pages/dashboard-page.mjs +40 -0
  54. package/dist/client/components/shared/default-error.cjs +17 -0
  55. package/dist/client/components/shared/default-error.mjs +15 -0
  56. package/dist/client/components/shared/empty-state.cjs +16 -0
  57. package/dist/client/components/shared/empty-state.mjs +14 -0
  58. package/dist/client/components/shared/page-wrapper.cjs +29 -0
  59. package/dist/client/components/shared/page-wrapper.mjs +27 -0
  60. package/dist/client/constants.cjs +5 -0
  61. package/dist/client/constants.mjs +3 -0
  62. package/dist/client/hooks/cms-hooks.cjs +300 -0
  63. package/dist/client/hooks/cms-hooks.mjs +280 -0
  64. package/dist/client/hooks/cms-resource.cjs +13 -0
  65. package/dist/client/hooks/cms-resource.mjs +11 -0
  66. package/dist/client/hooks/index.cjs +25 -0
  67. package/dist/client/hooks/index.d.cts +693 -0
  68. package/dist/client/hooks/index.d.mts +693 -0
  69. package/dist/client/hooks/index.d.ts +693 -0
  70. package/dist/client/hooks/index.mjs +1 -0
  71. package/dist/client/index.cjs +15 -0
  72. package/dist/client/index.d.cts +654 -0
  73. package/dist/client/index.d.mts +654 -0
  74. package/dist/client/index.d.ts +654 -0
  75. package/dist/client/index.mjs +3 -0
  76. package/dist/client/overrides.cjs +26 -0
  77. package/dist/client/overrides.mjs +24 -0
  78. package/dist/client/plugin.cjs +316 -0
  79. package/dist/client/plugin.mjs +314 -0
  80. package/dist/client.css +3 -0
  81. package/dist/db.cjs +118 -0
  82. package/dist/db.mjs +116 -0
  83. package/dist/permissions.cjs +46 -0
  84. package/dist/permissions.d.cts +42 -0
  85. package/dist/permissions.d.mts +42 -0
  86. package/dist/permissions.d.ts +42 -0
  87. package/dist/permissions.mjs +44 -0
  88. package/dist/query-keys.cjs +229 -0
  89. package/dist/query-keys.d.cts +8 -0
  90. package/dist/query-keys.d.mts +8 -0
  91. package/dist/query-keys.d.ts +8 -0
  92. package/dist/query-keys.mjs +225 -0
  93. package/dist/schemas.cjs +81 -0
  94. package/dist/schemas.mjs +72 -0
  95. package/dist/shared/plugin-cms.BBshPRkb.d.cts +6 -0
  96. package/dist/shared/plugin-cms.BBshPRkb.d.mts +6 -0
  97. package/dist/shared/plugin-cms.BBshPRkb.d.ts +6 -0
  98. package/dist/shared/plugin-cms.Bptwe33B.d.cts +1749 -0
  99. package/dist/shared/plugin-cms.Csx7tNDO.d.mts +1749 -0
  100. package/dist/shared/plugin-cms.eNW9_FO5.d.ts +1749 -0
  101. package/dist/style.css +6 -0
  102. package/dist/types.cjs +2 -0
  103. package/dist/types.d.cts +406 -0
  104. package/dist/types.d.mts +406 -0
  105. package/dist/types.d.ts +406 -0
  106. package/dist/types.mjs +1 -0
  107. package/dist/ui/src/components/accordion.cjs +81 -0
  108. package/dist/ui/src/components/accordion.mjs +62 -0
  109. package/dist/ui/src/components/alert-dialog.cjs +157 -0
  110. package/dist/ui/src/components/alert-dialog.mjs +132 -0
  111. package/dist/ui/src/components/auto-form/common/label.cjs +18 -0
  112. package/dist/ui/src/components/auto-form/common/label.mjs +16 -0
  113. package/dist/ui/src/components/auto-form/common/tooltip.cjs +9 -0
  114. package/dist/ui/src/components/auto-form/common/tooltip.mjs +7 -0
  115. package/dist/ui/src/components/auto-form/config.cjs +40 -0
  116. package/dist/ui/src/components/auto-form/config.mjs +37 -0
  117. package/dist/ui/src/components/auto-form/dependencies.cjs +48 -0
  118. package/dist/ui/src/components/auto-form/dependencies.mjs +46 -0
  119. package/dist/ui/src/components/auto-form/fields/array.cjs +266 -0
  120. package/dist/ui/src/components/auto-form/fields/array.mjs +264 -0
  121. package/dist/ui/src/components/auto-form/fields/checkbox.cjs +38 -0
  122. package/dist/ui/src/components/auto-form/fields/checkbox.mjs +36 -0
  123. package/dist/ui/src/components/auto-form/fields/date.cjs +67 -0
  124. package/dist/ui/src/components/auto-form/fields/date.mjs +65 -0
  125. package/dist/ui/src/components/auto-form/fields/enum.cjs +73 -0
  126. package/dist/ui/src/components/auto-form/fields/enum.mjs +71 -0
  127. package/dist/ui/src/components/auto-form/fields/input.cjs +32 -0
  128. package/dist/ui/src/components/auto-form/fields/input.mjs +30 -0
  129. package/dist/ui/src/components/auto-form/fields/number.cjs +31 -0
  130. package/dist/ui/src/components/auto-form/fields/number.mjs +29 -0
  131. package/dist/ui/src/components/auto-form/fields/object.cjs +233 -0
  132. package/dist/ui/src/components/auto-form/fields/object.mjs +217 -0
  133. package/dist/ui/src/components/auto-form/fields/radio-group.cjs +67 -0
  134. package/dist/ui/src/components/auto-form/fields/radio-group.mjs +65 -0
  135. package/dist/ui/src/components/auto-form/fields/switch.cjs +38 -0
  136. package/dist/ui/src/components/auto-form/fields/switch.mjs +36 -0
  137. package/dist/ui/src/components/auto-form/fields/textarea.cjs +31 -0
  138. package/dist/ui/src/components/auto-form/fields/textarea.mjs +29 -0
  139. package/dist/ui/src/components/auto-form/helpers.cjs +270 -0
  140. package/dist/ui/src/components/auto-form/helpers.mjs +259 -0
  141. package/dist/ui/src/components/auto-form/index.cjs +92 -0
  142. package/dist/ui/src/components/auto-form/index.mjs +86 -0
  143. package/dist/ui/src/components/auto-form/stepped-auto-form.cjs +374 -0
  144. package/dist/ui/src/components/auto-form/stepped-auto-form.mjs +368 -0
  145. package/dist/ui/src/components/auto-form/types.cjs +11 -0
  146. package/dist/ui/src/components/auto-form/types.mjs +9 -0
  147. package/dist/ui/src/components/badge.cjs +42 -0
  148. package/dist/ui/src/components/badge.mjs +39 -0
  149. package/dist/ui/src/components/button.cjs +56 -0
  150. package/dist/ui/src/components/button.mjs +53 -0
  151. package/dist/ui/src/components/calendar.cjs +207 -0
  152. package/dist/ui/src/components/calendar.mjs +190 -0
  153. package/dist/ui/src/components/card.cjs +56 -0
  154. package/dist/ui/src/components/card.mjs +51 -0
  155. package/dist/ui/src/components/checkbox.cjs +48 -0
  156. package/dist/ui/src/components/checkbox.mjs +32 -0
  157. package/dist/ui/src/components/command.cjs +78 -0
  158. package/dist/ui/src/components/command.mjs +73 -0
  159. package/dist/ui/src/components/date-picker.cjs +41 -0
  160. package/dist/ui/src/components/date-picker.mjs +39 -0
  161. package/dist/ui/src/components/dialog.cjs +119 -0
  162. package/dist/ui/src/components/dialog.mjs +97 -0
  163. package/dist/ui/src/components/form.cjs +120 -0
  164. package/dist/ui/src/components/form.mjs +98 -0
  165. package/dist/ui/src/components/input.cjs +23 -0
  166. package/dist/ui/src/components/input.mjs +21 -0
  167. package/dist/ui/src/components/label.cjs +39 -0
  168. package/dist/ui/src/components/label.mjs +23 -0
  169. package/dist/ui/src/components/multi-select.cjs +555 -0
  170. package/dist/ui/src/components/multi-select.mjs +540 -0
  171. package/dist/ui/src/components/page-layout.cjs +25 -0
  172. package/dist/ui/src/components/page-layout.mjs +23 -0
  173. package/dist/ui/src/components/page-wrapper.cjs +20 -0
  174. package/dist/ui/src/components/page-wrapper.mjs +18 -0
  175. package/dist/ui/src/components/popover.cjs +60 -0
  176. package/dist/ui/src/components/popover.mjs +42 -0
  177. package/dist/ui/src/components/radio-group.cjs +62 -0
  178. package/dist/ui/src/components/radio-group.mjs +45 -0
  179. package/dist/ui/src/components/select.cjs +161 -0
  180. package/dist/ui/src/components/select.mjs +139 -0
  181. package/dist/ui/src/components/separator.cjs +43 -0
  182. package/dist/ui/src/components/separator.mjs +27 -0
  183. package/dist/ui/src/components/skeleton.cjs +17 -0
  184. package/dist/ui/src/components/skeleton.mjs +15 -0
  185. package/dist/ui/src/components/stack-attribution.cjs +24 -0
  186. package/dist/ui/src/components/stack-attribution.mjs +22 -0
  187. package/dist/ui/src/components/switch.cjs +48 -0
  188. package/dist/ui/src/components/switch.mjs +32 -0
  189. package/dist/ui/src/components/table.cjs +89 -0
  190. package/dist/ui/src/components/table.mjs +82 -0
  191. package/dist/ui/src/components/textarea.cjs +20 -0
  192. package/dist/ui/src/components/textarea.mjs +18 -0
  193. package/dist/ui/src/hooks/use-debounce.cjs +16 -0
  194. package/dist/ui/src/hooks/use-debounce.mjs +14 -0
  195. package/dist/ui/src/hooks/use-route-lifecycle.cjs +31 -0
  196. package/dist/ui/src/hooks/use-route-lifecycle.mjs +29 -0
  197. package/dist/ui/src/lib/schema-converter.cjs +133 -0
  198. package/dist/ui/src/lib/schema-converter.mjs +127 -0
  199. package/dist/ui/src/lib/utils.cjs +10 -0
  200. package/dist/ui/src/lib/utils.mjs +8 -0
  201. package/dist/utils.cjs +19 -0
  202. package/dist/utils.mjs +12 -0
  203. package/package.json +170 -3
  204. package/README.md +0 -3
@@ -0,0 +1,272 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const React = require('react');
6
+ const lucideReact = require('lucide-react');
7
+ const button = require('../../ui/src/components/button.cjs');
8
+ const card = require('../../ui/src/components/card.cjs');
9
+ const context = require('@btst/stack/context');
10
+ const permissions = require('../../permissions.cjs');
11
+ const constants = require('../constants.cjs');
12
+ const alertDialog = require('../../ui/src/components/alert-dialog.cjs');
13
+ const cmsHooks = require('../hooks/cms-hooks.cjs');
14
+
15
+ function InverseRelationsPanel({
16
+ contentTypeSlug,
17
+ itemId
18
+ }) {
19
+ const t = context.useTranslate();
20
+ const { localization } = context.usePluginOverrides(constants.CMS_PLUGIN_ID);
21
+ const { router, plugins, basePath: stackBasePath } = context.useStack();
22
+ const navigate = router?.navigate;
23
+ const Link = router?.Link;
24
+ const basePath = plugins?.[constants.CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
25
+ const { inverseRelations, isLoading } = cmsHooks.useInverseRelations(
26
+ contentTypeSlug,
27
+ itemId
28
+ );
29
+ if (isLoading) {
30
+ return /* @__PURE__ */ jsxRuntime.jsx(card.Card, { className: "animate-pulse", children: /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 w-32 bg-muted rounded" }) }) });
31
+ }
32
+ if (inverseRelations.length === 0) {
33
+ return null;
34
+ }
35
+ const sourceTypeCounts = /* @__PURE__ */ new Map();
36
+ for (const rel of inverseRelations) {
37
+ sourceTypeCounts.set(
38
+ rel.sourceType,
39
+ (sourceTypeCounts.get(rel.sourceType) ?? 0) + 1
40
+ );
41
+ }
42
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
43
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: localization?.CMS_RELATED_ITEMS_TITLE ?? t("cms.relations.relatedItemsTitle", "Related Items") }),
44
+ inverseRelations.map((relation) => /* @__PURE__ */ jsxRuntime.jsx(
45
+ InverseRelationSection,
46
+ {
47
+ relation,
48
+ contentTypeSlug,
49
+ itemId,
50
+ basePath,
51
+ navigate,
52
+ Link,
53
+ localization,
54
+ t,
55
+ ambiguous: (sourceTypeCounts.get(relation.sourceType) ?? 0) > 1
56
+ },
57
+ `${relation.sourceType}-${relation.fieldName}`
58
+ ))
59
+ ] });
60
+ }
61
+ function humanizeFieldName(fieldName) {
62
+ const stripped = fieldName.replace(/Ids?$/, "") || fieldName;
63
+ const words = stripped.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().split(/\s+/);
64
+ return words.map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
65
+ }
66
+ function InverseRelationSection({
67
+ relation,
68
+ contentTypeSlug,
69
+ itemId,
70
+ basePath,
71
+ navigate,
72
+ Link,
73
+ localization,
74
+ t,
75
+ ambiguous
76
+ }) {
77
+ const [isExpanded, setIsExpanded] = React.useState(true);
78
+ const [deleteItemId, setDeleteItemId] = React.useState(null);
79
+ const [deleteError, setDeleteError] = React.useState(null);
80
+ const deleteContent = cmsHooks.useDeleteContent(relation.sourceType);
81
+ const {
82
+ items,
83
+ total: fetchedTotal,
84
+ refetch
85
+ } = cmsHooks.useInverseRelationItems(
86
+ {
87
+ contentTypeSlug,
88
+ sourceType: relation.sourceType,
89
+ itemId,
90
+ fieldName: relation.fieldName
91
+ },
92
+ { enabled: isExpanded }
93
+ );
94
+ const total = fetchedTotal || relation.count;
95
+ const handleDelete = async () => {
96
+ if (deleteItemId) {
97
+ setDeleteError(null);
98
+ try {
99
+ await deleteContent.mutateAsync(deleteItemId);
100
+ setDeleteItemId(null);
101
+ void refetch();
102
+ } catch (error) {
103
+ const message = error instanceof Error ? error.message : localization?.CMS_RELATED_DELETE_ERROR ?? t(
104
+ "cms.relations.relatedDeleteError",
105
+ "Failed to delete item. Please try again."
106
+ );
107
+ setDeleteError(message);
108
+ }
109
+ }
110
+ };
111
+ const handleAddNew = () => {
112
+ const createUrl = context.joinBasePath(
113
+ basePath,
114
+ `/cms/${relation.sourceType}/new?prefill_${relation.fieldName}=${itemId}`
115
+ );
116
+ void navigate?.(createUrl);
117
+ };
118
+ const LinkComponent = Link ?? "a";
119
+ const fieldLabel = ambiguous ? humanizeFieldName(relation.fieldName) : null;
120
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.Card, { children: [
121
+ /* @__PURE__ */ jsxRuntime.jsx(card.CardHeader, { className: "py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
122
+ "button",
123
+ {
124
+ type: "button",
125
+ onClick: () => setIsExpanded(!isExpanded),
126
+ className: "flex items-center justify-between w-full text-left",
127
+ children: /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "text-base flex items-center gap-2", children: [
128
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" }),
129
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: relation.sourceTypeName }),
130
+ fieldLabel && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal text-muted-foreground", children: [
131
+ "\xB7 ",
132
+ fieldLabel
133
+ ] }),
134
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal text-muted-foreground", children: [
135
+ "(",
136
+ total,
137
+ ")"
138
+ ] })
139
+ ] })
140
+ }
141
+ ) }),
142
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(card.CardContent, { className: "pt-0", children: [
143
+ items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground py-2", children: (localization?.CMS_RELATED_EMPTY ?? t(
144
+ "cms.relations.relatedEmpty",
145
+ "No {sourceTypeName} items yet."
146
+ )).replace(
147
+ "{sourceTypeName}",
148
+ relation.sourceTypeName.toLowerCase()
149
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", children: items.map((item) => {
150
+ const displayValue = getDisplayValue(item);
151
+ const editUrl = context.joinBasePath(
152
+ basePath,
153
+ `/cms/${relation.sourceType}/${item.id}`
154
+ );
155
+ return /* @__PURE__ */ jsxRuntime.jsxs(
156
+ "li",
157
+ {
158
+ className: "flex items-center justify-between py-2 px-3 rounded-md bg-muted/50 hover:bg-muted transition-colors",
159
+ children: [
160
+ /* @__PURE__ */ jsxRuntime.jsxs(
161
+ LinkComponent,
162
+ {
163
+ href: editUrl,
164
+ className: "flex-1 text-sm hover:underline flex items-center gap-2",
165
+ children: [
166
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: displayValue }),
167
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-3 w-3 opacity-50" })
168
+ ]
169
+ }
170
+ ),
171
+ /* @__PURE__ */ jsxRuntime.jsx(
172
+ context.PermissionAccess,
173
+ {
174
+ permission: permissions.cmsPermissions.record.delete({
175
+ contentType: item.contentType?.slug ?? relation.sourceType,
176
+ recordId: item.id,
177
+ ...item.authorId ? { authorId: item.authorId } : {}
178
+ }),
179
+ children: /* @__PURE__ */ jsxRuntime.jsx(
180
+ button.Button,
181
+ {
182
+ variant: "ghost",
183
+ size: "icon",
184
+ className: "h-7 w-7 text-muted-foreground hover:text-destructive",
185
+ onClick: () => setDeleteItemId(item.id),
186
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3.5 w-3.5" })
187
+ }
188
+ )
189
+ }
190
+ )
191
+ ]
192
+ },
193
+ item.id
194
+ );
195
+ }) }),
196
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 pt-3 border-t", children: /* @__PURE__ */ jsxRuntime.jsx(
197
+ context.PermissionAccess,
198
+ {
199
+ permission: permissions.cmsPermissions.record.create({
200
+ contentType: relation.sourceType
201
+ }),
202
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
203
+ button.Button,
204
+ {
205
+ variant: "outline",
206
+ size: "sm",
207
+ onClick: handleAddNew,
208
+ className: "w-full",
209
+ children: [
210
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
211
+ (localization?.CMS_RELATED_ADD ?? t("cms.relations.relatedAdd", "Add {sourceTypeName}")).replace("{sourceTypeName}", relation.sourceTypeName),
212
+ fieldLabel ? ` (${fieldLabel})` : ""
213
+ ]
214
+ }
215
+ )
216
+ }
217
+ ) })
218
+ ] }),
219
+ /* @__PURE__ */ jsxRuntime.jsx(
220
+ alertDialog.AlertDialog,
221
+ {
222
+ open: !!deleteItemId,
223
+ onOpenChange: (open) => {
224
+ if (!open) {
225
+ setDeleteItemId(null);
226
+ setDeleteError(null);
227
+ }
228
+ },
229
+ children: /* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogContent, { children: [
230
+ /* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogHeader, { children: [
231
+ /* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogTitle, { children: (localization?.CMS_RELATED_DELETE_TITLE ?? t(
232
+ "cms.relations.relatedDeleteTitle",
233
+ "Delete {sourceTypeName}?"
234
+ )).replace("{sourceTypeName}", relation.sourceTypeName) }),
235
+ /* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogDescription, { children: (localization?.CMS_RELATED_DELETE_DESCRIPTION ?? t(
236
+ "cms.relations.relatedDeleteDescription",
237
+ "This action cannot be undone. This will permanently delete this {sourceTypeName}."
238
+ )).replace(
239
+ "{sourceTypeName}",
240
+ relation.sourceTypeName.toLowerCase()
241
+ ) })
242
+ ] }),
243
+ deleteError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: deleteError }),
244
+ /* @__PURE__ */ jsxRuntime.jsxs(alertDialog.AlertDialogFooter, { children: [
245
+ /* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialogCancel, { children: localization?.CMS_BUTTON_CANCEL ?? t("cms.common.cancel", "Cancel") }),
246
+ /* @__PURE__ */ jsxRuntime.jsx(
247
+ alertDialog.AlertDialogAction,
248
+ {
249
+ onClick: handleDelete,
250
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
251
+ children: localization?.CMS_BUTTON_DELETE ?? t("cms.common.delete", "Delete")
252
+ }
253
+ )
254
+ ] })
255
+ ] })
256
+ }
257
+ )
258
+ ] });
259
+ }
260
+ function getDisplayValue(item) {
261
+ const data = item.parsedData;
262
+ const displayFields = ["name", "title", "label", "content", "author", "slug"];
263
+ for (const field of displayFields) {
264
+ if (typeof data[field] === "string" && data[field]) {
265
+ const value = data[field];
266
+ return value.length > 50 ? `${value.slice(0, 50)}...` : value;
267
+ }
268
+ }
269
+ return item.slug;
270
+ }
271
+
272
+ exports.InverseRelationsPanel = InverseRelationsPanel;
@@ -0,0 +1,270 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
4
+ import { ChevronDown, ChevronRight, ExternalLink, Trash2, Plus } from 'lucide-react';
5
+ import { Button } from '../../ui/src/components/button.mjs';
6
+ import { Card, CardHeader, CardTitle, CardContent } from '../../ui/src/components/card.mjs';
7
+ import { useTranslate, usePluginOverrides, useStack, joinBasePath, PermissionAccess } from '@btst/stack/context';
8
+ import { cmsPermissions } from '../../permissions.mjs';
9
+ import { CMS_PLUGIN_ID } from '../constants.mjs';
10
+ import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from '../../ui/src/components/alert-dialog.mjs';
11
+ import { useInverseRelations, useDeleteContent, useInverseRelationItems } from '../hooks/cms-hooks.mjs';
12
+
13
+ function InverseRelationsPanel({
14
+ contentTypeSlug,
15
+ itemId
16
+ }) {
17
+ const t = useTranslate();
18
+ const { localization } = usePluginOverrides(CMS_PLUGIN_ID);
19
+ const { router, plugins, basePath: stackBasePath } = useStack();
20
+ const navigate = router?.navigate;
21
+ const Link = router?.Link;
22
+ const basePath = plugins?.[CMS_PLUGIN_ID]?.site.basePath ?? stackBasePath;
23
+ const { inverseRelations, isLoading } = useInverseRelations(
24
+ contentTypeSlug,
25
+ itemId
26
+ );
27
+ if (isLoading) {
28
+ return /* @__PURE__ */ jsx(Card, { className: "animate-pulse", children: /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx("div", { className: "h-5 w-32 bg-muted rounded" }) }) });
29
+ }
30
+ if (inverseRelations.length === 0) {
31
+ return null;
32
+ }
33
+ const sourceTypeCounts = /* @__PURE__ */ new Map();
34
+ for (const rel of inverseRelations) {
35
+ sourceTypeCounts.set(
36
+ rel.sourceType,
37
+ (sourceTypeCounts.get(rel.sourceType) ?? 0) + 1
38
+ );
39
+ }
40
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
41
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: localization?.CMS_RELATED_ITEMS_TITLE ?? t("cms.relations.relatedItemsTitle", "Related Items") }),
42
+ inverseRelations.map((relation) => /* @__PURE__ */ jsx(
43
+ InverseRelationSection,
44
+ {
45
+ relation,
46
+ contentTypeSlug,
47
+ itemId,
48
+ basePath,
49
+ navigate,
50
+ Link,
51
+ localization,
52
+ t,
53
+ ambiguous: (sourceTypeCounts.get(relation.sourceType) ?? 0) > 1
54
+ },
55
+ `${relation.sourceType}-${relation.fieldName}`
56
+ ))
57
+ ] });
58
+ }
59
+ function humanizeFieldName(fieldName) {
60
+ const stripped = fieldName.replace(/Ids?$/, "") || fieldName;
61
+ const words = stripped.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().split(/\s+/);
62
+ return words.map((w) => w ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
63
+ }
64
+ function InverseRelationSection({
65
+ relation,
66
+ contentTypeSlug,
67
+ itemId,
68
+ basePath,
69
+ navigate,
70
+ Link,
71
+ localization,
72
+ t,
73
+ ambiguous
74
+ }) {
75
+ const [isExpanded, setIsExpanded] = useState(true);
76
+ const [deleteItemId, setDeleteItemId] = useState(null);
77
+ const [deleteError, setDeleteError] = useState(null);
78
+ const deleteContent = useDeleteContent(relation.sourceType);
79
+ const {
80
+ items,
81
+ total: fetchedTotal,
82
+ refetch
83
+ } = useInverseRelationItems(
84
+ {
85
+ contentTypeSlug,
86
+ sourceType: relation.sourceType,
87
+ itemId,
88
+ fieldName: relation.fieldName
89
+ },
90
+ { enabled: isExpanded }
91
+ );
92
+ const total = fetchedTotal || relation.count;
93
+ const handleDelete = async () => {
94
+ if (deleteItemId) {
95
+ setDeleteError(null);
96
+ try {
97
+ await deleteContent.mutateAsync(deleteItemId);
98
+ setDeleteItemId(null);
99
+ void refetch();
100
+ } catch (error) {
101
+ const message = error instanceof Error ? error.message : localization?.CMS_RELATED_DELETE_ERROR ?? t(
102
+ "cms.relations.relatedDeleteError",
103
+ "Failed to delete item. Please try again."
104
+ );
105
+ setDeleteError(message);
106
+ }
107
+ }
108
+ };
109
+ const handleAddNew = () => {
110
+ const createUrl = joinBasePath(
111
+ basePath,
112
+ `/cms/${relation.sourceType}/new?prefill_${relation.fieldName}=${itemId}`
113
+ );
114
+ void navigate?.(createUrl);
115
+ };
116
+ const LinkComponent = Link ?? "a";
117
+ const fieldLabel = ambiguous ? humanizeFieldName(relation.fieldName) : null;
118
+ return /* @__PURE__ */ jsxs(Card, { children: [
119
+ /* @__PURE__ */ jsx(CardHeader, { className: "py-3", children: /* @__PURE__ */ jsx(
120
+ "button",
121
+ {
122
+ type: "button",
123
+ onClick: () => setIsExpanded(!isExpanded),
124
+ className: "flex items-center justify-between w-full text-left",
125
+ children: /* @__PURE__ */ jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [
126
+ isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" }),
127
+ /* @__PURE__ */ jsx("span", { children: relation.sourceTypeName }),
128
+ fieldLabel && /* @__PURE__ */ jsxs("span", { className: "font-normal text-muted-foreground", children: [
129
+ "\xB7 ",
130
+ fieldLabel
131
+ ] }),
132
+ /* @__PURE__ */ jsxs("span", { className: "font-normal text-muted-foreground", children: [
133
+ "(",
134
+ total,
135
+ ")"
136
+ ] })
137
+ ] })
138
+ }
139
+ ) }),
140
+ isExpanded && /* @__PURE__ */ jsxs(CardContent, { className: "pt-0", children: [
141
+ items.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground py-2", children: (localization?.CMS_RELATED_EMPTY ?? t(
142
+ "cms.relations.relatedEmpty",
143
+ "No {sourceTypeName} items yet."
144
+ )).replace(
145
+ "{sourceTypeName}",
146
+ relation.sourceTypeName.toLowerCase()
147
+ ) }) : /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: items.map((item) => {
148
+ const displayValue = getDisplayValue(item);
149
+ const editUrl = joinBasePath(
150
+ basePath,
151
+ `/cms/${relation.sourceType}/${item.id}`
152
+ );
153
+ return /* @__PURE__ */ jsxs(
154
+ "li",
155
+ {
156
+ className: "flex items-center justify-between py-2 px-3 rounded-md bg-muted/50 hover:bg-muted transition-colors",
157
+ children: [
158
+ /* @__PURE__ */ jsxs(
159
+ LinkComponent,
160
+ {
161
+ href: editUrl,
162
+ className: "flex-1 text-sm hover:underline flex items-center gap-2",
163
+ children: [
164
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: displayValue }),
165
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 opacity-50" })
166
+ ]
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsx(
170
+ PermissionAccess,
171
+ {
172
+ permission: cmsPermissions.record.delete({
173
+ contentType: item.contentType?.slug ?? relation.sourceType,
174
+ recordId: item.id,
175
+ ...item.authorId ? { authorId: item.authorId } : {}
176
+ }),
177
+ children: /* @__PURE__ */ jsx(
178
+ Button,
179
+ {
180
+ variant: "ghost",
181
+ size: "icon",
182
+ className: "h-7 w-7 text-muted-foreground hover:text-destructive",
183
+ onClick: () => setDeleteItemId(item.id),
184
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
185
+ }
186
+ )
187
+ }
188
+ )
189
+ ]
190
+ },
191
+ item.id
192
+ );
193
+ }) }),
194
+ /* @__PURE__ */ jsx("div", { className: "mt-3 pt-3 border-t", children: /* @__PURE__ */ jsx(
195
+ PermissionAccess,
196
+ {
197
+ permission: cmsPermissions.record.create({
198
+ contentType: relation.sourceType
199
+ }),
200
+ children: /* @__PURE__ */ jsxs(
201
+ Button,
202
+ {
203
+ variant: "outline",
204
+ size: "sm",
205
+ onClick: handleAddNew,
206
+ className: "w-full",
207
+ children: [
208
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
209
+ (localization?.CMS_RELATED_ADD ?? t("cms.relations.relatedAdd", "Add {sourceTypeName}")).replace("{sourceTypeName}", relation.sourceTypeName),
210
+ fieldLabel ? ` (${fieldLabel})` : ""
211
+ ]
212
+ }
213
+ )
214
+ }
215
+ ) })
216
+ ] }),
217
+ /* @__PURE__ */ jsx(
218
+ AlertDialog,
219
+ {
220
+ open: !!deleteItemId,
221
+ onOpenChange: (open) => {
222
+ if (!open) {
223
+ setDeleteItemId(null);
224
+ setDeleteError(null);
225
+ }
226
+ },
227
+ children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
228
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
229
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: (localization?.CMS_RELATED_DELETE_TITLE ?? t(
230
+ "cms.relations.relatedDeleteTitle",
231
+ "Delete {sourceTypeName}?"
232
+ )).replace("{sourceTypeName}", relation.sourceTypeName) }),
233
+ /* @__PURE__ */ jsx(AlertDialogDescription, { children: (localization?.CMS_RELATED_DELETE_DESCRIPTION ?? t(
234
+ "cms.relations.relatedDeleteDescription",
235
+ "This action cannot be undone. This will permanently delete this {sourceTypeName}."
236
+ )).replace(
237
+ "{sourceTypeName}",
238
+ relation.sourceTypeName.toLowerCase()
239
+ ) })
240
+ ] }),
241
+ deleteError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: deleteError }),
242
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
243
+ /* @__PURE__ */ jsx(AlertDialogCancel, { children: localization?.CMS_BUTTON_CANCEL ?? t("cms.common.cancel", "Cancel") }),
244
+ /* @__PURE__ */ jsx(
245
+ AlertDialogAction,
246
+ {
247
+ onClick: handleDelete,
248
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
249
+ children: localization?.CMS_BUTTON_DELETE ?? t("cms.common.delete", "Delete")
250
+ }
251
+ )
252
+ ] })
253
+ ] })
254
+ }
255
+ )
256
+ ] });
257
+ }
258
+ function getDisplayValue(item) {
259
+ const data = item.parsedData;
260
+ const displayFields = ["name", "title", "label", "content", "author", "slug"];
261
+ for (const field of displayFields) {
262
+ if (typeof data[field] === "string" && data[field]) {
263
+ const value = data[field];
264
+ return value.length > 50 ? `${value.slice(0, 50)}...` : value;
265
+ }
266
+ }
267
+ return item.slug;
268
+ }
269
+
270
+ export { InverseRelationsPanel };
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const skeleton = require('../../../ui/src/components/skeleton.cjs');
6
+ const pageWrapper = require('../shared/page-wrapper.cjs');
7
+
8
+ function DashboardSkeleton() {
9
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-dashboard-skeleton", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-5xl space-y-6", children: [
10
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-48" }),
12
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-64" })
13
+ ] }),
14
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-32 rounded-lg" }, i)) })
15
+ ] }) });
16
+ }
17
+
18
+ exports.DashboardSkeleton = DashboardSkeleton;
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { Skeleton } from '../../../ui/src/components/skeleton.mjs';
4
+ import { PageWrapper } from '../shared/page-wrapper.mjs';
5
+
6
+ function DashboardSkeleton() {
7
+ return /* @__PURE__ */ jsx(PageWrapper, { testId: "cms-dashboard-skeleton", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-5xl space-y-6", children: [
8
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
9
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48" }),
10
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-64" })
11
+ ] }),
12
+ /* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-32 rounded-lg" }, i)) })
13
+ ] }) });
14
+ }
15
+
16
+ export { DashboardSkeleton };
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const skeleton = require('../../../ui/src/components/skeleton.cjs');
6
+
7
+ function EditorSkeleton() {
8
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
9
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-48" }) }),
10
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
11
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
12
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-16" }),
13
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-10 w-full" })
14
+ ] }),
15
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
16
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }),
17
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-10 w-full" })
18
+ ] }),
19
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-20" }),
21
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-24 w-full" })
22
+ ] }),
23
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
24
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-16" }),
25
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-10 w-full" })
26
+ ] })
27
+ ] }),
28
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-10 w-24" })
29
+ ] });
30
+ }
31
+
32
+ exports.EditorSkeleton = EditorSkeleton;
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { Skeleton } from '../../../ui/src/components/skeleton.mjs';
4
+
5
+ function EditorSkeleton() {
6
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
7
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48" }) }),
8
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
9
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
11
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
12
+ ] }),
13
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
14
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
15
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
16
+ ] }),
17
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
18
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
19
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })
20
+ ] }),
21
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
22
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
23
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
24
+ ] })
25
+ ] }),
26
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-24" })
27
+ ] });
28
+ }
29
+
30
+ export { EditorSkeleton };
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ const jsxRuntime = require('react/jsx-runtime');
5
+ const skeleton = require('../../../ui/src/components/skeleton.cjs');
6
+ const pageWrapper = require('../shared/page-wrapper.cjs');
7
+
8
+ function ListSkeleton() {
9
+ return /* @__PURE__ */ jsxRuntime.jsx(pageWrapper.PageWrapper, { testId: "cms-list-skeleton", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-5xl space-y-6", children: [
10
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
11
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
12
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-48" }),
13
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-32" })
14
+ ] }),
15
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-10 w-28" })
16
+ ] }),
17
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg", children: [
18
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
19
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }),
20
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }),
21
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" })
22
+ ] }) }),
23
+ Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-3 border-b last:border-b-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
24
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-32" }),
25
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }),
26
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" })
27
+ ] }) }, i))
28
+ ] })
29
+ ] }) });
30
+ }
31
+
32
+ exports.ListSkeleton = ListSkeleton;