kempo 4.2.16 → 4.2.18

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 (274) hide show
  1. package/bin/cli.js +21 -4
  2. package/dist/admin/components/AddGroupControl.js +2 -2
  3. package/dist/admin/components/AddGroupControl.js.map +1 -1
  4. package/dist/admin/components/ClearExpiredSessionsControl.js +2 -2
  5. package/dist/admin/components/ClearExpiredSessionsControl.js.map +1 -1
  6. package/dist/admin/components/FragmentEditor.js +15 -15
  7. package/dist/admin/components/FragmentEditor.js.map +1 -1
  8. package/dist/admin/components/GlobalContentEditor.js +12 -12
  9. package/dist/admin/components/GlobalContentEditor.js.map +1 -1
  10. package/dist/admin/components/GroupDeleteSelected.js +2 -2
  11. package/dist/admin/components/GroupDeleteSelected.js.map +1 -1
  12. package/dist/admin/components/GroupRemoveRecord.js +2 -2
  13. package/dist/admin/components/GroupRemoveRecord.js.map +1 -1
  14. package/dist/admin/components/Monaco.js +1 -1
  15. package/dist/admin/components/Monaco.js.map +1 -1
  16. package/dist/admin/components/PageEditor.js +42 -28
  17. package/dist/admin/components/PageEditor.js.map +1 -1
  18. package/dist/admin/components/TableRowDelete.js +2 -2
  19. package/dist/admin/components/TableRowDelete.js.map +1 -1
  20. package/dist/admin/components/TableRowLink.js +2 -2
  21. package/dist/admin/components/TableRowLink.js.map +1 -1
  22. package/dist/admin/components/TemplateEditor.js +18 -18
  23. package/dist/admin/components/TemplateEditor.js.map +1 -1
  24. package/dist/admin/components/ValueEditor.js +17 -17
  25. package/dist/admin/components/ValueEditor.js.map +1 -1
  26. package/dist/admin/components/tableControls/AddMember.js +2 -2
  27. package/dist/admin/components/tableControls/AddMember.js.map +1 -1
  28. package/dist/admin/components/tableControls/AddPermission.js +2 -2
  29. package/dist/admin/components/tableControls/AddPermission.js.map +1 -1
  30. package/dist/admin/components/tableControls/InstallExtension.js +2 -2
  31. package/dist/admin/components/tableControls/InstallExtension.js.map +1 -1
  32. package/dist/admin/components/tableControls/UninstallExtension.js +2 -2
  33. package/dist/admin/components/tableControls/UninstallExtension.js.map +1 -1
  34. package/dist/admin/extensions/index.page.html +49 -15
  35. package/dist/admin/icons/open_in_new.svg +1 -0
  36. package/dist/admin/nav.fragment.html +1 -1
  37. package/dist/kempo/api/admin-globals/DELETE.js +1 -1
  38. package/dist/kempo/api/admin-globals/DELETE.js.map +1 -1
  39. package/dist/kempo/api/admin-globals/GET.js +1 -1
  40. package/dist/kempo/api/admin-globals/GET.js.map +1 -1
  41. package/dist/kempo/api/admin-globals/POST.js +1 -1
  42. package/dist/kempo/api/admin-globals/POST.js.map +1 -1
  43. package/dist/kempo/api/admin-globals/[id]/GET.js +1 -1
  44. package/dist/kempo/api/admin-globals/[id]/GET.js.map +1 -1
  45. package/dist/kempo/api/admin-globals/[id]/PUT.js +1 -1
  46. package/dist/kempo/api/admin-globals/[id]/PUT.js.map +1 -1
  47. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js +1 -1
  48. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js.map +1 -1
  49. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js +1 -1
  50. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js.map +1 -1
  51. package/dist/kempo/api/auth/change-password/POST.js +1 -1
  52. package/dist/kempo/api/auth/change-password/POST.js.map +1 -1
  53. package/dist/kempo/api/auth/login/email/POST.js +1 -1
  54. package/dist/kempo/api/auth/login/email/POST.js.map +1 -1
  55. package/dist/kempo/api/auth/logout/POST.js +1 -1
  56. package/dist/kempo/api/auth/logout/POST.js.map +1 -1
  57. package/dist/kempo/api/auth/register/email/POST.js +1 -1
  58. package/dist/kempo/api/auth/register/email/POST.js.map +1 -1
  59. package/dist/kempo/api/auth/reset-password/POST.js +1 -1
  60. package/dist/kempo/api/auth/reset-password/POST.js.map +1 -1
  61. package/dist/kempo/api/auth/session/GET.js +1 -1
  62. package/dist/kempo/api/auth/session/GET.js.map +1 -1
  63. package/dist/kempo/api/auth/verify-email/POST.js +1 -1
  64. package/dist/kempo/api/auth/verify-email/POST.js.map +1 -1
  65. package/dist/kempo/api/extensions/DELETE.js +1 -1
  66. package/dist/kempo/api/extensions/DELETE.js.map +1 -1
  67. package/dist/kempo/api/extensions/GET.js +1 -1
  68. package/dist/kempo/api/extensions/GET.js.map +1 -1
  69. package/dist/kempo/api/extensions/POST.js +1 -1
  70. package/dist/kempo/api/extensions/POST.js.map +1 -1
  71. package/dist/kempo/api/extensions/[name]/disable/POST.js +1 -1
  72. package/dist/kempo/api/extensions/[name]/disable/POST.js.map +1 -1
  73. package/dist/kempo/api/extensions/[name]/enable/POST.js +1 -1
  74. package/dist/kempo/api/extensions/[name]/enable/POST.js.map +1 -1
  75. package/dist/kempo/api/extensions/[name]/update/POST.js +1 -1
  76. package/dist/kempo/api/extensions/[name]/update/POST.js.map +1 -1
  77. package/dist/kempo/api/extensions/[name]/update-check/GET.js +1 -1
  78. package/dist/kempo/api/extensions/[name]/update-check/GET.js.map +1 -1
  79. package/dist/kempo/api/extensions/available/GET.js +1 -1
  80. package/dist/kempo/api/extensions/available/GET.js.map +1 -1
  81. package/dist/kempo/api/extensions/known/GET.js +1 -1
  82. package/dist/kempo/api/extensions/known/GET.js.map +1 -1
  83. package/dist/kempo/api/forgot-password/POST.js +1 -1
  84. package/dist/kempo/api/forgot-password/POST.js.map +1 -1
  85. package/dist/kempo/api/fragments/DELETE.js +1 -1
  86. package/dist/kempo/api/fragments/DELETE.js.map +1 -1
  87. package/dist/kempo/api/fragments/GET.js +1 -1
  88. package/dist/kempo/api/fragments/GET.js.map +1 -1
  89. package/dist/kempo/api/fragments/POST.js +1 -1
  90. package/dist/kempo/api/fragments/POST.js.map +1 -1
  91. package/dist/kempo/api/fragments/disable/PUT.js +1 -1
  92. package/dist/kempo/api/fragments/disable/PUT.js.map +1 -1
  93. package/dist/kempo/api/fragments/enable/PUT.js +1 -1
  94. package/dist/kempo/api/fragments/enable/PUT.js.map +1 -1
  95. package/dist/kempo/api/fragments/file/GET.js +1 -1
  96. package/dist/kempo/api/fragments/file/GET.js.map +1 -1
  97. package/dist/kempo/api/fragments/file/PATCH.js +1 -1
  98. package/dist/kempo/api/fragments/file/PATCH.js.map +1 -1
  99. package/dist/kempo/api/fragments/file/PUT.js +1 -1
  100. package/dist/kempo/api/fragments/file/PUT.js.map +1 -1
  101. package/dist/kempo/api/fragments/lock/PUT.js +2 -2
  102. package/dist/kempo/api/fragments/lock/PUT.js.map +1 -1
  103. package/dist/kempo/api/globals/DELETE.js +1 -1
  104. package/dist/kempo/api/globals/DELETE.js.map +1 -1
  105. package/dist/kempo/api/globals/GET.js +1 -1
  106. package/dist/kempo/api/globals/GET.js.map +1 -1
  107. package/dist/kempo/api/globals/POST.js +1 -1
  108. package/dist/kempo/api/globals/POST.js.map +1 -1
  109. package/dist/kempo/api/globals/disable/PUT.js +1 -1
  110. package/dist/kempo/api/globals/disable/PUT.js.map +1 -1
  111. package/dist/kempo/api/globals/enable/PUT.js +1 -1
  112. package/dist/kempo/api/globals/enable/PUT.js.map +1 -1
  113. package/dist/kempo/api/globals/entry/GET.js +1 -1
  114. package/dist/kempo/api/globals/entry/GET.js.map +1 -1
  115. package/dist/kempo/api/globals/entry/PUT.js +1 -1
  116. package/dist/kempo/api/globals/entry/PUT.js.map +1 -1
  117. package/dist/kempo/api/globals/lock/PUT.js +2 -2
  118. package/dist/kempo/api/globals/lock/PUT.js.map +1 -1
  119. package/dist/kempo/api/groups/DELETE.js +1 -1
  120. package/dist/kempo/api/groups/DELETE.js.map +1 -1
  121. package/dist/kempo/api/groups/GET.js +1 -1
  122. package/dist/kempo/api/groups/GET.js.map +1 -1
  123. package/dist/kempo/api/groups/PATCH.js +1 -1
  124. package/dist/kempo/api/groups/PATCH.js.map +1 -1
  125. package/dist/kempo/api/groups/POST.js +1 -1
  126. package/dist/kempo/api/groups/POST.js.map +1 -1
  127. package/dist/kempo/api/groups/[name]/GET.js +1 -1
  128. package/dist/kempo/api/groups/[name]/GET.js.map +1 -1
  129. package/dist/kempo/api/groups/[name]/members/DELETE.js +1 -1
  130. package/dist/kempo/api/groups/[name]/members/DELETE.js.map +1 -1
  131. package/dist/kempo/api/groups/[name]/members/GET.js +1 -1
  132. package/dist/kempo/api/groups/[name]/members/GET.js.map +1 -1
  133. package/dist/kempo/api/groups/[name]/members/POST.js +1 -1
  134. package/dist/kempo/api/groups/[name]/members/POST.js.map +1 -1
  135. package/dist/kempo/api/groups/[name]/permissions/DELETE.js +1 -1
  136. package/dist/kempo/api/groups/[name]/permissions/DELETE.js.map +1 -1
  137. package/dist/kempo/api/groups/[name]/permissions/GET.js +1 -1
  138. package/dist/kempo/api/groups/[name]/permissions/GET.js.map +1 -1
  139. package/dist/kempo/api/groups/[name]/permissions/POST.js +1 -1
  140. package/dist/kempo/api/groups/[name]/permissions/POST.js.map +1 -1
  141. package/dist/kempo/api/pages/DELETE.js +1 -1
  142. package/dist/kempo/api/pages/DELETE.js.map +1 -1
  143. package/dist/kempo/api/pages/GET.js +1 -1
  144. package/dist/kempo/api/pages/GET.js.map +1 -1
  145. package/dist/kempo/api/pages/POST.js +1 -1
  146. package/dist/kempo/api/pages/POST.js.map +1 -1
  147. package/dist/kempo/api/pages/directories/GET.js +1 -1
  148. package/dist/kempo/api/pages/directories/GET.js.map +1 -1
  149. package/dist/kempo/api/pages/disable/PUT.js +1 -1
  150. package/dist/kempo/api/pages/disable/PUT.js.map +1 -1
  151. package/dist/kempo/api/pages/enable/PUT.js +1 -1
  152. package/dist/kempo/api/pages/enable/PUT.js.map +1 -1
  153. package/dist/kempo/api/pages/file/GET.js +1 -1
  154. package/dist/kempo/api/pages/file/GET.js.map +1 -1
  155. package/dist/kempo/api/pages/file/PATCH.js +1 -1
  156. package/dist/kempo/api/pages/file/PATCH.js.map +1 -1
  157. package/dist/kempo/api/pages/file/PUT.js +1 -1
  158. package/dist/kempo/api/pages/file/PUT.js.map +1 -1
  159. package/dist/kempo/api/pages/lock/PUT.js +2 -2
  160. package/dist/kempo/api/pages/lock/PUT.js.map +1 -1
  161. package/dist/kempo/api/pages/search/GET.js +2 -2
  162. package/dist/kempo/api/pages/search/GET.js.map +1 -1
  163. package/dist/kempo/api/pages/templates/GET.js +1 -1
  164. package/dist/kempo/api/pages/templates/GET.js.map +1 -1
  165. package/dist/kempo/api/permissions/DELETE.js +1 -1
  166. package/dist/kempo/api/permissions/DELETE.js.map +1 -1
  167. package/dist/kempo/api/permissions/GET.js +1 -1
  168. package/dist/kempo/api/permissions/GET.js.map +1 -1
  169. package/dist/kempo/api/permissions/PATCH.js +1 -1
  170. package/dist/kempo/api/permissions/PATCH.js.map +1 -1
  171. package/dist/kempo/api/permissions/POST.js +1 -1
  172. package/dist/kempo/api/permissions/POST.js.map +1 -1
  173. package/dist/kempo/api/settings/[owner]/GET.js +1 -1
  174. package/dist/kempo/api/settings/[owner]/GET.js.map +1 -1
  175. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js +1 -1
  176. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js.map +1 -1
  177. package/dist/kempo/api/settings/[owner]/[name]/GET.js +1 -1
  178. package/dist/kempo/api/settings/[owner]/[name]/GET.js.map +1 -1
  179. package/dist/kempo/api/settings/[owner]/[name]/POST.js +1 -1
  180. package/dist/kempo/api/settings/[owner]/[name]/POST.js.map +1 -1
  181. package/dist/kempo/api/settings/public/GET.js +1 -1
  182. package/dist/kempo/api/settings/public/GET.js.map +1 -1
  183. package/dist/kempo/api/templates/DELETE.js +1 -1
  184. package/dist/kempo/api/templates/DELETE.js.map +1 -1
  185. package/dist/kempo/api/templates/GET.js +1 -1
  186. package/dist/kempo/api/templates/GET.js.map +1 -1
  187. package/dist/kempo/api/templates/POST.js +1 -1
  188. package/dist/kempo/api/templates/POST.js.map +1 -1
  189. package/dist/kempo/api/templates/disable/PUT.js +1 -1
  190. package/dist/kempo/api/templates/disable/PUT.js.map +1 -1
  191. package/dist/kempo/api/templates/enable/PUT.js +1 -1
  192. package/dist/kempo/api/templates/enable/PUT.js.map +1 -1
  193. package/dist/kempo/api/templates/file/GET.js +1 -1
  194. package/dist/kempo/api/templates/file/GET.js.map +1 -1
  195. package/dist/kempo/api/templates/file/PATCH.js +1 -1
  196. package/dist/kempo/api/templates/file/PATCH.js.map +1 -1
  197. package/dist/kempo/api/templates/file/PUT.js +1 -1
  198. package/dist/kempo/api/templates/file/PUT.js.map +1 -1
  199. package/dist/kempo/api/templates/lock/PUT.js +2 -2
  200. package/dist/kempo/api/templates/lock/PUT.js.map +1 -1
  201. package/dist/kempo/api/user/DELETE.js +1 -1
  202. package/dist/kempo/api/user/DELETE.js.map +1 -1
  203. package/dist/kempo/api/user/GET.js +1 -1
  204. package/dist/kempo/api/user/GET.js.map +1 -1
  205. package/dist/kempo/api/user/PATCH.js +1 -1
  206. package/dist/kempo/api/user/PATCH.js.map +1 -1
  207. package/dist/kempo/api/user/[userid]/GET.js +1 -1
  208. package/dist/kempo/api/user/[userid]/GET.js.map +1 -1
  209. package/dist/kempo/api/user/[userid]/groups/DELETE.js +1 -1
  210. package/dist/kempo/api/user/[userid]/groups/DELETE.js.map +1 -1
  211. package/dist/kempo/api/user/[userid]/groups/GET.js +1 -1
  212. package/dist/kempo/api/user/[userid]/groups/GET.js.map +1 -1
  213. package/dist/kempo/api/user/[userid]/groups/POST.js +1 -1
  214. package/dist/kempo/api/user/[userid]/groups/POST.js.map +1 -1
  215. package/dist/kempo/api/user/[userid]/permissions/GET.js +1 -1
  216. package/dist/kempo/api/user/[userid]/permissions/GET.js.map +1 -1
  217. package/dist/kempo/api/user/[userid]/permissions/all/GET.js +1 -1
  218. package/dist/kempo/api/user/[userid]/permissions/all/GET.js.map +1 -1
  219. package/dist/kempo/api/user/[userid]/permissions/list/GET.js +1 -1
  220. package/dist/kempo/api/user/[userid]/permissions/list/GET.js.map +1 -1
  221. package/dist/kempo/api/user/[userid]/permissions/some/GET.js +1 -1
  222. package/dist/kempo/api/user/[userid]/permissions/some/GET.js.map +1 -1
  223. package/dist/kempo/api/user/[userid]/sessions/DELETE.js +1 -1
  224. package/dist/kempo/api/user/[userid]/sessions/DELETE.js.map +1 -1
  225. package/dist/kempo/api/user/[userid]/sessions/GET.js +1 -1
  226. package/dist/kempo/api/user/[userid]/sessions/GET.js.map +1 -1
  227. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js +1 -1
  228. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js.map +1 -1
  229. package/dist/kempo/api/user/create/POST.js +1 -1
  230. package/dist/kempo/api/user/create/POST.js.map +1 -1
  231. package/dist/kempo/api/user/search/GET.js +1 -1
  232. package/dist/kempo/api/user/search/GET.js.map +1 -1
  233. package/dist/kempo/components/LogoutBtn.js +1 -1
  234. package/dist/kempo/components/LogoutBtn.js.map +1 -1
  235. package/dist/kempo/components/Menu.js +9 -9
  236. package/dist/kempo/components/Menu.js.map +1 -1
  237. package/dist/kempo/components/Permission.js +1 -1
  238. package/dist/kempo/components/Permission.js.map +1 -1
  239. package/dist/kempo/components/Role.js +1 -1
  240. package/dist/kempo/components/Role.js.map +1 -1
  241. package/dist/kempo/components/UserCreatedAt.js +1 -1
  242. package/dist/kempo/components/UserCreatedAt.js.map +1 -1
  243. package/dist/kempo/components/UserEmail.js +1 -1
  244. package/dist/kempo/components/UserEmail.js.map +1 -1
  245. package/dist/kempo/components/UserEmailVerified.js +1 -1
  246. package/dist/kempo/components/UserEmailVerified.js.map +1 -1
  247. package/dist/kempo/components/UserName.js +1 -1
  248. package/dist/kempo/components/UserName.js.map +1 -1
  249. package/dist/kempo/fetch.js +1 -1
  250. package/dist/kempo/fetch.js.map +1 -1
  251. package/dist/kempo/sdk.js +1 -1
  252. package/dist/kempo/sdk.js.map +1 -1
  253. package/middleware/kempo.js +36 -6
  254. package/package.json +2 -2
  255. package/server/utils/extensions/installExtension.js +19 -13
  256. package/server/utils/extensions/uninstallExtension.js +6 -10
  257. package/server/utils/pages/deletePage.js +2 -10
  258. package/dist/admin/accounts/groups/[name]/index.html +0 -518
  259. package/dist/admin/accounts/groups/index.html +0 -378
  260. package/dist/admin/accounts/permissions/index.html +0 -397
  261. package/dist/admin/accounts/users/[id]/index.html +0 -541
  262. package/dist/admin/accounts/users/index.html +0 -396
  263. package/dist/admin/content/fragments/edit/index.html +0 -132
  264. package/dist/admin/content/fragments/index.html +0 -375
  265. package/dist/admin/content/globals/edit/index.html +0 -132
  266. package/dist/admin/content/globals/index.html +0 -358
  267. package/dist/admin/content/pages/edit/index.html +0 -132
  268. package/dist/admin/content/pages/index.html +0 -509
  269. package/dist/admin/content/templates/edit/index.html +0 -132
  270. package/dist/admin/content/templates/index.html +0 -429
  271. package/dist/admin/extensions/index.html +0 -222
  272. package/dist/admin/index.html +0 -130
  273. package/dist/admin/settings/[owner]/[name]/index.html +0 -449
  274. package/dist/admin/settings/index.html +0 -410
@@ -1,13 +1,13 @@
1
- import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html,repeat}from"/kempo-ui/lit-all.min.js";import{getPage,updatePage,listTemplates,deletePages,listDirectories,movePage}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/HtmlEditor.js";const CODE_MODE_LOCATIONS=new Set(["head","scripts"]),slugify=e=>e.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");export default class PageEditor extends ShadowComponent{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},page:{state:!0},templates:{state:!0},contents:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.page=null,this.templates=[],this.contents=[],this.file=""}async connectedCallback(){if(super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown),this.file=new URLSearchParams(window.location.search).get("path")+".page.html",!this.file||".page.html"===this.file)return this.loading=!1,void(this.error=!0);const[[e,t],[,a]]=await Promise.all([getPage(this.file),listTemplates()]);this.loading=!1,e?this.error=!0:(this.templates=a?.templates||[],this.page=t,this.contents=this.buildContents(t.template,t.contents),document.title=`Edit: ${t.name||t.title||this.file} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}getPageUrl(){return"/"+this.file.replace(/\.page\.html$/,"").split("/").filter(Boolean).join("/")}buildContents(e,t){const a=this.templates.find(t=>t.name===e),l=(a?.locations||[{name:"default",label:null}]).map(e=>"string"==typeof e?{name:e,label:null}:e),i=l.map(({name:e,label:a})=>{const l=t.find(t=>t.location===e);return{location:e,label:a||null,content:l?.content||"",orphaned:!1}});for(const e of t)l.some(t=>t.name===e.location)||i.push({location:e.location,label:null,content:e.content,orphaned:!0});return i}getFormState(){const e=this.shadowRoot,t=new Map([...e.querySelectorAll("k-html-editor[data-location]")].map(e=>[e.dataset.location,e.getValue()]));return{name:e.querySelector("#metaName").value,title:e.querySelector("#metaTitle").value,description:e.querySelector("#metaDescription").value,template:e.querySelector("#metaTemplate").value,contents:this.contents.map(({location:e,content:a,orphaned:l})=>({location:e,content:l?t.get(e)?.trim()||a:t.get(e)??a}))}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.page?.locked||this.handleSave())};handleTemplateChange=e=>{const t=e.target.value,a=new Map([...this.shadowRoot.querySelectorAll("k-html-editor[data-location]")].map(e=>[e.dataset.location,e.getValue()])),l=this.contents.map(({location:e,content:t})=>({location:e,content:a.get(e)?.trim()||t}));this.contents=this.buildContents(t,l),this.page={...this.page,template:t}};handleDelete=()=>{Dialog.confirm("Delete this page? This action cannot be undone.",async e=>{if(!e)return;const[t]=await deletePages([this.file]);t?Toast.error(t.msg||"Failed to delete page"):(Toast.success("Page deleted"),setTimeout(()=>{window.location.href="/admin/pages"},1e3))})};handleMove=async()=>{const[,e]=await listDirectories(),t=e?.directories||["."],a=this.file.replace(/\.page\.html$/,"").split("/"),l=a.pop(),i=a.join("/")||".",s=e=>/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(e)&&!e.includes("..")&&!e.includes("//"),n=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",o="."===i?"/":"/"+i,r=Dialog.create(html`
1
+ import e from"/kempo-ui/components/ShadowComponent.js";import{html as t,repeat as a}from"/kempo-ui/lit-all.min.js";import{getPage as n,updatePage as s,listTemplates as i,deletePages as l,listDirectories as o,movePage as r}from"/kempo/sdk.js";import c from"/kempo-ui/components/Dialog.js";import d from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";import"/kempo-ui/components/Accordion.js";import"/kempo-ui/components/HtmlEditor.js";const m=new Set(["head","scripts"]),p=e=>e.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");export default class g extends e{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},page:{state:!0},templates:{state:!0},contents:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.page=null,this.templates=[],this.contents=[],this.file=""}async connectedCallback(){if(super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown),this.file=new URLSearchParams(window.location.search).get("path")+".page.html",!this.file||".page.html"===this.file)return this.loading=!1,void(this.error=!0);const[[e,t],[,a]]=await Promise.all([n(this.file),i()]);this.loading=!1,e?this.error=!0:(this.templates=a?.templates||[],this.page=t,this.contents=this.buildContents(t.template,t.contents),document.title=`Edit: ${t.name||t.title||this.file} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}getPageUrl(){return"/"+this.file.replace(/\.page\.html$/,"").split("/").filter(Boolean).join("/")}buildContents(e,t){const a=this.templates.find(t=>t.name===e),n=(a?.locations||[{name:"default",label:null}]).map(e=>"string"==typeof e?{name:e,label:null}:e),s=n.map(({name:e,label:a})=>{const n=t.find(t=>t.location===e);return{location:e,label:a||null,content:n?.content||"",orphaned:!1}});for(const e of t)n.some(t=>t.name===e.location)||s.push({location:e.location,label:null,content:e.content,orphaned:!0});return s}getFormState(){const e=this.shadowRoot,t=new Map([...e.querySelectorAll("k-html-editor[data-location]")].map(e=>[e.dataset.location,e.getValue()]));return{name:e.querySelector("#metaName").value,title:e.querySelector("#metaTitle").value,description:e.querySelector("#metaDescription").value,template:e.querySelector("#metaTemplate").value,contents:this.contents.map(({location:e,content:a,orphaned:n})=>({location:e,content:n?t.get(e)?.trim()||a:t.get(e)??a}))}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.page?.locked||this.handleSave())};handleTemplateChange=e=>{if(this.page?.locked)return;const t=e.target.value,a=new Map([...this.shadowRoot.querySelectorAll("k-html-editor[data-location]")].map(e=>[e.dataset.location,e.getValue()])),n=this.contents.map(({location:e,content:t})=>({location:e,content:a.get(e)?.trim()||t}));this.contents=this.buildContents(t,n),this.page={...this.page,template:t}};handleDelete=()=>{c.confirm("Delete this page? This action cannot be undone.",async e=>{if(!e)return;const[t]=await l([this.file]);t?d.error(t.msg||"Failed to delete page"):(d.success("Page deleted"),setTimeout(()=>{window.location.href="/admin/pages"},1e3))})};handleMove=async()=>{const[,e]=await o(),a=e?.directories||["."],n=this.file.replace(/\.page\.html$/,"").split("/"),i=n.pop(),l=n.join("/")||".",m=e=>/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(e)&&!e.includes("..")&&!e.includes("//"),g=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",h="."===l?"/":"/"+l,u=c.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="${o}" placeholder="/">
5
+ <input type="text" id="dlg-move-dir" class="full" list="dlg-move-dir-list" .value="${h}" 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
  <p id="dlg-move-dir-error" class="mt-sm tc-danger d-n"><small>Invalid path — use format: /path/to/directory</small></p>
10
- <p class="mt-sm muted"><small>Supports dynamic segments e.g. <code>/blog/[slug]</code>. <button class="link" @click="${()=>Dialog.alert(html`
10
+ <p class="mt-sm muted"><small>Supports dynamic segments e.g. <code>/blog/[slug]</code>. <button class="link" @click="${()=>c.alert(t`
11
11
  <div class="p">
12
12
  <p>Directory paths define where a page lives in the URL structure.</p>
13
13
  <p><strong>Examples:</strong></p>
@@ -23,19 +23,19 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
23
23
  </div>
24
24
  <div>
25
25
  <label class="d-b mb-sm"><strong>Page Name</strong></label>
26
- <input type="text" id="dlg-move-name" class="full" .value="${l}">
26
+ <input type="text" id="dlg-move-name" class="full" .value="${i}">
27
27
  <p class="mt-sm muted"><small id="dlg-move-preview"></small></p>
28
28
  </div>
29
29
  </div>
30
- `,{title:"Move Page",confirmText:"Save and Move Page",confirmAction:async()=>{const e=r.querySelector("#dlg-move-dir").value.trim()||"/",t=slugify(r.querySelector("#dlg-move-name").value.trim());if(!t)return void Toast.error("Page name is required");if(!s(e))return void Toast.error("Invalid directory path");const a=n(e),l="."===a?`${t}.page.html`:`${a}/${t}.page.html`;this.saving=!0;const[i]=await updatePage({file:this.file,...this.getFormState()});if(this.saving=!1,i)return void Toast.error(i.msg||"Failed to save page");const[o,c]=await movePage({file:this.file,newFile:l});o?Toast.error(o.msg||"Failed to move page"):(Toast.success("Page saved and moved"),setTimeout(()=>{window.location.href=`/admin/pages/edit?path=${encodeURIComponent(c.file.replace(/\.page\.html$/,""))}`},1e3))},cancelText:"Cancel"}),c=()=>{const e=n(r.querySelector("#dlg-move-dir").value||"/"),t=slugify(r.querySelector("#dlg-move-name").value),a="."===e?"/":"/"+e+"/";r.querySelector("#dlg-move-preview").textContent=t?a+t:""};r.querySelector("#dlg-move-dir").addEventListener("input",e=>{r.querySelector("#dlg-move-dir-error").classList.toggle("d-n",s(e.target.value||"/")),c()}),r.querySelector("#dlg-move-name").addEventListener("input",c),c()};handleReset=()=>{Dialog.confirm("Reset this page? Any unsaved changes will be lost.",e=>{e&&(this.contents=this.buildContents(this.page.template,this.page.contents),this.page={...this.page})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await updatePage({file:this.file,...e});this.saving=!1,t?Toast.error(t.msg||"Failed to save page"):(this.contents=this.contents.map(t=>{const a=e.contents.find(e=>e.location===t.location);return a?{...t,content:a.content}:t}),this.page={...this.page,...e,contents:e.contents.filter(e=>e.content.trim()),updatedAt:a.updatedAt},document.title=`Edit: ${e.name||e.title||this.file} - Admin`,Toast.success("Page saved"))};render(){if(this.loading)return html`<div>Loading page...</div>`;if(this.error)return html`
30
+ `,{title:"Move Page",confirmText:"Save and Move Page",confirmAction:async()=>{const e=u.querySelector("#dlg-move-dir").value.trim()||"/",t=p(u.querySelector("#dlg-move-name").value.trim());if(!t)return void d.error("Page name is required");if(!m(e))return void d.error("Invalid directory path");const a=g(e),n="."===a?`${t}.page.html`:`${a}/${t}.page.html`;this.saving=!0;const[i]=await s({file:this.file,...this.getFormState()});if(this.saving=!1,i)return void d.error(i.msg||"Failed to save page");const[l,o]=await r({file:this.file,newFile:n});l?d.error(l.msg||"Failed to move page"):(d.success("Page saved and moved"),setTimeout(()=>{window.location.href=`/admin/pages/edit?path=${encodeURIComponent(o.file.replace(/\.page\.html$/,""))}`},1e3))},cancelText:"Cancel"}),v=()=>{const e=g(u.querySelector("#dlg-move-dir").value||"/"),t=p(u.querySelector("#dlg-move-name").value),a="."===e?"/":"/"+e+"/";u.querySelector("#dlg-move-preview").textContent=t?a+t:""};u.querySelector("#dlg-move-dir").addEventListener("input",e=>{u.querySelector("#dlg-move-dir-error").classList.toggle("d-n",m(e.target.value||"/")),v()}),u.querySelector("#dlg-move-name").addEventListener("input",v),v()};handleReset=()=>{c.confirm("Reset this page? Any unsaved changes will be lost.",e=>{e&&(this.contents=this.buildContents(this.page.template,this.page.contents),this.page={...this.page})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await s({file:this.file,...e});this.saving=!1,t?d.error(t.msg||"Failed to save page"):(this.contents=this.contents.map(t=>{const a=e.contents.find(e=>e.location===t.location);return a?{...t,content:a.content}:t}),this.page={...this.page,...e,contents:e.contents.filter(e=>e.content.trim()),updatedAt:a.updatedAt},document.title=`Edit: ${e.name||e.title||this.file} - Admin`,d.success("Page saved"))};render(){if(this.loading)return t`<div>Loading page...</div>`;if(this.error)return t`
31
31
  <div>
32
32
  <p>Page not found.</p>
33
33
  <a href="/admin/pages">Back to Pages</a>
34
34
  </div>
35
- `;const{page:e,templates:t,contents:a}=this,l="system"===e.owner,i=e.locked;return html`
36
- ${i?html`
35
+ `;const{page:e,templates:n,contents:s}=this,i="system"===e.owner,l=e.locked;return t`
36
+ ${l?t`
37
37
  <div class="p r mb bc-warning tc-warning">
38
- <k-icon name="lock"></k-icon> This page is locked and cannot be edited. It is managed by an extension.
38
+ <k-icon name="lock"></k-icon> This page is locked and cannot be edited. ${"custom"===e.owner?"Locked by developer":`Managed by: ${e.owner||"external system"}`}
39
39
  </div>
40
40
  `:""}
41
41
  <div class="d-f mb">
@@ -49,13 +49,13 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
49
49
  </div>
50
50
 
51
51
  <div class="flex"></div>
52
- ${l||i?"":html`
52
+ ${i||l?"":t`
53
53
  <div class="btn-grp mrh mb">
54
54
  <button class="danger" @click="${this.handleDelete}"><k-icon name="delete"></k-icon> Delete</button>
55
55
  <button @click="${this.handleMove}"><k-icon name="drive_file_move"></k-icon> Move Page</button>
56
56
  </div>
57
57
  `}
58
- ${i?"":html`
58
+ ${l?"":t`
59
59
  <div class="btn-grp mrh mb">
60
60
  <button @click="${this.handleReset}"><k-icon name="restart_alt"></k-icon> Reset</button>
61
61
  <button id="saveBtn" class="primary" ?disabled="${this.saving}" @click="${this.handleSave}">
@@ -74,17 +74,17 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
74
74
  <div class="p">
75
75
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
76
76
  <label style="min-width: 120px;"><strong>Name</strong></label>
77
- <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${l||i}">
77
+ <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${i||l}">
78
78
  </div>
79
79
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
80
80
  <label style="min-width: 120px;"><strong>Title</strong></label>
81
- <input type="text" id="metaTitle" class="flex" .value="${e.title||""}" ?disabled="${i}">
81
+ <input type="text" id="metaTitle" class="flex" .value="${e.title||""}" ?disabled="${l}">
82
82
  </div>
83
83
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
84
84
  <label style="min-width: 120px;"><strong>Description</strong></label>
85
- <input type="text" id="metaDescription" class="flex" .value="${e.description||""}" ?disabled="${l||i}">
85
+ <input type="text" id="metaDescription" class="flex" .value="${e.description||""}" ?disabled="${i||l}">
86
86
  </div>
87
- ${l?"":html`
87
+ ${i?"":t`
88
88
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
89
89
  <label style="min-width: 120px;"><strong>Author</strong></label>
90
90
  <span class="muted">${e.author||""}</span>
@@ -92,11 +92,11 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
92
92
  `}
93
93
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
94
94
  <label style="min-width: 120px;"><strong>Template</strong></label>
95
- ${(()=>{const a=this.file.replace(/\.page\.html$/,"").split("/").slice(0,-1).join("/")||".",l=t.filter(e=>{const t="."===e.directory?"":e.directory,l="."===a?"":a;return""===t||l===t||l.startsWith(t+"/")}),s=l.some(t=>t.name===e.template);return html`
96
- <select id="metaTemplate" class="flex" @change="${this.handleTemplateChange}" ?disabled="${i}">
97
- ${s?"":html`<option value="${e.template}" selected>${e.template} (Not Found, using default)</option>`}
98
- ${l.map(t=>html`
99
- <option value="${t.name}" ?selected="${t.name===e.template}">${(e=>"."===e.directory?`/${e.name}`:`/${e.directory}/${e.name}`)(t)}</option>
95
+ ${(()=>{const a=this.file.replace(/\.page\.html$/,"").split("/").slice(0,-1).join("/")||".",s=n.filter(e=>{const t="."===e.directory?"":e.directory,n="."===a?"":a;return""===t||n===t||n.startsWith(t+"/")}),i=s.some(t=>t.name===e.template);return t`
96
+ <select id="metaTemplate" class="flex" @change="${this.handleTemplateChange}" ?disabled="${l}">
97
+ ${i?"":t`<option value="${e.template}" selected>${e.template} (Not Found, using default)</option>`}
98
+ ${s.map(a=>t`
99
+ <option value="${a.name}" ?selected="${a.name===e.template}">${(e=>"."===e.directory?`/${e.name}`:`/${e.directory}/${e.name}`)(a)}</option>
100
100
  `)}
101
101
  </select>
102
102
  `})()}
@@ -115,24 +115,38 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
115
115
  </div>
116
116
  </div>
117
117
  </k-accordion-panel>
118
- ${repeat(a,e=>e.location,({location:e,label:t,content:a,orphaned:l})=>{const s="default"===e,n=t||(s?"Content":e.slice(0,1).toUpperCase()+e.slice(1));return html`
119
- <k-accordion-header for-panel="content-${e}" ?active="${s}">
120
- ${n}${l?html` <span class="tc-warning"><small>(not in template)</small></span>`:""}
118
+ ${Object.keys(e.extraMetadata||{}).length?t`
119
+ <k-accordion-header for-panel="extra-metadata">Extra Metadata</k-accordion-header>
120
+ <k-accordion-panel name="extra-metadata">
121
+ <div class="p">
122
+ ${Object.entries(e.extraMetadata).map(([e,a])=>t`
123
+ <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
124
+ <label style="min-width: 120px;" class="muted"><strong>${e}</strong></label>
125
+ <span>${a}</span>
126
+ </div>
127
+ `)}
128
+ <p class="muted mt0"><small>Extra metadata is managed by extensions and cannot be edited here.</small></p>
129
+ </div>
130
+ </k-accordion-panel>
131
+ `:""}
132
+ ${a(s,e=>e.location,({location:e,label:a,content:n,orphaned:s})=>{const i="default"===e,o=a||(i?"Content":e.slice(0,1).toUpperCase()+e.slice(1));return t`
133
+ <k-accordion-header for-panel="content-${e}" ?active="${i}">
134
+ ${o}${s?t` <span class="tc-warning"><small>(not in template)</small></span>`:""}
121
135
  </k-accordion-header>
122
- <k-accordion-panel name="content-${e}" ?active="${s}">
136
+ <k-accordion-panel name="content-${e}" ?active="${i}">
123
137
  <div class="p">
124
138
  <k-html-editor
125
139
  class="r b"
126
140
  data-location="${e}"
127
141
  controls="full"
128
- .value="${a}"
129
- mode="${CODE_MODE_LOCATIONS.has(e)?"code":"visual"}"
142
+ .value="${n}"
143
+ mode="${m.has(e)?"code":"visual"}"
130
144
  style="height: 400px;"
131
- ?disabled="${i}"
145
+ ?disabled="${l}"
132
146
  ></k-html-editor>
133
147
  </div>
134
148
  </k-accordion-panel>
135
149
  `})}
136
150
  </k-accordion>
137
- `}}customElements.define("admin-page-editor",PageEditor);
151
+ `}}customElements.define("admin-page-editor",g);
138
152
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\PageEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\PageEditor.js","names":["ShadowComponent","html","repeat","getPage","updatePage","listTemplates","deletePages","listDirectories","movePage","Dialog","Toast","CODE_MODE_LOCATIONS","Set","slugify","name","toLowerCase","trim","replace","PageEditor","static","loading","state","error","saving","page","templates","contents","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","URLSearchParams","window","location","search","get","err","tmplData","Promise","all","buildContents","template","title","disconnectedCallback","removeEventListener","getPageUrl","split","filter","Boolean","join","templateName","existingContents","tmpl","find","t","locations","label","map","l","result","block","b","content","orphaned","some","push","getFormState","root","shadowRoot","editorMap","Map","querySelectorAll","ed","dataset","getValue","querySelector","value","description","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleTemplateChange","newTemplate","target","currentContents","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","currentName","pop","currentDir","isValidDir","p","test","includes","dirToInternal","currentDirDisplay","$dialog","create","d","alert","confirmText","confirmAction","dirInput","newName","newDir","newFile","saveError","moveError","moved","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","classList","toggle","handleReset","saved","c","current","x","updatedAt","render","isSystem","owner","isLocked","author","pageDir","slice","reachable","tDir","directory","pDir","startsWith","currentFound","templateLabel","createdAt","Date","toLocaleString","isDefault","headerTitle","toUpperCase","has","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html, repeat } from '/kempo-ui/lit-all.min.js';\nimport { getPage, updatePage, listTemplates, deletePages, listDirectories, movePage } 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/HtmlEditor.js';\n\nconst CODE_MODE_LOCATIONS = new Set(['head', 'scripts']);\n\nconst slugify = name => name\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n\nexport default class PageEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n page: { state: true },\n templates: { state: true },\n contents: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.page = null;\n this.templates = [];\n this.contents = [];\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n this.file = new URLSearchParams(window.location.search).get('path') + '.page.html';\n\n if (!this.file || this.file === '.page.html') {\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [[err, page], [, tmplData]] = await Promise.all([\n getPage(this.file),\n listTemplates()\n ]);\n\n this.loading = false;\n\n if (err) {\n this.error = true;\n return;\n }\n\n this.templates = tmplData?.templates || [];\n this.page = page;\n this.contents = this.buildContents(page.template, page.contents);\n document.title = `Edit: ${page.name || page.title || this.file} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getPageUrl() {\n const path = this.file.replace(/\\.page\\.html$/, '');\n return '/' + path.split('/').filter(Boolean).join('/');\n }\n\n buildContents(templateName, existingContents) {\n const tmpl = this.templates.find(t => t.name === templateName);\n const raw = tmpl?.locations || [{ name: 'default', label: null }];\n const locations = raw.map(l => typeof l === 'string' ? { name: l, label: null } : l);\n const result = locations.map(({ name, label }) => {\n const block = existingContents.find(b => b.location === name);\n return { location: name, label: label || null, content: block?.content || '', orphaned: false };\n });\n for (const block of existingContents) {\n if (!locations.some(l => l.name === block.location))\n result.push({ location: block.location, label: null, content: block.content, orphaned: true });\n }\n return result;\n }\n\n getFormState() {\n const root = this.shadowRoot;\n const editorMap = new Map(\n [...root.querySelectorAll('k-html-editor[data-location]')].map(ed => [ed.dataset.location, ed.getValue()])\n );\n return {\n name: root.querySelector('#metaName').value,\n title: root.querySelector('#metaTitle').value,\n description: root.querySelector('#metaDescription').value,\n template: root.querySelector('#metaTemplate').value,\n contents: this.contents.map(({ location, content, orphaned }) => ({\n location,\n content: orphaned\n ? (editorMap.get(location)?.trim() || content)\n : (editorMap.get(location) ?? content)\n }))\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.page?.locked) this.handleSave();\n }\n };\n\n handleTemplateChange = e => {\n const newTemplate = e.target.value;\n const editorMap = new Map(\n [...this.shadowRoot.querySelectorAll('k-html-editor[data-location]')].map(ed => [ed.dataset.location, ed.getValue()])\n );\n // Fall back to state content for any editor that hasn't initialized (Monaco lazy-loads)\n const currentContents = this.contents.map(({ location, content }) => ({\n location,\n content: editorMap.get(location)?.trim() || content\n }));\n this.contents = this.buildContents(newTemplate, currentContents);\n this.page = { ...this.page, template: newTemplate };\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this page? This action cannot be undone.', async confirmed => {\n if (!confirmed) return;\n const [error] = await deletePages([this.file]);\n if (error) {\n Toast.error(error.msg || 'Failed to delete page');\n return;\n }\n Toast.success('Page deleted');\n setTimeout(() => { window.location.href = '/admin/pages'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.page\\.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 openLearnMore = () => Dialog.alert(html`\n <div class=\"p\">\n <p>Directory paths define where a page lives in the URL structure.</p>\n <p><strong>Examples:</strong></p>\n <ul>\n <li><code>/</code> — root, e.g. <code>/about</code></li>\n <li><code>/blog</code> — e.g. <code>/blog/my-post</code></li>\n <li><code>/blog/[slug]</code> — dynamic segment; <code>[slug]</code> matches any value</li>\n </ul>\n <p>Dynamic segments like <code>[token]</code> allow a single page to handle many URLs. The segment name is available to the page as a URL parameter.</p>\n <p>You can nest segments: <code>/store/[category]/[id]</code></p>\n </div>\n `, null, { title: 'About Directory Paths' });\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 <p id=\"dlg-move-dir-error\" class=\"mt-sm tc-danger d-n\"><small>Invalid path — use format: /path/to/directory</small></p>\n <p class=\"mt-sm muted\"><small>Supports dynamic segments e.g. <code>/blog/[slug]</code>. <button class=\"link\" @click=\"${openLearnMore}\">Learn more</button></small></p>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Page 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 Page',\n confirmText: 'Save and Move Page',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = slugify($dialog.querySelector('#dlg-move-name').value.trim());\n if (!newName) {\n Toast.error('Page 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}.page.html`\n : `${newDir}/${newName}.page.html`;\n\n this.saving = true;\n const [saveError] = await updatePage({ file: this.file, ...this.getFormState() });\n this.saving = false;\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save page');\n return;\n }\n\n const [moveError, moved] = await movePage({ file: this.file, newFile });\n if (moveError) {\n Toast.error(moveError.msg || 'Failed to move page');\n return;\n }\n\n Toast.success('Page saved and moved');\n setTimeout(() => {\n window.location.href = `/admin/pages/edit?path=${encodeURIComponent(moved.file.replace(/\\.page\\.html$/, ''))}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = slugify($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', e => {\n $dialog.querySelector('#dlg-move-dir-error').classList.toggle('d-n', isValidDir(e.target.value || '/'));\n updatePreview();\n });\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this page? Any unsaved changes will be lost.', confirmed => {\n if (!confirmed) return;\n this.contents = this.buildContents(this.page.template, this.page.contents);\n this.page = { ...this.page };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updatePage({ file: this.file, ...state });\n this.saving = false;\n\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save page');\n return;\n }\n\n this.contents = this.contents.map(c => {\n const current = state.contents.find(x => x.location === c.location);\n return current ? { ...c, content: current.content } : c;\n });\n this.page = {\n ...this.page,\n ...state,\n contents: state.contents.filter(b => b.content.trim()),\n updatedAt: saved.updatedAt\n };\n\n document.title = `Edit: ${state.name || state.title || this.file} - Admin`;\n Toast.success('Page saved');\n };\n\n /*\n Render\n */\n\n render() {\n if (this.loading) return html`<div>Loading page...</div>`;\n\n if (this.error) return html`\n <div>\n <p>Page not found.</p>\n <a href=\"/admin/pages\">Back to Pages</a>\n </div>\n `;\n\n const { page, templates, contents } = this;\n const isSystem = page.owner === 'system';\n const isLocked = page.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 page is locked and cannot be edited. It is managed by an extension.\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/pages\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Pages\n </a>\n <a href=\"${this.getPageUrl()}\" id=\"page-link\" class=\"btn\">\n <k-icon name=\"visibility\"></k-icon> View Page\n </a>\n </div>\n \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 <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Page</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=\"mb0\">Page: ${page.name || page.title || this.file}</h1>\n\n <a href=\"${this.getPageUrl()}\" class=\"d-b mb\"><code>${this.getPageUrl()}</code></a>\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=\"${page.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>Title</strong></label>\n <input type=\"text\" id=\"metaTitle\" class=\"flex\" .value=\"${page.title || ''}\" ?disabled=\"${isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Description</strong></label>\n <input type=\"text\" id=\"metaDescription\" class=\"flex\" .value=\"${page.description || ''}\" ?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\">${page.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>Template</strong></label>\n ${(() => {\n const pageDir = this.file.replace(/\\.page\\.html$/, '').split('/').slice(0, -1).join('/') || '.';\n const reachable = templates.filter(t => {\n const tDir = t.directory === '.' ? '' : t.directory;\n const pDir = pageDir === '.' ? '' : pageDir;\n return tDir === '' || pDir === tDir || pDir.startsWith(tDir + '/');\n });\n const templateLabel = t => t.directory === '.' ? `/${t.name}` : `/${t.directory}/${t.name}`;\n const currentFound = reachable.some(t => t.name === page.template);\n return html`\n <select id=\"metaTemplate\" class=\"flex\" @change=\"${this.handleTemplateChange}\" ?disabled=\"${isLocked}\">\n ${!currentFound ? html`<option value=\"${page.template}\" selected>${page.template} (Not Found, using default)</option>` : ''}\n ${reachable.map(t => html`\n <option value=\"${t.name}\" ?selected=\"${t.name === page.template}\">${templateLabel(t)}</option>\n `)}\n </select>\n `;\n })()}\n </div>\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\">${page.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\">${page.createdAt ? new Date(page.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\">${page.updatedAt ? new Date(page.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n ${repeat(contents, c => c.location, ({ location, label, content, orphaned }) => {\n const isDefault = location === 'default';\n const headerTitle = label || (isDefault ? 'Content' : location.slice(0, 1).toUpperCase() + location.slice(1));\n return html`\n <k-accordion-header for-panel=\"content-${location}\" ?active=\"${isDefault}\">\n ${headerTitle}${orphaned ? html` <span class=\"tc-warning\"><small>(not in template)</small></span>` : ''}\n </k-accordion-header>\n <k-accordion-panel name=\"content-${location}\" ?active=\"${isDefault}\">\n <div class=\"p\">\n <k-html-editor\n class=\"r b\"\n data-location=\"${location}\"\n controls=\"full\"\n .value=\"${content}\"\n mode=\"${CODE_MODE_LOCATIONS.has(location) ? 'code' : 'visual'}\"\n style=\"height: 400px;\"\n ?disabled=\"${isLocked}\"\n ></k-html-editor>\n </div>\n </k-accordion-panel>\n `;\n })}\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-page-editor', PageEditor);\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\PageEditor.js","names":["ShadowComponent","html","repeat","getPage","updatePage","listTemplates","deletePages","listDirectories","movePage","Dialog","Toast","CODE_MODE_LOCATIONS","Set","slugify","name","toLowerCase","trim","replace","PageEditor","static","loading","state","error","saving","page","templates","contents","constructor","super","this","file","connectedCallback","document","addEventListener","handleKeyDown","URLSearchParams","window","location","search","get","err","tmplData","Promise","all","buildContents","template","title","disconnectedCallback","removeEventListener","getPageUrl","split","filter","Boolean","join","templateName","existingContents","tmpl","find","t","locations","label","map","l","result","block","b","content","orphaned","some","push","getFormState","root","shadowRoot","editorMap","Map","querySelectorAll","ed","dataset","getValue","querySelector","value","description","e","ctrlKey","metaKey","key","preventDefault","locked","handleSave","handleTemplateChange","newTemplate","target","currentContents","handleDelete","confirm","async","confirmed","msg","success","setTimeout","href","handleMove","dirData","directories","parts","currentName","pop","currentDir","isValidDir","p","test","includes","dirToInternal","currentDirDisplay","$dialog","create","d","alert","confirmText","confirmAction","dirInput","newName","newDir","newFile","saveError","moveError","moved","encodeURIComponent","cancelText","updatePreview","dir","prefix","textContent","classList","toggle","handleReset","saved","c","current","x","updatedAt","render","isSystem","owner","isLocked","author","pageDir","slice","reachable","tDir","directory","pDir","startsWith","currentFound","templateLabel","createdAt","Date","toLocaleString","Object","keys","extraMetadata","length","entries","isDefault","headerTitle","toUpperCase","has","customElements","define"],"sources":["0"],"sourcesContent":["import ShadowComponent from '/kempo-ui/components/ShadowComponent.js';\nimport { html, repeat } from '/kempo-ui/lit-all.min.js';\nimport { getPage, updatePage, listTemplates, deletePages, listDirectories, movePage } 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/HtmlEditor.js';\n\nconst CODE_MODE_LOCATIONS = new Set(['head', 'scripts']);\n\nconst slugify = name => name\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n\nexport default class PageEditor extends ShadowComponent {\n static properties = {\n loading: { state: true },\n error: { state: true },\n saving: { state: true },\n page: { state: true },\n templates: { state: true },\n contents: { state: true }\n };\n\n constructor() {\n super();\n this.loading = true;\n this.error = false;\n this.saving = false;\n this.page = null;\n this.templates = [];\n this.contents = [];\n this.file = '';\n }\n\n async connectedCallback() {\n super.connectedCallback();\n document.addEventListener('keydown', this.handleKeyDown);\n this.file = new URLSearchParams(window.location.search).get('path') + '.page.html';\n\n if (!this.file || this.file === '.page.html') {\n this.loading = false;\n this.error = true;\n return;\n }\n\n const [[err, page], [, tmplData]] = await Promise.all([\n getPage(this.file),\n listTemplates()\n ]);\n\n this.loading = false;\n\n if (err) {\n this.error = true;\n return;\n }\n\n this.templates = tmplData?.templates || [];\n this.page = page;\n this.contents = this.buildContents(page.template, page.contents);\n document.title = `Edit: ${page.name || page.title || this.file} - Admin`;\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this.handleKeyDown);\n }\n\n /*\n Helpers\n */\n\n getPageUrl() {\n const path = this.file.replace(/\\.page\\.html$/, '');\n return '/' + path.split('/').filter(Boolean).join('/');\n }\n\n buildContents(templateName, existingContents) {\n const tmpl = this.templates.find(t => t.name === templateName);\n const raw = tmpl?.locations || [{ name: 'default', label: null }];\n const locations = raw.map(l => typeof l === 'string' ? { name: l, label: null } : l);\n const result = locations.map(({ name, label }) => {\n const block = existingContents.find(b => b.location === name);\n return { location: name, label: label || null, content: block?.content || '', orphaned: false };\n });\n for (const block of existingContents) {\n if (!locations.some(l => l.name === block.location))\n result.push({ location: block.location, label: null, content: block.content, orphaned: true });\n }\n return result;\n }\n\n getFormState() {\n const root = this.shadowRoot;\n const editorMap = new Map(\n [...root.querySelectorAll('k-html-editor[data-location]')].map(ed => [ed.dataset.location, ed.getValue()])\n );\n return {\n name: root.querySelector('#metaName').value,\n title: root.querySelector('#metaTitle').value,\n description: root.querySelector('#metaDescription').value,\n template: root.querySelector('#metaTemplate').value,\n contents: this.contents.map(({ location, content, orphaned }) => ({\n location,\n content: orphaned\n ? (editorMap.get(location)?.trim() || content)\n : (editorMap.get(location) ?? content)\n }))\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.page?.locked) this.handleSave();\n }\n };\n\n handleTemplateChange = e => {\n if(this.page?.locked) return;\n const newTemplate = e.target.value;\n const editorMap = new Map(\n [...this.shadowRoot.querySelectorAll('k-html-editor[data-location]')].map(ed => [ed.dataset.location, ed.getValue()])\n );\n // Fall back to state content for any editor that hasn't initialized (Monaco lazy-loads)\n const currentContents = this.contents.map(({ location, content }) => ({\n location,\n content: editorMap.get(location)?.trim() || content\n }));\n this.contents = this.buildContents(newTemplate, currentContents);\n this.page = { ...this.page, template: newTemplate };\n };\n\n handleDelete = () => {\n Dialog.confirm('Delete this page? This action cannot be undone.', async confirmed => {\n if (!confirmed) return;\n const [error] = await deletePages([this.file]);\n if (error) {\n Toast.error(error.msg || 'Failed to delete page');\n return;\n }\n Toast.success('Page deleted');\n setTimeout(() => { window.location.href = '/admin/pages'; }, 1000);\n });\n };\n\n handleMove = async () => {\n const [, dirData] = await listDirectories();\n const directories = dirData?.directories || ['.'];\n\n const parts = this.file.replace(/\\.page\\.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 openLearnMore = () => Dialog.alert(html`\n <div class=\"p\">\n <p>Directory paths define where a page lives in the URL structure.</p>\n <p><strong>Examples:</strong></p>\n <ul>\n <li><code>/</code> — root, e.g. <code>/about</code></li>\n <li><code>/blog</code> — e.g. <code>/blog/my-post</code></li>\n <li><code>/blog/[slug]</code> — dynamic segment; <code>[slug]</code> matches any value</li>\n </ul>\n <p>Dynamic segments like <code>[token]</code> allow a single page to handle many URLs. The segment name is available to the page as a URL parameter.</p>\n <p>You can nest segments: <code>/store/[category]/[id]</code></p>\n </div>\n `, null, { title: 'About Directory Paths' });\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 <p id=\"dlg-move-dir-error\" class=\"mt-sm tc-danger d-n\"><small>Invalid path — use format: /path/to/directory</small></p>\n <p class=\"mt-sm muted\"><small>Supports dynamic segments e.g. <code>/blog/[slug]</code>. <button class=\"link\" @click=\"${openLearnMore}\">Learn more</button></small></p>\n </div>\n <div>\n <label class=\"d-b mb-sm\"><strong>Page 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 Page',\n confirmText: 'Save and Move Page',\n confirmAction: async () => {\n const dirInput = $dialog.querySelector('#dlg-move-dir').value.trim() || '/';\n const newName = slugify($dialog.querySelector('#dlg-move-name').value.trim());\n if (!newName) {\n Toast.error('Page 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}.page.html`\n : `${newDir}/${newName}.page.html`;\n\n this.saving = true;\n const [saveError] = await updatePage({ file: this.file, ...this.getFormState() });\n this.saving = false;\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save page');\n return;\n }\n\n const [moveError, moved] = await movePage({ file: this.file, newFile });\n if (moveError) {\n Toast.error(moveError.msg || 'Failed to move page');\n return;\n }\n\n Toast.success('Page saved and moved');\n setTimeout(() => {\n window.location.href = `/admin/pages/edit?path=${encodeURIComponent(moved.file.replace(/\\.page\\.html$/, ''))}`;\n }, 1000);\n },\n cancelText: 'Cancel'\n });\n\n const updatePreview = () => {\n const dir = dirToInternal($dialog.querySelector('#dlg-move-dir').value || '/');\n const name = slugify($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', e => {\n $dialog.querySelector('#dlg-move-dir-error').classList.toggle('d-n', isValidDir(e.target.value || '/'));\n updatePreview();\n });\n $dialog.querySelector('#dlg-move-name').addEventListener('input', updatePreview);\n updatePreview();\n };\n\n handleReset = () => {\n Dialog.confirm('Reset this page? Any unsaved changes will be lost.', confirmed => {\n if (!confirmed) return;\n this.contents = this.buildContents(this.page.template, this.page.contents);\n this.page = { ...this.page };\n });\n };\n\n handleSave = async () => {\n this.saving = true;\n const state = this.getFormState();\n const [saveError, saved] = await updatePage({ file: this.file, ...state });\n this.saving = false;\n\n if (saveError) {\n Toast.error(saveError.msg || 'Failed to save page');\n return;\n }\n\n this.contents = this.contents.map(c => {\n const current = state.contents.find(x => x.location === c.location);\n return current ? { ...c, content: current.content } : c;\n });\n this.page = {\n ...this.page,\n ...state,\n contents: state.contents.filter(b => b.content.trim()),\n updatedAt: saved.updatedAt\n };\n\n document.title = `Edit: ${state.name || state.title || this.file} - Admin`;\n Toast.success('Page saved');\n };\n\n /*\n Render\n */\n\n render() {\n if (this.loading) return html`<div>Loading page...</div>`;\n\n if (this.error) return html`\n <div>\n <p>Page not found.</p>\n <a href=\"/admin/pages\">Back to Pages</a>\n </div>\n `;\n\n const { page, templates, contents } = this;\n const isSystem = page.owner === 'system';\n const isLocked = page.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 page is locked and cannot be edited. ${page.owner === 'custom' ? 'Locked by developer' : `Managed by: ${page.owner || 'external system'}`}\n </div>\n ` : ''}\n <div class=\"d-f mb\">\n <div class=\"btn-grp mrh mb\">\n <a href=\"/admin/content/pages\" class=\"btn\">\n <k-icon name=\"arrow\" direction=\"left\"></k-icon> Pages\n </a>\n <a href=\"${this.getPageUrl()}\" id=\"page-link\" class=\"btn\">\n <k-icon name=\"visibility\"></k-icon> View Page\n </a>\n </div>\n \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 <button @click=\"${this.handleMove}\"><k-icon name=\"drive_file_move\"></k-icon> Move Page</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=\"mb0\">Page: ${page.name || page.title || this.file}</h1>\n\n <a href=\"${this.getPageUrl()}\" class=\"d-b mb\"><code>${this.getPageUrl()}</code></a>\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=\"${page.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>Title</strong></label>\n <input type=\"text\" id=\"metaTitle\" class=\"flex\" .value=\"${page.title || ''}\" ?disabled=\"${isLocked}\">\n </div>\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\"><strong>Description</strong></label>\n <input type=\"text\" id=\"metaDescription\" class=\"flex\" .value=\"${page.description || ''}\" ?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\">${page.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>Template</strong></label>\n ${(() => {\n const pageDir = this.file.replace(/\\.page\\.html$/, '').split('/').slice(0, -1).join('/') || '.';\n const reachable = templates.filter(t => {\n const tDir = t.directory === '.' ? '' : t.directory;\n const pDir = pageDir === '.' ? '' : pageDir;\n return tDir === '' || pDir === tDir || pDir.startsWith(tDir + '/');\n });\n const templateLabel = t => t.directory === '.' ? `/${t.name}` : `/${t.directory}/${t.name}`;\n const currentFound = reachable.some(t => t.name === page.template);\n return html`\n <select id=\"metaTemplate\" class=\"flex\" @change=\"${this.handleTemplateChange}\" ?disabled=\"${isLocked}\">\n ${!currentFound ? html`<option value=\"${page.template}\" selected>${page.template} (Not Found, using default)</option>` : ''}\n ${reachable.map(t => html`\n <option value=\"${t.name}\" ?selected=\"${t.name === page.template}\">${templateLabel(t)}</option>\n `)}\n </select>\n `;\n })()}\n </div>\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\">${page.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\">${page.createdAt ? new Date(page.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\">${page.updatedAt ? new Date(page.updatedAt).toLocaleString() : ''}</span>\n </div>\n </div>\n </k-accordion-panel>\n ${Object.keys(page.extraMetadata || {}).length ? html`\n <k-accordion-header for-panel=\"extra-metadata\">Extra Metadata</k-accordion-header>\n <k-accordion-panel name=\"extra-metadata\">\n <div class=\"p\">\n ${Object.entries(page.extraMetadata).map(([key, value]) => html`\n <div class=\"d-f mb\" style=\"align-items: center; gap: var(--spacer);\">\n <label style=\"min-width: 120px;\" class=\"muted\"><strong>${key}</strong></label>\n <span>${value}</span>\n </div>\n `)}\n <p class=\"muted mt0\"><small>Extra metadata is managed by extensions and cannot be edited here.</small></p>\n </div>\n </k-accordion-panel>\n ` : ''}\n ${repeat(contents, c => c.location, ({ location, label, content, orphaned }) => {\n const isDefault = location === 'default';\n const headerTitle = label || (isDefault ? 'Content' : location.slice(0, 1).toUpperCase() + location.slice(1));\n return html`\n <k-accordion-header for-panel=\"content-${location}\" ?active=\"${isDefault}\">\n ${headerTitle}${orphaned ? html` <span class=\"tc-warning\"><small>(not in template)</small></span>` : ''}\n </k-accordion-header>\n <k-accordion-panel name=\"content-${location}\" ?active=\"${isDefault}\">\n <div class=\"p\">\n <k-html-editor\n class=\"r b\"\n data-location=\"${location}\"\n controls=\"full\"\n .value=\"${content}\"\n mode=\"${CODE_MODE_LOCATIONS.has(location) ? 'code' : 'visual'}\"\n style=\"height: 400px;\"\n ?disabled=\"${isLocked}\"\n ></k-html-editor>\n </div>\n </k-accordion-panel>\n `;\n })}\n </k-accordion>\n `;\n }\n}\n\ncustomElements.define('admin-page-editor', PageEditor);\n"],"mappings":"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","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import{html}from"/kempo-ui/lit-all.min.js";import TableControl from"/kempo-ui/components/tableControls/TableControl.js";import Dialog from"/kempo-ui/components/Dialog.js";import Toast from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";export default class TableRowDelete extends TableControl{static properties={maxWidth:{type:Number,attribute:"max-width"},sdkMethod:{type:String,attribute:"sdk-method"},primaryKey:{type:String,attribute:"primary-key"}};constructor(){super(),this.maxWidth=40,this.sdkMethod="deleteUsers",this.idField="id"}delete=()=>{this.record&&Dialog.confirm("Are you sure you want to delete this record? This action cannot be undone.",async e=>{if(!e)return;const t=(await import("../../kempo/sdk.js"))[this.sdkMethod];if(!t)return void Toast.error("Delete method not found");const[o,r]=await t([this.record[this.primaryKey]]);o?Toast.error(o.msg||"Failed to delete record"):(this.table.deleteRecord(this.record),Toast.success("Record deleted successfully"))})};render(){return html`<button class="no-btn icon-btn" @click="${this.delete}">
1
+ import{html as e}from"/kempo-ui/lit-all.min.js";import t from"/kempo-ui/components/tableControls/TableControl.js";import o from"/kempo-ui/components/Dialog.js";import r from"/kempo-ui/components/Toast.js";import"/kempo-ui/components/Icon.js";export default class i extends t{static properties={maxWidth:{type:Number,attribute:"max-width"},sdkMethod:{type:String,attribute:"sdk-method"},primaryKey:{type:String,attribute:"primary-key"}};constructor(){super(),this.maxWidth=40,this.sdkMethod="deleteUsers",this.idField="id"}delete=()=>{this.record&&o.confirm("Are you sure you want to delete this record? This action cannot be undone.",async e=>{if(!e)return;const t=(await import("../../kempo/sdk.js"))[this.sdkMethod];if(!t)return void r.error("Delete method not found");const[o,i]=await t([this.record[this.primaryKey]]);o?r.error(o.msg||"Failed to delete record"):(this.table.deleteRecord(this.record),r.success("Record deleted successfully"))})};render(){return e`<button class="no-btn icon-btn" @click="${this.delete}">
2
2
  <slot><k-icon name="delete"></k-icon></slot>
3
- </button>`}}customElements.define("admin-table-row-delete",TableRowDelete);
3
+ </button>`}}customElements.define("admin-table-row-delete",i);
4
4
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\TableRowDelete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\TableRowDelete.js","names":["html","TableControl","Dialog","Toast","TableRowDelete","static","maxWidth","type","Number","attribute","sdkMethod","String","primaryKey","constructor","super","this","idField","delete","record","confirm","async","confirmed","deleteMethod","import","error","result","msg","table","deleteRecord","success","render","customElements","define"],"sources":["0"],"sourcesContent":["import { html } from '/kempo-ui/lit-all.min.js';\r\nimport TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class TableRowDelete extends TableControl {\r\n static properties = {\r\n maxWidth: { type: Number, attribute: 'max-width' },\r\n sdkMethod: { type: String, attribute: 'sdk-method' },\r\n primaryKey: { type: String, attribute: 'primary-key' }\r\n };\r\n\r\n constructor(){\r\n super();\r\n this.maxWidth = 40;\r\n this.sdkMethod = 'deleteUsers';\r\n this.idField = 'id';\r\n }\r\n\r\n delete = () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm('Are you sure you want to delete this record? This action cannot be undone.', async (confirmed) => {\r\n if(!confirmed) return;\r\n\r\n const module = await import('../../kempo/sdk.js');\r\n const deleteMethod = module[this.sdkMethod];\r\n\r\n if(!deleteMethod){\r\n Toast.error('Delete method not found');\r\n return;\r\n }\r\n\r\n const [error, result] = await deleteMethod([this.record[this.primaryKey]]);\r\n\r\n if(error){\r\n Toast.error(error.msg || 'Failed to delete record');\r\n return;\r\n }\r\n\r\n this.table.deleteRecord(this.record);\r\n Toast.success('Record deleted successfully');\r\n });\r\n };\r\n\r\n render(){\r\n return html`<button class=\"no-btn icon-btn\" @click=\"${this.delete}\">\r\n <slot><k-icon name=\"delete\"></k-icon></slot>\r\n </button>`;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-table-row-delete', TableRowDelete);\r\n"],"mappings":"OAASA,SAAY,kCACdC,iBAAkB,4DAClBC,WAAY,wCACZC,UAAW,sCACX,8CAEQ,MAAMC,uBAAuBH,aAC1CI,kBAAoB,CAClBC,SAAU,CAAEC,KAAMC,OAAQC,UAAW,aACrCC,UAAW,CAAEH,KAAMI,OAAQF,UAAW,cACtCG,WAAY,CAAEL,KAAMI,OAAQF,UAAW,gBAGzC,WAAAI,GACEC,QACAC,KAAKT,SAAW,GAChBS,KAAKL,UAAY,cACjBK,KAAKC,QAAU,IACjB,CAEAC,OAAS,KACHF,KAAKG,QAEThB,OAAOiB,QAAQ,6EAA8EC,MAAOC,IAClG,IAAIA,EAAW,OAEf,MACMC,SADeC,OAAO,uBACAR,KAAKL,WAEjC,IAAIY,EAEF,YADAnB,MAAMqB,MAAM,2BAId,MAAOA,EAAOC,SAAgBH,EAAa,CAACP,KAAKG,OAAOH,KAAKH,cAE1DY,EACDrB,MAAMqB,MAAMA,EAAME,KAAO,4BAI3BX,KAAKY,MAAMC,aAAab,KAAKG,QAC7Bf,MAAM0B,QAAQ,mCAIlB,MAAAC,GACE,OAAO9B,IAAI,2CAA2Ce,KAAKE;;cAG7D,EAGFc,eAAeC,OAAO,yBAA0B5B","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\TableRowDelete.js","names":["html","TableControl","Dialog","Toast","TableRowDelete","static","maxWidth","type","Number","attribute","sdkMethod","String","primaryKey","constructor","super","this","idField","delete","record","confirm","async","confirmed","deleteMethod","import","error","result","msg","table","deleteRecord","success","render","customElements","define"],"sources":["0"],"sourcesContent":["import { html } from '/kempo-ui/lit-all.min.js';\r\nimport TableControl from '/kempo-ui/components/tableControls/TableControl.js';\r\nimport Dialog from '/kempo-ui/components/Dialog.js';\r\nimport Toast from '/kempo-ui/components/Toast.js';\r\nimport '/kempo-ui/components/Icon.js';\r\n\r\nexport default class TableRowDelete extends TableControl {\r\n static properties = {\r\n maxWidth: { type: Number, attribute: 'max-width' },\r\n sdkMethod: { type: String, attribute: 'sdk-method' },\r\n primaryKey: { type: String, attribute: 'primary-key' }\r\n };\r\n\r\n constructor(){\r\n super();\r\n this.maxWidth = 40;\r\n this.sdkMethod = 'deleteUsers';\r\n this.idField = 'id';\r\n }\r\n\r\n delete = () => {\r\n if(!this.record) return;\r\n\r\n Dialog.confirm('Are you sure you want to delete this record? This action cannot be undone.', async (confirmed) => {\r\n if(!confirmed) return;\r\n\r\n const module = await import('../../kempo/sdk.js');\r\n const deleteMethod = module[this.sdkMethod];\r\n\r\n if(!deleteMethod){\r\n Toast.error('Delete method not found');\r\n return;\r\n }\r\n\r\n const [error, result] = await deleteMethod([this.record[this.primaryKey]]);\r\n\r\n if(error){\r\n Toast.error(error.msg || 'Failed to delete record');\r\n return;\r\n }\r\n\r\n this.table.deleteRecord(this.record);\r\n Toast.success('Record deleted successfully');\r\n });\r\n };\r\n\r\n render(){\r\n return html`<button class=\"no-btn icon-btn\" @click=\"${this.delete}\">\r\n <slot><k-icon name=\"delete\"></k-icon></slot>\r\n </button>`;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-table-row-delete', TableRowDelete);\r\n"],"mappings":"eAASA,MAAY,kCACdC,MAAkB,4DAClBC,MAAY,wCACZC,MAAW,sCACX,8CAEQ,MAAMC,UAAuBH,EAC1CI,kBAAoB,CAClBC,SAAU,CAAEC,KAAMC,OAAQC,UAAW,aACrCC,UAAW,CAAEH,KAAMI,OAAQF,UAAW,cACtCG,WAAY,CAAEL,KAAMI,OAAQF,UAAW,gBAGzC,WAAAI,GACEC,QACAC,KAAKT,SAAW,GAChBS,KAAKL,UAAY,cACjBK,KAAKC,QAAU,IACjB,CAEAC,OAAS,KACHF,KAAKG,QAEThB,EAAOiB,QAAQ,6EAA8EC,MAAOC,IAClG,IAAIA,EAAW,OAEf,MACMC,SADeC,OAAO,uBACAR,KAAKL,WAEjC,IAAIY,EAEF,YADAnB,EAAMqB,MAAM,2BAId,MAAOA,EAAOC,SAAgBH,EAAa,CAACP,KAAKG,OAAOH,KAAKH,cAE1DY,EACDrB,EAAMqB,MAAMA,EAAME,KAAO,4BAI3BX,KAAKY,MAAMC,aAAab,KAAKG,QAC7Bf,EAAM0B,QAAQ,mCAIlB,MAAAC,GACE,OAAO9B,CAAI,2CAA2Ce,KAAKE;;cAG7D,EAGFc,eAAeC,OAAO,yBAA0B5B","ignoreList":[]}
@@ -1,8 +1,8 @@
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 TableRowLink extends TableControl{static get properties(){return{urlPattern:{type:String,attribute:"url-pattern"},fieldName:{type:String,attribute:"field-name"}}}constructor(){super(),this.fieldName="id",this.maxWidth=40}navigate=()=>{if(!this.record)return;const t=this.record[this.fieldName];if(!t)return;const e=this.urlPattern.replace(`{${this.fieldName}}`,t);window.location.href=e};render(){return html`
1
+ import t from"/kempo-ui/components/tableControls/TableControl.js";import{html as e}from"/kempo-ui/lit-all.min.js";import"/kempo-ui/components/Icon.js";export default class i extends t{static get properties(){return{urlPattern:{type:String,attribute:"url-pattern"},fieldName:{type:String,attribute:"field-name"}}}constructor(){super(),this.fieldName="id",this.maxWidth=40}navigate=()=>{if(!this.record)return;const t=this.record[this.fieldName];if(!t)return;const e=this.urlPattern.replace(`{${this.fieldName}}`,t);window.location.href=e};render(){return e`
2
2
  <button class="no-btn icon-btn" @click="${this.navigate}">
3
3
  <slot>
4
4
  <k-icon name="visibility"></k-icon>
5
5
  </slot>
6
6
  </button>
7
- `}}customElements.define("admin-table-row-link",TableRowLink);
7
+ `}}customElements.define("admin-table-row-link",i);
8
8
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\TableRowLink.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"src\\admin\\components\\TableRowLink.js","names":["TableControl","html","TableRowLink","properties","urlPattern","type","String","attribute","fieldName","constructor","super","this","maxWidth","navigate","record","fieldValue","url","replace","window","location","href","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 TableRowLink extends TableControl {\r\n static get properties() {\r\n return {\r\n urlPattern: { type: String, attribute: 'url-pattern' },\r\n fieldName: { type: String, attribute: 'field-name' }\r\n };\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.fieldName = 'id';\r\n this.maxWidth = 40;\r\n }\r\n\r\n navigate = () => {\r\n if(!this.record) return;\r\n\r\n const fieldValue = this.record[this.fieldName];\r\n if(!fieldValue) return;\r\n\r\n const url = this.urlPattern.replace(`{${this.fieldName}}`, fieldValue);\r\n window.location.href = url;\r\n };\r\n\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" @click=\"${this.navigate}\">\r\n <slot>\r\n <k-icon name=\"visibility\"></k-icon>\r\n </slot>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-table-row-link', TableRowLink);\r\n\r\n"],"mappings":"OAAOA,iBAAkB,4DAChBC,SAAY,iCACd,8CAEQ,MAAMC,qBAAqBF,aACxC,qBAAWG,GACT,MAAO,CACLC,WAAY,CAAEC,KAAMC,OAAQC,UAAW,eACvCC,UAAW,CAAEH,KAAMC,OAAQC,UAAW,cAE1C,CAEA,WAAAE,GACEC,QACAC,KAAKH,UAAY,KACjBG,KAAKC,SAAW,EAClB,CAEAC,SAAW,KACT,IAAIF,KAAKG,OAAQ,OAEjB,MAAMC,EAAaJ,KAAKG,OAAOH,KAAKH,WACpC,IAAIO,EAAY,OAEhB,MAAMC,EAAML,KAAKP,WAAWa,QAAQ,IAAIN,KAAKH,aAAcO,GAC3DG,OAAOC,SAASC,KAAOJ,GAGzB,MAAAK,GACE,OAAOpB,IAAI;gDACiCU,KAAKE;;;;;KAMnD,EAGFS,eAAeC,OAAO,uBAAwBrB","ignoreList":[]}
1
+ {"version":3,"file":"src\\admin\\components\\TableRowLink.js","names":["TableControl","html","TableRowLink","properties","urlPattern","type","String","attribute","fieldName","constructor","super","this","maxWidth","navigate","record","fieldValue","url","replace","window","location","href","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 TableRowLink extends TableControl {\r\n static get properties() {\r\n return {\r\n urlPattern: { type: String, attribute: 'url-pattern' },\r\n fieldName: { type: String, attribute: 'field-name' }\r\n };\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.fieldName = 'id';\r\n this.maxWidth = 40;\r\n }\r\n\r\n navigate = () => {\r\n if(!this.record) return;\r\n\r\n const fieldValue = this.record[this.fieldName];\r\n if(!fieldValue) return;\r\n\r\n const url = this.urlPattern.replace(`{${this.fieldName}}`, fieldValue);\r\n window.location.href = url;\r\n };\r\n\r\n render() {\r\n return html`\r\n <button class=\"no-btn icon-btn\" @click=\"${this.navigate}\">\r\n <slot>\r\n <k-icon name=\"visibility\"></k-icon>\r\n </slot>\r\n </button>\r\n `;\r\n }\r\n}\r\n\r\ncustomElements.define('admin-table-row-link', TableRowLink);\r\n\r\n"],"mappings":"OAAOA,MAAkB,oEAChBC,MAAY,iCACd,8CAEQ,MAAMC,UAAqBF,EACxC,qBAAWG,GACT,MAAO,CACLC,WAAY,CAAEC,KAAMC,OAAQC,UAAW,eACvCC,UAAW,CAAEH,KAAMC,OAAQC,UAAW,cAE1C,CAEA,WAAAE,GACEC,QACAC,KAAKH,UAAY,KACjBG,KAAKC,SAAW,EAClB,CAEAC,SAAW,KACT,IAAIF,KAAKG,OAAQ,OAEjB,MAAMC,EAAaJ,KAAKG,OAAOH,KAAKH,WACpC,IAAIO,EAAY,OAEhB,MAAMC,EAAML,KAAKP,WAAWa,QAAQ,IAAIN,KAAKH,aAAcO,GAC3DG,OAAOC,SAASC,KAAOJ,GAGzB,MAAAK,GACE,OAAOpB,CAAI;gDACiCU,KAAKE;;;;;KAMnD,EAGFS,eAAeC,OAAO,uBAAwBrB","ignoreList":[]}
@@ -1,4 +1,4 @@
1
- import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html}from"/kempo-ui/lit-all.min.js";import{getTemplate,updateTemplate,deleteTemplates,moveTemplate,createTemplate,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 TemplateEditor extends ShadowComponent{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},template:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.template=null,this.file=""}async connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown);const e=new URLSearchParams(window.location.search).get("template");if(this.file=e+".template.html",!this.file||".template.html"===this.file)return this.loading=!1,void(this.error=!0);const[t,a]=await getTemplate(this.file);this.loading=!1,t?this.error=!0:(this.template=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.template.name,markup:e.querySelector("#templateEditor")?.getValue()??this.template.markup}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.template?.locked||this.handleSave())};handleDelete=()=>{Dialog.confirm("Delete this template? This action cannot be undone.",async e=>{if(!e)return;const[t]=await deleteTemplates([this.file]);t?Toast.error(t.msg||"Failed to delete template"):(Toast.success("Template deleted"),setTimeout(()=>{window.location.href="/admin/content/templates"},1e3))})};handleMove=async()=>{const[,e]=await listDirectories(),t=e?.directories||["."],a=this.file.replace(/\.template\.html$/,"").split("/"),l=a.pop(),i=a.join("/")||".",o=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",n="."===i?"/":"/"+i,s=Dialog.create(html`
1
+ import e from"/kempo-ui/components/ShadowComponent.js";import{html as t}from"/kempo-ui/lit-all.min.js";import{getTemplate as a,updateTemplate as i,deleteTemplates as l,moveTemplate as n,createTemplate as o,listDirectories as s}from"/kempo/sdk.js";import r from"/kempo-ui/components/Dialog.js";import d 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 c extends e{static properties={loading:{state:!0},error:{state:!0},saving:{state:!0},template:{state:!0}};constructor(){super(),this.loading=!0,this.error=!1,this.saving=!1,this.template=null,this.file=""}async connectedCallback(){super.connectedCallback(),document.addEventListener("keydown",this.handleKeyDown);const e=new URLSearchParams(window.location.search).get("template");if(this.file=e+".template.html",!this.file||".template.html"===this.file)return this.loading=!1,void(this.error=!0);const[t,i]=await a(this.file);this.loading=!1,t?this.error=!0:(this.template=i,document.title=`Edit: ${i.name} - Admin`)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("keydown",this.handleKeyDown)}getFormState(){const e=this.shadowRoot;return{name:e.querySelector("#metaName")?.value??this.template.name,markup:e.querySelector("#templateEditor")?.getValue()??this.template.markup}}handleKeyDown=e=>{(e.ctrlKey||e.metaKey)&&"s"===e.key&&(e.preventDefault(),this.saving||this.template?.locked||this.handleSave())};handleDelete=()=>{r.confirm("Delete this template? This action cannot be undone.",async e=>{if(!e)return;const[t]=await l([this.file]);t?d.error(t.msg||"Failed to delete template"):(d.success("Template deleted"),setTimeout(()=>{window.location.href="/admin/content/templates"},1e3))})};handleMove=async()=>{const[,e]=await s(),a=e?.directories||["."],l=this.file.replace(/\.template\.html$/,"").split("/"),o=l.pop(),c=l.join("/")||".",m=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",p="."===c?"/":"/"+c,v=r.create(t`
2
2
  <div class="p">
3
3
  <div class="p r mb bc-warning tc-warning">
4
4
  <k-icon name="warning"></k-icon>
@@ -6,24 +6,24 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
6
6
  </div>
7
7
  <div class="mb">
8
8
  <label class="d-b mb-sm"><strong>Location</strong></label>
9
- <input type="text" id="dlg-move-dir" class="full" list="dlg-move-dir-list" .value="${n}" placeholder="/">
9
+ <input type="text" id="dlg-move-dir" class="full" list="dlg-move-dir-list" .value="${p}" placeholder="/">
10
10
  <datalist id="dlg-move-dir-list">
11
- ${t.map(e=>html`<option value="${"."===e?"/":"/"+e}">`)}
11
+ ${a.map(e=>t`<option value="${"."===e?"/":"/"+e}">`)}
12
12
  </datalist>
13
13
  </div>
14
14
  <div>
15
15
  <label class="d-b mb-sm"><strong>Template Name</strong></label>
16
- <input type="text" id="dlg-move-name" class="full" .value="${l}">
16
+ <input type="text" id="dlg-move-name" class="full" .value="${o}">
17
17
  <p class="mt-sm muted"><small id="dlg-move-preview"></small></p>
18
18
  </div>
19
19
  </div>
20
- `,{title:"Move Template",confirmText:"Save and Move Template",confirmAction:async()=>{const e=s.querySelector("#dlg-move-dir").value.trim()||"/",t=s.querySelector("#dlg-move-name").value.trim();if(!t)return void Toast.error("Template 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 l=o(e),i="."===l?`${t}.template.html`:`${l}/${t}.template.html`;this.saving=!0;const[n]=await updateTemplate({file:this.file,...this.getFormState()});if(this.saving=!1,n)return void Toast.error(n.msg||"Failed to save template");const[r,m]=await moveTemplate({file:this.file,newFile:i});if(r)return void Toast.error(r.msg||"Failed to move template");Toast.success("Template saved and moved");const d=m.file.replace(/\.template\.html$/,"");setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(d)}`},1e3)},cancelText:"Cancel"}),r=()=>{const e=o(s.querySelector("#dlg-move-dir").value||"/"),t=s.querySelector("#dlg-move-name").value,a="."===e?"/":"/"+e+"/";s.querySelector("#dlg-move-preview").textContent=t?a+t:""};s.querySelector("#dlg-move-dir").addEventListener("input",r),s.querySelector("#dlg-move-name").addEventListener("input",r),r()};handleCopy=async()=>{const[,e]=await listDirectories(),t=e?.directories||["."],a=this.file.replace(/\.template\.html$/,"").split("/"),l=a.pop(),i=a.join("/")||".",o=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",n="."===i?"/":"/"+i,s=Dialog.create(html`
20
+ `,{title:"Move Template",confirmText:"Save and Move Template",confirmAction:async()=>{const e=v.querySelector("#dlg-move-dir").value.trim()||"/",t=v.querySelector("#dlg-move-name").value.trim();if(!t)return void d.error("Template name is required");if(!/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(a=e)||a.includes("..")||a.includes("//"))return void d.error("Invalid directory path");var a;const l=m(e),o="."===l?`${t}.template.html`:`${l}/${t}.template.html`;this.saving=!0;const[s]=await i({file:this.file,...this.getFormState()});if(this.saving=!1,s)return void d.error(s.msg||"Failed to save template");const[r,c]=await n({file:this.file,newFile:o});if(r)return void d.error(r.msg||"Failed to move template");d.success("Template saved and moved");const p=c.file.replace(/\.template\.html$/,"");setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(p)}`},1e3)},cancelText:"Cancel"}),u=()=>{const e=m(v.querySelector("#dlg-move-dir").value||"/"),t=v.querySelector("#dlg-move-name").value,a="."===e?"/":"/"+e+"/";v.querySelector("#dlg-move-preview").textContent=t?a+t:""};v.querySelector("#dlg-move-dir").addEventListener("input",u),v.querySelector("#dlg-move-name").addEventListener("input",u),u()};handleCopy=async()=>{const[,e]=await s(),a=e?.directories||["."],i=this.file.replace(/\.template\.html$/,"").split("/"),l=i.pop(),n=i.join("/")||".",c=e=>(e||"/").replace(/^\//,"").replace(/\/$/,"")||".",m="."===n?"/":"/"+n,p=r.create(t`
21
21
  <div class="p">
22
22
  <div class="mb">
23
23
  <label class="d-b mb-sm"><strong>Location</strong></label>
24
- <input type="text" id="dlg-copy-dir" class="full" list="dlg-copy-dir-list" .value="${n}" placeholder="/">
24
+ <input type="text" id="dlg-copy-dir" class="full" list="dlg-copy-dir-list" .value="${m}" placeholder="/">
25
25
  <datalist id="dlg-copy-dir-list">
26
- ${t.map(e=>html`<option value="${"."===e?"/":"/"+e}">`)}
26
+ ${a.map(e=>t`<option value="${"."===e?"/":"/"+e}">`)}
27
27
  </datalist>
28
28
  </div>
29
29
  <div>
@@ -32,15 +32,15 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
32
32
  <p class="mt-sm muted"><small id="dlg-copy-preview"></small></p>
33
33
  </div>
34
34
  </div>
35
- `,{title:"Copy Template",confirmText:"Copy Template",confirmAction:async()=>{const e=s.querySelector("#dlg-copy-dir").value.trim()||"/",t=s.querySelector("#dlg-copy-name").value.trim();if(!t)return void Toast.error("Template 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 l=o(e),[i,n]=await createTemplate({directory:"."===l?"":l,name:t,copyFrom:this.file});i?Toast.error(i.msg||"Failed to copy template"):(Toast.success("Template copied"),setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(n.file.replace(/\.template\.html$/,""))}`},1e3))},cancelText:"Cancel"}),r=()=>{const e=o(s.querySelector("#dlg-copy-dir").value||"/"),t=s.querySelector("#dlg-copy-name").value,a="."===e?"/":"/"+e+"/";s.querySelector("#dlg-copy-preview").textContent=t?a+t:""};s.querySelector("#dlg-copy-dir").addEventListener("input",r),s.querySelector("#dlg-copy-name").addEventListener("input",r),r()};handleReset=()=>{Dialog.confirm("Reset this template? Any unsaved changes will be lost.",e=>{e&&(this.template={...this.template})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await updateTemplate({file:this.file,markup:e.markup});if(this.saving=!1,t)return void Toast.error(t.msg||"Failed to save template");this.template={...this.template,markup:e.markup,updatedAt:a.updatedAt};const l=this.file.replace(/\.template\.html$/,"").split("/"),i=l.pop(),o=l.join("/"),n=e.name.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");if(n&&n!==i){const e=o?`${o}/${n}.template.html`:`${n}.template.html`,[t,a]=await moveTemplate({file:this.file,newFile:e});if(t)return void Toast.error(t.msg||"Failed to rename template file");Toast.success("Template saved and renamed");const l=a.file.replace(/\.template\.html$/,"");return void setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(l)}`},1e3)}document.title=`Edit: ${template.name} - Admin`,Toast.success("Template saved")};render(){if(this.loading)return html`<div>Loading template...</div>`;if(this.error)return html`
35
+ `,{title:"Copy Template",confirmText:"Copy Template",confirmAction:async()=>{const e=p.querySelector("#dlg-copy-dir").value.trim()||"/",t=p.querySelector("#dlg-copy-name").value.trim();if(!t)return void d.error("Template name is required");if(!/^\/[a-zA-Z0-9_\-\[\]\/]*$/.test(a=e)||a.includes("..")||a.includes("//"))return void d.error("Invalid directory path");var a;const i=c(e),[l,n]=await o({directory:"."===i?"":i,name:t,copyFrom:this.file});l?d.error(l.msg||"Failed to copy template"):(d.success("Template copied"),setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(n.file.replace(/\.template\.html$/,""))}`},1e3))},cancelText:"Cancel"}),v=()=>{const e=c(p.querySelector("#dlg-copy-dir").value||"/"),t=p.querySelector("#dlg-copy-name").value,a="."===e?"/":"/"+e+"/";p.querySelector("#dlg-copy-preview").textContent=t?a+t:""};p.querySelector("#dlg-copy-dir").addEventListener("input",v),p.querySelector("#dlg-copy-name").addEventListener("input",v),v()};handleReset=()=>{r.confirm("Reset this template? Any unsaved changes will be lost.",e=>{e&&(this.template={...this.template})})};handleSave=async()=>{this.saving=!0;const e=this.getFormState(),[t,a]=await i({file:this.file,markup:e.markup});if(this.saving=!1,t)return void d.error(t.msg||"Failed to save template");this.template={...this.template,markup:e.markup,updatedAt:a.updatedAt};const l=this.file.replace(/\.template\.html$/,"").split("/"),o=l.pop(),s=l.join("/"),r=e.name.toLowerCase().trim().replace(/[^\w\s-]/g,"").replace(/[\s_]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"");if(r&&r!==o){const e=s?`${s}/${r}.template.html`:`${r}.template.html`,[t,a]=await n({file:this.file,newFile:e});if(t)return void d.error(t.msg||"Failed to rename template file");d.success("Template saved and renamed");const i=a.file.replace(/\.template\.html$/,"");return void setTimeout(()=>{window.location.href=`/admin/content/templates/edit?template=${encodeURIComponent(i)}`},1e3)}document.title=`Edit: ${template.name} - Admin`,d.success("Template saved")};render(){if(this.loading)return t`<div>Loading template...</div>`;if(this.error)return t`
36
36
  <div>
37
37
  <p>Template not found.</p>
38
38
  <a href="/admin/content/templates">Back to Templates</a>
39
39
  </div>
40
- `;const{template:e}=this,t="custom"===e.owner,a=e.locked;return html`
41
- ${a?html`
40
+ `;const{template:e}=this,a="custom"===e.owner,i=e.locked;return t`
41
+ ${i?t`
42
42
  <div class="p r mb bc-warning tc-warning">
43
- <k-icon name="lock"></k-icon> This template is locked and cannot be edited. It is managed by an extension.
43
+ <k-icon name="lock"></k-icon> This template is locked and cannot be edited. ${"custom"===e.owner?"Locked by developer":`Managed by: ${e.owner||"external system"}`}
44
44
  </div>
45
45
  `:""}
46
46
  <div class="d-f mb">
@@ -50,7 +50,7 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
50
50
  </a>
51
51
  </div>
52
52
  <div class="flex"></div>
53
- ${t&&!a?html`
53
+ ${a&&!i?t`
54
54
  <div class="btn-grp mrh mb">
55
55
  <button class="danger" @click="${this.handleDelete}"><k-icon name="delete"></k-icon> Delete</button>
56
56
  <button @click="${this.handleMove}"><k-icon name="drive_file_move"></k-icon> Move Template</button>
@@ -59,7 +59,7 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
59
59
  <div class="btn-grp mrh mb">
60
60
  <button @click="${this.handleCopy}"><k-icon name="content_copy"></k-icon> Copy Template</button>
61
61
  </div>
62
- ${a?"":html`
62
+ ${i?"":t`
63
63
  <div class="btn-grp mrh mb">
64
64
  <button @click="${this.handleReset}"><k-icon name="restart_alt"></k-icon> Reset</button>
65
65
  <button id="saveBtn" class="primary" ?disabled="${this.saving}" @click="${this.handleSave}">
@@ -77,16 +77,16 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
77
77
  <div class="p">
78
78
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
79
79
  <label style="min-width: 120px;"><strong>Name</strong></label>
80
- <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${!t||a}">
80
+ <input type="text" id="metaName" class="flex" .value="${e.name||""}" ?disabled="${!a||i}">
81
81
  </div>
82
82
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
83
83
  <label style="min-width: 120px;"><strong>Directory</strong></label>
84
84
  <span class="muted">${(()=>{const e=this.file.replace(/\.template\.html$/,"").split("/");return e.pop(),e.length?e.join("/"):"/"})()}</span>
85
- ${t&&!a?html`
85
+ ${a&&!i?t`
86
86
  <button class="icon-btn no-btn ph" title="Move Template" @click="${this.handleMove}"><k-icon name="drive_file_move"></k-icon></button>
87
87
  `:""}
88
88
  </div>
89
- ${e.author?html`
89
+ ${e.author?t`
90
90
  <div class="d-f mb" style="align-items: center; gap: var(--spacer);">
91
91
  <label style="min-width: 120px;"><strong>Author</strong></label>
92
92
  <span class="muted">${e.author}</span>
@@ -116,10 +116,10 @@ import ShadowComponent from"/kempo-ui/components/ShadowComponent.js";import{html
116
116
  language="html"
117
117
  .value="${e.markup||""}"
118
118
  style="height: 70vh; min-height: 400px;"
119
- ?disabled="${a}"
119
+ ?disabled="${i}"
120
120
  ></k-code-editor>
121
121
  </div>
122
122
  </k-accordion-panel>
123
123
  </k-accordion>
124
- `}}customElements.define("admin-template-editor",TemplateEditor);
124
+ `}}customElements.define("admin-template-editor",c);
125
125
  //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\admin\components\TemplateEditor.js.map