@karibsen/eponyme 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +609 -0
  3. package/dist/eponyme.d.mts +15 -0
  4. package/dist/eponyme.mjs +38 -0
  5. package/dist/module.d.mts +26 -0
  6. package/dist/module.json +9 -0
  7. package/dist/module.mjs +154 -0
  8. package/dist/runtime/assets/dashboard.css +1 -0
  9. package/dist/runtime/components/editor/EponymeCollectionPage.d.vue.ts +9 -0
  10. package/dist/runtime/components/editor/EponymeCollectionPage.vue +238 -0
  11. package/dist/runtime/components/editor/EponymeCollectionPage.vue.d.ts +9 -0
  12. package/dist/runtime/components/editor/EponymeCopy.d.vue.ts +7 -0
  13. package/dist/runtime/components/editor/EponymeCopy.vue +28 -0
  14. package/dist/runtime/components/editor/EponymeCopy.vue.d.ts +7 -0
  15. package/dist/runtime/components/editor/EponymeFolderNav.d.vue.ts +7 -0
  16. package/dist/runtime/components/editor/EponymeFolderNav.vue +146 -0
  17. package/dist/runtime/components/editor/EponymeFolderNav.vue.d.ts +7 -0
  18. package/dist/runtime/components/editor/EponymeFolderPage.d.vue.ts +7 -0
  19. package/dist/runtime/components/editor/EponymeFolderPage.vue +62 -0
  20. package/dist/runtime/components/editor/EponymeFolderPage.vue.d.ts +7 -0
  21. package/dist/runtime/components/editor/EponymeForm.d.vue.ts +9 -0
  22. package/dist/runtime/components/editor/EponymeForm.vue +309 -0
  23. package/dist/runtime/components/editor/EponymeForm.vue.d.ts +9 -0
  24. package/dist/runtime/components/editor/EponymeFormPage.d.vue.ts +8 -0
  25. package/dist/runtime/components/editor/EponymeFormPage.vue +288 -0
  26. package/dist/runtime/components/editor/EponymeFormPage.vue.d.ts +8 -0
  27. package/dist/runtime/components/editor/EponymeHistoryDialog.d.vue.ts +14 -0
  28. package/dist/runtime/components/editor/EponymeHistoryDialog.vue +97 -0
  29. package/dist/runtime/components/editor/EponymeHistoryDialog.vue.d.ts +14 -0
  30. package/dist/runtime/components/editor/EponymeNavigationLink.d.vue.ts +14 -0
  31. package/dist/runtime/components/editor/EponymeNavigationLink.vue +80 -0
  32. package/dist/runtime/components/editor/EponymeNavigationLink.vue.d.ts +14 -0
  33. package/dist/runtime/components/editor/EponymePageNavigation.d.vue.ts +8 -0
  34. package/dist/runtime/components/editor/EponymePageNavigation.vue +58 -0
  35. package/dist/runtime/components/editor/EponymePageNavigation.vue.d.ts +8 -0
  36. package/dist/runtime/components/editor/EponymePreviewPanel.d.vue.ts +16 -0
  37. package/dist/runtime/components/editor/EponymePreviewPanel.vue +100 -0
  38. package/dist/runtime/components/editor/EponymePreviewPanel.vue.d.ts +16 -0
  39. package/dist/runtime/components/editor/EponymeSidebar.d.vue.ts +6 -0
  40. package/dist/runtime/components/editor/EponymeSidebar.vue +244 -0
  41. package/dist/runtime/components/editor/EponymeSidebar.vue.d.ts +6 -0
  42. package/dist/runtime/components/editor/EponymeSidebarTree.d.vue.ts +18 -0
  43. package/dist/runtime/components/editor/EponymeSidebarTree.vue +84 -0
  44. package/dist/runtime/components/editor/EponymeSidebarTree.vue.d.ts +18 -0
  45. package/dist/runtime/components/fields/ArrayField.d.vue.ts +19 -0
  46. package/dist/runtime/components/fields/ArrayField.vue +198 -0
  47. package/dist/runtime/components/fields/ArrayField.vue.d.ts +19 -0
  48. package/dist/runtime/components/fields/BooleanField.d.vue.ts +16 -0
  49. package/dist/runtime/components/fields/BooleanField.vue +36 -0
  50. package/dist/runtime/components/fields/BooleanField.vue.d.ts +16 -0
  51. package/dist/runtime/components/fields/CheckboxGroupField.d.vue.ts +20 -0
  52. package/dist/runtime/components/fields/CheckboxGroupField.vue +52 -0
  53. package/dist/runtime/components/fields/CheckboxGroupField.vue.d.ts +20 -0
  54. package/dist/runtime/components/fields/ColorField.d.vue.ts +19 -0
  55. package/dist/runtime/components/fields/ColorField.vue +39 -0
  56. package/dist/runtime/components/fields/ColorField.vue.d.ts +19 -0
  57. package/dist/runtime/components/fields/DateField.d.vue.ts +18 -0
  58. package/dist/runtime/components/fields/DateField.vue +39 -0
  59. package/dist/runtime/components/fields/DateField.vue.d.ts +18 -0
  60. package/dist/runtime/components/fields/FieldRenderer.d.vue.ts +24 -0
  61. package/dist/runtime/components/fields/FieldRenderer.vue +135 -0
  62. package/dist/runtime/components/fields/FieldRenderer.vue.d.ts +24 -0
  63. package/dist/runtime/components/fields/NumberField.d.vue.ts +20 -0
  64. package/dist/runtime/components/fields/NumberField.vue +58 -0
  65. package/dist/runtime/components/fields/NumberField.vue.d.ts +20 -0
  66. package/dist/runtime/components/fields/RadioField.d.vue.ts +20 -0
  67. package/dist/runtime/components/fields/RadioField.vue +44 -0
  68. package/dist/runtime/components/fields/RadioField.vue.d.ts +20 -0
  69. package/dist/runtime/components/fields/RichTextField.d.vue.ts +20 -0
  70. package/dist/runtime/components/fields/RichTextField.vue +176 -0
  71. package/dist/runtime/components/fields/RichTextField.vue.d.ts +20 -0
  72. package/dist/runtime/components/fields/SectionField.d.vue.ts +20 -0
  73. package/dist/runtime/components/fields/SectionField.vue +127 -0
  74. package/dist/runtime/components/fields/SectionField.vue.d.ts +20 -0
  75. package/dist/runtime/components/fields/SelectField.d.vue.ts +21 -0
  76. package/dist/runtime/components/fields/SelectField.vue +42 -0
  77. package/dist/runtime/components/fields/SelectField.vue.d.ts +21 -0
  78. package/dist/runtime/components/fields/SlugField.d.vue.ts +20 -0
  79. package/dist/runtime/components/fields/SlugField.vue +35 -0
  80. package/dist/runtime/components/fields/SlugField.vue.d.ts +20 -0
  81. package/dist/runtime/components/fields/TabsField.d.vue.ts +19 -0
  82. package/dist/runtime/components/fields/TabsField.vue +109 -0
  83. package/dist/runtime/components/fields/TabsField.vue.d.ts +19 -0
  84. package/dist/runtime/components/fields/TextField.d.vue.ts +22 -0
  85. package/dist/runtime/components/fields/TextField.vue +56 -0
  86. package/dist/runtime/components/fields/TextField.vue.d.ts +22 -0
  87. package/dist/runtime/components/fields/TextareaField.d.vue.ts +20 -0
  88. package/dist/runtime/components/fields/TextareaField.vue +47 -0
  89. package/dist/runtime/components/fields/TextareaField.vue.d.ts +20 -0
  90. package/dist/runtime/components/fields/UrlField.d.vue.ts +17 -0
  91. package/dist/runtime/components/fields/UrlField.vue +35 -0
  92. package/dist/runtime/components/fields/UrlField.vue.d.ts +17 -0
  93. package/dist/runtime/components/ui/EPAccordion.d.vue.ts +26 -0
  94. package/dist/runtime/components/ui/EPAccordion.vue +64 -0
  95. package/dist/runtime/components/ui/EPAccordion.vue.d.ts +26 -0
  96. package/dist/runtime/components/ui/EPAvatar.d.vue.ts +9 -0
  97. package/dist/runtime/components/ui/EPAvatar.vue +25 -0
  98. package/dist/runtime/components/ui/EPAvatar.vue.d.ts +9 -0
  99. package/dist/runtime/components/ui/EPBadge.d.vue.ts +16 -0
  100. package/dist/runtime/components/ui/EPBadge.vue +17 -0
  101. package/dist/runtime/components/ui/EPBadge.vue.d.ts +16 -0
  102. package/dist/runtime/components/ui/EPButton.d.vue.ts +22 -0
  103. package/dist/runtime/components/ui/EPButton.vue +55 -0
  104. package/dist/runtime/components/ui/EPButton.vue.d.ts +22 -0
  105. package/dist/runtime/components/ui/EPCheckbox.d.vue.ts +11 -0
  106. package/dist/runtime/components/ui/EPCheckbox.vue +21 -0
  107. package/dist/runtime/components/ui/EPCheckbox.vue.d.ts +11 -0
  108. package/dist/runtime/components/ui/EPColorPicker.d.vue.ts +19 -0
  109. package/dist/runtime/components/ui/EPColorPicker.vue +63 -0
  110. package/dist/runtime/components/ui/EPColorPicker.vue.d.ts +19 -0
  111. package/dist/runtime/components/ui/EPDialog.d.vue.ts +24 -0
  112. package/dist/runtime/components/ui/EPDialog.vue +54 -0
  113. package/dist/runtime/components/ui/EPDialog.vue.d.ts +24 -0
  114. package/dist/runtime/components/ui/EPDropdownMenu.d.vue.ts +25 -0
  115. package/dist/runtime/components/ui/EPDropdownMenu.vue +40 -0
  116. package/dist/runtime/components/ui/EPDropdownMenu.vue.d.ts +25 -0
  117. package/dist/runtime/components/ui/EPFormField.d.vue.ts +24 -0
  118. package/dist/runtime/components/ui/EPFormField.vue +62 -0
  119. package/dist/runtime/components/ui/EPFormField.vue.d.ts +24 -0
  120. package/dist/runtime/components/ui/EPInputText.d.vue.ts +17 -0
  121. package/dist/runtime/components/ui/EPInputText.vue +33 -0
  122. package/dist/runtime/components/ui/EPInputText.vue.d.ts +17 -0
  123. package/dist/runtime/components/ui/EPLinkEditor.d.vue.ts +16 -0
  124. package/dist/runtime/components/ui/EPLinkEditor.vue +169 -0
  125. package/dist/runtime/components/ui/EPLinkEditor.vue.d.ts +16 -0
  126. package/dist/runtime/components/ui/EPRadioButton.d.vue.ts +16 -0
  127. package/dist/runtime/components/ui/EPRadioButton.vue +34 -0
  128. package/dist/runtime/components/ui/EPRadioButton.vue.d.ts +16 -0
  129. package/dist/runtime/components/ui/EPSelect.d.vue.ts +21 -0
  130. package/dist/runtime/components/ui/EPSelect.vue +73 -0
  131. package/dist/runtime/components/ui/EPSelect.vue.d.ts +21 -0
  132. package/dist/runtime/components/ui/EPSlider.d.vue.ts +16 -0
  133. package/dist/runtime/components/ui/EPSlider.vue +51 -0
  134. package/dist/runtime/components/ui/EPSlider.vue.d.ts +16 -0
  135. package/dist/runtime/components/ui/EPSwitch.d.vue.ts +11 -0
  136. package/dist/runtime/components/ui/EPSwitch.vue +23 -0
  137. package/dist/runtime/components/ui/EPSwitch.vue.d.ts +11 -0
  138. package/dist/runtime/components/ui/EPTextarea.d.vue.ts +12 -0
  139. package/dist/runtime/components/ui/EPTextarea.vue +18 -0
  140. package/dist/runtime/components/ui/EPTextarea.vue.d.ts +12 -0
  141. package/dist/runtime/components/ui/EPToast.d.vue.ts +13 -0
  142. package/dist/runtime/components/ui/EPToast.vue +60 -0
  143. package/dist/runtime/components/ui/EPToast.vue.d.ts +13 -0
  144. package/dist/runtime/components/ui/EPTooltip.d.vue.ts +17 -0
  145. package/dist/runtime/components/ui/EPTooltip.vue +34 -0
  146. package/dist/runtime/components/ui/EPTooltip.vue.d.ts +17 -0
  147. package/dist/runtime/components/ui/form-field-context.d.ts +12 -0
  148. package/dist/runtime/components/ui/form-field-context.js +1 -0
  149. package/dist/runtime/composables/useEponyme.d.ts +24 -0
  150. package/dist/runtime/composables/useEponyme.js +63 -0
  151. package/dist/runtime/composables/useEponymeAuth.d.ts +16 -0
  152. package/dist/runtime/composables/useEponymeAuth.js +81 -0
  153. package/dist/runtime/composables/useEponymeCollection.d.ts +27 -0
  154. package/dist/runtime/composables/useEponymeCollection.js +44 -0
  155. package/dist/runtime/composables/useEponymeColorPresets.d.ts +5 -0
  156. package/dist/runtime/composables/useEponymeColorPresets.js +16 -0
  157. package/dist/runtime/composables/useEponymeConfig.d.ts +1 -0
  158. package/dist/runtime/composables/useEponymeConfig.js +4 -0
  159. package/dist/runtime/composables/useEponymeForm.d.ts +35 -0
  160. package/dist/runtime/composables/useEponymeForm.js +75 -0
  161. package/dist/runtime/composables/useEponymeHistory.d.ts +26 -0
  162. package/dist/runtime/composables/useEponymeHistory.js +24 -0
  163. package/dist/runtime/composables/useEponymeValidation.d.ts +21 -0
  164. package/dist/runtime/composables/useEponymeValidation.js +34 -0
  165. package/dist/runtime/fields/array.d.ts +2 -0
  166. package/dist/runtime/fields/array.js +3 -0
  167. package/dist/runtime/fields/boolean.d.ts +2 -0
  168. package/dist/runtime/fields/boolean.js +3 -0
  169. package/dist/runtime/fields/checkbox-group.d.ts +2 -0
  170. package/dist/runtime/fields/checkbox-group.js +3 -0
  171. package/dist/runtime/fields/color.d.ts +2 -0
  172. package/dist/runtime/fields/color.js +3 -0
  173. package/dist/runtime/fields/date.d.ts +3 -0
  174. package/dist/runtime/fields/date.js +6 -0
  175. package/dist/runtime/fields/email.d.ts +2 -0
  176. package/dist/runtime/fields/email.js +3 -0
  177. package/dist/runtime/fields/image.d.ts +2 -0
  178. package/dist/runtime/fields/image.js +3 -0
  179. package/dist/runtime/fields/index.d.ts +37 -0
  180. package/dist/runtime/fields/index.js +19 -0
  181. package/dist/runtime/fields/number.d.ts +2 -0
  182. package/dist/runtime/fields/number.js +3 -0
  183. package/dist/runtime/fields/radio.d.ts +2 -0
  184. package/dist/runtime/fields/radio.js +3 -0
  185. package/dist/runtime/fields/rich-text.d.ts +2 -0
  186. package/dist/runtime/fields/rich-text.js +3 -0
  187. package/dist/runtime/fields/section.d.ts +2 -0
  188. package/dist/runtime/fields/section.js +3 -0
  189. package/dist/runtime/fields/select.d.ts +2 -0
  190. package/dist/runtime/fields/select.js +3 -0
  191. package/dist/runtime/fields/slug.d.ts +2 -0
  192. package/dist/runtime/fields/slug.js +3 -0
  193. package/dist/runtime/fields/string.d.ts +2 -0
  194. package/dist/runtime/fields/string.js +3 -0
  195. package/dist/runtime/fields/tab.d.ts +2 -0
  196. package/dist/runtime/fields/tab.js +3 -0
  197. package/dist/runtime/fields/textarea.d.ts +2 -0
  198. package/dist/runtime/fields/textarea.js +3 -0
  199. package/dist/runtime/fields/url.d.ts +2 -0
  200. package/dist/runtime/fields/url.js +3 -0
  201. package/dist/runtime/middleware/eponyme-auth.d.ts +2 -0
  202. package/dist/runtime/middleware/eponyme-auth.js +13 -0
  203. package/dist/runtime/middleware/eponyme-owner.d.ts +2 -0
  204. package/dist/runtime/middleware/eponyme-owner.js +7 -0
  205. package/dist/runtime/pages/EponymeChangePasswordPage.d.vue.ts +3 -0
  206. package/dist/runtime/pages/EponymeChangePasswordPage.vue +118 -0
  207. package/dist/runtime/pages/EponymeChangePasswordPage.vue.d.ts +3 -0
  208. package/dist/runtime/pages/EponymeDetailPage.d.vue.ts +3 -0
  209. package/dist/runtime/pages/EponymeDetailPage.vue +83 -0
  210. package/dist/runtime/pages/EponymeDetailPage.vue.d.ts +3 -0
  211. package/dist/runtime/pages/EponymeIndexPage.d.vue.ts +3 -0
  212. package/dist/runtime/pages/EponymeIndexPage.vue +51 -0
  213. package/dist/runtime/pages/EponymeIndexPage.vue.d.ts +3 -0
  214. package/dist/runtime/pages/EponymeLoginPage.d.vue.ts +3 -0
  215. package/dist/runtime/pages/EponymeLoginPage.vue +102 -0
  216. package/dist/runtime/pages/EponymeLoginPage.vue.d.ts +3 -0
  217. package/dist/runtime/pages/EponymeUsersPage.d.vue.ts +3 -0
  218. package/dist/runtime/pages/EponymeUsersPage.vue +261 -0
  219. package/dist/runtime/pages/EponymeUsersPage.vue.d.ts +3 -0
  220. package/dist/runtime/server/api/eponyme/[name].get.d.ts +4 -0
  221. package/dist/runtime/server/api/eponyme/[name].get.js +20 -0
  222. package/dist/runtime/server/api/eponyme/[name].patch.d.ts +11 -0
  223. package/dist/runtime/server/api/eponyme/[name].patch.js +20 -0
  224. package/dist/runtime/server/api/eponyme-auth/change-password.post.d.ts +4 -0
  225. package/dist/runtime/server/api/eponyme-auth/change-password.post.js +21 -0
  226. package/dist/runtime/server/api/eponyme-auth/login.post.d.ts +4 -0
  227. package/dist/runtime/server/api/eponyme-auth/login.post.js +12 -0
  228. package/dist/runtime/server/api/eponyme-auth/logout.post.d.ts +4 -0
  229. package/dist/runtime/server/api/eponyme-auth/logout.post.js +13 -0
  230. package/dist/runtime/server/api/eponyme-auth/session.get.d.ts +4 -0
  231. package/dist/runtime/server/api/eponyme-auth/session.get.js +5 -0
  232. package/dist/runtime/server/api/eponyme-collections/[path].delete.d.ts +4 -0
  233. package/dist/runtime/server/api/eponyme-collections/[path].delete.js +11 -0
  234. package/dist/runtime/server/api/eponyme-collections/[path].get.d.ts +4 -0
  235. package/dist/runtime/server/api/eponyme-collections/[path].get.js +11 -0
  236. package/dist/runtime/server/api/eponyme-collections/[path].post.d.ts +7 -0
  237. package/dist/runtime/server/api/eponyme-collections/[path].post.js +16 -0
  238. package/dist/runtime/server/api/eponyme-forms/[path].delete.d.ts +6 -0
  239. package/dist/runtime/server/api/eponyme-forms/[path].delete.js +19 -0
  240. package/dist/runtime/server/api/eponyme-forms/[path].get.d.ts +4 -0
  241. package/dist/runtime/server/api/eponyme-forms/[path].get.js +22 -0
  242. package/dist/runtime/server/api/eponyme-forms/[path].post.d.ts +19 -0
  243. package/dist/runtime/server/api/eponyme-forms/[path].post.js +36 -0
  244. package/dist/runtime/server/api/eponyme-history/[path].get.d.ts +4 -0
  245. package/dist/runtime/server/api/eponyme-history/[path].get.js +11 -0
  246. package/dist/runtime/server/api/eponyme-history/[path].patch.d.ts +2 -0
  247. package/dist/runtime/server/api/eponyme-history/[path].patch.js +18 -0
  248. package/dist/runtime/server/api/eponyme-sitemap.get.d.ts +4 -0
  249. package/dist/runtime/server/api/eponyme-sitemap.get.js +5 -0
  250. package/dist/runtime/server/api/eponyme-statuses.get.d.ts +4 -0
  251. package/dist/runtime/server/api/eponyme-statuses.get.js +7 -0
  252. package/dist/runtime/server/api/eponyme-users/[id]/reset-password.post.d.ts +5 -0
  253. package/dist/runtime/server/api/eponyme-users/[id]/reset-password.post.js +12 -0
  254. package/dist/runtime/server/api/eponyme-users/[id].patch.d.ts +4 -0
  255. package/dist/runtime/server/api/eponyme-users/[id].patch.js +14 -0
  256. package/dist/runtime/server/api/eponyme-users/index.get.d.ts +4 -0
  257. package/dist/runtime/server/api/eponyme-users/index.get.js +7 -0
  258. package/dist/runtime/server/api/eponyme-users/index.post.d.ts +5 -0
  259. package/dist/runtime/server/api/eponyme-users/index.post.js +13 -0
  260. package/dist/runtime/server/plugins/eponyme-sync.d.ts +2 -0
  261. package/dist/runtime/server/plugins/eponyme-sync.js +14 -0
  262. package/dist/runtime/server/services/eponyme-auth-service.d.ts +2 -0
  263. package/dist/runtime/server/services/eponyme-auth-service.js +15 -0
  264. package/dist/runtime/server/services/eponyme-auth-store.d.ts +119 -0
  265. package/dist/runtime/server/services/eponyme-auth-store.js +227 -0
  266. package/dist/runtime/server/services/eponyme-form-service.d.ts +3 -0
  267. package/dist/runtime/server/services/eponyme-form-service.js +8 -0
  268. package/dist/runtime/server/services/eponyme-form-store.d.ts +100 -0
  269. package/dist/runtime/server/services/eponyme-form-store.js +109 -0
  270. package/dist/runtime/server/services/eponyme-service.d.ts +3 -0
  271. package/dist/runtime/server/services/eponyme-service.js +8 -0
  272. package/dist/runtime/server/services/eponyme-store.d.ts +202 -0
  273. package/dist/runtime/server/services/eponyme-store.js +338 -0
  274. package/dist/runtime/server/utils/auth.d.ts +11 -0
  275. package/dist/runtime/server/utils/auth.js +41 -0
  276. package/dist/runtime/server/utils/eponyme-form.d.ts +14 -0
  277. package/dist/runtime/server/utils/eponyme-form.js +6 -0
  278. package/dist/runtime/server/utils/eponyme-sitemap.d.ts +7 -0
  279. package/dist/runtime/server/utils/eponyme-sitemap.js +7 -0
  280. package/dist/runtime/server/utils/form-route.d.ts +14 -0
  281. package/dist/runtime/server/utils/form-route.js +14 -0
  282. package/dist/runtime/server/utils/password.d.ts +4 -0
  283. package/dist/runtime/server/utils/password.js +30 -0
  284. package/dist/runtime/types/auth.d.ts +20 -0
  285. package/dist/runtime/types/auth.js +7 -0
  286. package/dist/runtime/types/eponyme-config.d.ts +11 -0
  287. package/dist/runtime/types/eponyme-navigation.d.ts +6 -0
  288. package/dist/runtime/types/eponyme-navigation.js +0 -0
  289. package/dist/runtime/types/eponyme.d.ts +87 -0
  290. package/dist/runtime/types/eponyme.js +0 -0
  291. package/dist/runtime/types/field.d.ts +203 -0
  292. package/dist/runtime/types/field.js +0 -0
  293. package/dist/runtime/types/index.d.ts +3 -0
  294. package/dist/runtime/types/index.js +3 -0
  295. package/dist/runtime/types/nuxt.d.ts +11 -0
  296. package/dist/runtime/utils/as-record.d.ts +1 -0
  297. package/dist/runtime/utils/as-record.js +3 -0
  298. package/dist/runtime/utils/build-eponyme-schema.d.ts +22 -0
  299. package/dist/runtime/utils/build-eponyme-schema.js +42 -0
  300. package/dist/runtime/utils/changed-paths.d.ts +6 -0
  301. package/dist/runtime/utils/changed-paths.js +25 -0
  302. package/dist/runtime/utils/create-default-eponyme-data.d.ts +5 -0
  303. package/dist/runtime/utils/create-default-eponyme-data.js +12 -0
  304. package/dist/runtime/utils/field-path.d.ts +14 -0
  305. package/dist/runtime/utils/field-path.js +23 -0
  306. package/dist/runtime/utils/get-eponyme-schemas.d.ts +7 -0
  307. package/dist/runtime/utils/get-eponyme-schemas.js +33 -0
  308. package/dist/runtime/utils/get-field-default-value.d.ts +4 -0
  309. package/dist/runtime/utils/get-field-default-value.js +56 -0
  310. package/dist/runtime/utils/humanize-label.d.ts +6 -0
  311. package/dist/runtime/utils/humanize-label.js +3 -0
  312. package/dist/runtime/utils/initials.d.ts +1 -0
  313. package/dist/runtime/utils/initials.js +3 -0
  314. package/dist/runtime/utils/is-field-visible.d.ts +2 -0
  315. package/dist/runtime/utils/is-field-visible.js +14 -0
  316. package/dist/runtime/utils/normalize-hex-color.d.ts +8 -0
  317. package/dist/runtime/utils/normalize-hex-color.js +11 -0
  318. package/dist/runtime/utils/normalize-slug.d.ts +1 -0
  319. package/dist/runtime/utils/normalize-slug.js +4 -0
  320. package/dist/runtime/utils/preview.d.ts +30 -0
  321. package/dist/runtime/utils/preview.js +30 -0
  322. package/dist/runtime/utils/validate-eponyme-data.d.ts +10 -0
  323. package/dist/runtime/utils/validate-eponyme-data.js +204 -0
  324. package/dist/types.d.mts +11 -0
  325. package/package.json +96 -0
@@ -0,0 +1,26 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ export { collection, defineEponymeConfig, form } from './eponyme.mjs';
3
+ export { field, today } from '../dist/runtime/fields/index.js';
4
+ export { EPONYME_ROLES, canEditEponyme, isEponymeRole } from '../dist/runtime/types/auth.js';
5
+ export { ArrayFieldDefinition, ArrayFieldOptions, ArrayItemDefinition, ArrayItemFieldDefinition, ArrayItemSchema, ArrayItemValue, BooleanFieldDefinition, BooleanFieldOptions, CheckboxGroupFieldDefinition, CheckboxGroupFieldOptions, CollectionSlugField, ColorFieldDefinition, ColorFieldOptions, DateFieldDefinition, DateFieldOptions, EmailFieldDefinition, EmailFieldOptions, EponymeAuthSession, EponymeAuthUser, EponymeCollectionDataByName, EponymeCollectionDefinition, EponymeCollectionDefinitionBase, EponymeCollectionName, EponymeCollectionOptions, EponymeConfig, EponymeData, EponymeDataByName, EponymeFormDataByName, EponymeFormDefinition, EponymeFormDefinitionBase, EponymeFormFieldDefinition, EponymeFormMode, EponymeFormName, EponymeFormOptions, EponymeFormSchema, EponymeManagedUserResult, EponymeName, EponymeRole, EponymeSchema, FieldDefinition, FieldValidationResult, FieldValidator, FieldVisibilityCondition, ImageFieldDefinition, ImageFieldOptions, NumberFieldDefinition, NumberFieldOptions, RadioFieldDefinition, RadioFieldOptions, RichTextFieldDefinition, RichTextFieldOptions, SectionFieldDefinition, SectionFieldOptions, SectionItemFieldDefinition, SectionItemValue, SectionSchema, SectionValue, SelectFieldDefinition, SelectFieldOptions, SelectOption, SlugFieldDefinition, SlugFieldOptions, StringFieldDefinition, StringFieldOptions, TabDefinition, TabFieldDefinition, TabFieldOptions, TabsSchema, TabsValue, TextareaFieldDefinition, TextareaFieldOptions, TodayDateDefault, UrlFieldDefinition, UrlFieldOptions, UrlType, UrlValue } from '../dist/runtime/types/index.js';
6
+
7
+ interface ModuleOptions {
8
+ dashboardPath?: string;
9
+ /** Public routes used for previews and sitemap entries. Collections use a `:slug` placeholder. */
10
+ previewPaths?: Record<string, string>;
11
+ /** Path to a server module exporting an already initialized PrismaClient. */
12
+ prismaClient: string;
13
+ /** Default palette offered by every color field; a field can override it with its own `presets`. */
14
+ colorPresets?: Array<string | {
15
+ label: string;
16
+ value: string;
17
+ }>;
18
+ auth?: {
19
+ /** Fixed lifetime of an authenticated session. */
20
+ sessionDurationDays?: number;
21
+ };
22
+ }
23
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
24
+
25
+ export { _default as default };
26
+ export type { ModuleOptions };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@karibsen/eponyme",
3
+ "configKey": "eponyme",
4
+ "version": "0.1.0",
5
+ "builder": {
6
+ "@nuxt/module-builder": "1.0.2",
7
+ "unbuild": "3.6.1"
8
+ }
9
+ }
@@ -0,0 +1,154 @@
1
+ import { defineNuxtModule, useLogger, createResolver, installModule, findPath, addImports, addImportsDir, addServerImports, addRouteMiddleware, addTypeTemplate, addServerHandler, addServerPlugin } from '@nuxt/kit';
2
+ import pc from 'picocolors';
3
+ import tailwindcss from '@tailwindcss/vite';
4
+ import { resolve } from 'node:path';
5
+
6
+ const module$1 = defineNuxtModule({
7
+ meta: {
8
+ name: "@karibsen/eponyme",
9
+ configKey: "eponyme"
10
+ },
11
+ defaults: {
12
+ dashboardPath: "/__eponyme",
13
+ previewPaths: {},
14
+ prismaClient: "",
15
+ colorPresets: [],
16
+ auth: {
17
+ sessionDurationDays: 7
18
+ }
19
+ },
20
+ async setup(options, nuxt) {
21
+ const logger = useLogger("eponyme");
22
+ const resolver = createResolver(import.meta.url);
23
+ const dashboardPath = `/${(options.dashboardPath || "__eponyme").replace(/^\/+|\/+$/g, "")}`;
24
+ const publicRuntimeConfig = nuxt.options.runtimeConfig.public;
25
+ publicRuntimeConfig.eponyme = {
26
+ previewPaths: options.previewPaths ?? {},
27
+ dashboardPath,
28
+ colorPresets: options.colorPresets ?? []
29
+ };
30
+ nuxt.options.runtimeConfig.eponymeAuth = {
31
+ sessionDurationDays: options.auth?.sessionDurationDays ?? 7
32
+ };
33
+ await installModule("@nuxt/icon", {
34
+ serverBundle: { collections: ["mingcute"] },
35
+ clientBundle: {
36
+ // Explicit list: an icon missing here is not bundled and renders blank in production.
37
+ icons: [
38
+ "mingcute:history-anticlockwise-line",
39
+ "mingcute:eye-2-line",
40
+ "mingcute:layout-leftbar-close-line",
41
+ "mingcute:layout-leftbar-open-line",
42
+ "mingcute:down-small-line",
43
+ "mingcute:search-line",
44
+ "mingcute:close-line",
45
+ "mingcute:arrow-right-line",
46
+ "mingcute:align-arrow-right-line",
47
+ "mingcute:link-2-line",
48
+ "mingcute:settings-3-line",
49
+ "mingcute:refresh-2-line",
50
+ "mingcute:external-link-line",
51
+ "mingcute:paragraph-line",
52
+ "mingcute:heading-2-line",
53
+ "mingcute:heading-3-line",
54
+ "mingcute:bold-line",
55
+ "mingcute:italic-line",
56
+ "mingcute:strikethrough-line",
57
+ "mingcute:link-line",
58
+ "mingcute:pic-line",
59
+ "mingcute:list-check-line",
60
+ "mingcute:list-ordered-line",
61
+ "mingcute:quote-left-line",
62
+ "mingcute:back-2-line",
63
+ "mingcute:forward-2-line"
64
+ ]
65
+ }
66
+ }, nuxt);
67
+ const preparing = Boolean(nuxt.options._prepare);
68
+ if (!options.prismaClient) {
69
+ if (!preparing) throw new Error(`${pc.red("[Eponyme]")} eponyme.prismaClient is required.`);
70
+ logger.info("No prismaClient configured, skipping wiring (prepare).");
71
+ return;
72
+ }
73
+ const prismaPath = await findPath(resolve(nuxt.options.rootDir, options.prismaClient));
74
+ if (!prismaPath)
75
+ throw new Error(`${pc.red("[Eponyme]")} Prisma client module not found: ${options.prismaClient}`);
76
+ addImports([
77
+ { name: "defineEponymeConfig", from: resolver.resolve("./config/config") },
78
+ { name: "collection", from: resolver.resolve("./config/collection") },
79
+ { name: "form", from: resolver.resolve("./config/form") },
80
+ { name: "field", from: resolver.resolve("./runtime/fields") },
81
+ { name: "today", from: resolver.resolve("./runtime/fields") }
82
+ ]);
83
+ addImportsDir(resolver.resolve("./runtime/composables"));
84
+ addServerImports([
85
+ { name: "getEponymeSitemapEntries", from: resolver.resolve("./runtime/server/utils/eponyme-sitemap") },
86
+ // A `custom` form posts to the host application's own route, so this is what
87
+ // keeps server-side validation as the security boundary.
88
+ { name: "validateEponymeForm", from: resolver.resolve("./runtime/server/utils/eponyme-form") }
89
+ ]);
90
+ addRouteMiddleware({
91
+ name: "eponyme-auth",
92
+ path: resolver.resolve("./runtime/middleware/eponyme-auth")
93
+ });
94
+ addRouteMiddleware({
95
+ name: "eponyme-owner",
96
+ path: resolver.resolve("./runtime/middleware/eponyme-owner")
97
+ });
98
+ nuxt.options.build.transpile.push("reka-ui");
99
+ nuxt.options.css.push(resolver.resolve("./runtime/assets/dashboard.css"));
100
+ nuxt.hook("vite:extendConfig", (viteConfig) => {
101
+ const plugins = viteConfig.plugins;
102
+ plugins?.push(tailwindcss());
103
+ });
104
+ const configPath = await findPath(resolve(nuxt.options.rootDir, "eponyme.config.ts"));
105
+ if (!configPath) {
106
+ if (!preparing) throw new Error(`${pc.red("[Eponyme]")} eponyme.config.ts not found at the project root.`);
107
+ logger.info("No eponyme.config.ts found, skipping wiring (prepare).");
108
+ return;
109
+ }
110
+ nuxt.options.alias["#eponyme/config"] = configPath;
111
+ nuxt.options.alias["#eponyme/prisma"] = prismaPath;
112
+ addTypeTemplate({
113
+ filename: "types/eponyme-config.d.ts",
114
+ getContents: () => `declare module '#eponyme/config' {
115
+ const config: typeof import(${JSON.stringify(configPath)})['default']
116
+ export default config
117
+ }
118
+ `
119
+ });
120
+ addServerHandler({ route: "/api/eponyme/**", handler: resolver.resolve("./runtime/server/api/eponyme/[name].get") });
121
+ addServerHandler({ route: "/api/eponyme/**", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme/[name].patch") });
122
+ addServerHandler({ route: "/api/eponyme-statuses", handler: resolver.resolve("./runtime/server/api/eponyme-statuses.get") });
123
+ addServerHandler({ route: "/api/eponyme-sitemap", handler: resolver.resolve("./runtime/server/api/eponyme-sitemap.get") });
124
+ addServerHandler({ route: "/api/eponyme-history/**", handler: resolver.resolve("./runtime/server/api/eponyme-history/[path].get") });
125
+ addServerHandler({ route: "/api/eponyme-history/**", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme-history/[path].patch") });
126
+ addServerHandler({ route: "/api/eponyme-collections/**", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].get") });
127
+ addServerHandler({ route: "/api/eponyme-collections/**", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].post") });
128
+ addServerHandler({ route: "/api/eponyme-collections/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-collections/[path].delete") });
129
+ addServerHandler({ route: "/api/eponyme-forms/**", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].get") });
130
+ addServerHandler({ route: "/api/eponyme-forms/**", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].post") });
131
+ addServerHandler({ route: "/api/eponyme-forms/**", method: "delete", handler: resolver.resolve("./runtime/server/api/eponyme-forms/[path].delete") });
132
+ addServerHandler({ route: "/api/eponyme-auth/session", handler: resolver.resolve("./runtime/server/api/eponyme-auth/session.get") });
133
+ addServerHandler({ route: "/api/eponyme-auth/login", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-auth/login.post") });
134
+ addServerHandler({ route: "/api/eponyme-auth/logout", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-auth/logout.post") });
135
+ addServerHandler({ route: "/api/eponyme-auth/change-password", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-auth/change-password.post") });
136
+ addServerHandler({ route: "/api/eponyme-users", handler: resolver.resolve("./runtime/server/api/eponyme-users/index.get") });
137
+ addServerHandler({ route: "/api/eponyme-users", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-users/index.post") });
138
+ addServerHandler({ route: "/api/eponyme-users/:id", method: "patch", handler: resolver.resolve("./runtime/server/api/eponyme-users/[id].patch") });
139
+ addServerHandler({ route: "/api/eponyme-users/:id/reset-password", method: "post", handler: resolver.resolve("./runtime/server/api/eponyme-users/[id]/reset-password.post") });
140
+ addServerPlugin(resolver.resolve("./runtime/server/plugins/eponyme-sync"));
141
+ nuxt.hook("pages:extend", (pages) => {
142
+ pages.push(
143
+ { name: "eponyme-login", path: `${dashboardPath}/login`, file: resolver.resolve("./runtime/pages/EponymeLoginPage.vue") },
144
+ { name: "eponyme-change-password", path: `${dashboardPath}/change-password`, file: resolver.resolve("./runtime/pages/EponymeChangePasswordPage.vue"), meta: { middleware: ["eponyme-auth"] } },
145
+ { name: "eponyme-users", path: `${dashboardPath}/users`, file: resolver.resolve("./runtime/pages/EponymeUsersPage.vue"), meta: { middleware: ["eponyme-auth", "eponyme-owner"] } },
146
+ { name: "eponyme-index", path: dashboardPath, file: resolver.resolve("./runtime/pages/EponymeIndexPage.vue"), meta: { middleware: ["eponyme-auth"] } },
147
+ { name: "eponyme-detail", path: `${dashboardPath}/:eponyme(.*)*`, file: resolver.resolve("./runtime/pages/EponymeDetailPage.vue"), meta: { middleware: ["eponyme-auth"] } }
148
+ );
149
+ });
150
+ logger.debug(`config loaded: ${configPath}`);
151
+ }
152
+ });
153
+
154
+ export { module$1 as default };
@@ -0,0 +1 @@
1
+ @import "tailwindcss/theme" layer(theme) prefix(ep);@import "tailwindcss/preflight" layer(base);@import "tailwindcss/utilities" layer(utilities) prefix(ep);@source "../components";@source "../pages";@theme{--font-sans:"SF Pro Text",Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;--color-theme-ep:#1c1c1c;--color-border-ep:#343434;--color-selected-ep:#262626;--color-text-ep:#e7e7e7;--color-muted-ep:#8d8d8d;--color-success-ep:#72d39a;--color-warning-ep:#e6b85c;--color-danger-ep:#ff8585}:root.dark{--color-eponyme-50:#fafafa;--color-eponyme-100:#f5f5f5;--color-eponyme-200:#e6e6e6;--color-eponyme-300:#d3d3d3;--color-eponyme-400:#a3a3a3;--color-eponyme-500:#727272;--color-eponyme-600:#535353;--color-eponyme-700:#404040;--color-eponyme-800:#272727;--color-eponyme-900:#1c1c1c;--color-eponyme-950:#0b0b0b}@layer base{.eponyme-portal,.eponyme-root{font-family:var(--ep-font-sans)}:where(.eponyme-root,.eponyme-portal),:where(.eponyme-root,.eponyme-portal) *,:where(.eponyme-root,.eponyme-portal) :after,:where(.eponyme-root,.eponyme-portal) :before{border:0 solid;box-sizing:border-box;margin:0;padding:0}}.eponyme-date-input{color-scheme:dark}
@@ -0,0 +1,9 @@
1
+ import type { EponymeCollectionDefinitionBase } from '../../types/index.js';
2
+ type __VLS_Props = {
3
+ basePath: string;
4
+ name: string;
5
+ definition: EponymeCollectionDefinitionBase;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,238 @@
1
+ <script setup>
2
+ import { useAsyncData, useRequestFetch, useRoute, useRouter, useState } from "#app";
3
+ import { computed, ref, watch } from "vue";
4
+ import { normalizeSlug } from "../../utils/normalize-slug";
5
+ import { useEponymeAuth } from "../../composables/useEponymeAuth";
6
+ import EPBadge from "../ui/EPBadge.vue";
7
+ import EPButton from "../ui/EPButton.vue";
8
+ import EPDialog from "../ui/EPDialog.vue";
9
+ import EPFormField from "../ui/EPFormField.vue";
10
+ import EPInputText from "../ui/EPInputText.vue";
11
+ const props = defineProps({
12
+ basePath: { type: String, required: true },
13
+ name: { type: String, required: true },
14
+ definition: { type: Object, required: true }
15
+ });
16
+ const route = useRoute();
17
+ const router = useRouter();
18
+ const requestFetch = useRequestFetch();
19
+ const createOpen = ref(route.query.create === "1");
20
+ const creating = ref(false);
21
+ const title = ref("");
22
+ const slug = ref("");
23
+ const slugTouched = ref(false);
24
+ const errors = ref({});
25
+ const collectionEntries = useState("eponyme:collection-entries", () => ({}));
26
+ const endpoint = computed(() => `/api/eponyme-collections/${props.name}`);
27
+ const auth = useEponymeAuth();
28
+ const { data: response, pending, refresh } = useAsyncData(
29
+ `eponyme:collection:${props.name}`,
30
+ () => requestFetch(endpoint.value, { query: { version: "draft" } })
31
+ );
32
+ const entries = computed(() => response.value?.entries ?? []);
33
+ const label = computed(() => props.definition.label || humanize(props.name.split("/").at(-1) || props.name));
34
+ watch(title, (value) => {
35
+ if (!slugTouched.value) slug.value = normalizeSlug(value);
36
+ });
37
+ watch(() => route.query.create, (value) => createOpen.value = value === "1");
38
+ watch(entries, (value) => collectionEntries.value = { ...collectionEntries.value, [props.name]: value }, { immediate: true });
39
+ function humanize(value) {
40
+ return value.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
41
+ }
42
+ function truncateTitle(value, maxLength = 48) {
43
+ const characters = [...value];
44
+ if (characters.length <= maxLength) return value;
45
+ return `${characters.slice(0, maxLength - 1).join("")}\u2026`;
46
+ }
47
+ function setSlug(value) {
48
+ slugTouched.value = true;
49
+ slug.value = normalizeSlug(String(value));
50
+ }
51
+ function resetCreateForm() {
52
+ title.value = "";
53
+ slug.value = "";
54
+ slugTouched.value = false;
55
+ errors.value = {};
56
+ }
57
+ async function setCreateOpen(open) {
58
+ createOpen.value = open;
59
+ if (!open) {
60
+ resetCreateForm();
61
+ if (route.query.create === "1") {
62
+ const query = { ...route.query };
63
+ delete query.create;
64
+ await router.replace({ query });
65
+ }
66
+ }
67
+ }
68
+ async function createEntry() {
69
+ creating.value = true;
70
+ errors.value = {};
71
+ try {
72
+ const result = await requestFetch(endpoint.value, {
73
+ method: "POST",
74
+ body: {
75
+ [props.definition.titleField]: title.value,
76
+ [props.definition.slugField]: slug.value
77
+ }
78
+ });
79
+ await refresh();
80
+ await setCreateOpen(false);
81
+ await router.push(`${props.basePath}/${props.name}/${result.slug}`);
82
+ } catch (error) {
83
+ const fetchError = error;
84
+ errors.value = fetchError.data?.errors ?? { _form: ["Unable to create this entry."] };
85
+ } finally {
86
+ creating.value = false;
87
+ }
88
+ }
89
+ async function deleteEntry(entry) {
90
+ if (!confirm(`Delete \u201C${entry.title}\u201D? This cannot be undone.`)) return;
91
+ await requestFetch(`${endpoint.value}/${entry.slug}`, { method: "DELETE" });
92
+ await refresh();
93
+ }
94
+ function formatDate(value) {
95
+ return value ? new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value)) : "";
96
+ }
97
+ </script>
98
+
99
+ <template>
100
+ <section class="ep:mx-auto ep:w-full ep:max-w-3xl ep:px-6 ep:py-8 ep:md:px-10 ep:md:py-12">
101
+ <header class="ep:flex ep:flex-wrap ep:items-start ep:justify-between ep:gap-4">
102
+ <div>
103
+ <p class="ep:m-0 ep:text-[11px] ep:font-semibold ep:tracking-widest ep:text-muted-ep ep:uppercase">
104
+ Collection
105
+ </p>
106
+ <h1 class="ep:mt-2 ep:mb-0 ep:text-3xl ep:font-semibold ep:tracking-tight ep:text-white">
107
+ {{ label }}
108
+ </h1>
109
+ <p
110
+ v-if="definition.description"
111
+ class="ep:mt-2 ep:mb-0 ep:text-sm ep:text-muted-ep"
112
+ >
113
+ {{ definition.description }}
114
+ </p>
115
+ </div>
116
+ <EPButton
117
+ v-if="auth.canEdit.value"
118
+ variant="primary"
119
+ @click="createOpen = true"
120
+ >
121
+ + New {{ humanize(name.split("/").at(-1) || "entry").replace(/s$/, "") }}
122
+ </EPButton>
123
+ </header>
124
+
125
+ <p
126
+ v-if="pending"
127
+ class="ep:mt-8 ep:text-sm ep:text-muted-ep"
128
+ >
129
+ Loading…
130
+ </p>
131
+ <div
132
+ v-else-if="entries.length"
133
+ class="ep:mt-8 ep:grid ep:gap-3"
134
+ >
135
+ <article
136
+ v-for="entry in entries"
137
+ :key="entry.slug"
138
+ class="ep:group ep:flex ep:items-center ep:justify-between ep:gap-4 ep:rounded-xl ep:bg-selected-ep/50 ep:p-4"
139
+ >
140
+ <NuxtLink
141
+ :to="`${basePath}/${name}/${entry.slug}`"
142
+ :title="entry.title"
143
+ class="ep:min-w-0 ep:flex-1 ep:no-underline"
144
+ >
145
+ <span class="ep:flex ep:min-w-0 ep:items-center ep:gap-2">
146
+ <span class="ep:min-w-0 ep:flex-1 ep:overflow-hidden ep:text-ellipsis ep:whitespace-nowrap ep:text-sm ep:font-semibold ep:text-white">{{ truncateTitle(entry.title) }}</span>
147
+ <EPBadge
148
+ class="ep:shrink-0"
149
+ :variant="entry.status === 'draft' ? 'warning' : 'success'"
150
+ >{{ entry.status }}</EPBadge>
151
+ </span>
152
+ <span class="ep:mt-1 ep:block ep:text-xs ep:text-muted-ep">/{{ entry.slug }}<template v-if="entry.updatedAt"> · {{ formatDate(entry.updatedAt) }}</template></span>
153
+ </NuxtLink>
154
+ <EPButton
155
+ v-if="auth.canEdit.value"
156
+ size="sm"
157
+ variant="danger"
158
+ class="ep:opacity-0 ep:group-hover:opacity-100 ep:focus-visible:opacity-100"
159
+ @click="deleteEntry(entry)"
160
+ >
161
+ Delete
162
+ </EPButton>
163
+ </article>
164
+ </div>
165
+ <div
166
+ v-else
167
+ class="ep:mt-8 ep:rounded-xl ep:border ep:border-dashed ep:border-border-ep ep:p-8 ep:text-center"
168
+ >
169
+ <p class="ep:m-0 ep:text-sm ep:text-muted-ep">
170
+ No entries yet.
171
+ </p>
172
+ <EPButton
173
+ v-if="auth.canEdit.value"
174
+ class="ep:mt-4"
175
+ @click="createOpen = true"
176
+ >
177
+ Create the first one
178
+ </EPButton>
179
+ </div>
180
+
181
+ <EPDialog
182
+ :open="createOpen && auth.canEdit.value"
183
+ :title="`New ${label.replace(/s$/, '')}`"
184
+ description="Give the entry a title and a permanent URL slug."
185
+ @update:open="setCreateOpen"
186
+ >
187
+ <form
188
+ class="ep:grid ep:gap-4"
189
+ @submit.prevent="createEntry"
190
+ >
191
+ <EPFormField
192
+ :id="`collection-${name}-title`"
193
+ :label="humanize(definition.titleField)"
194
+ required
195
+ :errors="errors[definition.titleField]"
196
+ >
197
+ <EPInputText
198
+ :id="`collection-${name}-title`"
199
+ v-model="title"
200
+ autofocus
201
+ :invalid="Boolean(errors[definition.titleField]?.length)"
202
+ />
203
+ </EPFormField>
204
+ <EPFormField
205
+ :id="`collection-${name}-slug`"
206
+ :label="humanize(definition.slugField)"
207
+ required
208
+ :errors="errors[definition.slugField]"
209
+ >
210
+ <EPInputText
211
+ :id="`collection-${name}-slug`"
212
+ :model-value="slug"
213
+ :invalid="Boolean(errors[definition.slugField]?.length)"
214
+ @update:model-value="setSlug"
215
+ />
216
+ </EPFormField>
217
+ <p
218
+ v-if="errors._form"
219
+ class="ep:m-0 ep:text-xs ep:text-danger-ep"
220
+ >
221
+ {{ errors._form.join(" ") }}
222
+ </p>
223
+ <div class="ep:flex ep:justify-end ep:gap-2">
224
+ <EPButton @click="setCreateOpen(false)">
225
+ Cancel
226
+ </EPButton>
227
+ <EPButton
228
+ type="submit"
229
+ variant="primary"
230
+ :loading="creating"
231
+ >
232
+ Create
233
+ </EPButton>
234
+ </div>
235
+ </form>
236
+ </EPDialog>
237
+ </section>
238
+ </template>
@@ -0,0 +1,9 @@
1
+ import type { EponymeCollectionDefinitionBase } from '../../types/index.js';
2
+ type __VLS_Props = {
3
+ basePath: string;
4
+ name: string;
5
+ definition: EponymeCollectionDefinitionBase;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,7 @@
1
+ type __VLS_Props = {
2
+ value: string;
3
+ label?: string;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,28 @@
1
+ <script setup>
2
+ import { useClipboard } from "@vueuse/core";
3
+ import { computed } from "vue";
4
+ import EPButton from "../ui/EPButton.vue";
5
+ const props = defineProps({
6
+ value: { type: String, required: true },
7
+ label: { type: String, required: false, default: "Copy" }
8
+ });
9
+ const source = computed(() => props.value);
10
+ const { copy, copied, isSupported } = useClipboard({ source });
11
+ </script>
12
+
13
+ <template>
14
+ <div class="ep:flex ep:items-center ep:gap-2 ep:rounded-xl ep:bg-selected-ep ep:p-2">
15
+ <code class="ep:min-w-0 ep:flex-1 ep:break-all ep:px-1 ep:font-mono ep:text-sm ep:text-white">
16
+ {{ value }}
17
+ </code>
18
+ <EPButton
19
+ size="sm"
20
+ variant="secondary"
21
+ :disabled="!isSupported"
22
+ :aria-label="label"
23
+ @click="copy()"
24
+ >
25
+ {{ copied ? "Copied" : label }}
26
+ </EPButton>
27
+ </div>
28
+ </template>
@@ -0,0 +1,7 @@
1
+ type __VLS_Props = {
2
+ value: string;
3
+ label?: string;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,7 @@
1
+ type __VLS_Props = {
2
+ basePath: string;
3
+ eponyme: string;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,146 @@
1
+ <script setup>
2
+ import { computed, ref, watch } from "vue";
3
+ const props = defineProps({
4
+ basePath: { type: String, required: true },
5
+ eponyme: { type: String, required: true }
6
+ });
7
+ const parts = computed(() => props.eponyme.split("/"));
8
+ const folder = computed(() => parts.value.slice(0, -1).join("/"));
9
+ const eponymeLabel = computed(() => label(parts.value[parts.value.length - 1] ?? ""));
10
+ const breadcrumbs = computed(() => parts.value.slice(0, -1).map((part, index) => ({
11
+ label: label(part),
12
+ path: parts.value.slice(0, index + 1).join("/")
13
+ })));
14
+ const hiddenBreadcrumbs = computed(() => breadcrumbs.value.length > 3 ? breadcrumbs.value.slice(1, -1) : []);
15
+ const breadcrumbMenuAtBottom = ref(false);
16
+ const visibleBreadcrumbs = computed(() => {
17
+ if (!hiddenBreadcrumbs.value.length) return breadcrumbs.value.map((breadcrumb) => ({ kind: "link", ...breadcrumb }));
18
+ return [
19
+ { kind: "link", ...breadcrumbs.value[0] },
20
+ { kind: "collapsed", label: "Hidden folders", path: "__collapsed__" },
21
+ { kind: "link", ...breadcrumbs.value.at(-1) }
22
+ ];
23
+ });
24
+ function label(name) {
25
+ return name.replace(/[-_]/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
26
+ }
27
+ function middleEllipsis(value, maxLength = 28) {
28
+ const characters = [...value];
29
+ if (characters.length <= maxLength) return value;
30
+ const available = maxLength - 1;
31
+ const startLength = Math.ceil(available / 2);
32
+ const endLength = Math.floor(available / 2);
33
+ return `${characters.slice(0, startLength).join("")}\u2026${characters.slice(-endLength).join("")}`;
34
+ }
35
+ function updateBreadcrumbMenuScroll(event) {
36
+ const menu = event.currentTarget;
37
+ if (!menu) return;
38
+ const remainingScroll = menu.scrollHeight - menu.clientHeight - menu.scrollTop;
39
+ breadcrumbMenuAtBottom.value = remainingScroll <= 2;
40
+ }
41
+ watch(() => hiddenBreadcrumbs.value.map((breadcrumb) => breadcrumb.path).join("|"), () => {
42
+ breadcrumbMenuAtBottom.value = false;
43
+ });
44
+ </script>
45
+
46
+ <template>
47
+ <nav
48
+ v-if="folder"
49
+ class="ep:relative ep:z-50 ep:flex ep:min-h-14 ep:min-w-0 ep:items-center ep:overflow-visible ep:border-b ep:border-border-ep ep:bg-theme-ep/95 ep:px-3 ep:text-xs ep:backdrop-blur"
50
+ aria-label="Eponyme navigation"
51
+ >
52
+ <div class="eponyme-mobile-breadcrumbs ep:flex ep:min-w-0 ep:flex-1 ep:touch-pan-x ep:items-center ep:overflow-x-auto ep:overscroll-x-contain ep:sm:hidden">
53
+ <template
54
+ v-for="breadcrumb in breadcrumbs"
55
+ :key="breadcrumb.path"
56
+ >
57
+ <NuxtLink
58
+ :to="`${basePath}/${breadcrumb.path}`"
59
+ :title="breadcrumb.label"
60
+ class="ep:max-w-40 ep:shrink-0 ep:overflow-hidden ep:text-ellipsis ep:whitespace-nowrap ep:rounded-md ep:px-2 ep:py-1.5 ep:font-medium ep:text-muted-ep ep:no-underline"
61
+ >
62
+ {{ middleEllipsis(breadcrumb.label) }}
63
+ </NuxtLink>
64
+ <span
65
+ class="ep:mx-1 ep:shrink-0 ep:text-muted-ep"
66
+ aria-hidden="true"
67
+ >/</span>
68
+ </template>
69
+ <span
70
+ :title="eponymeLabel"
71
+ class="ep:shrink-0 ep:whitespace-nowrap ep:px-2 ep:font-medium ep:text-text-ep"
72
+ >{{ middleEllipsis(eponymeLabel, 36) }}</span>
73
+ </div>
74
+
75
+ <div class="ep:hidden ep:min-w-0 ep:flex-1 ep:items-center ep:sm:flex">
76
+ <template
77
+ v-for="breadcrumb in visibleBreadcrumbs"
78
+ :key="breadcrumb.path"
79
+ >
80
+ <NuxtLink
81
+ v-if="breadcrumb.kind === 'link'"
82
+ :to="`${basePath}/${breadcrumb.path}`"
83
+ :title="breadcrumb.label"
84
+ class="ep:max-w-40 ep:shrink-0 ep:overflow-hidden ep:text-ellipsis ep:whitespace-nowrap ep:rounded-md ep:px-2 ep:py-1.5 ep:font-medium ep:text-muted-ep ep:no-underline ep:transition ep:hover:bg-selected-ep ep:hover:text-white"
85
+ >
86
+ {{ middleEllipsis(breadcrumb.label) }}
87
+ </NuxtLink>
88
+ <div
89
+ v-else
90
+ class="ep:group ep:relative ep:shrink-0"
91
+ >
92
+ <button
93
+ type="button"
94
+ class="ep:cursor-default ep:rounded-md ep:border-0 ep:bg-transparent ep:px-2 ep:py-1.5 ep:font-semibold ep:text-muted-ep ep:transition ep:hover:bg-selected-ep ep:hover:text-white ep:focus-visible:bg-selected-ep ep:focus-visible:text-white ep:focus-visible:outline-none ep:focus-visible:ring-2 ep:focus-visible:ring-white/20"
95
+ aria-haspopup="menu"
96
+ :aria-label="`${hiddenBreadcrumbs.length} hidden folders`"
97
+ >
98
+ …
99
+ </button>
100
+ <div class="ep:invisible ep:absolute ep:top-full ep:left-0 ep:z-[60] ep:w-max ep:max-w-72 ep:pt-1 ep:opacity-0 ep:transition ep:group-hover:visible ep:group-hover:opacity-100 ep:group-focus-within:visible ep:group-focus-within:opacity-100">
101
+ <div class="ep:relative ep:overflow-hidden ep:rounded-xl ep:border ep:border-border-ep ep:bg-theme-ep ep:p-2">
102
+ <div
103
+ :key="folder"
104
+ role="menu"
105
+ class="eponyme-breadcrumb-menu ep:grid ep:max-h-[212px] ep:gap-1 ep:overflow-y-auto ep:overscroll-contain ep:pr-1"
106
+ @scroll.passive="updateBreadcrumbMenuScroll"
107
+ >
108
+ <NuxtLink
109
+ v-for="hiddenBreadcrumb in hiddenBreadcrumbs"
110
+ :key="hiddenBreadcrumb.path"
111
+ :to="`${basePath}/${hiddenBreadcrumb.path}`"
112
+ :title="hiddenBreadcrumb.label"
113
+ role="menuitem"
114
+ class="ep:block ep:max-w-64 ep:overflow-hidden ep:text-ellipsis ep:whitespace-nowrap ep:rounded-lg ep:px-3 ep:py-2 ep:font-medium ep:text-text-ep ep:no-underline ep:transition ep:hover:bg-selected-ep ep:hover:text-white"
115
+ >
116
+ {{ hiddenBreadcrumb.label }}
117
+ </NuxtLink>
118
+ </div>
119
+ <Transition name="breadcrumb-scroll-hint">
120
+ <div
121
+ v-if="hiddenBreadcrumbs.length > 6 && !breadcrumbMenuAtBottom"
122
+ class="eponyme-breadcrumb-scroll-hint ep:pointer-events-none ep:absolute ep:right-2 ep:bottom-2 ep:left-2 ep:flex ep:h-14 ep:items-end ep:justify-center ep:pb-1 ep:text-center ep:text-[10px] ep:font-semibold ep:tracking-widest ep:text-muted-ep ep:uppercase"
123
+ aria-hidden="true"
124
+ >
125
+ Scroll ↓
126
+ </div>
127
+ </Transition>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ <span
132
+ class="ep:mx-1 ep:shrink-0 ep:text-muted-ep"
133
+ aria-hidden="true"
134
+ >/</span>
135
+ </template>
136
+ <span
137
+ :title="eponymeLabel"
138
+ class="ep:min-w-0 ep:overflow-hidden ep:text-ellipsis ep:whitespace-nowrap ep:px-2 ep:font-medium ep:text-text-ep"
139
+ >{{ middleEllipsis(eponymeLabel, 36) }}</span>
140
+ </div>
141
+ </nav>
142
+ </template>
143
+
144
+ <style scoped>
145
+ .eponyme-breadcrumb-menu{scrollbar-color:hsla(0,0%,100%,.35) transparent;scrollbar-width:thin}.eponyme-breadcrumb-menu::-webkit-scrollbar{width:6px}.eponyme-breadcrumb-menu::-webkit-scrollbar-thumb{background:hsla(0,0%,100%,.35);border-radius:999px}.eponyme-breadcrumb-scroll-hint{background:linear-gradient(180deg,transparent,var(--ep-color-theme-ep,#1c1c1c) 65%)}.breadcrumb-scroll-hint-enter-active,.breadcrumb-scroll-hint-leave-active{transition:opacity .16s ease,transform .16s ease}.breadcrumb-scroll-hint-enter-from,.breadcrumb-scroll-hint-leave-to{opacity:0;transform:translateY(4px)}@media (prefers-reduced-motion:reduce){.breadcrumb-scroll-hint-enter-active,.breadcrumb-scroll-hint-leave-active{transition:none}}
146
+ </style>