@withwiz/cms-kit 0.1.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 (327) hide show
  1. package/README.ko.md +146 -0
  2. package/README.md +146 -0
  3. package/dist/chunk-2REYWBQ6.js +32 -0
  4. package/dist/chunk-2REYWBQ6.js.map +1 -0
  5. package/dist/chunk-2SYUEQ6J.mjs +17 -0
  6. package/dist/chunk-2SYUEQ6J.mjs.map +1 -0
  7. package/dist/chunk-3ILEMZAL.mjs +32 -0
  8. package/dist/chunk-3ILEMZAL.mjs.map +1 -0
  9. package/dist/chunk-3Y2TQCHU.mjs +33 -0
  10. package/dist/chunk-3Y2TQCHU.mjs.map +1 -0
  11. package/dist/chunk-4LSFAAZW.js +1 -0
  12. package/dist/chunk-4LSFAAZW.js.map +1 -0
  13. package/dist/chunk-4W3X7OKF.js +100 -0
  14. package/dist/chunk-4W3X7OKF.js.map +1 -0
  15. package/dist/chunk-5JUIMXNF.js +108 -0
  16. package/dist/chunk-5JUIMXNF.js.map +1 -0
  17. package/dist/chunk-5RDMODGV.mjs +34 -0
  18. package/dist/chunk-5RDMODGV.mjs.map +1 -0
  19. package/dist/chunk-6ES4W2DL.mjs +1 -0
  20. package/dist/chunk-6ES4W2DL.mjs.map +1 -0
  21. package/dist/chunk-6EZ3QE5N.js +71 -0
  22. package/dist/chunk-6EZ3QE5N.js.map +1 -0
  23. package/dist/chunk-6JFERXNE.mjs +16 -0
  24. package/dist/chunk-6JFERXNE.mjs.map +1 -0
  25. package/dist/chunk-7SWW3ZIN.js +17 -0
  26. package/dist/chunk-7SWW3ZIN.js.map +1 -0
  27. package/dist/chunk-AXR56AUD.mjs +1 -0
  28. package/dist/chunk-AXR56AUD.mjs.map +1 -0
  29. package/dist/chunk-BE7JDL64.js +154 -0
  30. package/dist/chunk-BE7JDL64.js.map +1 -0
  31. package/dist/chunk-BHN2SRZC.js +51 -0
  32. package/dist/chunk-BHN2SRZC.js.map +1 -0
  33. package/dist/chunk-BJTO5JO5.mjs +11 -0
  34. package/dist/chunk-BJTO5JO5.mjs.map +1 -0
  35. package/dist/chunk-BWKKHCDG.mjs +164 -0
  36. package/dist/chunk-BWKKHCDG.mjs.map +1 -0
  37. package/dist/chunk-C5WFZJM4.js +218 -0
  38. package/dist/chunk-C5WFZJM4.js.map +1 -0
  39. package/dist/chunk-CGVFB23E.mjs +123 -0
  40. package/dist/chunk-CGVFB23E.mjs.map +1 -0
  41. package/dist/chunk-D2VDTRXO.js +1 -0
  42. package/dist/chunk-D2VDTRXO.js.map +1 -0
  43. package/dist/chunk-D75ADHVM.mjs +181 -0
  44. package/dist/chunk-D75ADHVM.mjs.map +1 -0
  45. package/dist/chunk-DCIF4XJL.js +309 -0
  46. package/dist/chunk-DCIF4XJL.js.map +1 -0
  47. package/dist/chunk-DGUM43GV.js +11 -0
  48. package/dist/chunk-DGUM43GV.js.map +1 -0
  49. package/dist/chunk-DSORCGJK.js +44 -0
  50. package/dist/chunk-DSORCGJK.js.map +1 -0
  51. package/dist/chunk-E5YUAOJI.js +27 -0
  52. package/dist/chunk-E5YUAOJI.js.map +1 -0
  53. package/dist/chunk-EG6NVPP2.js +164 -0
  54. package/dist/chunk-EG6NVPP2.js.map +1 -0
  55. package/dist/chunk-EL7YGOTY.js +1 -0
  56. package/dist/chunk-EL7YGOTY.js.map +1 -0
  57. package/dist/chunk-EM4MQEWV.mjs +100 -0
  58. package/dist/chunk-EM4MQEWV.mjs.map +1 -0
  59. package/dist/chunk-FCCCG5Z7.mjs +108 -0
  60. package/dist/chunk-FCCCG5Z7.mjs.map +1 -0
  61. package/dist/chunk-FEPGJ7WN.mjs +218 -0
  62. package/dist/chunk-FEPGJ7WN.mjs.map +1 -0
  63. package/dist/chunk-HXVWBFCN.js +16 -0
  64. package/dist/chunk-HXVWBFCN.js.map +1 -0
  65. package/dist/chunk-I5YMTJV6.mjs +51 -0
  66. package/dist/chunk-I5YMTJV6.mjs.map +1 -0
  67. package/dist/chunk-IMNWW7Q5.mjs +13 -0
  68. package/dist/chunk-IMNWW7Q5.mjs.map +1 -0
  69. package/dist/chunk-J5N76ASB.mjs +114 -0
  70. package/dist/chunk-J5N76ASB.mjs.map +1 -0
  71. package/dist/chunk-JBV26CUG.mjs +51 -0
  72. package/dist/chunk-JBV26CUG.mjs.map +1 -0
  73. package/dist/chunk-JMWXVXK5.js +53 -0
  74. package/dist/chunk-JMWXVXK5.js.map +1 -0
  75. package/dist/chunk-KWKV2GAH.js +60 -0
  76. package/dist/chunk-KWKV2GAH.js.map +1 -0
  77. package/dist/chunk-LDFE33ML.mjs +53 -0
  78. package/dist/chunk-LDFE33ML.mjs.map +1 -0
  79. package/dist/chunk-LF5LOI7K.mjs +174 -0
  80. package/dist/chunk-LF5LOI7K.mjs.map +1 -0
  81. package/dist/chunk-MMKAMH4U.mjs +16 -0
  82. package/dist/chunk-MMKAMH4U.mjs.map +1 -0
  83. package/dist/chunk-MUHFEEYW.js +33 -0
  84. package/dist/chunk-MUHFEEYW.js.map +1 -0
  85. package/dist/chunk-MUQYK5EO.js +1 -0
  86. package/dist/chunk-MUQYK5EO.js.map +1 -0
  87. package/dist/chunk-OBNALAMG.mjs +71 -0
  88. package/dist/chunk-OBNALAMG.mjs.map +1 -0
  89. package/dist/chunk-OLEYNPW6.js +25 -0
  90. package/dist/chunk-OLEYNPW6.js.map +1 -0
  91. package/dist/chunk-OYJRR3G2.js +123 -0
  92. package/dist/chunk-OYJRR3G2.js.map +1 -0
  93. package/dist/chunk-PLVG7AW3.js +16 -0
  94. package/dist/chunk-PLVG7AW3.js.map +1 -0
  95. package/dist/chunk-PYD4CES4.js +1 -0
  96. package/dist/chunk-PYD4CES4.js.map +1 -0
  97. package/dist/chunk-QACD2U6P.mjs +1 -0
  98. package/dist/chunk-QACD2U6P.mjs.map +1 -0
  99. package/dist/chunk-R5GGIVD4.js +10 -0
  100. package/dist/chunk-R5GGIVD4.js.map +1 -0
  101. package/dist/chunk-RCK5WCU5.mjs +25 -0
  102. package/dist/chunk-RCK5WCU5.mjs.map +1 -0
  103. package/dist/chunk-S6UUSM7S.js +13 -0
  104. package/dist/chunk-S6UUSM7S.js.map +1 -0
  105. package/dist/chunk-S7GOXCRM.js +114 -0
  106. package/dist/chunk-S7GOXCRM.js.map +1 -0
  107. package/dist/chunk-SMV5D5LO.mjs +28 -0
  108. package/dist/chunk-SMV5D5LO.mjs.map +1 -0
  109. package/dist/chunk-T7EVFD4G.mjs +60 -0
  110. package/dist/chunk-T7EVFD4G.mjs.map +1 -0
  111. package/dist/chunk-TLH3V4SY.mjs +1 -0
  112. package/dist/chunk-TLH3V4SY.mjs.map +1 -0
  113. package/dist/chunk-TUQ2CVAK.mjs +10 -0
  114. package/dist/chunk-TUQ2CVAK.mjs.map +1 -0
  115. package/dist/chunk-U6PVJKTB.js +51 -0
  116. package/dist/chunk-U6PVJKTB.js.map +1 -0
  117. package/dist/chunk-UXMMEEX4.mjs +27 -0
  118. package/dist/chunk-UXMMEEX4.mjs.map +1 -0
  119. package/dist/chunk-VVXNFFKI.mjs +44 -0
  120. package/dist/chunk-VVXNFFKI.mjs.map +1 -0
  121. package/dist/chunk-VZZ3RU3Q.js +28 -0
  122. package/dist/chunk-VZZ3RU3Q.js.map +1 -0
  123. package/dist/chunk-W4FWIZ2Y.js +34 -0
  124. package/dist/chunk-W4FWIZ2Y.js.map +1 -0
  125. package/dist/chunk-YEQFKOWD.mjs +154 -0
  126. package/dist/chunk-YEQFKOWD.mjs.map +1 -0
  127. package/dist/chunk-YPBKY4KY.mjs +1 -0
  128. package/dist/chunk-YPBKY4KY.mjs.map +1 -0
  129. package/dist/chunk-YY7K5CXX.js +174 -0
  130. package/dist/chunk-YY7K5CXX.js.map +1 -0
  131. package/dist/chunk-ZFORODOX.js +181 -0
  132. package/dist/chunk-ZFORODOX.js.map +1 -0
  133. package/dist/chunk-ZULSFSDG.mjs +309 -0
  134. package/dist/chunk-ZULSFSDG.mjs.map +1 -0
  135. package/dist/components/AdminManagerBase.d.mts +26 -0
  136. package/dist/components/AdminManagerBase.d.ts +26 -0
  137. package/dist/components/AdminManagerBase.js +13 -0
  138. package/dist/components/AdminManagerBase.js.map +1 -0
  139. package/dist/components/AdminManagerBase.mjs +12 -0
  140. package/dist/components/AdminManagerBase.mjs.map +1 -0
  141. package/dist/components/AdminManagerConfig.d.mts +83 -0
  142. package/dist/components/AdminManagerConfig.d.ts +83 -0
  143. package/dist/components/AdminManagerConfig.js +2 -0
  144. package/dist/components/AdminManagerConfig.js.map +1 -0
  145. package/dist/components/AdminManagerConfig.mjs +2 -0
  146. package/dist/components/AdminManagerConfig.mjs.map +1 -0
  147. package/dist/components/AdminShell.d.mts +30 -0
  148. package/dist/components/AdminShell.d.ts +30 -0
  149. package/dist/components/AdminShell.js +12 -0
  150. package/dist/components/AdminShell.js.map +1 -0
  151. package/dist/components/AdminShell.mjs +11 -0
  152. package/dist/components/AdminShell.mjs.map +1 -0
  153. package/dist/components/JsonLd.d.mts +32 -0
  154. package/dist/components/JsonLd.d.ts +32 -0
  155. package/dist/components/JsonLd.js +11 -0
  156. package/dist/components/JsonLd.js.map +1 -0
  157. package/dist/components/JsonLd.mjs +11 -0
  158. package/dist/components/JsonLd.mjs.map +1 -0
  159. package/dist/components/ResizableImage.d.mts +18 -0
  160. package/dist/components/ResizableImage.d.ts +18 -0
  161. package/dist/components/ResizableImage.js +10 -0
  162. package/dist/components/ResizableImage.js.map +1 -0
  163. package/dist/components/ResizableImage.mjs +9 -0
  164. package/dist/components/ResizableImage.mjs.map +1 -0
  165. package/dist/components/ToggleSwitch.d.mts +11 -0
  166. package/dist/components/ToggleSwitch.d.ts +11 -0
  167. package/dist/components/ToggleSwitch.js +10 -0
  168. package/dist/components/ToggleSwitch.js.map +1 -0
  169. package/dist/components/ToggleSwitch.mjs +9 -0
  170. package/dist/components/ToggleSwitch.mjs.map +1 -0
  171. package/dist/components/image-drop-zone.css +115 -0
  172. package/dist/components/index.d.mts +26 -0
  173. package/dist/components/index.d.ts +26 -0
  174. package/dist/components/index.js +35 -0
  175. package/dist/components/index.js.map +1 -0
  176. package/dist/components/index.mjs +35 -0
  177. package/dist/components/index.mjs.map +1 -0
  178. package/dist/components/toggle-switch.css +55 -0
  179. package/dist/hooks/index.d.mts +45 -0
  180. package/dist/hooks/index.d.ts +45 -0
  181. package/dist/hooks/index.js +25 -0
  182. package/dist/hooks/index.js.map +1 -0
  183. package/dist/hooks/index.mjs +25 -0
  184. package/dist/hooks/index.mjs.map +1 -0
  185. package/dist/hooks/useImageDropZone.d.mts +37 -0
  186. package/dist/hooks/useImageDropZone.d.ts +37 -0
  187. package/dist/hooks/useImageDropZone.js +13 -0
  188. package/dist/hooks/useImageDropZone.js.map +1 -0
  189. package/dist/hooks/useImageDropZone.mjs +12 -0
  190. package/dist/hooks/useImageDropZone.mjs.map +1 -0
  191. package/dist/hooks/useScrollReveal.d.mts +6 -0
  192. package/dist/hooks/useScrollReveal.d.ts +6 -0
  193. package/dist/hooks/useScrollReveal.js +12 -0
  194. package/dist/hooks/useScrollReveal.js.map +1 -0
  195. package/dist/hooks/useScrollReveal.mjs +11 -0
  196. package/dist/hooks/useScrollReveal.mjs.map +1 -0
  197. package/dist/image-drop-zone.css +115 -0
  198. package/dist/index-00a40-FQ.d.mts +136 -0
  199. package/dist/index-00a40-FQ.d.ts +136 -0
  200. package/dist/index.d.mts +35 -0
  201. package/dist/index.d.ts +35 -0
  202. package/dist/index.js +169 -0
  203. package/dist/index.js.map +1 -0
  204. package/dist/index.mjs +169 -0
  205. package/dist/index.mjs.map +1 -0
  206. package/dist/infrastructure/index.d.mts +4 -0
  207. package/dist/infrastructure/index.d.ts +4 -0
  208. package/dist/infrastructure/index.js +20 -0
  209. package/dist/infrastructure/index.js.map +1 -0
  210. package/dist/infrastructure/index.mjs +20 -0
  211. package/dist/infrastructure/index.mjs.map +1 -0
  212. package/dist/infrastructure/middleware/index.d.mts +3 -0
  213. package/dist/infrastructure/middleware/index.d.ts +3 -0
  214. package/dist/infrastructure/middleware/index.js +15 -0
  215. package/dist/infrastructure/middleware/index.js.map +1 -0
  216. package/dist/infrastructure/middleware/index.mjs +15 -0
  217. package/dist/infrastructure/middleware/index.mjs.map +1 -0
  218. package/dist/infrastructure/middleware/wrappers.d.mts +10 -0
  219. package/dist/infrastructure/middleware/wrappers.d.ts +10 -0
  220. package/dist/infrastructure/middleware/wrappers.js +15 -0
  221. package/dist/infrastructure/middleware/wrappers.js.map +1 -0
  222. package/dist/infrastructure/middleware/wrappers.mjs +15 -0
  223. package/dist/infrastructure/middleware/wrappers.mjs.map +1 -0
  224. package/dist/infrastructure/prisma.d.mts +5 -0
  225. package/dist/infrastructure/prisma.d.ts +5 -0
  226. package/dist/infrastructure/prisma.js +12 -0
  227. package/dist/infrastructure/prisma.js.map +1 -0
  228. package/dist/infrastructure/prisma.mjs +12 -0
  229. package/dist/infrastructure/prisma.mjs.map +1 -0
  230. package/dist/services/index.d.mts +22 -0
  231. package/dist/services/index.d.ts +22 -0
  232. package/dist/services/index.js +36 -0
  233. package/dist/services/index.js.map +1 -0
  234. package/dist/services/index.mjs +36 -0
  235. package/dist/services/index.mjs.map +1 -0
  236. package/dist/toggle-switch.css +55 -0
  237. package/dist/types/common.d.mts +14 -0
  238. package/dist/types/common.d.ts +14 -0
  239. package/dist/types/common.js +8 -0
  240. package/dist/types/common.js.map +1 -0
  241. package/dist/types/common.mjs +8 -0
  242. package/dist/types/common.mjs.map +1 -0
  243. package/dist/types/index.d.mts +1 -0
  244. package/dist/types/index.d.ts +1 -0
  245. package/dist/types/index.js +9 -0
  246. package/dist/types/index.js.map +1 -0
  247. package/dist/types/index.mjs +9 -0
  248. package/dist/types/index.mjs.map +1 -0
  249. package/dist/utils/admin-fetch.d.mts +11 -0
  250. package/dist/utils/admin-fetch.d.ts +11 -0
  251. package/dist/utils/admin-fetch.js +13 -0
  252. package/dist/utils/admin-fetch.js.map +1 -0
  253. package/dist/utils/admin-fetch.mjs +13 -0
  254. package/dist/utils/admin-fetch.mjs.map +1 -0
  255. package/dist/utils/api-helpers.d.mts +20 -0
  256. package/dist/utils/api-helpers.d.ts +20 -0
  257. package/dist/utils/api-helpers.js +12 -0
  258. package/dist/utils/api-helpers.js.map +1 -0
  259. package/dist/utils/api-helpers.mjs +12 -0
  260. package/dist/utils/api-helpers.mjs.map +1 -0
  261. package/dist/utils/date.d.mts +5 -0
  262. package/dist/utils/date.d.ts +5 -0
  263. package/dist/utils/date.js +12 -0
  264. package/dist/utils/date.js.map +1 -0
  265. package/dist/utils/date.mjs +12 -0
  266. package/dist/utils/date.mjs.map +1 -0
  267. package/dist/utils/html-sanitizer.d.mts +56 -0
  268. package/dist/utils/html-sanitizer.d.ts +56 -0
  269. package/dist/utils/html-sanitizer.js +11 -0
  270. package/dist/utils/html-sanitizer.js.map +1 -0
  271. package/dist/utils/html-sanitizer.mjs +11 -0
  272. package/dist/utils/html-sanitizer.mjs.map +1 -0
  273. package/dist/utils/image-variant-utils.d.mts +14 -0
  274. package/dist/utils/image-variant-utils.d.ts +14 -0
  275. package/dist/utils/image-variant-utils.js +10 -0
  276. package/dist/utils/image-variant-utils.js.map +1 -0
  277. package/dist/utils/image-variant-utils.mjs +10 -0
  278. package/dist/utils/image-variant-utils.mjs.map +1 -0
  279. package/dist/utils/image-variants.d.mts +13 -0
  280. package/dist/utils/image-variants.d.ts +13 -0
  281. package/dist/utils/image-variants.js +12 -0
  282. package/dist/utils/image-variants.js.map +1 -0
  283. package/dist/utils/image-variants.mjs +12 -0
  284. package/dist/utils/image-variants.mjs.map +1 -0
  285. package/dist/utils/index.d.mts +88 -0
  286. package/dist/utils/index.d.ts +88 -0
  287. package/dist/utils/index.js +92 -0
  288. package/dist/utils/index.js.map +1 -0
  289. package/dist/utils/index.mjs +92 -0
  290. package/dist/utils/index.mjs.map +1 -0
  291. package/dist/utils/jwt.d.mts +19 -0
  292. package/dist/utils/jwt.d.ts +19 -0
  293. package/dist/utils/jwt.js +9 -0
  294. package/dist/utils/jwt.js.map +1 -0
  295. package/dist/utils/jwt.mjs +9 -0
  296. package/dist/utils/jwt.mjs.map +1 -0
  297. package/dist/utils/r2-helpers.d.mts +9 -0
  298. package/dist/utils/r2-helpers.d.ts +9 -0
  299. package/dist/utils/r2-helpers.js +20 -0
  300. package/dist/utils/r2-helpers.js.map +1 -0
  301. package/dist/utils/r2-helpers.mjs +20 -0
  302. package/dist/utils/r2-helpers.mjs.map +1 -0
  303. package/dist/utils/r2-storage.d.mts +38 -0
  304. package/dist/utils/r2-storage.d.ts +38 -0
  305. package/dist/utils/r2-storage.js +17 -0
  306. package/dist/utils/r2-storage.js.map +1 -0
  307. package/dist/utils/r2-storage.mjs +17 -0
  308. package/dist/utils/r2-storage.mjs.map +1 -0
  309. package/dist/utils/route-params.d.mts +3 -0
  310. package/dist/utils/route-params.d.ts +3 -0
  311. package/dist/utils/route-params.js +8 -0
  312. package/dist/utils/route-params.js.map +1 -0
  313. package/dist/utils/route-params.mjs +8 -0
  314. package/dist/utils/route-params.mjs.map +1 -0
  315. package/dist/validators/index.d.mts +2 -0
  316. package/dist/validators/index.d.ts +2 -0
  317. package/dist/validators/index.js +11 -0
  318. package/dist/validators/index.js.map +1 -0
  319. package/dist/validators/index.mjs +11 -0
  320. package/dist/validators/index.mjs.map +1 -0
  321. package/dist/validators/shared.d.mts +6 -0
  322. package/dist/validators/shared.d.ts +6 -0
  323. package/dist/validators/shared.js +10 -0
  324. package/dist/validators/shared.js.map +1 -0
  325. package/dist/validators/shared.mjs +10 -0
  326. package/dist/validators/shared.mjs.map +1 -0
  327. package/package.json +257 -0
@@ -0,0 +1,309 @@
1
+ import {
2
+ useAdminForm,
3
+ useAdminList
4
+ } from "./chunk-FCCCG5Z7.mjs";
5
+ import {
6
+ adminFetch,
7
+ getAuthHeaders
8
+ } from "./chunk-T7EVFD4G.mjs";
9
+
10
+ // src/components/AdminManagerBase.tsx
11
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef } from "react";
12
+ import { useVirtualizer } from "@tanstack/react-virtual";
13
+ import { toast } from "sonner";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ function AdminManagerBaseInner({
16
+ initialItems,
17
+ config,
18
+ initialSelectedId,
19
+ startWithNew,
20
+ defaultFilterValue,
21
+ innerRef
22
+ }) {
23
+ const list = useAdminList({
24
+ initialItems,
25
+ apiPath: config.apiPath,
26
+ defaultSortKey: config.defaultSortKey,
27
+ normalizeItem: config.normalizeListItem,
28
+ defaultFilterValue
29
+ });
30
+ const {
31
+ items,
32
+ setItems,
33
+ searchQuery,
34
+ setSearchQuery,
35
+ sortKey,
36
+ setSortKey,
37
+ filterValue,
38
+ setFilterValue
39
+ } = list;
40
+ const adminForm = useAdminForm(config.emptyForm);
41
+ const {
42
+ tab,
43
+ setTab,
44
+ form,
45
+ setForm,
46
+ updateField,
47
+ selectedId,
48
+ setSelectedId,
49
+ isNew,
50
+ setIsNew,
51
+ saving,
52
+ setSaving,
53
+ loading,
54
+ setLoading,
55
+ mobilePv,
56
+ setMobilePv,
57
+ addNew,
58
+ startEdit
59
+ } = adminForm;
60
+ useEffect(() => {
61
+ if (startWithNew) {
62
+ handleAdd();
63
+ return;
64
+ }
65
+ if (initialSelectedId) {
66
+ selectItem(initialSelectedId);
67
+ }
68
+ }, []);
69
+ const filteredItems = useMemo(
70
+ () => config.filterItems(items, filterValue, searchQuery),
71
+ [items, filterValue, searchQuery, config]
72
+ );
73
+ const publishedItems = useMemo(
74
+ () => items.filter(config.meta.getItemPublished),
75
+ [items, config]
76
+ );
77
+ const selectItem = useCallback(async (id) => {
78
+ startEdit(id, config.emptyForm);
79
+ try {
80
+ const res = await adminFetch(`${config.apiPath}/${id}`);
81
+ const json = await res.json();
82
+ if (json.success) {
83
+ setForm(config.loadItem(json.data));
84
+ } else {
85
+ toast.error(json.error?.message || "\uB370\uC774\uD130 \uB85C\uB4DC \uC2E4\uD328");
86
+ }
87
+ } catch {
88
+ toast.error("\uB370\uC774\uD130 \uB85C\uB4DC \uC2E4\uD328");
89
+ } finally {
90
+ setLoading(false);
91
+ }
92
+ }, [config.apiPath, config.loadItem, config.emptyForm]);
93
+ useImperativeHandle(innerRef, () => ({ selectItem }), [selectItem]);
94
+ const handleAdd = useCallback(() => {
95
+ addNew(config.emptyForm);
96
+ }, [config.emptyForm]);
97
+ async function handleSave() {
98
+ const err = config.validate(form);
99
+ if (err) {
100
+ toast.error(err);
101
+ return;
102
+ }
103
+ const payload = config.buildSavePayload(form, { isNew, selectedId, items });
104
+ const url = isNew ? config.apiPath : `${config.apiPath}/${selectedId}`;
105
+ const method = isNew ? "POST" : "PUT";
106
+ setSaving(true);
107
+ try {
108
+ const res = await adminFetch(url, {
109
+ method,
110
+ headers: { ...getAuthHeaders(), "Content-Type": "application/json" },
111
+ body: JSON.stringify(payload)
112
+ });
113
+ const json = await res.json();
114
+ if (json.success) {
115
+ const listRes = await adminFetch(`${config.apiPath}?limit=100&sortBy=${sortKey}`);
116
+ const listJson = await listRes.json();
117
+ if (listJson.success) {
118
+ setItems(listJson.data.items.map(config.normalizeListItem));
119
+ }
120
+ setTab("list");
121
+ setSelectedId(null);
122
+ toast.success("\uC800\uC7A5 \uC644\uB8CC");
123
+ config.onAfterSave?.();
124
+ config.onNavigateToList?.();
125
+ } else {
126
+ toast.error(json.error?.message || "\uC800\uC7A5 \uC2E4\uD328");
127
+ }
128
+ } catch {
129
+ toast.error("\uC800\uC7A5 \uC911 \uC624\uB958 \uBC1C\uC0DD");
130
+ } finally {
131
+ setSaving(false);
132
+ }
133
+ }
134
+ const handleDelete = useCallback(async (id) => {
135
+ const item = items.find((i) => i.id === id);
136
+ const label = item ? config.meta.getItemLabel(item) : id;
137
+ if (!confirm(`"${label}"\uC744(\uB97C) \uC0AD\uC81C\uD558\uC2DC\uACA0\uC2B5\uB2C8\uAE4C?`)) return;
138
+ try {
139
+ const res = await adminFetch(`${config.apiPath}/${id}`, {
140
+ method: "DELETE"
141
+ });
142
+ if (res.ok) {
143
+ setItems((prev) => prev.filter((i) => i.id !== id));
144
+ if (selectedId === id) {
145
+ setSelectedId(null);
146
+ setTab("list");
147
+ }
148
+ } else {
149
+ toast.error("\uC0AD\uC81C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
150
+ }
151
+ } catch {
152
+ toast.error("\uC0AD\uC81C \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
153
+ }
154
+ }, [items, selectedId, config.apiPath, config.meta]);
155
+ const listScrollRef = useRef(null);
156
+ const virtualizer = useVirtualizer({
157
+ count: filteredItems.length,
158
+ getScrollElement: () => listScrollRef.current,
159
+ estimateSize: () => 58,
160
+ overscan: 5
161
+ });
162
+ return /* @__PURE__ */ jsxs("div", { className: `pm${mobilePv ? " mobile-pv-on" : ""}`, children: [
163
+ /* @__PURE__ */ jsx("div", { className: "pm-topbar", children: /* @__PURE__ */ jsxs("div", { className: "pm-tb-l", children: [
164
+ /* @__PURE__ */ jsx("span", { className: "pm-tb-logo", children: config.meta.appTitle }),
165
+ /* @__PURE__ */ jsx("span", { className: "pm-tb-sep" }),
166
+ /* @__PURE__ */ jsx("span", { className: "pm-tb-pg", children: config.meta.pageTitle })
167
+ ] }) }),
168
+ /* @__PURE__ */ jsxs("div", { className: "pm-tabs", children: [
169
+ /* @__PURE__ */ jsx(
170
+ "div",
171
+ {
172
+ className: `pm-tab ${tab === "list" ? "on" : ""}`,
173
+ onClick: () => {
174
+ setTab("list");
175
+ config.onNavigateToList?.();
176
+ },
177
+ children: config.meta.listTabLabel
178
+ }
179
+ ),
180
+ /* @__PURE__ */ jsx(
181
+ "div",
182
+ {
183
+ className: `pm-tab ${tab === "edit" ? "on" : ""}`,
184
+ onClick: () => setTab("edit"),
185
+ children: "\uD3B8\uC9D1 + \uBBF8\uB9AC\uBCF4\uAE30"
186
+ }
187
+ )
188
+ ] }),
189
+ /* @__PURE__ */ jsxs("div", { className: "mobile-pv-bar", children: [
190
+ /* @__PURE__ */ jsx(
191
+ "button",
192
+ {
193
+ type: "button",
194
+ className: `mobile-pv-btn${!mobilePv ? " on" : ""}`,
195
+ onClick: () => setMobilePv(false),
196
+ children: "\uD3B8\uC9D1"
197
+ }
198
+ ),
199
+ /* @__PURE__ */ jsx(
200
+ "button",
201
+ {
202
+ type: "button",
203
+ className: `mobile-pv-btn${mobilePv ? " on" : ""}`,
204
+ onClick: () => setMobilePv(true),
205
+ children: "\uBBF8\uB9AC\uBCF4\uAE30"
206
+ }
207
+ )
208
+ ] }),
209
+ /* @__PURE__ */ jsxs("div", { className: "pm-body", children: [
210
+ /* @__PURE__ */ jsxs("div", { className: `pm-panel pm-panel-list ${tab === "list" ? "on" : ""}`, children: [
211
+ /* @__PURE__ */ jsxs("div", { className: "pm-list-left", children: [
212
+ /* @__PURE__ */ jsx("div", { className: "pm-list-header", children: config.renderFilterControls({
213
+ filterValue,
214
+ setFilterValue,
215
+ sortKey,
216
+ setSortKey,
217
+ sortOptions: config.sortOptions,
218
+ searchQuery,
219
+ setSearchQuery,
220
+ filteredCount: filteredItems.length,
221
+ filteredItems,
222
+ onAdd: handleAdd,
223
+ addButtonLabel: config.meta.addButtonLabel,
224
+ allItems: items
225
+ }) }),
226
+ /* @__PURE__ */ jsx("div", { className: "pm-perf-list", ref: listScrollRef, children: /* @__PURE__ */ jsx(
227
+ "div",
228
+ {
229
+ style: {
230
+ height: `${virtualizer.getTotalSize()}px`,
231
+ width: "100%",
232
+ position: "relative"
233
+ },
234
+ children: virtualizer.getVirtualItems().map((virtualRow) => {
235
+ const item = filteredItems[virtualRow.index];
236
+ return /* @__PURE__ */ jsx(
237
+ "div",
238
+ {
239
+ "data-index": virtualRow.index,
240
+ ref: virtualizer.measureElement,
241
+ style: {
242
+ position: "absolute",
243
+ top: 0,
244
+ left: 0,
245
+ width: "100%",
246
+ transform: `translateY(${virtualRow.start}px)`
247
+ },
248
+ children: config.renderListItem(item, {
249
+ isSelected: selectedId === item.id,
250
+ onSelect: selectItem,
251
+ onDelete: handleDelete
252
+ })
253
+ },
254
+ item.id
255
+ );
256
+ })
257
+ }
258
+ ) })
259
+ ] }),
260
+ /* @__PURE__ */ jsxs("div", { className: "pm-list-right", children: [
261
+ /* @__PURE__ */ jsx("div", { className: "pm-pv-label", children: "\uD648\uD398\uC774\uC9C0 \uBBF8\uB9AC\uBCF4\uAE30" }),
262
+ config.renderListPreview({
263
+ publishedItems,
264
+ onSelectItem: selectItem
265
+ })
266
+ ] })
267
+ ] }),
268
+ /* @__PURE__ */ jsxs(
269
+ "div",
270
+ {
271
+ className: `pm-panel pm-panel-edit ${tab === "edit" ? "on" : ""}`,
272
+ children: [
273
+ /* @__PURE__ */ jsx("div", { className: "pm-edit-left", children: config.renderEditForm({
274
+ form,
275
+ setForm,
276
+ updateField,
277
+ isNew,
278
+ selectedId,
279
+ saving,
280
+ loading,
281
+ onSave: handleSave,
282
+ onCancel: () => {
283
+ setTab("list");
284
+ config.onNavigateToList?.();
285
+ },
286
+ onDelete: () => {
287
+ if (selectedId) handleDelete(selectedId);
288
+ }
289
+ }) }),
290
+ /* @__PURE__ */ jsxs("div", { className: "pm-edit-right", children: [
291
+ /* @__PURE__ */ jsx("div", { className: "pm-pv-label", children: "\uC2E4\uC2DC\uAC04 \uBBF8\uB9AC\uBCF4\uAE30" }),
292
+ config.renderDetailPreview({ form, isNew, selectedId })
293
+ ] })
294
+ ]
295
+ }
296
+ )
297
+ ] }),
298
+ config.renderModal?.()
299
+ ] });
300
+ }
301
+ function AdminManagerBase(props) {
302
+ const { ref, ...rest } = props;
303
+ return /* @__PURE__ */ jsx(AdminManagerBaseInner, { ...rest, innerRef: ref });
304
+ }
305
+
306
+ export {
307
+ AdminManagerBase
308
+ };
309
+ //# sourceMappingURL=chunk-ZULSFSDG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AdminManagerBase.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useImperativeHandle, useMemo, useRef, forwardRef } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport { toast } from \"sonner\";\nimport { adminFetch, getAuthHeaders } from \"../utils/admin-fetch\";\nimport { useAdminList } from \"../hooks/useAdminList\";\nimport { useAdminForm } from \"../hooks/useAdminForm\";\nimport type { AdminManagerConfig } from \"./AdminManagerConfig\";\n\ninterface Props<TItem extends { id: string }, TForm extends object> {\n initialItems: TItem[];\n config: AdminManagerConfig<TItem, TForm>;\n /** 초기에 선택할 항목 ID (예: detail 라우트의 [id] 세그먼트) */\n initialSelectedId?: string | null;\n /** 최초 진입 시 새 항목 편집 모드로 시작할지 여부 (예: 새 항목 라우트) */\n startWithNew?: boolean;\n /** 초기 필터 값 (예: 카테고리 필터링) */\n defaultFilterValue?: string;\n}\n\nexport interface AdminManagerBaseHandle {\n selectItem: (id: string) => void;\n}\n\nfunction AdminManagerBaseInner<\n TItem extends { id: string },\n TForm extends object\n>({\n initialItems,\n config,\n initialSelectedId,\n startWithNew,\n defaultFilterValue,\n innerRef,\n}: Props<TItem, TForm> & { innerRef?: React.Ref<AdminManagerBaseHandle> }) {\n const list = useAdminList<TItem>({\n initialItems,\n apiPath: config.apiPath,\n defaultSortKey: config.defaultSortKey,\n normalizeItem: config.normalizeListItem,\n defaultFilterValue,\n });\n const {\n items,\n setItems,\n searchQuery,\n setSearchQuery,\n sortKey,\n setSortKey,\n filterValue,\n setFilterValue,\n } = list;\n\n const adminForm = useAdminForm<TForm>(config.emptyForm);\n const {\n tab,\n setTab,\n form,\n setForm,\n updateField,\n selectedId,\n setSelectedId,\n isNew,\n setIsNew,\n saving,\n setSaving,\n loading,\n setLoading,\n mobilePv,\n setMobilePv,\n addNew,\n startEdit,\n } = adminForm;\n\n useEffect(() => {\n if (startWithNew) {\n handleAdd();\n return;\n }\n if (initialSelectedId) {\n selectItem(initialSelectedId);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const filteredItems = useMemo(\n () => config.filterItems(items, filterValue, searchQuery),\n [items, filterValue, searchQuery, config]\n );\n\n const publishedItems = useMemo(\n () => items.filter(config.meta.getItemPublished),\n [items, config]\n );\n\n const selectItem = useCallback(async (id: string) => {\n startEdit(id, config.emptyForm);\n try {\n const res = await adminFetch(`${config.apiPath}/${id}`);\n const json = await res.json();\n if (json.success) {\n setForm(config.loadItem(json.data));\n } else {\n toast.error(json.error?.message || \"데이터 로드 실패\");\n }\n } catch {\n toast.error(\"데이터 로드 실패\");\n } finally {\n setLoading(false);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [config.apiPath, config.loadItem, config.emptyForm]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useImperativeHandle(innerRef, () => ({ selectItem }), [selectItem]);\n\n const handleAdd = useCallback(() => {\n addNew(config.emptyForm);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [config.emptyForm]);\n\n async function handleSave() {\n const err = config.validate(form);\n if (err) {\n toast.error(err);\n return;\n }\n const payload = config.buildSavePayload(form, { isNew, selectedId, items });\n const url = isNew ? config.apiPath : `${config.apiPath}/${selectedId}`;\n const method = isNew ? \"POST\" : \"PUT\";\n\n setSaving(true);\n try {\n const res = await adminFetch(url, {\n method,\n headers: { ...getAuthHeaders(), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n });\n const json = await res.json();\n if (json.success) {\n const listRes = await adminFetch(`${config.apiPath}?limit=100&sortBy=${sortKey}`);\n const listJson = await listRes.json();\n if (listJson.success) {\n setItems(listJson.data.items.map(config.normalizeListItem));\n }\n setTab(\"list\");\n setSelectedId(null);\n toast.success(\"저장 완료\");\n config.onAfterSave?.();\n config.onNavigateToList?.();\n } else {\n toast.error(json.error?.message || \"저장 실패\");\n }\n } catch {\n toast.error(\"저장 중 오류 발생\");\n } finally {\n setSaving(false);\n }\n }\n\n const handleDelete = useCallback(async (id: string) => {\n const item = items.find((i) => i.id === id);\n const label = item ? config.meta.getItemLabel(item) : id;\n if (!confirm(`\"${label}\"을(를) 삭제하시겠습니까?`)) return;\n try {\n const res = await adminFetch(`${config.apiPath}/${id}`, {\n method: \"DELETE\",\n });\n if (res.ok) {\n setItems((prev) => prev.filter((i) => i.id !== id));\n if (selectedId === id) {\n setSelectedId(null);\n setTab(\"list\");\n }\n } else {\n toast.error(\"삭제에 실패했습니다.\");\n }\n } catch {\n toast.error(\"삭제 중 오류가 발생했습니다.\");\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [items, selectedId, config.apiPath, config.meta]);\n\n const listScrollRef = useRef<HTMLDivElement>(null);\n\n const virtualizer = useVirtualizer({\n count: filteredItems.length,\n getScrollElement: () => listScrollRef.current,\n estimateSize: () => 58,\n overscan: 5,\n });\n\n return (\n <div className={`pm${mobilePv ? \" mobile-pv-on\" : \"\"}`}>\n {/* Topbar */}\n <div className=\"pm-topbar\">\n <div className=\"pm-tb-l\">\n <span className=\"pm-tb-logo\">{config.meta.appTitle}</span>\n <span className=\"pm-tb-sep\" />\n <span className=\"pm-tb-pg\">{config.meta.pageTitle}</span>\n </div>\n </div>\n\n {/* Tabs */}\n <div className=\"pm-tabs\">\n <div\n className={`pm-tab ${tab === \"list\" ? \"on\" : \"\"}`}\n onClick={() => { setTab(\"list\"); config.onNavigateToList?.(); }}\n >\n {config.meta.listTabLabel}\n </div>\n <div\n className={`pm-tab ${tab === \"edit\" ? \"on\" : \"\"}`}\n onClick={() => setTab(\"edit\")}\n >\n 편집 + 미리보기\n </div>\n </div>\n\n {/* Mobile Preview Toggle */}\n <div className=\"mobile-pv-bar\">\n <button\n type=\"button\"\n className={`mobile-pv-btn${!mobilePv ? \" on\" : \"\"}`}\n onClick={() => setMobilePv(false)}\n >\n 편집\n </button>\n <button\n type=\"button\"\n className={`mobile-pv-btn${mobilePv ? \" on\" : \"\"}`}\n onClick={() => setMobilePv(true)}\n >\n 미리보기\n </button>\n </div>\n\n {/* Body */}\n <div className=\"pm-body\">\n {/* List Panel */}\n <div className={`pm-panel pm-panel-list ${tab === \"list\" ? \"on\" : \"\"}`}>\n <div className=\"pm-list-left\">\n <div className=\"pm-list-header\">\n {config.renderFilterControls({\n filterValue,\n setFilterValue,\n sortKey,\n setSortKey,\n sortOptions: config.sortOptions,\n searchQuery,\n setSearchQuery,\n filteredCount: filteredItems.length,\n filteredItems,\n onAdd: handleAdd,\n addButtonLabel: config.meta.addButtonLabel,\n allItems: items,\n })}\n </div>\n <div className=\"pm-perf-list\" ref={listScrollRef}>\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualRow) => {\n const item = filteredItems[virtualRow.index];\n return (\n <div\n key={item.id}\n data-index={virtualRow.index}\n ref={virtualizer.measureElement}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n }}\n >\n {config.renderListItem(item, {\n isSelected: selectedId === item.id,\n onSelect: selectItem,\n onDelete: handleDelete,\n })}\n </div>\n );\n })}\n </div>\n </div>\n </div>\n <div className=\"pm-list-right\">\n <div className=\"pm-pv-label\">홈페이지 미리보기</div>\n {config.renderListPreview({\n publishedItems,\n onSelectItem: selectItem,\n })}\n </div>\n </div>\n\n {/* Edit Panel */}\n <div\n className={`pm-panel pm-panel-edit ${tab === \"edit\" ? \"on\" : \"\"}`}\n >\n <div className=\"pm-edit-left\">\n {config.renderEditForm({\n form,\n setForm,\n updateField,\n isNew,\n selectedId,\n saving,\n loading,\n onSave: handleSave,\n onCancel: () => { setTab(\"list\"); config.onNavigateToList?.(); },\n onDelete: () => { if (selectedId) handleDelete(selectedId); },\n })}\n </div>\n <div className=\"pm-edit-right\">\n <div className=\"pm-pv-label\">실시간 미리보기</div>\n {config.renderDetailPreview({ form, isNew, selectedId })}\n </div>\n </div>\n </div>\n\n {/* Domain Modal */}\n {config.renderModal?.()}\n </div>\n );\n}\n\nexport default function AdminManagerBase<\n TItem extends { id: string },\n TForm extends object\n>(props: Props<TItem, TForm> & { ref?: React.Ref<AdminManagerBaseHandle> }) {\n const { ref, ...rest } = props;\n return <AdminManagerBaseInner {...rest} innerRef={ref} />;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,26 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { AdminManagerConfig } from './AdminManagerConfig.mjs';
3
+ import 'react';
4
+
5
+ interface Props<TItem extends {
6
+ id: string;
7
+ }, TForm extends object> {
8
+ initialItems: TItem[];
9
+ config: AdminManagerConfig<TItem, TForm>;
10
+ /** 초기에 선택할 항목 ID (예: detail 라우트의 [id] 세그먼트) */
11
+ initialSelectedId?: string | null;
12
+ /** 최초 진입 시 새 항목 편집 모드로 시작할지 여부 (예: 새 항목 라우트) */
13
+ startWithNew?: boolean;
14
+ /** 초기 필터 값 (예: 카테고리 필터링) */
15
+ defaultFilterValue?: string;
16
+ }
17
+ interface AdminManagerBaseHandle {
18
+ selectItem: (id: string) => void;
19
+ }
20
+ declare function AdminManagerBase<TItem extends {
21
+ id: string;
22
+ }, TForm extends object>(props: Props<TItem, TForm> & {
23
+ ref?: React.Ref<AdminManagerBaseHandle>;
24
+ }): react_jsx_runtime.JSX.Element;
25
+
26
+ export { type AdminManagerBaseHandle, AdminManagerBase as default };
@@ -0,0 +1,26 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { AdminManagerConfig } from './AdminManagerConfig.js';
3
+ import 'react';
4
+
5
+ interface Props<TItem extends {
6
+ id: string;
7
+ }, TForm extends object> {
8
+ initialItems: TItem[];
9
+ config: AdminManagerConfig<TItem, TForm>;
10
+ /** 초기에 선택할 항목 ID (예: detail 라우트의 [id] 세그먼트) */
11
+ initialSelectedId?: string | null;
12
+ /** 최초 진입 시 새 항목 편집 모드로 시작할지 여부 (예: 새 항목 라우트) */
13
+ startWithNew?: boolean;
14
+ /** 초기 필터 값 (예: 카테고리 필터링) */
15
+ defaultFilterValue?: string;
16
+ }
17
+ interface AdminManagerBaseHandle {
18
+ selectItem: (id: string) => void;
19
+ }
20
+ declare function AdminManagerBase<TItem extends {
21
+ id: string;
22
+ }, TForm extends object>(props: Props<TItem, TForm> & {
23
+ ref?: React.Ref<AdminManagerBaseHandle>;
24
+ }): react_jsx_runtime.JSX.Element;
25
+
26
+ export { type AdminManagerBaseHandle, AdminManagerBase as default };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
3
+
4
+
5
+ var _chunkDCIF4XJLjs = require('../chunk-DCIF4XJL.js');
6
+ require('../chunk-5JUIMXNF.js');
7
+ require('../chunk-KWKV2GAH.js');
8
+ require('../chunk-EG6NVPP2.js');
9
+ require('../chunk-DGUM43GV.js');
10
+
11
+
12
+ exports.default = _chunkDCIF4XJLjs.AdminManagerBase;
13
+ //# sourceMappingURL=AdminManagerBase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/uni4love/project/workspace/211-withwiz/node-packages/withwiz-cms-kit/dist/components/AdminManagerBase.js"],"names":[],"mappings":"AAAA,qFAAY;AACZ;AACE;AACF,uDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACF,oDAAC","file":"/Users/uni4love/project/workspace/211-withwiz/node-packages/withwiz-cms-kit/dist/components/AdminManagerBase.js"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import {
3
+ AdminManagerBase
4
+ } from "../chunk-ZULSFSDG.mjs";
5
+ import "../chunk-FCCCG5Z7.mjs";
6
+ import "../chunk-T7EVFD4G.mjs";
7
+ import "../chunk-BWKKHCDG.mjs";
8
+ import "../chunk-BJTO5JO5.mjs";
9
+ export {
10
+ AdminManagerBase as default
11
+ };
12
+ //# sourceMappingURL=AdminManagerBase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,83 @@
1
+ import { ReactNode, Dispatch, SetStateAction } from 'react';
2
+
3
+ interface FilterSlotProps<TItem = unknown> {
4
+ filterValue: string;
5
+ setFilterValue: (v: string) => void;
6
+ sortKey: string;
7
+ setSortKey: (v: string) => void;
8
+ sortOptions: {
9
+ value: string;
10
+ label: string;
11
+ }[];
12
+ searchQuery: string;
13
+ setSearchQuery: (v: string) => void;
14
+ filteredCount: number;
15
+ filteredItems: TItem[];
16
+ onAdd: () => void;
17
+ addButtonLabel: string;
18
+ allItems: TItem[];
19
+ }
20
+ interface ListItemSlotProps<TItem> {
21
+ isSelected: boolean;
22
+ onSelect: (id: string) => void;
23
+ onDelete: (id: string) => void;
24
+ }
25
+ interface EditFormSlotProps<TForm> {
26
+ form: TForm;
27
+ setForm: Dispatch<SetStateAction<TForm>>;
28
+ updateField: <K extends keyof TForm>(key: K, value: TForm[K]) => void;
29
+ isNew: boolean;
30
+ selectedId: string | null;
31
+ saving: boolean;
32
+ loading: boolean;
33
+ onSave: () => void;
34
+ onCancel: () => void;
35
+ onDelete: () => void;
36
+ }
37
+ interface DetailPreviewSlotProps<TForm> {
38
+ form: TForm;
39
+ isNew: boolean;
40
+ selectedId: string | null;
41
+ }
42
+ interface ListPreviewSlotProps<TItem> {
43
+ publishedItems: TItem[];
44
+ onSelectItem: (id: string) => void;
45
+ }
46
+ interface AdminManagerConfig<TItem extends {
47
+ id: string;
48
+ }, TForm extends object> {
49
+ meta: {
50
+ appTitle: string;
51
+ pageTitle: string;
52
+ listTabLabel: string;
53
+ addButtonLabel: string;
54
+ getItemLabel: (item: TItem) => string;
55
+ getItemPublished: (item: TItem) => boolean;
56
+ };
57
+ apiPath: string;
58
+ defaultSortKey: string;
59
+ sortOptions: {
60
+ value: string;
61
+ label: string;
62
+ }[];
63
+ emptyForm: TForm;
64
+ loadItem: (apiData: unknown) => TForm;
65
+ buildSavePayload: (form: TForm, ctx: {
66
+ isNew: boolean;
67
+ selectedId: string | null;
68
+ items: TItem[];
69
+ }) => Record<string, unknown>;
70
+ validate: (form: TForm) => string | null;
71
+ normalizeListItem: (raw: unknown) => TItem;
72
+ filterItems: (items: TItem[], filter: string, search: string) => TItem[];
73
+ renderFilterControls: (props: FilterSlotProps<TItem>) => ReactNode;
74
+ renderListItem: (item: TItem, props: ListItemSlotProps<TItem>) => ReactNode;
75
+ renderEditForm: (props: EditFormSlotProps<TForm>) => ReactNode;
76
+ renderDetailPreview: (props: DetailPreviewSlotProps<TForm>) => ReactNode;
77
+ renderListPreview: (props: ListPreviewSlotProps<TItem>) => ReactNode;
78
+ renderModal?: () => ReactNode;
79
+ onAfterSave?: () => void;
80
+ onNavigateToList?: () => void;
81
+ }
82
+
83
+ export type { AdminManagerConfig, DetailPreviewSlotProps, EditFormSlotProps, FilterSlotProps, ListItemSlotProps, ListPreviewSlotProps };
@@ -0,0 +1,83 @@
1
+ import { ReactNode, Dispatch, SetStateAction } from 'react';
2
+
3
+ interface FilterSlotProps<TItem = unknown> {
4
+ filterValue: string;
5
+ setFilterValue: (v: string) => void;
6
+ sortKey: string;
7
+ setSortKey: (v: string) => void;
8
+ sortOptions: {
9
+ value: string;
10
+ label: string;
11
+ }[];
12
+ searchQuery: string;
13
+ setSearchQuery: (v: string) => void;
14
+ filteredCount: number;
15
+ filteredItems: TItem[];
16
+ onAdd: () => void;
17
+ addButtonLabel: string;
18
+ allItems: TItem[];
19
+ }
20
+ interface ListItemSlotProps<TItem> {
21
+ isSelected: boolean;
22
+ onSelect: (id: string) => void;
23
+ onDelete: (id: string) => void;
24
+ }
25
+ interface EditFormSlotProps<TForm> {
26
+ form: TForm;
27
+ setForm: Dispatch<SetStateAction<TForm>>;
28
+ updateField: <K extends keyof TForm>(key: K, value: TForm[K]) => void;
29
+ isNew: boolean;
30
+ selectedId: string | null;
31
+ saving: boolean;
32
+ loading: boolean;
33
+ onSave: () => void;
34
+ onCancel: () => void;
35
+ onDelete: () => void;
36
+ }
37
+ interface DetailPreviewSlotProps<TForm> {
38
+ form: TForm;
39
+ isNew: boolean;
40
+ selectedId: string | null;
41
+ }
42
+ interface ListPreviewSlotProps<TItem> {
43
+ publishedItems: TItem[];
44
+ onSelectItem: (id: string) => void;
45
+ }
46
+ interface AdminManagerConfig<TItem extends {
47
+ id: string;
48
+ }, TForm extends object> {
49
+ meta: {
50
+ appTitle: string;
51
+ pageTitle: string;
52
+ listTabLabel: string;
53
+ addButtonLabel: string;
54
+ getItemLabel: (item: TItem) => string;
55
+ getItemPublished: (item: TItem) => boolean;
56
+ };
57
+ apiPath: string;
58
+ defaultSortKey: string;
59
+ sortOptions: {
60
+ value: string;
61
+ label: string;
62
+ }[];
63
+ emptyForm: TForm;
64
+ loadItem: (apiData: unknown) => TForm;
65
+ buildSavePayload: (form: TForm, ctx: {
66
+ isNew: boolean;
67
+ selectedId: string | null;
68
+ items: TItem[];
69
+ }) => Record<string, unknown>;
70
+ validate: (form: TForm) => string | null;
71
+ normalizeListItem: (raw: unknown) => TItem;
72
+ filterItems: (items: TItem[], filter: string, search: string) => TItem[];
73
+ renderFilterControls: (props: FilterSlotProps<TItem>) => ReactNode;
74
+ renderListItem: (item: TItem, props: ListItemSlotProps<TItem>) => ReactNode;
75
+ renderEditForm: (props: EditFormSlotProps<TForm>) => ReactNode;
76
+ renderDetailPreview: (props: DetailPreviewSlotProps<TForm>) => ReactNode;
77
+ renderListPreview: (props: ListPreviewSlotProps<TItem>) => ReactNode;
78
+ renderModal?: () => ReactNode;
79
+ onAfterSave?: () => void;
80
+ onNavigateToList?: () => void;
81
+ }
82
+
83
+ export type { AdminManagerConfig, DetailPreviewSlotProps, EditFormSlotProps, FilterSlotProps, ListItemSlotProps, ListPreviewSlotProps };
@@ -0,0 +1,2 @@
1
+ "use strict";require('../chunk-D2VDTRXO.js');
2
+ //# sourceMappingURL=AdminManagerConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/uni4love/project/workspace/211-withwiz/node-packages/withwiz-cms-kit/dist/components/AdminManagerConfig.js"],"names":[],"mappings":"AAAA,6CAA6B","file":"/Users/uni4love/project/workspace/211-withwiz/node-packages/withwiz-cms-kit/dist/components/AdminManagerConfig.js"}
@@ -0,0 +1,2 @@
1
+ import "../chunk-6ES4W2DL.mjs";
2
+ //# sourceMappingURL=AdminManagerConfig.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,30 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { d as CmsNavItem } from '../index-00a40-FQ.mjs';
3
+
4
+ /**
5
+ * AdminShell props (spec.md §4.1 / Sprint 1 C1/C2).
6
+ *
7
+ * brand/nav/route 는 더 이상 하드코딩되지 않는다. 우선순위:
8
+ * props > §5 config boundary (`setCmsConfig`) > 안전 중립 기본값
9
+ * (빈 nav + 1회 `@withwiz/cms-kit:` warn, route 는 레거시 기본 경로).
10
+ */
11
+ interface AdminShellProps {
12
+ children: React.ReactNode;
13
+ /** 브랜드 라벨 (사이드바 홈 링크 텍스트). 미지정 시 §5 config. */
14
+ brandLabel?: string;
15
+ /** 브랜드 홈 링크 href. */
16
+ brandHref?: string;
17
+ /** admin 링크 href. */
18
+ adminHref?: string;
19
+ /** 순서 있는 nav 항목 목록 (label/href/glyph). */
20
+ navItems?: CmsNavItem[];
21
+ /** 로그인 페이지 경로 (라우트 가드/리다이렉트). */
22
+ loginPath?: string;
23
+ /** "현재 사용자" 엔드포인트. */
24
+ meEndpoint?: string;
25
+ /** 로그아웃 엔드포인트. */
26
+ logoutEndpoint?: string;
27
+ }
28
+ declare function AdminShell({ children, brandLabel, brandHref, adminHref, navItems, loginPath, meEndpoint, logoutEndpoint, }: AdminShellProps): react_jsx_runtime.JSX.Element;
29
+
30
+ export { type AdminShellProps, AdminShell as default };