kempo 4.2.15 → 4.2.17

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 (306) hide show
  1. package/app-public/account/split2.template.html +1 -0
  2. package/app-public/test.page.html +1 -0
  3. package/bin/cli.js +21 -4
  4. package/dist/admin/components/AddGroupControl.js +2 -2
  5. package/dist/admin/components/AddGroupControl.js.map +1 -1
  6. package/dist/admin/components/ClearExpiredSessionsControl.js +2 -2
  7. package/dist/admin/components/ClearExpiredSessionsControl.js.map +1 -1
  8. package/dist/admin/components/FragmentEditor.js +15 -15
  9. package/dist/admin/components/FragmentEditor.js.map +1 -1
  10. package/dist/admin/components/GlobalContentEditor.js +12 -12
  11. package/dist/admin/components/GlobalContentEditor.js.map +1 -1
  12. package/dist/admin/components/GroupDeleteSelected.js +2 -2
  13. package/dist/admin/components/GroupDeleteSelected.js.map +1 -1
  14. package/dist/admin/components/GroupRemoveRecord.js +2 -2
  15. package/dist/admin/components/GroupRemoveRecord.js.map +1 -1
  16. package/dist/admin/components/Monaco.js +1 -1
  17. package/dist/admin/components/Monaco.js.map +1 -1
  18. package/dist/admin/components/PageEditor.js +42 -28
  19. package/dist/admin/components/PageEditor.js.map +1 -1
  20. package/dist/admin/components/TableRowDelete.js +2 -2
  21. package/dist/admin/components/TableRowDelete.js.map +1 -1
  22. package/dist/admin/components/TableRowLink.js +2 -2
  23. package/dist/admin/components/TableRowLink.js.map +1 -1
  24. package/dist/admin/components/TemplateEditor.js +18 -18
  25. package/dist/admin/components/TemplateEditor.js.map +1 -1
  26. package/dist/admin/components/ValueEditor.js +17 -17
  27. package/dist/admin/components/ValueEditor.js.map +1 -1
  28. package/dist/admin/components/tableControls/AddMember.js +2 -2
  29. package/dist/admin/components/tableControls/AddMember.js.map +1 -1
  30. package/dist/admin/components/tableControls/AddPermission.js +2 -2
  31. package/dist/admin/components/tableControls/AddPermission.js.map +1 -1
  32. package/dist/admin/components/tableControls/InstallExtension.js +2 -2
  33. package/dist/admin/components/tableControls/InstallExtension.js.map +1 -1
  34. package/dist/admin/components/tableControls/UninstallExtension.js +2 -2
  35. package/dist/admin/components/tableControls/UninstallExtension.js.map +1 -1
  36. package/dist/admin/extensions/index.page.html +49 -15
  37. package/dist/admin/icons/open_in_new.svg +1 -0
  38. package/dist/admin/nav.fragment.html +1 -1
  39. package/dist/kempo/api/admin-globals/DELETE.js +1 -1
  40. package/dist/kempo/api/admin-globals/DELETE.js.map +1 -1
  41. package/dist/kempo/api/admin-globals/GET.js +1 -1
  42. package/dist/kempo/api/admin-globals/GET.js.map +1 -1
  43. package/dist/kempo/api/admin-globals/POST.js +1 -1
  44. package/dist/kempo/api/admin-globals/POST.js.map +1 -1
  45. package/dist/kempo/api/admin-globals/[id]/GET.js +1 -1
  46. package/dist/kempo/api/admin-globals/[id]/GET.js.map +1 -1
  47. package/dist/kempo/api/admin-globals/[id]/PUT.js +1 -1
  48. package/dist/kempo/api/admin-globals/[id]/PUT.js.map +1 -1
  49. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js +1 -1
  50. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js.map +1 -1
  51. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js +1 -1
  52. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js.map +1 -1
  53. package/dist/kempo/api/auth/change-password/POST.js +1 -1
  54. package/dist/kempo/api/auth/change-password/POST.js.map +1 -1
  55. package/dist/kempo/api/auth/login/email/POST.js +1 -1
  56. package/dist/kempo/api/auth/login/email/POST.js.map +1 -1
  57. package/dist/kempo/api/auth/logout/POST.js +1 -1
  58. package/dist/kempo/api/auth/logout/POST.js.map +1 -1
  59. package/dist/kempo/api/auth/register/email/POST.js +1 -1
  60. package/dist/kempo/api/auth/register/email/POST.js.map +1 -1
  61. package/dist/kempo/api/auth/reset-password/POST.js +1 -1
  62. package/dist/kempo/api/auth/reset-password/POST.js.map +1 -1
  63. package/dist/kempo/api/auth/session/GET.js +1 -1
  64. package/dist/kempo/api/auth/session/GET.js.map +1 -1
  65. package/dist/kempo/api/auth/verify-email/POST.js +1 -1
  66. package/dist/kempo/api/auth/verify-email/POST.js.map +1 -1
  67. package/dist/kempo/api/extensions/DELETE.js +1 -1
  68. package/dist/kempo/api/extensions/DELETE.js.map +1 -1
  69. package/dist/kempo/api/extensions/GET.js +1 -1
  70. package/dist/kempo/api/extensions/GET.js.map +1 -1
  71. package/dist/kempo/api/extensions/POST.js +1 -1
  72. package/dist/kempo/api/extensions/POST.js.map +1 -1
  73. package/dist/kempo/api/extensions/[name]/disable/POST.js +1 -1
  74. package/dist/kempo/api/extensions/[name]/disable/POST.js.map +1 -1
  75. package/dist/kempo/api/extensions/[name]/enable/POST.js +1 -1
  76. package/dist/kempo/api/extensions/[name]/enable/POST.js.map +1 -1
  77. package/dist/kempo/api/extensions/[name]/update/POST.js +1 -1
  78. package/dist/kempo/api/extensions/[name]/update/POST.js.map +1 -1
  79. package/dist/kempo/api/extensions/[name]/update-check/GET.js +1 -1
  80. package/dist/kempo/api/extensions/[name]/update-check/GET.js.map +1 -1
  81. package/dist/kempo/api/extensions/available/GET.js +1 -1
  82. package/dist/kempo/api/extensions/available/GET.js.map +1 -1
  83. package/dist/kempo/api/extensions/known/GET.js +1 -1
  84. package/dist/kempo/api/extensions/known/GET.js.map +1 -1
  85. package/dist/kempo/api/forgot-password/POST.js +1 -1
  86. package/dist/kempo/api/forgot-password/POST.js.map +1 -1
  87. package/dist/kempo/api/fragments/DELETE.js +1 -1
  88. package/dist/kempo/api/fragments/DELETE.js.map +1 -1
  89. package/dist/kempo/api/fragments/GET.js +1 -1
  90. package/dist/kempo/api/fragments/GET.js.map +1 -1
  91. package/dist/kempo/api/fragments/POST.js +1 -1
  92. package/dist/kempo/api/fragments/POST.js.map +1 -1
  93. package/dist/kempo/api/fragments/disable/PUT.js +1 -1
  94. package/dist/kempo/api/fragments/disable/PUT.js.map +1 -1
  95. package/dist/kempo/api/fragments/enable/PUT.js +1 -1
  96. package/dist/kempo/api/fragments/enable/PUT.js.map +1 -1
  97. package/dist/kempo/api/fragments/file/GET.js +1 -1
  98. package/dist/kempo/api/fragments/file/GET.js.map +1 -1
  99. package/dist/kempo/api/fragments/file/PATCH.js +1 -1
  100. package/dist/kempo/api/fragments/file/PATCH.js.map +1 -1
  101. package/dist/kempo/api/fragments/file/PUT.js +1 -1
  102. package/dist/kempo/api/fragments/file/PUT.js.map +1 -1
  103. package/dist/kempo/api/fragments/lock/PUT.js +2 -0
  104. package/dist/kempo/api/fragments/lock/PUT.js.map +1 -0
  105. package/dist/kempo/api/globals/DELETE.js +1 -1
  106. package/dist/kempo/api/globals/DELETE.js.map +1 -1
  107. package/dist/kempo/api/globals/GET.js +1 -1
  108. package/dist/kempo/api/globals/GET.js.map +1 -1
  109. package/dist/kempo/api/globals/POST.js +1 -1
  110. package/dist/kempo/api/globals/POST.js.map +1 -1
  111. package/dist/kempo/api/globals/disable/PUT.js +1 -1
  112. package/dist/kempo/api/globals/disable/PUT.js.map +1 -1
  113. package/dist/kempo/api/globals/enable/PUT.js +1 -1
  114. package/dist/kempo/api/globals/enable/PUT.js.map +1 -1
  115. package/dist/kempo/api/globals/entry/GET.js +1 -1
  116. package/dist/kempo/api/globals/entry/GET.js.map +1 -1
  117. package/dist/kempo/api/globals/entry/PUT.js +1 -1
  118. package/dist/kempo/api/globals/entry/PUT.js.map +1 -1
  119. package/dist/kempo/api/globals/lock/PUT.js +2 -0
  120. package/dist/kempo/api/globals/lock/PUT.js.map +1 -0
  121. package/dist/kempo/api/groups/DELETE.js +1 -1
  122. package/dist/kempo/api/groups/DELETE.js.map +1 -1
  123. package/dist/kempo/api/groups/GET.js +1 -1
  124. package/dist/kempo/api/groups/GET.js.map +1 -1
  125. package/dist/kempo/api/groups/PATCH.js +1 -1
  126. package/dist/kempo/api/groups/PATCH.js.map +1 -1
  127. package/dist/kempo/api/groups/POST.js +1 -1
  128. package/dist/kempo/api/groups/POST.js.map +1 -1
  129. package/dist/kempo/api/groups/[name]/GET.js +1 -1
  130. package/dist/kempo/api/groups/[name]/GET.js.map +1 -1
  131. package/dist/kempo/api/groups/[name]/members/DELETE.js +1 -1
  132. package/dist/kempo/api/groups/[name]/members/DELETE.js.map +1 -1
  133. package/dist/kempo/api/groups/[name]/members/GET.js +1 -1
  134. package/dist/kempo/api/groups/[name]/members/GET.js.map +1 -1
  135. package/dist/kempo/api/groups/[name]/members/POST.js +1 -1
  136. package/dist/kempo/api/groups/[name]/members/POST.js.map +1 -1
  137. package/dist/kempo/api/groups/[name]/permissions/DELETE.js +1 -1
  138. package/dist/kempo/api/groups/[name]/permissions/DELETE.js.map +1 -1
  139. package/dist/kempo/api/groups/[name]/permissions/GET.js +1 -1
  140. package/dist/kempo/api/groups/[name]/permissions/GET.js.map +1 -1
  141. package/dist/kempo/api/groups/[name]/permissions/POST.js +1 -1
  142. package/dist/kempo/api/groups/[name]/permissions/POST.js.map +1 -1
  143. package/dist/kempo/api/pages/DELETE.js +1 -1
  144. package/dist/kempo/api/pages/DELETE.js.map +1 -1
  145. package/dist/kempo/api/pages/GET.js +1 -1
  146. package/dist/kempo/api/pages/GET.js.map +1 -1
  147. package/dist/kempo/api/pages/POST.js +1 -1
  148. package/dist/kempo/api/pages/POST.js.map +1 -1
  149. package/dist/kempo/api/pages/directories/GET.js +1 -1
  150. package/dist/kempo/api/pages/directories/GET.js.map +1 -1
  151. package/dist/kempo/api/pages/disable/PUT.js +1 -1
  152. package/dist/kempo/api/pages/disable/PUT.js.map +1 -1
  153. package/dist/kempo/api/pages/enable/PUT.js +1 -1
  154. package/dist/kempo/api/pages/enable/PUT.js.map +1 -1
  155. package/dist/kempo/api/pages/file/GET.js +1 -1
  156. package/dist/kempo/api/pages/file/GET.js.map +1 -1
  157. package/dist/kempo/api/pages/file/PATCH.js +1 -1
  158. package/dist/kempo/api/pages/file/PATCH.js.map +1 -1
  159. package/dist/kempo/api/pages/file/PUT.js +1 -1
  160. package/dist/kempo/api/pages/file/PUT.js.map +1 -1
  161. package/dist/kempo/api/pages/lock/PUT.js +2 -0
  162. package/dist/kempo/api/pages/lock/PUT.js.map +1 -0
  163. package/dist/kempo/api/pages/search/GET.js +2 -0
  164. package/dist/kempo/api/pages/search/GET.js.map +1 -0
  165. package/dist/kempo/api/pages/templates/GET.js +1 -1
  166. package/dist/kempo/api/pages/templates/GET.js.map +1 -1
  167. package/dist/kempo/api/permissions/DELETE.js +1 -1
  168. package/dist/kempo/api/permissions/DELETE.js.map +1 -1
  169. package/dist/kempo/api/permissions/GET.js +1 -1
  170. package/dist/kempo/api/permissions/GET.js.map +1 -1
  171. package/dist/kempo/api/permissions/PATCH.js +1 -1
  172. package/dist/kempo/api/permissions/PATCH.js.map +1 -1
  173. package/dist/kempo/api/permissions/POST.js +1 -1
  174. package/dist/kempo/api/permissions/POST.js.map +1 -1
  175. package/dist/kempo/api/settings/[owner]/GET.js +1 -1
  176. package/dist/kempo/api/settings/[owner]/GET.js.map +1 -1
  177. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js +1 -1
  178. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js.map +1 -1
  179. package/dist/kempo/api/settings/[owner]/[name]/GET.js +1 -1
  180. package/dist/kempo/api/settings/[owner]/[name]/GET.js.map +1 -1
  181. package/dist/kempo/api/settings/[owner]/[name]/POST.js +1 -1
  182. package/dist/kempo/api/settings/[owner]/[name]/POST.js.map +1 -1
  183. package/dist/kempo/api/settings/public/GET.js +1 -1
  184. package/dist/kempo/api/settings/public/GET.js.map +1 -1
  185. package/dist/kempo/api/templates/DELETE.js +1 -1
  186. package/dist/kempo/api/templates/DELETE.js.map +1 -1
  187. package/dist/kempo/api/templates/GET.js +1 -1
  188. package/dist/kempo/api/templates/GET.js.map +1 -1
  189. package/dist/kempo/api/templates/POST.js +1 -1
  190. package/dist/kempo/api/templates/POST.js.map +1 -1
  191. package/dist/kempo/api/templates/disable/PUT.js +1 -1
  192. package/dist/kempo/api/templates/disable/PUT.js.map +1 -1
  193. package/dist/kempo/api/templates/enable/PUT.js +1 -1
  194. package/dist/kempo/api/templates/enable/PUT.js.map +1 -1
  195. package/dist/kempo/api/templates/file/GET.js +1 -1
  196. package/dist/kempo/api/templates/file/GET.js.map +1 -1
  197. package/dist/kempo/api/templates/file/PATCH.js +1 -1
  198. package/dist/kempo/api/templates/file/PATCH.js.map +1 -1
  199. package/dist/kempo/api/templates/file/PUT.js +1 -1
  200. package/dist/kempo/api/templates/file/PUT.js.map +1 -1
  201. package/dist/kempo/api/templates/lock/PUT.js +2 -0
  202. package/dist/kempo/api/templates/lock/PUT.js.map +1 -0
  203. package/dist/kempo/api/user/DELETE.js +1 -1
  204. package/dist/kempo/api/user/DELETE.js.map +1 -1
  205. package/dist/kempo/api/user/GET.js +1 -1
  206. package/dist/kempo/api/user/GET.js.map +1 -1
  207. package/dist/kempo/api/user/PATCH.js +1 -1
  208. package/dist/kempo/api/user/PATCH.js.map +1 -1
  209. package/dist/kempo/api/user/[userid]/GET.js +1 -1
  210. package/dist/kempo/api/user/[userid]/GET.js.map +1 -1
  211. package/dist/kempo/api/user/[userid]/groups/DELETE.js +1 -1
  212. package/dist/kempo/api/user/[userid]/groups/DELETE.js.map +1 -1
  213. package/dist/kempo/api/user/[userid]/groups/GET.js +1 -1
  214. package/dist/kempo/api/user/[userid]/groups/GET.js.map +1 -1
  215. package/dist/kempo/api/user/[userid]/groups/POST.js +1 -1
  216. package/dist/kempo/api/user/[userid]/groups/POST.js.map +1 -1
  217. package/dist/kempo/api/user/[userid]/permissions/GET.js +1 -1
  218. package/dist/kempo/api/user/[userid]/permissions/GET.js.map +1 -1
  219. package/dist/kempo/api/user/[userid]/permissions/all/GET.js +1 -1
  220. package/dist/kempo/api/user/[userid]/permissions/all/GET.js.map +1 -1
  221. package/dist/kempo/api/user/[userid]/permissions/list/GET.js +1 -1
  222. package/dist/kempo/api/user/[userid]/permissions/list/GET.js.map +1 -1
  223. package/dist/kempo/api/user/[userid]/permissions/some/GET.js +1 -1
  224. package/dist/kempo/api/user/[userid]/permissions/some/GET.js.map +1 -1
  225. package/dist/kempo/api/user/[userid]/sessions/DELETE.js +1 -1
  226. package/dist/kempo/api/user/[userid]/sessions/DELETE.js.map +1 -1
  227. package/dist/kempo/api/user/[userid]/sessions/GET.js +1 -1
  228. package/dist/kempo/api/user/[userid]/sessions/GET.js.map +1 -1
  229. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js +1 -1
  230. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js.map +1 -1
  231. package/dist/kempo/api/user/create/POST.js +1 -1
  232. package/dist/kempo/api/user/create/POST.js.map +1 -1
  233. package/dist/kempo/api/user/search/GET.js +1 -1
  234. package/dist/kempo/api/user/search/GET.js.map +1 -1
  235. package/dist/kempo/components/LogoutBtn.js +1 -1
  236. package/dist/kempo/components/LogoutBtn.js.map +1 -1
  237. package/dist/kempo/components/Menu.js +9 -9
  238. package/dist/kempo/components/Menu.js.map +1 -1
  239. package/dist/kempo/components/Permission.js +1 -1
  240. package/dist/kempo/components/Permission.js.map +1 -1
  241. package/dist/kempo/components/Role.js +1 -1
  242. package/dist/kempo/components/Role.js.map +1 -1
  243. package/dist/kempo/components/UserCreatedAt.js +1 -1
  244. package/dist/kempo/components/UserCreatedAt.js.map +1 -1
  245. package/dist/kempo/components/UserEmail.js +1 -1
  246. package/dist/kempo/components/UserEmail.js.map +1 -1
  247. package/dist/kempo/components/UserEmailVerified.js +1 -1
  248. package/dist/kempo/components/UserEmailVerified.js.map +1 -1
  249. package/dist/kempo/components/UserName.js +1 -1
  250. package/dist/kempo/components/UserName.js.map +1 -1
  251. package/dist/kempo/fetch.js +1 -1
  252. package/dist/kempo/fetch.js.map +1 -1
  253. package/dist/kempo/sdk.js +1 -1
  254. package/dist/kempo/sdk.js.map +1 -1
  255. package/middleware/kempo.js +36 -6
  256. package/package.json +3 -3
  257. package/server/sdk.js +5 -0
  258. package/server/utils/extensions/installExtension.js +19 -13
  259. package/server/utils/extensions/uninstallExtension.js +6 -10
  260. package/server/utils/fragments/createFragment.js +5 -1
  261. package/server/utils/fragments/deleteFragment.js +2 -3
  262. package/server/utils/fragments/disableFragment.js +0 -3
  263. package/server/utils/fragments/getFragmentMetadata.js +32 -0
  264. package/server/utils/fragments/moveFragment.js +0 -3
  265. package/server/utils/fragments/setFragmentLocked.js +48 -0
  266. package/server/utils/fragments/updateFragment.js +3 -3
  267. package/server/utils/fs/isResourceLocked.js +22 -0
  268. package/server/utils/global-content/createGlobalContent.js +3 -0
  269. package/server/utils/global-content/deleteGlobalContent.js +3 -3
  270. package/server/utils/global-content/getGlobalContentMetadata.js +37 -0
  271. package/server/utils/global-content/setGlobalContentLocked.js +44 -0
  272. package/server/utils/global-content/updateGlobalContent.js +3 -4
  273. package/server/utils/pages/createPage.js +19 -7
  274. package/server/utils/pages/deletePage.js +4 -13
  275. package/server/utils/pages/disablePage.js +0 -3
  276. package/server/utils/pages/getPage.js +7 -0
  277. package/server/utils/pages/getPageMetadata.js +32 -0
  278. package/server/utils/pages/listPages.js +11 -3
  279. package/server/utils/pages/movePage.js +0 -3
  280. package/server/utils/pages/searchByMetadata.js +61 -0
  281. package/server/utils/pages/setPageLocked.js +48 -0
  282. package/server/utils/pages/updatePage.js +19 -3
  283. package/server/utils/templates/createTemplate.js +5 -1
  284. package/server/utils/templates/deleteTemplate.js +2 -3
  285. package/server/utils/templates/disableTemplate.js +0 -3
  286. package/server/utils/templates/getTemplateMetadata.js +32 -0
  287. package/server/utils/templates/moveTemplate.js +0 -3
  288. package/server/utils/templates/setTemplateLocked.js +48 -0
  289. package/server/utils/templates/updateTemplate.js +3 -3
  290. package/dist/admin/accounts/groups/[name]/index.html +0 -518
  291. package/dist/admin/accounts/groups/index.html +0 -378
  292. package/dist/admin/accounts/permissions/index.html +0 -397
  293. package/dist/admin/accounts/users/[id]/index.html +0 -541
  294. package/dist/admin/accounts/users/index.html +0 -396
  295. package/dist/admin/content/fragments/edit/index.html +0 -132
  296. package/dist/admin/content/fragments/index.html +0 -375
  297. package/dist/admin/content/globals/edit/index.html +0 -132
  298. package/dist/admin/content/globals/index.html +0 -358
  299. package/dist/admin/content/pages/edit/index.html +0 -132
  300. package/dist/admin/content/pages/index.html +0 -509
  301. package/dist/admin/content/templates/edit/index.html +0 -132
  302. package/dist/admin/content/templates/index.html +0 -429
  303. package/dist/admin/extensions/index.html +0 -222
  304. package/dist/admin/index.html +0 -130
  305. package/dist/admin/settings/[owner]/[name]/index.html +0 -449
  306. package/dist/admin/settings/index.html +0 -410
@@ -3,6 +3,7 @@
3
3
  author: Copilot Admin
4
4
  created: 2026-04-16T20:40:58.376Z
5
5
  updated: 2026-04-19T20:43:06.103Z
6
+ locked: true
6
7
  -->
7
8
  <!DOCTYPE html>
8
9
  <html lang="en">
@@ -6,6 +6,7 @@
6
6
  updated: 2026-04-16T21:13:12.153Z
7
7
  title: test
8
8
  description:
9
+ locked: true
9
10
  -->
10
11
  <page template="split" title="test">
11
12
  <content location="left">
package/bin/cli.js CHANGED
@@ -289,6 +289,18 @@ if(!useDefaults){
289
289
  }
290
290
  }
291
291
 
292
+ let wantsDrizzleStudio = false;
293
+
294
+ if(!useDefaults){
295
+ const { drizzleStudio } = await inquirer.prompt([{
296
+ type: 'confirm',
297
+ name: 'drizzleStudio',
298
+ message: 'Would you like to install drizzle-studio? It is used for interacting with the database during development, not recommended for production.',
299
+ default: true
300
+ }]);
301
+ wantsDrizzleStudio = drizzleStudio;
302
+ }
303
+
292
304
  /*
293
305
  Step 3: Scaffold project files
294
306
  */
@@ -297,15 +309,19 @@ console.log('\n--- Scaffolding project files ---\n');
297
309
 
298
310
  const pkgPath = join(projectDir, 'package.json');
299
311
  if(!existsSync(pkgPath)){
312
+ const scripts = {
313
+ dev: 'kempo-server --root public --port 9876',
314
+ start: 'kempo-server --root public --port 9876'
315
+ };
316
+ if(wantsDrizzleStudio){
317
+ scripts['db:studio'] = 'drizzle-kit studio';
318
+ }
300
319
  writeFileSync(pkgPath, JSON.stringify({
301
320
  name: projectName,
302
321
  version: '1.0.0',
303
322
  type: 'module',
304
323
  private: true,
305
- scripts: {
306
- dev: 'kempo-server --root public --port 9876',
307
- start: 'kempo-server --root public --port 9876'
308
- }
324
+ scripts
309
325
  }, null, 2) + '\n');
310
326
  console.log('Created package.json');
311
327
  }
@@ -511,4 +527,5 @@ Next steps:
511
527
  Then open:
512
528
  http://localhost:9876 (your site)
513
529
  http://localhost:9876/admin (admin panel)
530
+ ${wantsDrizzleStudio ? '\nTo view your database:\n npm run db:studio\n' : ''}
514
531
  `);
@@ -1,6 +1,6 @@
1
- import TableControl from"/kempo-ui/components/tableControls/TableControl.js";import{html}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class AddGroupControl extends TableControl{render(){return html`
1
+ import o from"/kempo-ui/components/tableControls/TableControl.js";import{html as t}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class n extends o{render(){return t`
2
2
  <button class="no-btn icon-btn" title="Add to Group">
3
3
  <k-icon name="add"></k-icon>
4
4
  </button>
5
- `}}customElements.define("admin-add-group-control",AddGroupControl);
5
+ `}}customElements.define("admin-add-group-control",n);
6
6
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\AddGroupControl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\AddGroupControl.js","names":["TableControl","html","AddGroupControl","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class AddGroupControl extends TableControl {\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add to Group\">\r\n <k-icon name=\"add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-group-control', AddGroupControl);\r\n"],"mappings":"OAAOA,iBAAkB,4DAChBC,SAAY,iCACd,8CAEQ,MAAMC,wBAAwBF,aAC3C,MAAAG,GACE,OAAOF,IAAI;;;;KAKb,EAGFG,eAAeC,OAAO,0BAA2BH","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\AddGroupControl.js","names":["TableControl","html","AddGroupControl","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class AddGroupControl extends TableControl {\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Add to Group\">\r\n <k-icon name=\"add\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-add-group-control', AddGroupControl);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,iCACd,8CAEQ,MAAMC,UAAwBF,EAC3C,MAAAG,GACE,OAAOF,CAAI;;;;KAKb,EAGFG,eAAeC,OAAO,0BAA2BH","ignoreList":[]}
@@ -1,6 +1,6 @@
1
- import TableControl from"/kempo-ui/components/tableControls/TableControl.js";import{html}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class ClearExpiredSessionsControl extends TableControl{render(){return html`
1
+ import e from"/kempo-ui/components/tableControls/TableControl.js";import{html as o}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class n extends e{render(){return o`
2
2
  <button class="no-btn icon-btn" title="Clear Expired Sessions">
3
3
  <k-icon name="timer_off"></k-icon>
4
4
  </button>
5
- `}}customElements.define("admin-clear-expired-sessions",ClearExpiredSessionsControl);
5
+ `}}customElements.define("admin-clear-expired-sessions",n);
6
6
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\ClearExpiredSessionsControl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\ClearExpiredSessionsControl.js","names":["TableControl","html","ClearExpiredSessionsControl","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class ClearExpiredSessionsControl extends TableControl {\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Clear Expired Sessions\">\r\n <k-icon name=\"timer_off\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-clear-expired-sessions', ClearExpiredSessionsControl);\r\n"],"mappings":"OAAOA,iBAAkB,4DAChBC,SAAY,iCACd,8CAEQ,MAAMC,oCAAoCF,aACvD,MAAAG,GACE,OAAOF,IAAI;;;;KAKb,EAGFG,eAAeC,OAAO,+BAAgCH","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\ClearExpiredSessionsControl.js","names":["TableControl","html","ClearExpiredSessionsControl","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class ClearExpiredSessionsControl extends TableControl {\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" title=\"Clear Expired Sessions\">\r\n <k-icon name=\"timer_off\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-clear-expired-sessions', ClearExpiredSessionsControl);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,iCACd,8CAEQ,MAAMC,UAAoCF,EACvD,MAAAG,GACE,OAAOF,CAAI;;;;KAKb,EAGFG,eAAeC,OAAO,+BAAgCH","ignoreList":[]}
@@ -1,27 +1,27 @@
1
- import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html}from"/kempo-ui/lit-all.min.js";import{getFragment,updateFragment,deleteFragments,moveFragment,listDirectories}from"/kempo/sdk.js";import Dialog from"/kempo-ui/components/Dialog.js";import Toast from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Accordion.js";import"/kempo-ui/components/CodeEditor.js";export default class FragmentEditor extends ShadowComponent{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},fragment:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.fragment=null,this.file=""}async connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown);const e=new URLSearchParams(window.location.search).get("fragment");if(this.file=e?e+".fragment.html":"",!this.file)return this.loading=!1,void(this.error=!0);const[t,a]=await getFragment(this.file);this.loading=!1,t?this.error=!0:(this.fragment=a,document.title=`Edit: ${a.name} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}getFormState(){const e=this.shadowRoot;return{name:e.querySelector("#metaName")?.value??this.fragment.name,markup:e.querySelector("k-code-editor")?.getValue()??this.fragment.markup}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.fragment?.locked||this.handleSave())};handleDelete=()=>{Dialog.confirm("Delete this fragment? This action cannot be undone.",async e=>{if(!e)return;const[t]=await deleteFragments([this.file]);t?Toast.error(t.msg||"Failed to delete fragment"):(Toast.success("Fragment deleted"),setTimeout(()=>{window.location.href="/admin/content/fragments"},1e3))})};handleMove=async()=>{const[,e]=await listDirectories(),t=e?.directories||["."],a=this.file.replace(/\.fragment\.html$/,"").split("/"),n=a.pop(),i=a.join("/")||".",r=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",s="."===i?"/":"/"+i,o=Dialog.create(html`
1
+ import e from"/kempo-ui/components/ShadowComponent.js";import{html as t}from"/kempo-ui/lit-all.min.js";import{getFragment as a,updateFragment as n,deleteFragments as i,moveFragment as r,listDirectories as s}from"/kempo/sdk.js";import o from"/kempo-ui/components/Dialog.js";import l from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Accordion.js";import"/kempo-ui/components/CodeEditor.js";export default class d extends e{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},fragment:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.fragment=null,this.file=""}async connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown);const e=new URLSearchParams(window.location.search).get("fragment");if(this.file=e?e+".fragment.html":"",!this.file)return this.loading=!1,void(this.error=!0);const[t,n]=await a(this.file);this.loading=!1,t?this.error=!0:(this.fragment=n,document.title=`Edit: ${n.name} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}getFormState(){const e=this.shadowRoot;return{name:e.querySelector("#metaName")?.value??this.fragment.name,markup:e.querySelector("k-code-editor")?.getValue()??this.fragment.markup}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.fragment?.locked||this.handleSave())};handleDelete=()=>{o.confirm("Delete this fragment? This action cannot be undone.",async e=>{if(!e)return;const[t]=await i([this.file]);t?l.error(t.msg||"Failed to delete fragment"):(l.success("Fragment deleted"),setTimeout(()=>{window.location.href="/admin/content/fragments"},1e3))})};handleMove=async()=>{const[,e]=await s(),a=e?.directories||["."],i=this.file.replace(/\.fragment\.html$/,"").split("/"),d=i.pop(),m=i.join("/")||".",c=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",g="."===m?"/":"/"+m,p=o.create(t`
2
2
  <div class="p">
3
3
  <div class="mb">
4
4
  <label class="d-b mb-sm"><strong>Location</strong></label>
5
- <input type="text" id="dlg-move-dir" class="full" list="dlg-move-dir-list" .value="${s}" placeholder="/">
5
+ <input type="text" id="dlg-move-dir" class="full" list="dlg-move-dir-list" .value="${g}" placeholder="/">
6
6
  <datalist id="dlg-move-dir-list">
7
- ${t.map(e=>html`<option value="${"."===e?"/":"/"+e}">`)}
7
+ ${a.map(e=>t`<option value="${"."===e?"/":"/"+e}">`)}
8
8
  </datalist>
9
9
  </div>
10
10
  <div>
11
11
  <label class="d-b mb-sm"><strong>Fragment Name</strong></label>
12
- <input type="text" id="dlg-move-name" class="full" .value="${n}">
12
+ <input type="text" id="dlg-move-name" class="full" .value="${d}">
13
13
  <p class="mt-sm muted"><small id="dlg-move-preview"></small></p>
14
14
  </div>
15
15
  </div>
16
- `,{title:"Move Fragment",confirmText:"Save and Move Fragment",confirmAction:async()=>{const e=o.querySelector("#dlg-move-dir").value.trim()||"/",t=o.querySelector("#dlg-move-name").value.trim();if(!t)return void Toast.error("Fragment name is required");if(!/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(a=e)||a.includes("..")||a.includes("//"))return void Toast.error("Invalid directory path");var a;const n=r(e),i="."===n?`${t}.fragment.html`:`${n}/${t}.fragment.html`;this.saving=!0;const[s]=await updateFragment({file:this.file,markup:this.getFormState().markup});if(this.saving=!1,s)return void Toast.error(s.msg||"Failed to save fragment");const[l,m]=await moveFragment({file:this.file,newFile:i});if(l)return void Toast.error(l.msg||"Failed to move fragment");Toast.success("Fragment saved and moved");const d=m.file.replace(/\.fragment\.html$/,"");setTimeout(()=>{window.location.href=`/admin/content/fragments/edit?fragment=${encodeURIComponent(d)}`},1e3)},cancelText:"Cancel"}),l=()=>{const e=r(o.querySelector("#dlg-move-dir").value||"/"),t=o.querySelector("#dlg-move-name").value,a="."===e?"/":"/"+e+"/";o.querySelector("#dlg-move-preview").textContent=t?a+t:""};o.querySelector("#dlg-move-dir").addEventListener("input",l),o.querySelector("#dlg-move-name").addEventListener("input",l),l()};handleReset=()=>{Dialog.confirm("Reset this fragment? Any unsaved changes will be lost.",e=>{e&&(this.fragment={...this.fragment})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await updateFragment({file:this.file,markup:e.markup});if(this.saving=!1,t)return void Toast.error(t.msg||"Failed to save fragment");this.fragment={...this.fragment,markup:e.markup,updatedAt:a.updatedAt};const n=this.file.replace(/\.fragment\.html$/,"").split("/"),i=n.pop(),r=n.join("/"),s=e.name.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");if(s&&s!==i){const e=r?`${r}/${s}.fragment.html`:`${s}.fragment.html`,[t,a]=await moveFragment({file:this.file,newFile:e});if(t)return void Toast.error(t.msg||"Failed to rename fragment file");Toast.success("Fragment saved and renamed");const n=a.file.replace(/\.fragment\.html$/,"");return void setTimeout(()=>{window.location.href=`/admin/content/fragments/edit?fragment=${encodeURIComponent(n)}`},1e3)}document.title=`Edit: ${this.fragment.name} - Admin`,Toast.success("Fragment saved")};render(){if(this.loading)return html`<div>Loading fragment...</div>`;if(this.error)return html`
16
+ `,{title:"Move Fragment",confirmText:"Save and Move Fragment",confirmAction:async()=>{const e=p.querySelector("#dlg-move-dir").value.trim()||"/",t=p.querySelector("#dlg-move-name").value.trim();if(!t)return void l.error("Fragment name is required");if(!/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(a=e)||a.includes("..")||a.includes("//"))return void l.error("Invalid directory path");var a;const i=c(e),s="."===i?`${t}.fragment.html`:`${i}/${t}.fragment.html`;this.saving=!0;const[o]=await n({file:this.file,markup:this.getFormState().markup});if(this.saving=!1,o)return void l.error(o.msg||"Failed to save fragment");const[d,m]=await r({file:this.file,newFile:s});if(d)return void l.error(d.msg||"Failed to move fragment");l.success("Fragment saved and moved");const g=m.file.replace(/\.fragment\.html$/,"");setTimeout(()=>{window.location.href=`/admin/content/fragments/edit?fragment=${encodeURIComponent(g)}`},1e3)},cancelText:"Cancel"}),v=()=>{const e=c(p.querySelector("#dlg-move-dir").value||"/"),t=p.querySelector("#dlg-move-name").value,a="."===e?"/":"/"+e+"/";p.querySelector("#dlg-move-preview").textContent=t?a+t:""};p.querySelector("#dlg-move-dir").addEventListener("input",v),p.querySelector("#dlg-move-name").addEventListener("input",v),v()};handleReset=()=>{o.confirm("Reset this fragment? Any unsaved changes will be lost.",e=>{e&&(this.fragment={...this.fragment})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await n({file:this.file,markup:e.markup});if(this.saving=!1,t)return void l.error(t.msg||"Failed to save fragment");this.fragment={...this.fragment,markup:e.markup,updatedAt:a.updatedAt};const i=this.file.replace(/\.fragment\.html$/,"").split("/"),s=i.pop(),o=i.join("/"),d=e.name.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");if(d&&d!==s){const e=o?`${o}/${d}.fragment.html`:`${d}.fragment.html`,[t,a]=await r({file:this.file,newFile:e});if(t)return void l.error(t.msg||"Failed to rename fragment file");l.success("Fragment saved and renamed");const n=a.file.replace(/\.fragment\.html$/,"");return void setTimeout(()=>{window.location.href=`/admin/content/fragments/edit?fragment=${encodeURIComponent(n)}`},1e3)}document.title=`Edit: ${this.fragment.name} - Admin`,l.success("Fragment saved")};render(){if(this.loading)return t`<div>Loading fragment...</div>`;if(this.error)return t`
17
17
  <div>
18
18
  <p>Fragment not found.</p>
19
19
  <a href="/admin/content/fragments">Back to Fragments</a>
20
20
  </div>
21
- `;const{fragment:e}=this,t="custom"===e.owner,a=e.locked;return html`
22
- ${a?html`
21
+ `;const{fragment:e}=this,a="custom"===e.owner,n=e.locked;return t`
22
+ ${n?t`
23
23
  <div class="p r mb bc-warning tc-warning">
24
- <k-icon name="lock"></k-icon> This fragment is locked and cannot be edited. It is managed by ${t?"an extension":"the system"}.
24
+ <k-icon name="lock"></k-icon> This fragment is locked and cannot be edited. ${"custom"===e.owner?"Locked by developer":`Managed by: ${e.owner||"external system"}`}
25
25
  </div>
26
26
  `:""}
27
27
  <div class="d-f mb">
@@ -31,13 +31,13 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
31
31
  </a>
32
32
  </div>
33
33
  <div class="flex"></div>
34
- ${t&&!a?html`
34
+ ${a&&!n?t`
35
35
  <div class="btn-grp mrh mb">
36
36
  <button class="danger" @click="${this.handleDelete}"><k-icon name="delete"></k-icon> Delete</button>
37
37
  <button @click="${this.handleMove}"><k-icon name="drive_file_move"></k-icon> Move Fragment</button>
38
38
  </div>
39
39
  `:""}
40
- ${a?"":html`
40
+ ${n?"":t`
41
41
  <div class="btn-grp mrh mb">
42
42
  <button @click="${this.handleReset}"><k-icon name="restart_alt"></k-icon> Reset</button>
43
43
  <button id="saveBtn" class="primary" ?disabled="${this.saving}" @click="${this.handleSave}">
@@ -55,16 +55,16 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
55
55
  <div class="p">
56
56
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
57
57
  <label style="min-width: 120px;"><strong>Name</strong></label>
58
- <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${!t||a}">
58
+ <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${!a||n}">
59
59
  </div>
60
60
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
61
61
  <label style="min-width: 120px;"><strong>Directory</strong></label>
62
62
  <span class="muted">${(()=>{const e=this.file.replace(/\.fragment\.html$/,"").split("/");return e.pop(),e.length?e.join("/"):"/"})()}</span>
63
- ${t&&!a?html`
63
+ ${a&&!n?t`
64
64
  <button class="icon-btn no-btn ph" title="Move Fragment" @click="${this.handleMove}"><k-icon name="drive_file_move"></k-icon></button>
65
65
  `:""}
66
66
  </div>
67
- ${e.author?html`
67
+ ${e.author?t`
68
68
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
69
69
  <label style="min-width: 120px;"><strong>Author</strong></label>
70
70
  <span class="muted">${e.author}</span>
@@ -92,10 +92,10 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
92
92
  language="html"
93
93
  .value="${e.markup||""}"
94
94
  style="height: 500px;"
95
- ?disabled="${a}"
95
+ ?disabled="${n}"
96
96
  ></k-code-editor>
97
97
  </div>
98
98
  </k-accordion-panel>
99
99
  </k-accordion>
100
- `}}customElements.define("admin-fragment-editor",FragmentEditor);
100
+ `}}customElements.define("admin-fragment-editor",d);
101
101
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\FragmentEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\FragmentEditor.js","names":["ShadowComponent","html","getFragment","updateFragment","deleteFragments","moveFragment","listDirectories","Dialog","Toast","FragmentEditor","static","loading","state","error","saving","fragment","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","param","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","getFormState","root","shadowRoot","querySelector","value","markup","getValue","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","replace","split","currentName","pop","currentDir","join","dirToInternal","p","currentDirDisplay","$dialog","create","map","d","confirmText","confirmAction","dirInput","trim","newName","test","includes","newDir","newFile","saveError","moveError","moved","newParam","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","handleReset","saved","updatedAt","currentSlug","newSlug","toLowerCase","render","isCustom","owner","isLocked","length","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getFragment, updateFragment, deleteFragments, moveFragment, listDirectories } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class FragmentEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n fragment: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.fragment = null;\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n const param = new URLSearchParams(window.location.search).get('fragment');\n this.file = param ? param + '.fragment.html' : '';\n\n if(!this.file){\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, fragment] = await getFragment(this.file);\n this.loading = false;\n\n if(err){\n this.error = true;\n return;\n }\n\n this.fragment = fragment;\n document.title = `Edit: ${fragment.name} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getFormState() {\n const root = this.shadowRoot;\n return {\n name: root.querySelector('#metaName')?.value ?? this.fragment.name,\n markup: root.querySelector('k-code-editor')?.getValue() ?? this.fragment.markup\n };\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if((e.ctrlKey || e.metaKey) && e.key === 's'){\n e.preventDefault();\n if(!this.saving && !this.fragment?.locked) this.handleSave();\n }\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this fragment? This action cannot be undone.', async confirmed => {\n if(!confirmed) return;\n const [error] = await deleteFragments([this.file]);\n if(error){\n Toast.error(error.msg || 'Failed to delete fragment');\n return;\n }\n Toast.success('Fragment deleted');\n setTimeout(() => { window.location.href = '/admin/content/fragments'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-move-dir\" class=\"full\" list=\"dlg-move-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-move-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)}\n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Fragment Name</strong></label>\n <input type=\"text\" id=\"dlg-move-name\" class=\"full\" .value=\"${currentName}\">\n <p class=\"mt-sm muted\"><small id=\"dlg-move-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Move Fragment',\n confirmText: 'Save and Move Fragment',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-move-name').value.trim();\n if(!newName){\n Toast.error('Fragment name is required');\n return;\n }\n if(!isValidDir(dirInput)){\n Toast.error('Invalid directory path');\n return;\n }\n const newDir = dirToInternal(dirInput);\n const newFile = newDir === '.'\n ? `${newName}.fragment.html`\n : `${newDir}/${newName}.fragment.html`;\n\n this.saving = true;\n const [saveError] = await updateFragment({ file: this.file, markup: this.getFormState().markup });\n this.saving = false;\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save fragment');\n return;\n }\n\n const [moveError, moved] = await moveFragment({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to move fragment');\n return;\n }\n\n Toast.success('Fragment saved and moved');\n const newParam = moved.file.replace(/\\.fragment\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/fragments/edit?fragment=${encodeURIComponent(newParam)}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = $dialog.querySelector('#dlg-move-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-move-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-move-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this fragment? Any unsaved changes will be lost.', confirmed => {\n if(!confirmed) return;\n this.fragment = { ...this.fragment };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updateFragment({ file: this.file, markup: state.markup });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save fragment');\n return;\n }\n\n this.fragment = { ...this.fragment, markup: state.markup, updatedAt: saved.updatedAt };\n\n const slugify = n => n.toLowerCase().trim().replace(/[^\\w\\s-]/g, '').replace(/[\\s_]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');\n const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/');\n const currentSlug = parts.pop();\n const dir = parts.join('/');\n const newSlug = slugify(state.name);\n\n if(newSlug && newSlug !== currentSlug){\n const newFile = dir ? `${dir}/${newSlug}.fragment.html` : `${newSlug}.fragment.html`;\n const [moveError, moved] = await moveFragment({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to rename fragment file');\n return;\n }\n Toast.success('Fragment saved and renamed');\n const newParam = moved.file.replace(/\\.fragment\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/fragments/edit?fragment=${encodeURIComponent(newParam)}`;\n }, 1000);\n return;\n }\n\n document.title = `Edit: ${this.fragment.name} - Admin`;\n Toast.success('Fragment saved');\n };\n\n /*\n Render\n */\n\n render() {\n if(this.loading) return html`<div>Loading fragment...</div>`;\n\n if(this.error) return html`\n <div>\n <p>Fragment not found.</p>\n <a href=\"/admin/content/fragments\">Back to Fragments</a>\n </div>\n `;\n\n const { fragment } = this;\n const isCustom = fragment.owner === 'custom';\n const isLocked = fragment.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This fragment is locked and cannot be edited. It is managed by ${isCustom ? 'an extension' : 'the system'}.\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/fragments\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Fragments\n </a>\n </div>\n <div class=\"flex\"></div>\n ${isCustom && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Fragment</button>\n </div>\n ` : ''}\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n\n <h1 class=\"mb\">Fragment: ${fragment.name}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${fragment.name || ''}\" ?disabled=\"${!isCustom || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Directory</strong></label>\n <span class=\"muted\">${(() => { const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/'); parts.pop(); return parts.length ? parts.join('/') : '/'; })()}</span>\n ${isCustom && !isLocked ? html`\n <button class=\"icon-btn no-btn ph\" title=\"Move Fragment\" @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon></button>\n ` : ''}\n </div>\n ${fragment.author ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${fragment.author}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${fragment.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${fragment.createdAt ? new Date(fragment.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${fragment.updatedAt ? new Date(fragment.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n <k-accordion-header for-panel=\"fragment\" active>Fragment</k-accordion-header>\n <k-accordion-panel name=\"fragment\" active>\n <div class=\"p\">\n <k-code-editor\n class=\"r b\"\n language=\"html\"\n .value=\"${fragment.markup || ''}\"\n style=\"height: 500px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-fragment-editor', FragmentEditor);\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\FragmentEditor.js","names":["ShadowComponent","html","getFragment","updateFragment","deleteFragments","moveFragment","listDirectories","Dialog","Toast","FragmentEditor","static","loading","state","error","saving","fragment","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","param","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","getFormState","root","shadowRoot","querySelector","value","markup","getValue","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","replace","split","currentName","pop","currentDir","join","dirToInternal","p","currentDirDisplay","$dialog","create","map","d","confirmText","confirmAction","dirInput","trim","newName","test","includes","newDir","newFile","saveError","moveError","moved","newParam","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","handleReset","saved","updatedAt","currentSlug","newSlug","toLowerCase","render","isCustom","owner","isLocked","length","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getFragment, updateFragment, deleteFragments, moveFragment, listDirectories } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class FragmentEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n fragment: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.fragment = null;\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n const param = new URLSearchParams(window.location.search).get('fragment');\n this.file = param ? param + '.fragment.html' : '';\n\n if(!this.file){\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, fragment] = await getFragment(this.file);\n this.loading = false;\n\n if(err){\n this.error = true;\n return;\n }\n\n this.fragment = fragment;\n document.title = `Edit: ${fragment.name} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getFormState() {\n const root = this.shadowRoot;\n return {\n name: root.querySelector('#metaName')?.value ?? this.fragment.name,\n markup: root.querySelector('k-code-editor')?.getValue() ?? this.fragment.markup\n };\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if((e.ctrlKey || e.metaKey) && e.key === 's'){\n e.preventDefault();\n if(!this.saving && !this.fragment?.locked) this.handleSave();\n }\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this fragment? This action cannot be undone.', async confirmed => {\n if(!confirmed) return;\n const [error] = await deleteFragments([this.file]);\n if(error){\n Toast.error(error.msg || 'Failed to delete fragment');\n return;\n }\n Toast.success('Fragment deleted');\n setTimeout(() => { window.location.href = '/admin/content/fragments'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/');\n const currentName = parts.pop();\n const currentDir = parts.join('/') || '.';\n\n const isValidDir = p => /^\\/[a-zA-Z0-9_\\-\\[\\]\\/]*$/.test(p) && !p.includes('..') && !p.includes('//');\n const dirToInternal = p => { const t = (p || '/').replace(/^\\//, '').replace(/\\/$/, ''); return t || '.'; };\n const currentDirDisplay = currentDir === '.' ? '/' : '/' + currentDir;\n\n const $dialog = Dialog.create(html`\n <div class=\"p\">\n <div class=\"mb\">\n <label class=\"d-b mb-sm\"><strong>Location</strong></label>\n <input type=\"text\" id=\"dlg-move-dir\" class=\"full\" list=\"dlg-move-dir-list\" .value=\"${currentDirDisplay}\" placeholder=\"/\">\n <datalist id=\"dlg-move-dir-list\">\n ${directories.map(d => html`<option value=\"${d === '.' ? '/' : '/' + d}\">`)}\n </datalist>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Fragment Name</strong></label>\n <input type=\"text\" id=\"dlg-move-name\" class=\"full\" .value=\"${currentName}\">\n <p class=\"mt-sm muted\"><small id=\"dlg-move-preview\"></small></p>\n </div>\n </div>\n `, {\n title: 'Move Fragment',\n confirmText: 'Save and Move Fragment',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = $dialog.querySelector('#dlg-move-name').value.trim();\n if(!newName){\n Toast.error('Fragment name is required');\n return;\n }\n if(!isValidDir(dirInput)){\n Toast.error('Invalid directory path');\n return;\n }\n const newDir = dirToInternal(dirInput);\n const newFile = newDir === '.'\n ? `${newName}.fragment.html`\n : `${newDir}/${newName}.fragment.html`;\n\n this.saving = true;\n const [saveError] = await updateFragment({ file: this.file, markup: this.getFormState().markup });\n this.saving = false;\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save fragment');\n return;\n }\n\n const [moveError, moved] = await moveFragment({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to move fragment');\n return;\n }\n\n Toast.success('Fragment saved and moved');\n const newParam = moved.file.replace(/\\.fragment\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/fragments/edit?fragment=${encodeURIComponent(newParam)}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = $dialog.querySelector('#dlg-move-name').value;\n const prefix = dir === '.' ? '/' : '/' + dir + '/';\n $dialog.querySelector('#dlg-move-preview').textContent = name ? prefix + name : '';\n };\n $dialog.querySelector('#dlg-move-dir').addEventListener('input', updatePreview);\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this fragment? Any unsaved changes will be lost.', confirmed => {\n if(!confirmed) return;\n this.fragment = { ...this.fragment };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updateFragment({ file: this.file, markup: state.markup });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save fragment');\n return;\n }\n\n this.fragment = { ...this.fragment, markup: state.markup, updatedAt: saved.updatedAt };\n\n const slugify = n => n.toLowerCase().trim().replace(/[^\\w\\s-]/g, '').replace(/[\\s_]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');\n const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/');\n const currentSlug = parts.pop();\n const dir = parts.join('/');\n const newSlug = slugify(state.name);\n\n if(newSlug && newSlug !== currentSlug){\n const newFile = dir ? `${dir}/${newSlug}.fragment.html` : `${newSlug}.fragment.html`;\n const [moveError, moved] = await moveFragment({ file: this.file, newFile });\n if(moveError){\n Toast.error(moveError.msg || 'Failed to rename fragment file');\n return;\n }\n Toast.success('Fragment saved and renamed');\n const newParam = moved.file.replace(/\\.fragment\\.html$/, '');\n setTimeout(() => {\n window.location.href = `/admin/content/fragments/edit?fragment=${encodeURIComponent(newParam)}`;\n }, 1000);\n return;\n }\n\n document.title = `Edit: ${this.fragment.name} - Admin`;\n Toast.success('Fragment saved');\n };\n\n /*\n Render\n */\n\n render() {\n if(this.loading) return html`<div>Loading fragment...</div>`;\n\n if(this.error) return html`\n <div>\n <p>Fragment not found.</p>\n <a href=\"/admin/content/fragments\">Back to Fragments</a>\n </div>\n `;\n\n const { fragment } = this;\n const isCustom = fragment.owner === 'custom';\n const isLocked = fragment.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This fragment is locked and cannot be edited. ${fragment.owner === 'custom' ? 'Locked by developer' : `Managed by: ${fragment.owner || 'external system'}`}\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/fragments\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Fragments\n </a>\n </div>\n <div class=\"flex\"></div>\n ${isCustom && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Fragment</button>\n </div>\n ` : ''}\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n\n <h1 class=\"mb\">Fragment: ${fragment.name}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${fragment.name || ''}\" ?disabled=\"${!isCustom || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Directory</strong></label>\n <span class=\"muted\">${(() => { const parts = this.file.replace(/\\.fragment\\.html$/, '').split('/'); parts.pop(); return parts.length ? parts.join('/') : '/'; })()}</span>\n ${isCustom && !isLocked ? html`\n <button class=\"icon-btn no-btn ph\" title=\"Move Fragment\" @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon></button>\n ` : ''}\n </div>\n ${fragment.author ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${fragment.author}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${fragment.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${fragment.createdAt ? new Date(fragment.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${fragment.updatedAt ? new Date(fragment.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n <k-accordion-header for-panel=\"fragment\" active>Fragment</k-accordion-header>\n <k-accordion-panel name=\"fragment\" active>\n <div class=\"p\">\n <k-code-editor\n class=\"r b\"\n language=\"html\"\n .value=\"${fragment.markup || ''}\"\n style=\"height: 500px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-fragment-editor', FragmentEditor);\n"],"mappings":"OAAOA,MAAqB,yDACnBC,MAAY,iDACZC,oBAAaC,qBAAgBC,kBAAiBC,qBAAcC,MAAuB,uBACrFC,MAAY,wCACZC,MAAW,sCACX,qCACA,0CACA,oDAEQ,MAAMC,UAAuBT,EAC1CU,kBAAoB,CAClBC,QAAS,CAAEC,OAAO,GAClBC,MAAO,CAAED,OAAO,GAChBE,OAAQ,CAAEF,OAAO,GACjBG,SAAU,CAAEH,OAAO,IAGrB,WAAAI,GACEC,QACAC,KAAKP,SAAU,EACfO,KAAKL,OAAQ,EACbK,KAAKJ,QAAS,EACdI,KAAKH,SAAW,KAChBG,KAAKC,KAAO,EACd,CAEA,uBAAMC,GACJH,MAAMG,oBACNC,SAASC,iBAAiB,UAAWJ,KAAKK,eAC1C,MAAMC,EAAQ,IAAIC,gBAAgBC,OAAOC,SAASC,QAAQC,IAAI,YAG9D,GAFAX,KAAKC,KAAOK,EAAQA,EAAQ,iBAAmB,IAE3CN,KAAKC,KAGP,OAFAD,KAAKP,SAAU,OACfO,KAAKL,OAAQ,GAIf,MAAOiB,EAAKf,SAAkBb,EAAYgB,KAAKC,MAC/CD,KAAKP,SAAU,EAEZmB,EACDZ,KAAKL,OAAQ,GAIfK,KAAKH,SAAWA,EAChBM,SAASU,MAAQ,SAAShB,EAASiB,eACrC,CAEA,oBAAAC,GACEhB,MAAMgB,uBACNZ,SAASa,oBAAoB,UAAWhB,KAAKK,cAC/C,CAMA,YAAAY,GACE,MAAMC,EAAOlB,KAAKmB,WAClB,MAAO,CACLL,KAAMI,EAAKE,cAAc,cAAcC,OAASrB,KAAKH,SAASiB,KAC9DQ,OAAQJ,EAAKE,cAAc,kBAAkBG,YAAcvB,KAAKH,SAASyB,OAE7E,CAMAjB,cAAgBmB,KACVA,EAAEC,SAAWD,EAAEE,UAAsB,MAAVF,EAAEG,MAC/BH,EAAEI,iBACE5B,KAAKJ,QAAWI,KAAKH,UAAUgC,QAAQ7B,KAAK8B,eAIpDC,aAAe,KACb1C,EAAO2C,QAAQ,sDAAuDC,UACpE,IAAIC,EAAW,OACf,MAAOvC,SAAeT,EAAgB,CAACc,KAAKC,OACzCN,EACDL,EAAMK,MAAMA,EAAMwC,KAAO,8BAG3B7C,EAAM8C,QAAQ,oBACdC,WAAW,KAAQ7B,OAAOC,SAAS6B,KAAO,4BAA+B,SAI7EC,WAAaN,UACX,MAAO,CAAEO,SAAiBpD,IACpBqD,EAAcD,GAASC,aAAe,CAAC,KAEvCC,EAAQ1C,KAAKC,KAAK0C,QAAQ,oBAAqB,IAAIC,MAAM,KACzDC,EAAcH,EAAMI,MACpBC,EAAaL,EAAMM,KAAK,MAAQ,IAGhCC,EAAgBC,IAAkBA,GAAK,KAAKP,QAAQ,MAAO,IAAIA,QAAQ,MAAO,KAAiB,IAC/FQ,EAAmC,MAAfJ,EAAqB,IAAM,IAAMA,EAErDK,EAAU/D,EAAOgE,OAAOtE,CAAI;;;;+FAIyDoE;;cAEjFV,EAAYa,IAAIC,GAAKxE,CAAI,kBAAwB,MAANwE,EAAY,IAAM,IAAMA;;;;;uEAKVV;;;;MAIhE,CACDhC,MAAO,gBACP2C,YAAa,yBACbC,cAAexB,UACb,MAAMyB,EAAWN,EAAQhC,cAAc,iBAAiBC,MAAMsC,QAAU,IAClEC,EAAUR,EAAQhC,cAAc,kBAAkBC,MAAMsC,OAC9D,IAAIC,EAEF,YADAtE,EAAMK,MAAM,6BAGd,IA7BoB,4BAA4BkE,KAAjCX,EA6BAQ,IA7B6CR,EAAEY,SAAS,OAAUZ,EAAEY,SAAS,MA+B1F,YADAxE,EAAMK,MAAM,0BA9BCuD,MAiCf,MAAMa,EAASd,EAAcS,GACvBM,EAAqB,MAAXD,EACZ,GAAGH,kBACH,GAAGG,KAAUH,kBAEjB5D,KAAKJ,QAAS,EACd,MAAOqE,SAAmBhF,EAAe,CAAEgB,KAAMD,KAAKC,KAAMqB,OAAQtB,KAAKiB,eAAeK,SAExF,GADAtB,KAAKJ,QAAS,EACXqE,EAED,YADA3E,EAAMK,MAAMsE,EAAU9B,KAAO,2BAI/B,MAAO+B,EAAWC,SAAehF,EAAa,CAAEc,KAAMD,KAAKC,KAAM+D,YACjE,GAAGE,EAED,YADA5E,EAAMK,MAAMuE,EAAU/B,KAAO,2BAI/B7C,EAAM8C,QAAQ,4BACd,MAAMgC,EAAWD,EAAMlE,KAAK0C,QAAQ,oBAAqB,IACzDN,WAAW,KACT7B,OAAOC,SAAS6B,KAAO,0CAA0C+B,mBAAmBD,MACnF,MAELE,WAAY,WAGRC,EAAgB,KACpB,MAAMC,EAAMvB,EAAcG,EAAQhC,cAAc,iBAAiBC,OAAS,KACpEP,EAAOsC,EAAQhC,cAAc,kBAAkBC,MAC/CoD,EAAiB,MAARD,EAAc,IAAM,IAAMA,EAAM,IAC/CpB,EAAQhC,cAAc,qBAAqBsD,YAAc5D,EAAO2D,EAAS3D,EAAO,IAElFsC,EAAQhC,cAAc,iBAAiBhB,iBAAiB,QAASmE,GACjEnB,EAAQhC,cAAc,kBAAkBhB,iBAAiB,QAASmE,GAClEA,KAGFI,YAAc,KACZtF,EAAO2C,QAAQ,yDAA0DE,IACnEA,IACJlC,KAAKH,SAAW,IAAKG,KAAKH,cAI9BiC,WAAaG,UACXjC,KAAKJ,QAAS,EACd,MAAMF,EAAQM,KAAKiB,gBACZgD,EAAWW,SAAe3F,EAAe,CAAEgB,KAAMD,KAAKC,KAAMqB,OAAQ5B,EAAM4B,SAGjF,GAFAtB,KAAKJ,QAAS,EAEXqE,EAED,YADA3E,EAAMK,MAAMsE,EAAU9B,KAAO,2BAI/BnC,KAAKH,SAAW,IAAKG,KAAKH,SAAUyB,OAAQ5B,EAAM4B,OAAQuD,UAAWD,EAAMC,WAE3E,MACMnC,EAAQ1C,KAAKC,KAAK0C,QAAQ,oBAAqB,IAAIC,MAAM,KACzDkC,EAAcpC,EAAMI,MACpB0B,EAAM9B,EAAMM,KAAK,KACjB+B,EAAkBrF,EAAMoB,KAJPkE,cAAcrB,OAAOhB,QAAQ,YAAa,IAAIA,QAAQ,UAAW,KAAKA,QAAQ,MAAO,KAAKA,QAAQ,SAAU,IAMnI,GAAGoC,GAAWA,IAAYD,EAAY,CACpC,MAAMd,EAAUQ,EAAM,GAAGA,KAAOO,kBAA0B,GAAGA,mBACtDb,EAAWC,SAAehF,EAAa,CAAEc,KAAMD,KAAKC,KAAM+D,YACjE,GAAGE,EAED,YADA5E,EAAMK,MAAMuE,EAAU/B,KAAO,kCAG/B7C,EAAM8C,QAAQ,8BACd,MAAMgC,EAAWD,EAAMlE,KAAK0C,QAAQ,oBAAqB,IAIzD,YAHAN,WAAW,KACT7B,OAAOC,SAAS6B,KAAO,0CAA0C+B,mBAAmBD,MACnF,IAEL,CAEAjE,SAASU,MAAQ,SAASb,KAAKH,SAASiB,eACxCxB,EAAM8C,QAAQ,mBAOhB,MAAA6C,GACE,GAAGjF,KAAKP,QAAS,OAAOV,CAAI,iCAE5B,GAAGiB,KAAKL,MAAO,OAAOZ,CAAI;;;;;MAO1B,MAAMc,SAAEA,GAAaG,KACfkF,EAA8B,WAAnBrF,EAASsF,MACpBC,EAAWvF,EAASgC,OAE1B,OAAO9C,CAAI;QACPqG,EAAWrG,CAAI;;wFAEoF,WAAnBc,EAASsF,MAAqB,sBAAwB,eAAetF,EAASsF,OAAS;;QAErK;;;;;;;;UAQAD,IAAaE,EAAWrG,CAAI;;6CAEOiB,KAAK+B;8BACpB/B,KAAKuC;;UAEvB;UACD6C,EAOC,GAPUrG,CAAI;;8BAEIiB,KAAK2E;8DAC2B3E,KAAKJ,mBAAmBI,KAAK8B;;;;;;;iCAO1DjC,EAASiB;;;;;;;;sEAQ4BjB,EAASiB,MAAQ,mBAAmBoE,GAAYE;;;;oCAIlF,MAAS,MAAM1C,EAAQ1C,KAAKC,KAAK0C,QAAQ,oBAAqB,IAAIC,MAAM,KAAmB,OAAbF,EAAMI,MAAcJ,EAAM2C,OAAS3C,EAAMM,KAAK,KAAO,GAAM,EAAzI;gBACpBkC,IAAaE,EAAWrG,CAAI;mFACuCiB,KAAKuC;gBACtE;;cAEJ1C,EAASyF,OAASvG,CAAI;;;sCAGEc,EAASyF;;cAE/B;;;oCAGoBzF,EAASsF,OAAS;;;;oCAIlBtF,EAAS0F,UAAY,IAAIC,KAAK3F,EAAS0F,WAAWE,iBAAmB;;;;oCAIrE5F,EAASgF,UAAY,IAAIW,KAAK3F,EAASgF,WAAWY,iBAAmB;;;;;;;;;;wBAUjF5F,EAASyB,QAAU;;2BAEhB8D;;;;;KAMzB,EAGFM,eAAeC,OAAO,wBAAyBpG","ignoreList":[]}
@@ -1,12 +1,12 @@
1
- import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html}from"/kempo-ui/lit-all.min.js";import{getGlobalContent,updateGlobalContent,deleteGlobalContent}from"/kempo/sdk.js";import Dialog from"/kempo-ui/components/Dialog.js";import Toast from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Accordion.js";import"/kempo-ui/components/CodeEditor.js";export default class GlobalContentEditor extends ShadowComponent{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},entry:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.entry=null,this.entryId=""}async connectedCallback(){if(super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown),this.entryId=new URLSearchParams(window.location.search).get("id")||"",!this.entryId)return this.loading=!1,void(this.error=!0);const[e,t]=await getGlobalContent(this.entryId);this.loading=!1,e?this.error=!0:(this.entry=t,document.title=`Edit: ${t.name||this.entryId} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.entry?.locked||this.handleSave())};handleSave=async()=>{this.saving=!0;const e=this.shadowRoot,t=e.querySelector("#metaName").value,n=e.querySelector("#metaLocation").value,a=e.querySelector("#metaPriority").value,o=e.querySelector("k-code-editor"),i=o?o.getValue():this.entry.markup,[s,l]=await updateGlobalContent({id:this.entryId,name:t,location:n,priority:a,markup:i});this.saving=!1,s?Toast.error(s.msg||"Failed to save global content"):(this.entry={...this.entry,name:t,location:n,priority:a,markup:i,updatedAt:l.updatedAt},document.title=`Edit: ${t||this.entryId} - Admin`,Toast.success("Global content saved"))};handleReset=()=>{Dialog.confirm("Reset this entry? Any unsaved changes will be lost.",e=>{e&&(this.entry={...this.entry})})};handleDelete=()=>{Dialog.confirm("Delete this global content entry? This action cannot be undone.",async e=>{if(!e)return;const[t]=await deleteGlobalContent([this.entryId]);t?Toast.error(t.msg||"Failed to delete global content"):(Toast.success("Global content deleted"),setTimeout(()=>{window.location.href="/admin/content/globals"},1e3))})};render(){if(this.loading)return html`<div>Loading global content...</div>`;if(this.error)return html`
1
+ import e from"/kempo-ui/components/ShadowComponent.js";import{html as t}from"/kempo-ui/lit-all.min.js";import{getGlobalContent as n,updateGlobalContent as a,deleteGlobalContent as i}from"/kempo/sdk.js";import s from"/kempo-ui/components/Dialog.js";import o from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Accordion.js";import"/kempo-ui/components/CodeEditor.js";export default class r extends e{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},entry:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.entry=null,this.entryId=""}async connectedCallback(){if(super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown),this.entryId=new URLSearchParams(window.location.search).get("id")||"",!this.entryId)return this.loading=!1,void(this.error=!0);const[e,t]=await n(this.entryId);this.loading=!1,e?this.error=!0:(this.entry=t,document.title=`Edit: ${t.name||this.entryId} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.entry?.locked||this.handleSave())};handleSave=async()=>{this.saving=!0;const e=this.shadowRoot,t=e.querySelector("#metaName").value,n=e.querySelector("#metaLocation").value,i=e.querySelector("#metaPriority").value,s=e.querySelector("k-code-editor"),r=s?s.getValue():this.entry.markup,[l,d]=await a({id:this.entryId,name:t,location:n,priority:i,markup:r});this.saving=!1,l?o.error(l.msg||"Failed to save global content"):(this.entry={...this.entry,name:t,location:n,priority:i,markup:r,updatedAt:d.updatedAt},document.title=`Edit: ${t||this.entryId} - Admin`,o.success("Global content saved"))};handleReset=()=>{s.confirm("Reset this entry? Any unsaved changes will be lost.",e=>{e&&(this.entry={...this.entry})})};handleDelete=()=>{s.confirm("Delete this global content entry? This action cannot be undone.",async e=>{if(!e)return;const[t]=await i([this.entryId]);t?o.error(t.msg||"Failed to delete global content"):(o.success("Global content deleted"),setTimeout(()=>{window.location.href="/admin/content/globals"},1e3))})};render(){if(this.loading)return t`<div>Loading global content...</div>`;if(this.error)return t`
2
2
  <div>
3
3
  <p>Global content entry not found.</p>
4
4
  <a href="/admin/content/globals">Back to Global Content</a>
5
5
  </div>
6
- `;const{entry:e}=this,t="system"===e.owner,n=e.locked;return html`
7
- ${n?html`
6
+ `;const{entry:e}=this,n="system"===e.owner,a=e.locked;return t`
7
+ ${a?t`
8
8
  <div class="p r mb bc-warning tc-warning">
9
- <k-icon name="lock"></k-icon> This entry is locked and cannot be edited. It is managed by ${t?"the system":"an extension"}.
9
+ <k-icon name="lock"></k-icon> This entry is locked and cannot be edited. ${"custom"===e.owner?"Locked by developer":`Managed by: ${e.owner||"external system"}`}
10
10
  </div>
11
11
  `:""}
12
12
  <div class="d-f mb">
@@ -16,12 +16,12 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
16
16
  </a>
17
17
  </div>
18
18
  <div class="flex"></div>
19
- ${t||n?"":html`
19
+ ${n||a?"":t`
20
20
  <div class="btn-grp mrh mb">
21
21
  <button class="danger" @click="${this.handleDelete}"><k-icon name="delete"></k-icon> Delete</button>
22
22
  </div>
23
23
  `}
24
- ${n?"":html`
24
+ ${a?"":t`
25
25
  <div class="btn-grp mrh mb">
26
26
  <button @click="${this.handleReset}"><k-icon name="restart_alt"></k-icon> Reset</button>
27
27
  <button id="saveBtn" class="primary" ?disabled="${this.saving}" @click="${this.handleSave}">
@@ -38,17 +38,17 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
38
38
  <div class="p">
39
39
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
40
40
  <label style="min-width: 120px;"><strong>Name</strong></label>
41
- <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${t||n}">
41
+ <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${n||a}">
42
42
  </div>
43
43
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
44
44
  <label style="min-width: 120px;"><strong>Location</strong></label>
45
- <input type="text" id="metaLocation" class="flex" .value="${e.location||""}" ?disabled="${t||n}">
45
+ <input type="text" id="metaLocation" class="flex" .value="${e.location||""}" ?disabled="${n||a}">
46
46
  </div>
47
47
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
48
48
  <label style="min-width: 120px;"><strong>Priority</strong></label>
49
- <input type="number" id="metaPriority" class="flex" .value="${e.priority??0}" ?disabled="${t||n}">
49
+ <input type="number" id="metaPriority" class="flex" .value="${e.priority??0}" ?disabled="${n||a}">
50
50
  </div>
51
- ${t?"":html`
51
+ ${n?"":t`
52
52
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
53
53
  <label style="min-width: 120px;"><strong>Author</strong></label>
54
54
  <span class="muted">${e.author||""}</span>
@@ -76,10 +76,10 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
76
76
  language="html"
77
77
  .value="${e.markup||""}"
78
78
  style="height: 500px;"
79
- ?disabled="${n}"
79
+ ?disabled="${a}"
80
80
  ></k-code-editor>
81
81
  </div>
82
82
  </k-accordion-panel>
83
83
  </k-accordion>
84
- `}}customElements.define("admin-global-content-editor",GlobalContentEditor);
84
+ `}}customElements.define("admin-global-content-editor",r);
85
85
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\GlobalContentEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\GlobalContentEditor.js","names":["ShadowComponent","html","getGlobalContent","updateGlobalContent","deleteGlobalContent","Dialog","Toast","GlobalContentEditor","static","loading","state","error","saving","entry","constructor","super","this","entryId","connectedCallback","document","addEventListener","handleKeyDown","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","async","root","shadowRoot","querySelector","value","priority","editor","markup","getValue","saveError","saved","id","msg","updatedAt","success","handleReset","confirm","confirmed","handleDelete","setTimeout","href","render","isSystem","owner","isLocked","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getGlobalContent, updateGlobalContent, deleteGlobalContent } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class GlobalContentEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n entry: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.entry = null;\n this.entryId = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n this.entryId = new URLSearchParams(window.location.search).get('id') || '';\n\n if(!this.entryId){\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, entry] = await getGlobalContent(this.entryId);\n this.loading = false;\n\n if(err){\n this.error = true;\n return;\n }\n\n this.entry = entry;\n document.title = `Edit: ${entry.name || this.entryId} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if((e.ctrlKey || e.metaKey) && e.key === 's'){\n e.preventDefault();\n if(!this.saving && !this.entry?.locked) this.handleSave();\n }\n };\n\n handleSave = async () => {\n this.saving = true;\n const root = this.shadowRoot;\n const name = root.querySelector('#metaName').value;\n const location = root.querySelector('#metaLocation').value;\n const priority = root.querySelector('#metaPriority').value;\n const editor = root.querySelector('k-code-editor');\n const markup = editor ? editor.getValue() : this.entry.markup;\n\n const [saveError, saved] = await updateGlobalContent({\n id: this.entryId, name, location, priority, markup\n });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save global content');\n return;\n }\n\n this.entry = { ...this.entry, name, location, priority, markup, updatedAt: saved.updatedAt };\n document.title = `Edit: ${name || this.entryId} - Admin`;\n Toast.success('Global content saved');\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this entry? Any unsaved changes will be lost.', confirmed => {\n if(!confirmed) return;\n this.entry = { ...this.entry };\n });\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this global content entry? This action cannot be undone.', async confirmed => {\n if(!confirmed) return;\n const [error] = await deleteGlobalContent([this.entryId]);\n if(error){\n Toast.error(error.msg || 'Failed to delete global content');\n return;\n }\n Toast.success('Global content deleted');\n setTimeout(() => { window.location.href = '/admin/content/globals'; }, 1000);\n });\n };\n\n /*\n Render\n */\n\n render() {\n if(this.loading) return html`<div>Loading global content...</div>`;\n\n if(this.error) return html`\n <div>\n <p>Global content entry not found.</p>\n <a href=\"/admin/content/globals\">Back to Global Content</a>\n </div>\n `;\n\n const { entry } = this;\n const isSystem = entry.owner === 'system';\n const isLocked = entry.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This entry is locked and cannot be edited. It is managed by ${isSystem ? 'the system' : 'an extension'}.\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/globals\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Global Content\n </a>\n </div>\n <div class=\"flex\"></div>\n ${!isSystem && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n </div>\n ` : ''}\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n <h1 class=\"mb\">Global Content: ${entry.name || this.entryId}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${entry.name || ''}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Location</strong></label>\n <input type=\"text\" id=\"metaLocation\" class=\"flex\" .value=\"${entry.location || ''}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Priority</strong></label>\n <input type=\"number\" id=\"metaPriority\" class=\"flex\" .value=\"${entry.priority ?? 0}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n ${!isSystem ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${entry.author || ''}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${entry.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${entry.updatedAt ? new Date(entry.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n <k-accordion-header for-panel=\"content\" active>Content</k-accordion-header>\n <k-accordion-panel name=\"content\" active>\n <div class=\"p\">\n <k-code-editor\n class=\"r b\"\n language=\"html\"\n .value=\"${entry.markup || ''}\"\n style=\"height: 500px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-global-content-editor', GlobalContentEditor);\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\GlobalContentEditor.js","names":["ShadowComponent","html","getGlobalContent","updateGlobalContent","deleteGlobalContent","Dialog","Toast","GlobalContentEditor","static","loading","state","error","saving","entry","constructor","super","this","entryId","connectedCallback","document","addEventListener","handleKeyDown","URLSearchParams","window","location","search","get","err","title","name","disconnectedCallback","removeEventListener","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","async","root","shadowRoot","querySelector","value","priority","editor","markup","getValue","saveError","saved","id","msg","updatedAt","success","handleReset","confirm","confirmed","handleDelete","setTimeout","href","render","isSystem","owner","isLocked","author","createdAt","Date","toLocaleString","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html } from '/kempo-ui/lit-all.min.js';\nimport { getGlobalContent, updateGlobalContent, deleteGlobalContent } from '/kempo/sdk.js';\nimport Dialog from '/kempo-ui/components/Dialog.js';\nimport Toast from '/kempo-ui/components/Toast.js';\nimport '/kempo-ui/components/Icon.js';\nimport '/kempo-ui/components/Accordion.js';\nimport '/kempo-ui/components/CodeEditor.js';\n\nexport default class GlobalContentEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n entry: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.entry = null;\n this.entryId = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n this.entryId = new URLSearchParams(window.location.search).get('id') || '';\n\n if(!this.entryId){\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [err, entry] = await getGlobalContent(this.entryId);\n this.loading = false;\n\n if(err){\n this.error = true;\n return;\n }\n\n this.entry = entry;\n document.title = `Edit: ${entry.name || this.entryId} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Event Handlers\n */\n\n handleKeyDown = e => {\n if((e.ctrlKey || e.metaKey) && e.key === 's'){\n e.preventDefault();\n if(!this.saving && !this.entry?.locked) this.handleSave();\n }\n };\n\n handleSave = async () => {\n this.saving = true;\n const root = this.shadowRoot;\n const name = root.querySelector('#metaName').value;\n const location = root.querySelector('#metaLocation').value;\n const priority = root.querySelector('#metaPriority').value;\n const editor = root.querySelector('k-code-editor');\n const markup = editor ? editor.getValue() : this.entry.markup;\n\n const [saveError, saved] = await updateGlobalContent({\n id: this.entryId, name, location, priority, markup\n });\n this.saving = false;\n\n if(saveError){\n Toast.error(saveError.msg || 'Failed to save global content');\n return;\n }\n\n this.entry = { ...this.entry, name, location, priority, markup, updatedAt: saved.updatedAt };\n document.title = `Edit: ${name || this.entryId} - Admin`;\n Toast.success('Global content saved');\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this entry? Any unsaved changes will be lost.', confirmed => {\n if(!confirmed) return;\n this.entry = { ...this.entry };\n });\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this global content entry? This action cannot be undone.', async confirmed => {\n if(!confirmed) return;\n const [error] = await deleteGlobalContent([this.entryId]);\n if(error){\n Toast.error(error.msg || 'Failed to delete global content');\n return;\n }\n Toast.success('Global content deleted');\n setTimeout(() => { window.location.href = '/admin/content/globals'; }, 1000);\n });\n };\n\n /*\n Render\n */\n\n render() {\n if(this.loading) return html`<div>Loading global content...</div>`;\n\n if(this.error) return html`\n <div>\n <p>Global content entry not found.</p>\n <a href=\"/admin/content/globals\">Back to Global Content</a>\n </div>\n `;\n\n const { entry } = this;\n const isSystem = entry.owner === 'system';\n const isLocked = entry.locked;\n\n return html`\n ${isLocked ? html`\n <div class=\"p r mb bc-warning tc-warning\">\n <k-icon name=\"lock\"></k-icon> This entry is locked and cannot be edited. ${entry.owner === 'custom' ? 'Locked by developer' : `Managed by: ${entry.owner || 'external system'}`}\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/globals\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Global Content\n </a>\n </div>\n <div class=\"flex\"></div>\n ${!isSystem && !isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button class=\"danger\" @click=\"${this.handleDelete}\"><k-icon name=\"delete\"></k-icon> Delete</button>\n </div>\n ` : ''}\n ${!isLocked ? html`\n <div class=\"btn-grp mrh mb\">\n <button @click=\"${this.handleReset}\"><k-icon name=\"restart_alt\"></k-icon> Reset</button>\n <button id=\"saveBtn\" class=\"primary\" ?disabled=\"${this.saving}\" @click=\"${this.handleSave}\">\n <k-icon name=\"save\"></k-icon> Save\n </button>\n </div>\n ` : ''}\n </div>\n <h1 class=\"mb\">Global Content: ${entry.name || this.entryId}</h1>\n\n <k-accordion>\n <k-accordion-header for-panel=\"metadata\">Metadata</k-accordion-header>\n <k-accordion-panel name=\"metadata\">\n <div class=\"p\">\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Name</strong></label>\n <input type=\"text\" id=\"metaName\" class=\"flex\" .value=\"${entry.name || ''}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Location</strong></label>\n <input type=\"text\" id=\"metaLocation\" class=\"flex\" .value=\"${entry.location || ''}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Priority</strong></label>\n <input type=\"number\" id=\"metaPriority\" class=\"flex\" .value=\"${entry.priority ?? 0}\" ?disabled=\"${isSystem || isLocked}\">\n </div>\n ${!isSystem ? html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Author</strong></label>\n <span class=\"muted\">${entry.author || ''}</span>\n </div>\n ` : ''}\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Owner</strong></label>\n <span class=\"muted\">${entry.owner || ''}</span>\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Created</strong></label>\n <span class=\"muted\">${entry.createdAt ? new Date(entry.createdAt).toLocaleString() : ''}</span>\n </div>\n <div class=\"d-f\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Updated</strong></label>\n <span class=\"muted\">${entry.updatedAt ? new Date(entry.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n <k-accordion-header for-panel=\"content\" active>Content</k-accordion-header>\n <k-accordion-panel name=\"content\" active>\n <div class=\"p\">\n <k-code-editor\n class=\"r b\"\n language=\"html\"\n .value=\"${entry.markup || ''}\"\n style=\"height: 500px;\"\n ?disabled=\"${isLocked}\"\n ></k-code-editor>\n </div>\n </k-accordion-panel>\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-global-content-editor', GlobalContentEditor);\n"],"mappings":"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","ignoreList":[]}
@@ -1,6 +1,6 @@
1
- import TableControl from"/kempo-ui/components/tableControls/TableControl.js";import{html}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class GroupDeleteSelected extends TableControl{constructor(){super({maxWidth:null}),this.selectionChangeHandler=()=>this.requestUpdate()}connectedCallback(){super.connectedCallback(),this.onTableEvent("selectionChange",this.selectionChangeHandler)}disconnectedCallback(){super.disconnectedCallback(),this.table&&this.table.removeEventListener("selectionChange",this.selectionChangeHandler)}deleteSelected=()=>{if(!this.table)return;const e=this.table.getSelectedRecords(),t=e.filter(e=>"system:Users"!==e.name);if(!t.length)return;const l=e.some(e=>"system:Users"===e.name);this.dispatchEvent(new CustomEvent("groupRemoveSelected",{detail:{records:t,systemUsersSkipped:l},bubbles:!0}))};get deletableCount(){return this.table?this.table.getSelectedRecords().filter(e=>"system:Users"!==e.name).length:0}render(){return html`
1
+ import e from"/kempo-ui/components/tableControls/TableControl.js";import{html as t}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class s extends e{constructor(){super({maxWidth:null}),this.selectionChangeHandler=()=>this.requestUpdate()}connectedCallback(){super.connectedCallback(),this.onTableEvent("selectionChange",this.selectionChangeHandler)}disconnectedCallback(){super.disconnectedCallback(),this.table&&this.table.removeEventListener("selectionChange",this.selectionChangeHandler)}deleteSelected=()=>{if(!this.table)return;const e=this.table.getSelectedRecords(),t=e.filter(e=>"system:Users"!==e.name);if(!t.length)return;const s=e.some(e=>"system:Users"===e.name);this.dispatchEvent(new CustomEvent("groupRemoveSelected",{detail:{records:t,systemUsersSkipped:s},bubbles:!0}))};get deletableCount(){return this.table?this.table.getSelectedRecords().filter(e=>"system:Users"!==e.name).length:0}render(){return t`
2
2
  <button class="no-btn icon-btn" ?disabled="${0===this.deletableCount}" @click="${this.deleteSelected}">
3
3
  <k-icon name="delete"></k-icon>
4
4
  </button>
5
- `}}customElements.define("admin-group-delete-selected",GroupDeleteSelected);
5
+ `}}customElements.define("admin-group-delete-selected",s);
6
6
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\GroupDeleteSelected.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\GroupDeleteSelected.js","names":["TableControl","html","GroupDeleteSelected","constructor","super","maxWidth","this","selectionChangeHandler","requestUpdate","connectedCallback","onTableEvent","disconnectedCallback","table","removeEventListener","deleteSelected","selected","getSelectedRecords","records","filter","r","name","length","systemUsersSkipped","some","dispatchEvent","CustomEvent","detail","bubbles","deletableCount","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class GroupDeleteSelected extends TableControl {\r\n constructor() {\r\n super({ maxWidth: null });\r\n this.selectionChangeHandler = () => this.requestUpdate();\r\n }\r\n\r\n connectedCallback() {\r\n super.connectedCallback();\r\n this.onTableEvent('selectionChange', this.selectionChangeHandler);\r\n }\r\n\r\n disconnectedCallback() {\r\n super.disconnectedCallback();\r\n if(this.table) this.table.removeEventListener('selectionChange', this.selectionChangeHandler);\r\n }\r\n\r\n deleteSelected = () => {\r\n if(!this.table) return;\r\n const selected = this.table.getSelectedRecords();\r\n const records = selected.filter(r => r.name !== 'system:Users');\r\n if(!records.length) return;\r\n const systemUsersSkipped = selected.some(r => r.name === 'system:Users');\r\n this.dispatchEvent(new CustomEvent('groupRemoveSelected', {\r\n detail: { records, systemUsersSkipped },\r\n bubbles: true\r\n }));\r\n };\r\n\r\n get deletableCount() {\r\n if(!this.table) return 0;\r\n return this.table.getSelectedRecords().filter(r => r.name !== 'system:Users').length;\r\n }\r\n\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" ?disabled=\"${this.deletableCount === 0}\" @click=\"${this.deleteSelected}\">\r\n <k-icon name=\"delete\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-group-delete-selected', GroupDeleteSelected);\r\n"],"mappings":"OAAOA,iBAAkB,4DAChBC,SAAY,iCACd,8CAEQ,MAAMC,4BAA4BF,aAC/C,WAAAG,GACEC,MAAM,CAAEC,SAAU,OAClBC,KAAKC,uBAAyB,IAAMD,KAAKE,eAC3C,CAEA,iBAAAC,GACEL,MAAMK,oBACNH,KAAKI,aAAa,kBAAmBJ,KAAKC,uBAC5C,CAEA,oBAAAI,GACEP,MAAMO,uBACHL,KAAKM,OAAON,KAAKM,MAAMC,oBAAoB,kBAAmBP,KAAKC,uBACxE,CAEAO,eAAiB,KACf,IAAIR,KAAKM,MAAO,OAChB,MAAMG,EAAWT,KAAKM,MAAMI,qBACtBC,EAAUF,EAASG,OAAOC,GAAgB,iBAAXA,EAAEC,MACvC,IAAIH,EAAQI,OAAQ,OACpB,MAAMC,EAAqBP,EAASQ,KAAKJ,GAAgB,iBAAXA,EAAEC,MAChDd,KAAKkB,cAAc,IAAIC,YAAY,sBAAuB,CACxDC,OAAQ,CAAET,UAASK,sBACnBK,SAAS,MAIb,kBAAIC,GACF,OAAItB,KAAKM,MACFN,KAAKM,MAAMI,qBAAqBE,OAAOC,GAAgB,iBAAXA,EAAEC,MAAyBC,OADvD,CAEzB,CAEA,MAAAQ,GACE,OAAO5B,IAAI;mDAC4D,IAAxBK,KAAKsB,2BAAiCtB,KAAKQ;;;KAI5F,EAGFgB,eAAeC,OAAO,8BAA+B7B","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\GroupDeleteSelected.js","names":["TableControl","html","GroupDeleteSelected","constructor","super","maxWidth","this","selectionChangeHandler","requestUpdate","connectedCallback","onTableEvent","disconnectedCallback","table","removeEventListener","deleteSelected","selected","getSelectedRecords","records","filter","r","name","length","systemUsersSkipped","some","dispatchEvent","CustomEvent","detail","bubbles","deletableCount","render","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class GroupDeleteSelected extends TableControl {\r\n constructor() {\r\n super({ maxWidth: null });\r\n this.selectionChangeHandler = () => this.requestUpdate();\r\n }\r\n\r\n connectedCallback() {\r\n super.connectedCallback();\r\n this.onTableEvent('selectionChange', this.selectionChangeHandler);\r\n }\r\n\r\n disconnectedCallback() {\r\n super.disconnectedCallback();\r\n if(this.table) this.table.removeEventListener('selectionChange', this.selectionChangeHandler);\r\n }\r\n\r\n deleteSelected = () => {\r\n if(!this.table) return;\r\n const selected = this.table.getSelectedRecords();\r\n const records = selected.filter(r => r.name !== 'system:Users');\r\n if(!records.length) return;\r\n const systemUsersSkipped = selected.some(r => r.name === 'system:Users');\r\n this.dispatchEvent(new CustomEvent('groupRemoveSelected', {\r\n detail: { records, systemUsersSkipped },\r\n bubbles: true\r\n }));\r\n };\r\n\r\n get deletableCount() {\r\n if(!this.table) return 0;\r\n return this.table.getSelectedRecords().filter(r => r.name !== 'system:Users').length;\r\n }\r\n\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" ?disabled=\"${this.deletableCount === 0}\" @click=\"${this.deleteSelected}\">\r\n <k-icon name=\"delete\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-group-delete-selected', GroupDeleteSelected);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,iCACd,8CAEQ,MAAMC,UAA4BF,EAC/C,WAAAG,GACEC,MAAM,CAAEC,SAAU,OAClBC,KAAKC,uBAAyB,IAAMD,KAAKE,eAC3C,CAEA,iBAAAC,GACEL,MAAMK,oBACNH,KAAKI,aAAa,kBAAmBJ,KAAKC,uBAC5C,CAEA,oBAAAI,GACEP,MAAMO,uBACHL,KAAKM,OAAON,KAAKM,MAAMC,oBAAoB,kBAAmBP,KAAKC,uBACxE,CAEAO,eAAiB,KACf,IAAIR,KAAKM,MAAO,OAChB,MAAMG,EAAWT,KAAKM,MAAMI,qBACtBC,EAAUF,EAASG,OAAOC,GAAgB,iBAAXA,EAAEC,MACvC,IAAIH,EAAQI,OAAQ,OACpB,MAAMC,EAAqBP,EAASQ,KAAKJ,GAAgB,iBAAXA,EAAEC,MAChDd,KAAKkB,cAAc,IAAIC,YAAY,sBAAuB,CACxDC,OAAQ,CAAET,UAASK,sBACnBK,SAAS,MAIb,kBAAIC,GACF,OAAItB,KAAKM,MACFN,KAAKM,MAAMI,qBAAqBE,OAAOC,GAAgB,iBAAXA,EAAEC,MAAyBC,OADvD,CAEzB,CAEA,MAAAQ,GACE,OAAO5B,CAAI;mDAC4D,IAAxBK,KAAKsB,2BAAiCtB,KAAKQ;;;KAI5F,EAGFgB,eAAeC,OAAO,8BAA+B7B","ignoreList":[]}
@@ -1,6 +1,6 @@
1
- import TableControl from"/kempo-ui/components/tableControls/TableControl.js";import{html}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class GroupRemoveRecord extends TableControl{remove=()=>{this.record&&this.table.deleteRecord(this.record)};render(){return"system:Users"===this.record?.name?html``:html`
1
+ import e from"/kempo-ui/components/tableControls/TableControl.js";import{html as o}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class t extends e{remove=()=>{this.record&&this.table.deleteRecord(this.record)};render(){return"system:Users"===this.record?.name?o``:o`
2
2
  <button class="no-btn icon-btn" @click="${this.remove}">
3
3
  <k-icon name="delete"></k-icon>
4
4
  </button>
5
- `}}customElements.define("admin-group-remove-record",GroupRemoveRecord);
5
+ `}}customElements.define("admin-group-remove-record",t);
6
6
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\GroupRemoveRecord.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\GroupRemoveRecord.js","names":["TableControl","html","GroupRemoveRecord","remove","this","record","table","deleteRecord","render","name","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class GroupRemoveRecord extends TableControl {\r\n remove = () => {\r\n if(this.record) this.table.deleteRecord(this.record);\r\n };\r\n\r\n render() {\r\n if(this.record?.name === 'system:Users') return html``;\r\n return html`\r\n <button class=\"no-btn icon-btn\" @click=\"${this.remove}\">\r\n <k-icon name=\"delete\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-group-remove-record', GroupRemoveRecord);\r\n"],"mappings":"OAAOA,iBAAkB,4DAChBC,SAAY,iCACd,8CAEQ,MAAMC,0BAA0BF,aAC7CG,OAAS,KACJC,KAAKC,QAAQD,KAAKE,MAAMC,aAAaH,KAAKC,SAG/C,MAAAG,GACE,MAAyB,iBAAtBJ,KAAKC,QAAQI,KAAgCR,IAAI,GAC7CA,IAAI;gDACiCG,KAAKD;;;KAInD,EAGFO,eAAeC,OAAO,4BAA6BT","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\GroupRemoveRecord.js","names":["TableControl","html","GroupRemoveRecord","remove","this","record","table","deleteRecord","render","name","customElements","define"],"sources":["0"],"sourcesContent":["import TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class GroupRemoveRecord extends TableControl {\r\n remove = () => {\r\n if(this.record) this.table.deleteRecord(this.record);\r\n };\r\n\r\n render() {\r\n if(this.record?.name === 'system:Users') return html``;\r\n return html`\r\n <button class=\"no-btn icon-btn\" @click=\"${this.remove}\">\r\n <k-icon name=\"delete\"></k-icon>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-group-remove-record', GroupRemoveRecord);\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,iCACd,8CAEQ,MAAMC,UAA0BF,EAC7CG,OAAS,KACJC,KAAKC,QAAQD,KAAKE,MAAMC,aAAaH,KAAKC,SAG/C,MAAAG,GACE,MAAyB,iBAAtBJ,KAAKC,QAAQI,KAAgCR,CAAI,GAC7CA,CAAI;gDACiCG,KAAKD;;;KAInD,EAGFO,eAAeC,OAAO,4BAA6BT","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- import LightComponent from"/kempo-ui/components/LightComponent.js";import{html}from"/kempo-ui/lit-all.min.js";let monacoLoadPromise=null;const ensureMonacoLoaded=()=>monacoLoadPromise||(monacoLoadPromise=new Promise(e=>{if(window.monaco)return void e();const t=document.createElement("script");t.src="/monaco-editor/vs/loader.js",t.onload=()=>{require.config({paths:{vs:"/monaco-editor/vs"}}),require(["vs/editor/editor.main"],()=>e())},document.head.appendChild(t)}),monacoLoadPromise);export default class Monaco extends LightComponent{static get properties(){return{language:{type:String},readOnly:{type:Boolean,attribute:"readonly"},height:{type:String}}}#e=null;#t=!1;#i="";constructor(){super(),this.language="json",this.readOnly=!1,this.height="400px"}get value(){return this.#e?this.#e.getValue():this.#i}set value(e){this.#e?this.#e.getValue()!==e&&this.#e.setValue(e):this.#i=e}updated(e){super.updated(e),this.#e||this.#t||(this.#t=!0,this.#o()),this.#e&&(e.has("readOnly")&&this.#e.updateOptions({readOnly:this.readOnly}),e.has("language")&&monaco.editor.setModelLanguage(this.#e.getModel(),this.language))}disconnectedCallback(){super.disconnectedCallback(),this.#e&&(this.#e.dispose(),this.#e=null)}#o=async()=>{await ensureMonacoLoaded();const e=this.querySelector("[data-monaco-container]");if(!e)return;const t="dark"===document.documentElement.getAttribute("theme")||"auto"===document.documentElement.getAttribute("theme")&&window.matchMedia("(prefers-color-scheme: dark)").matches;this.#e=monaco.editor.create(e,{value:this.#i,language:this.language,minimap:{enabled:!1},automaticLayout:!0,theme:t?"vs-dark":"vs",scrollBeyondLastLine:!1,fontSize:14,tabSize:2,readOnly:this.readOnly}),this.#e.onDidChangeModelContent(()=>{this.dispatchEvent(new Event("change"))})};renderLightDom(){return html`<div data-monaco-container style="height: ${this.height}; border: 1px solid var(--c_border); border-radius: var(--radius);"></div>`}}customElements.define("admin-monaco",Monaco);
1
+ import e from"/kempo-ui/components/LightComponent.js";import{html as t}from"/kempo-ui/lit-all.min.js";let i=null;export default class n extends e{static get properties(){return{language:{type:String},readOnly:{type:Boolean,attribute:"readonly"},height:{type:String}}}#e=null;#t=!1;#i="";constructor(){super(),this.language="json",this.readOnly=!1,this.height="400px"}get value(){return this.#e?this.#e.getValue():this.#i}set value(e){this.#e?this.#e.getValue()!==e&&this.#e.setValue(e):this.#i=e}updated(e){super.updated(e),this.#e||this.#t||(this.#t=!0,this.#n()),this.#e&&(e.has("readOnly")&&this.#e.updateOptions({readOnly:this.readOnly}),e.has("language")&&monaco.editor.setModelLanguage(this.#e.getModel(),this.language))}disconnectedCallback(){super.disconnectedCallback(),this.#e&&(this.#e.dispose(),this.#e=null)}#n=async()=>{await(i||(i=new Promise(e=>{if(window.monaco)return void e();const t=document.createElement("script");t.src="/monaco-editor/vs/loader.js",t.onload=()=>{require.config({paths:{vs:"/monaco-editor/vs"}}),require(["vs/editor/editor.main"],()=>e())},document.head.appendChild(t)}),i));const e=this.querySelector("[data-monaco-container]");if(!e)return;const t="dark"===document.documentElement.getAttribute("theme")||"auto"===document.documentElement.getAttribute("theme")&&window.matchMedia("(prefers-color-scheme: dark)").matches;this.#e=monaco.editor.create(e,{value:this.#i,language:this.language,minimap:{enabled:!1},automaticLayout:!0,theme:t?"vs-dark":"vs",scrollBeyondLastLine:!1,fontSize:14,tabSize:2,readOnly:this.readOnly}),this.#e.onDidChangeModelContent(()=>{this.dispatchEvent(new Event("change"))})};renderLightDom(){return t`<div data-monaco-container style="height: ${this.height}; border: 1px solid var(--c_border); border-radius: var(--radius);"></div>`}}customElements.define("admin-monaco",n);
2
2
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\Monaco.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\Monaco.js","names":["LightComponent","html","monacoLoadPromise","ensureMonacoLoaded","Promise","resolve","window","monaco","script","document","createElement","src","onload","require","config","paths","vs","head","appendChild","Monaco","properties","language","type","String","readOnly","Boolean","attribute","height","editor","initializing","pendingValue","constructor","super","this","value","getValue","v","setValue","updated","changedProperties","initEditor","has","updateOptions","setModelLanguage","getModel","disconnectedCallback","dispose","async","container","querySelector","isDark","documentElement","getAttribute","matchMedia","matches","create","minimap","enabled","automaticLayout","theme","scrollBeyondLastLine","fontSize","tabSize","onDidChangeModelContent","dispatchEvent","Event","renderLightDom","customElements","define"],"sources":["0"],"sourcesContent":["import LightComponent from '/kempo-ui/components/LightComponent.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\n\r\nlet monacoLoadPromise = null;\r\n\r\nconst ensureMonacoLoaded = () => {\r\n\tif(monacoLoadPromise) return monacoLoadPromise;\r\n\tmonacoLoadPromise = new Promise(resolve => {\r\n\t\tif(window.monaco){\r\n\t\t\tresolve();\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst script = document.createElement('script');\r\n\t\tscript.src = '/monaco-editor/vs/loader.js';\r\n\t\tscript.onload = () => {\r\n\t\t\trequire.config({ paths: { vs: '/monaco-editor/vs' } });\r\n\t\t\trequire(['vs/editor/editor.main'], () => resolve());\r\n\t\t};\r\n\t\tdocument.head.appendChild(script);\r\n\t});\r\n\treturn monacoLoadPromise;\r\n};\r\n\r\nexport default class Monaco extends LightComponent {\r\n\tstatic get properties() {\r\n\t\treturn {\r\n\t\t\tlanguage: { type: String },\r\n\t\t\treadOnly: { type: Boolean, attribute: 'readonly' },\r\n\t\t\theight: { type: String }\r\n\t\t};\r\n\t}\r\n\r\n\t#editor = null;\r\n\t#initializing = false;\r\n\t#pendingValue = '';\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.language = 'json';\r\n\t\tthis.readOnly = false;\r\n\t\tthis.height = '400px';\r\n\t}\r\n\r\n\t/*\r\n\t\tValue accessors\r\n\t*/\r\n\r\n\tget value() {\r\n\t\tif(this.#editor) return this.#editor.getValue();\r\n\t\treturn this.#pendingValue;\r\n\t}\r\n\r\n\tset value(v) {\r\n\t\tif(this.#editor){\r\n\t\t\tif(this.#editor.getValue() !== v) this.#editor.setValue(v);\r\n\t\t} else {\r\n\t\t\tthis.#pendingValue = v;\r\n\t\t}\r\n\t}\r\n\r\n\t/*\r\n\t\tLifecycle\r\n\t*/\r\n\r\n\tupdated(changedProperties) {\r\n\t\tsuper.updated(changedProperties);\r\n\t\tif(!this.#editor && !this.#initializing){\r\n\t\t\tthis.#initializing = true;\r\n\t\t\tthis.#initEditor();\r\n\t\t}\r\n\t\tif(this.#editor){\r\n\t\t\tif(changedProperties.has('readOnly')){\r\n\t\t\t\tthis.#editor.updateOptions({ readOnly: this.readOnly });\r\n\t\t\t}\r\n\t\t\tif(changedProperties.has('language')){\r\n\t\t\t\tmonaco.editor.setModelLanguage(this.#editor.getModel(), this.language);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdisconnectedCallback() {\r\n\t\tsuper.disconnectedCallback();\r\n\t\tif(this.#editor){\r\n\t\t\tthis.#editor.dispose();\r\n\t\t\tthis.#editor = null;\r\n\t\t}\r\n\t}\r\n\r\n\t/*\r\n\t\tEditor initialization\r\n\t*/\r\n\r\n\t#initEditor = async () => {\r\n\t\tawait ensureMonacoLoaded();\r\n\t\tconst container = this.querySelector('[data-monaco-container]');\r\n\t\tif(!container) return;\r\n\t\tconst isDark = document.documentElement.getAttribute('theme') === 'dark'\r\n\t\t\t|| (document.documentElement.getAttribute('theme') === 'auto'\r\n\t\t\t\t&& window.matchMedia('(prefers-color-scheme: dark)').matches);\r\n\t\tthis.#editor = monaco.editor.create(container, {\r\n\t\t\tvalue: this.#pendingValue,\r\n\t\t\tlanguage: this.language,\r\n\t\t\tminimap: { enabled: false },\r\n\t\t\tautomaticLayout: true,\r\n\t\t\ttheme: isDark ? 'vs-dark' : 'vs',\r\n\t\t\tscrollBeyondLastLine: false,\r\n\t\t\tfontSize: 14,\r\n\t\t\ttabSize: 2,\r\n\t\t\treadOnly: this.readOnly\r\n\t\t});\r\n\t\tthis.#editor.onDidChangeModelContent(() => {\r\n\t\t\tthis.dispatchEvent(new Event('change'));\r\n\t\t});\r\n\t};\r\n\r\n\t/*\r\n\t\tRender\r\n\t*/\r\n\r\n\trenderLightDom() {\r\n\t\treturn html`<div data-monaco-container style=\"height: ${this.height}; border: 1px solid var(--c_border); border-radius: var(--radius);\"></div>`;\r\n\t}\r\n}\r\n\r\ncustomElements.define('admin-monaco', Monaco);\r\n"],"mappings":"OAAOA,mBAAoB,gDAClBC,SAAY,2BAErB,IAAIC,kBAAoB,KAExB,MAAMC,mBAAqB,IACvBD,oBACHA,kBAAoB,IAAIE,QAAQC,IAC/B,GAAGC,OAAOC,OAET,YADAF,IAGD,MAAMG,EAASC,SAASC,cAAc,UACtCF,EAAOG,IAAM,8BACbH,EAAOI,OAAS,KACfC,QAAQC,OAAO,CAAEC,MAAO,CAAEC,GAAI,uBAC9BH,QAAQ,CAAC,yBAA0B,IAAMR,MAE1CI,SAASQ,KAAKC,YAAYV,KAEpBN,kCAGO,MAAMiB,eAAenB,eACnC,qBAAWoB,GACV,MAAO,CACNC,SAAU,CAAEC,KAAMC,QAClBC,SAAU,CAAEF,KAAMG,QAASC,UAAW,YACtCC,OAAQ,CAAEL,KAAMC,QAElB,CAEAK,GAAU,KACVC,IAAgB,EAChBC,GAAgB,GAEhB,WAAAC,GACCC,QACAC,KAAKZ,SAAW,OAChBY,KAAKT,UAAW,EAChBS,KAAKN,OAAS,OACf,CAMA,SAAIO,GACH,OAAGD,MAAKL,EAAgBK,MAAKL,EAAQO,WAC9BF,MAAKH,CACb,CAEA,SAAII,CAAME,GACNH,MAAKL,EACJK,MAAKL,EAAQO,aAAeC,GAAGH,MAAKL,EAAQS,SAASD,GAExDH,MAAKH,EAAgBM,CAEvB,CAMA,OAAAE,CAAQC,GACPP,MAAMM,QAAQC,GACVN,MAAKL,GAAYK,MAAKJ,IACzBI,MAAKJ,GAAgB,EACrBI,MAAKO,KAEHP,MAAKL,IACJW,EAAkBE,IAAI,aACxBR,MAAKL,EAAQc,cAAc,CAAElB,SAAUS,KAAKT,WAE1Ce,EAAkBE,IAAI,aACxBlC,OAAOqB,OAAOe,iBAAiBV,MAAKL,EAAQgB,WAAYX,KAAKZ,UAGhE,CAEA,oBAAAwB,GACCb,MAAMa,uBACHZ,MAAKL,IACPK,MAAKL,EAAQkB,UACbb,MAAKL,EAAU,KAEjB,CAMAY,GAAcO,gBACP5C,qBACN,MAAM6C,EAAYf,KAAKgB,cAAc,2BACrC,IAAID,EAAW,OACf,MAAME,EAA4D,SAAnDzC,SAAS0C,gBAAgBC,aAAa,UACG,SAAnD3C,SAAS0C,gBAAgBC,aAAa,UACtC9C,OAAO+C,WAAW,gCAAgCC,QACvDrB,MAAKL,EAAUrB,OAAOqB,OAAO2B,OAAOP,EAAW,CAC9Cd,MAAOD,MAAKH,EACZT,SAAUY,KAAKZ,SACfmC,QAAS,CAAEC,SAAS,GACpBC,iBAAiB,EACjBC,MAAOT,EAAS,UAAY,KAC5BU,sBAAsB,EACtBC,SAAU,GACVC,QAAS,EACTtC,SAAUS,KAAKT,WAEhBS,MAAKL,EAAQmC,wBAAwB,KACpC9B,KAAK+B,cAAc,IAAIC,MAAM,cAQ/B,cAAAC,GACC,OAAOjE,IAAI,6CAA6CgC,KAAKN,kFAC9D,EAGDwC,eAAeC,OAAO,eAAgBjD","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\Monaco.js","names":["LightComponent","html","monacoLoadPromise","Monaco","properties","language","type","String","readOnly","Boolean","attribute","height","editor","initializing","pendingValue","constructor","super","this","value","getValue","v","setValue","updated","changedProperties","initEditor","has","updateOptions","monaco","setModelLanguage","getModel","disconnectedCallback","dispose","async","Promise","resolve","window","script","document","createElement","src","onload","require","config","paths","vs","head","appendChild","container","querySelector","isDark","documentElement","getAttribute","matchMedia","matches","create","minimap","enabled","automaticLayout","theme","scrollBeyondLastLine","fontSize","tabSize","onDidChangeModelContent","dispatchEvent","Event","renderLightDom","customElements","define"],"sources":["0"],"sourcesContent":["import LightComponent from '/kempo-ui/components/LightComponent.js';\r\nimport { html } from '/kempo-ui/lit-all.min.js';\r\n\r\nlet monacoLoadPromise = null;\r\n\r\nconst ensureMonacoLoaded = () => {\r\n\tif(monacoLoadPromise) return monacoLoadPromise;\r\n\tmonacoLoadPromise = new Promise(resolve => {\r\n\t\tif(window.monaco){\r\n\t\t\tresolve();\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tconst script = document.createElement('script');\r\n\t\tscript.src = '/monaco-editor/vs/loader.js';\r\n\t\tscript.onload = () => {\r\n\t\t\trequire.config({ paths: { vs: '/monaco-editor/vs' } });\r\n\t\t\trequire(['vs/editor/editor.main'], () => resolve());\r\n\t\t};\r\n\t\tdocument.head.appendChild(script);\r\n\t});\r\n\treturn monacoLoadPromise;\r\n};\r\n\r\nexport default class Monaco extends LightComponent {\r\n\tstatic get properties() {\r\n\t\treturn {\r\n\t\t\tlanguage: { type: String },\r\n\t\t\treadOnly: { type: Boolean, attribute: 'readonly' },\r\n\t\t\theight: { type: String }\r\n\t\t};\r\n\t}\r\n\r\n\t#editor = null;\r\n\t#initializing = false;\r\n\t#pendingValue = '';\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.language = 'json';\r\n\t\tthis.readOnly = false;\r\n\t\tthis.height = '400px';\r\n\t}\r\n\r\n\t/*\r\n\t\tValue accessors\r\n\t*/\r\n\r\n\tget value() {\r\n\t\tif(this.#editor) return this.#editor.getValue();\r\n\t\treturn this.#pendingValue;\r\n\t}\r\n\r\n\tset value(v) {\r\n\t\tif(this.#editor){\r\n\t\t\tif(this.#editor.getValue() !== v) this.#editor.setValue(v);\r\n\t\t} else {\r\n\t\t\tthis.#pendingValue = v;\r\n\t\t}\r\n\t}\r\n\r\n\t/*\r\n\t\tLifecycle\r\n\t*/\r\n\r\n\tupdated(changedProperties) {\r\n\t\tsuper.updated(changedProperties);\r\n\t\tif(!this.#editor && !this.#initializing){\r\n\t\t\tthis.#initializing = true;\r\n\t\t\tthis.#initEditor();\r\n\t\t}\r\n\t\tif(this.#editor){\r\n\t\t\tif(changedProperties.has('readOnly')){\r\n\t\t\t\tthis.#editor.updateOptions({ readOnly: this.readOnly });\r\n\t\t\t}\r\n\t\t\tif(changedProperties.has('language')){\r\n\t\t\t\tmonaco.editor.setModelLanguage(this.#editor.getModel(), this.language);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tdisconnectedCallback() {\r\n\t\tsuper.disconnectedCallback();\r\n\t\tif(this.#editor){\r\n\t\t\tthis.#editor.dispose();\r\n\t\t\tthis.#editor = null;\r\n\t\t}\r\n\t}\r\n\r\n\t/*\r\n\t\tEditor initialization\r\n\t*/\r\n\r\n\t#initEditor = async () => {\r\n\t\tawait ensureMonacoLoaded();\r\n\t\tconst container = this.querySelector('[data-monaco-container]');\r\n\t\tif(!container) return;\r\n\t\tconst isDark = document.documentElement.getAttribute('theme') === 'dark'\r\n\t\t\t|| (document.documentElement.getAttribute('theme') === 'auto'\r\n\t\t\t\t&& window.matchMedia('(prefers-color-scheme: dark)').matches);\r\n\t\tthis.#editor = monaco.editor.create(container, {\r\n\t\t\tvalue: this.#pendingValue,\r\n\t\t\tlanguage: this.language,\r\n\t\t\tminimap: { enabled: false },\r\n\t\t\tautomaticLayout: true,\r\n\t\t\ttheme: isDark ? 'vs-dark' : 'vs',\r\n\t\t\tscrollBeyondLastLine: false,\r\n\t\t\tfontSize: 14,\r\n\t\t\ttabSize: 2,\r\n\t\t\treadOnly: this.readOnly\r\n\t\t});\r\n\t\tthis.#editor.onDidChangeModelContent(() => {\r\n\t\t\tthis.dispatchEvent(new Event('change'));\r\n\t\t});\r\n\t};\r\n\r\n\t/*\r\n\t\tRender\r\n\t*/\r\n\r\n\trenderLightDom() {\r\n\t\treturn html`<div data-monaco-container style=\"height: ${this.height}; border: 1px solid var(--c_border); border-radius: var(--radius);\"></div>`;\r\n\t}\r\n}\r\n\r\ncustomElements.define('admin-monaco', Monaco);\r\n"],"mappings":"OAAOA,MAAoB,wDAClBC,MAAY,2BAErB,IAAIC,EAAoB,oBAoBT,MAAMC,UAAeH,EACnC,qBAAWI,GACV,MAAO,CACNC,SAAU,CAAEC,KAAMC,QAClBC,SAAU,CAAEF,KAAMG,QAASC,UAAW,YACtCC,OAAQ,CAAEL,KAAMC,QAElB,CAEAK,GAAU,KACVC,IAAgB,EAChBC,GAAgB,GAEhB,WAAAC,GACCC,QACAC,KAAKZ,SAAW,OAChBY,KAAKT,UAAW,EAChBS,KAAKN,OAAS,OACf,CAMA,SAAIO,GACH,OAAGD,MAAKL,EAAgBK,MAAKL,EAAQO,WAC9BF,MAAKH,CACb,CAEA,SAAII,CAAME,GACNH,MAAKL,EACJK,MAAKL,EAAQO,aAAeC,GAAGH,MAAKL,EAAQS,SAASD,GAExDH,MAAKH,EAAgBM,CAEvB,CAMA,OAAAE,CAAQC,GACPP,MAAMM,QAAQC,GACVN,MAAKL,GAAYK,MAAKJ,IACzBI,MAAKJ,GAAgB,EACrBI,MAAKO,KAEHP,MAAKL,IACJW,EAAkBE,IAAI,aACxBR,MAAKL,EAAQc,cAAc,CAAElB,SAAUS,KAAKT,WAE1Ce,EAAkBE,IAAI,aACxBE,OAAOf,OAAOgB,iBAAiBX,MAAKL,EAAQiB,WAAYZ,KAAKZ,UAGhE,CAEA,oBAAAyB,GACCd,MAAMc,uBACHb,MAAKL,IACPK,MAAKL,EAAQmB,UACbd,MAAKL,EAAU,KAEjB,CAMAY,GAAcQ,gBAtFX9B,IACHA,EAAoB,IAAI+B,QAAQC,IAC/B,GAAGC,OAAOR,OAET,YADAO,IAGD,MAAME,EAASC,SAASC,cAAc,UACtCF,EAAOG,IAAM,8BACbH,EAAOI,OAAS,KACfC,QAAQC,OAAO,CAAEC,MAAO,CAAEC,GAAI,uBAC9BH,QAAQ,CAAC,yBAA0B,IAAMP,MAE1CG,SAASQ,KAAKC,YAAYV,KAEpBlC,IA0EN,MAAM6C,EAAY9B,KAAK+B,cAAc,2BACrC,IAAID,EAAW,OACf,MAAME,EAA4D,SAAnDZ,SAASa,gBAAgBC,aAAa,UACG,SAAnDd,SAASa,gBAAgBC,aAAa,UACtChB,OAAOiB,WAAW,gCAAgCC,QACvDpC,MAAKL,EAAUe,OAAOf,OAAO0C,OAAOP,EAAW,CAC9C7B,MAAOD,MAAKH,EACZT,SAAUY,KAAKZ,SACfkD,QAAS,CAAEC,SAAS,GACpBC,iBAAiB,EACjBC,MAAOT,EAAS,UAAY,KAC5BU,sBAAsB,EACtBC,SAAU,GACVC,QAAS,EACTrD,SAAUS,KAAKT,WAEhBS,MAAKL,EAAQkD,wBAAwB,KACpC7C,KAAK8C,cAAc,IAAIC,MAAM,cAQ/B,cAAAC,GACC,OAAOhE,CAAI,6CAA6CgB,KAAKN,kFAC9D,EAGDuD,eAAeC,OAAO,eAAgBhE","ignoreList":[]}