@dskripchenko/laravel-admin 1.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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/dist/.gitkeep +0 -0
  4. package/dist/api/bootstrap.d.ts +38 -0
  5. package/dist/api/bootstrap.test.d.ts +1 -0
  6. package/dist/api/client.d.ts +30 -0
  7. package/dist/api/client.test.d.ts +1 -0
  8. package/dist/api/envelope.d.ts +24 -0
  9. package/dist/api/envelope.test.d.ts +1 -0
  10. package/dist/api/errors.d.ts +40 -0
  11. package/dist/api/errors.test.d.ts +1 -0
  12. package/dist/components/AdminApp.vue.d.ts +2 -0
  13. package/dist/components/ForbiddenPage.vue.d.ts +2 -0
  14. package/dist/components/HomePage.vue.d.ts +2 -0
  15. package/dist/components/NotFoundPage.vue.d.ts +2 -0
  16. package/dist/components/SettingsPage.vue.d.ts +2 -0
  17. package/dist/components/UnknownScreenPage.vue.d.ts +2 -0
  18. package/dist/components/auth/LoginForm.test.d.ts +1 -0
  19. package/dist/components/auth/LoginForm.vue.d.ts +17 -0
  20. package/dist/components/auth/LoginPage.test.d.ts +1 -0
  21. package/dist/components/auth/LoginPage.vue.d.ts +26 -0
  22. package/dist/components/auth/TwoFactorForm.test.d.ts +1 -0
  23. package/dist/components/auth/TwoFactorForm.vue.d.ts +8 -0
  24. package/dist/components/auth/index.d.ts +6 -0
  25. package/dist/components/createComponentRegistry.d.ts +22 -0
  26. package/dist/components/dashboard/BarChartWidget.vue.d.ts +18 -0
  27. package/dist/components/dashboard/DashboardPage.test.d.ts +1 -0
  28. package/dist/components/dashboard/DashboardPage.vue.d.ts +28 -0
  29. package/dist/components/dashboard/DonutChartWidget.vue.d.ts +13 -0
  30. package/dist/components/dashboard/GaugeWidget.vue.d.ts +29 -0
  31. package/dist/components/dashboard/HeatmapWidget.vue.d.ts +18 -0
  32. package/dist/components/dashboard/MarkdownWidget.vue.d.ts +8 -0
  33. package/dist/components/dashboard/RecentTableWidget.vue.d.ts +12 -0
  34. package/dist/components/dashboard/StatWidget.vue.d.ts +22 -0
  35. package/dist/components/dashboard/UnknownWidget.vue.d.ts +5 -0
  36. package/dist/components/dashboard/WidgetRenderer.vue.d.ts +10 -0
  37. package/dist/components/dashboard/builtin.d.ts +4 -0
  38. package/dist/components/dashboard/index.d.ts +16 -0
  39. package/dist/components/dashboard/registry.d.ts +25 -0
  40. package/dist/components/dashboard/registry.test.d.ts +1 -0
  41. package/dist/components/fields/CheckboxField.vue.d.ts +16 -0
  42. package/dist/components/fields/DateField.vue.d.ts +25 -0
  43. package/dist/components/fields/NumberField.vue.d.ts +24 -0
  44. package/dist/components/fields/SelectField.vue.d.ts +28 -0
  45. package/dist/components/fields/TextAreaField.vue.d.ts +20 -0
  46. package/dist/components/fields/TextField.vue.d.ts +22 -0
  47. package/dist/components/fields/UnknownField.vue.d.ts +6 -0
  48. package/dist/components/fields/fields.test.d.ts +1 -0
  49. package/dist/components/fields/wysiwyg/quill/QuillField.vue.d.ts +26 -0
  50. package/dist/components/fields/wysiwyg/quill/index.d.ts +12 -0
  51. package/dist/components/fields/wysiwyg/tinymce/TinymceField.vue.d.ts +31 -0
  52. package/dist/components/fields/wysiwyg/tinymce/index.d.ts +12 -0
  53. package/dist/components/gallery/FieldGalleryPage.test.d.ts +1 -0
  54. package/dist/components/gallery/FieldGalleryPage.vue.d.ts +2 -0
  55. package/dist/components/gallery/index.d.ts +1 -0
  56. package/dist/components/import/ImportWizardPage.test.d.ts +1 -0
  57. package/dist/components/import/ImportWizardPage.vue.d.ts +59 -0
  58. package/dist/components/import/index.d.ts +1 -0
  59. package/dist/components/infolist/BadgeEntry.vue.d.ts +18 -0
  60. package/dist/components/infolist/IconEntry.vue.d.ts +22 -0
  61. package/dist/components/infolist/InfolistRenderer.test.d.ts +1 -0
  62. package/dist/components/infolist/InfolistRenderer.vue.d.ts +11 -0
  63. package/dist/components/infolist/KeyValueEntry.vue.d.ts +11 -0
  64. package/dist/components/infolist/TextEntry.vue.d.ts +17 -0
  65. package/dist/components/infolist/UnknownEntry.vue.d.ts +6 -0
  66. package/dist/components/infolist/builtin.d.ts +4 -0
  67. package/dist/components/infolist/index.d.ts +13 -0
  68. package/dist/components/infolist/recordContext.d.ts +9 -0
  69. package/dist/components/infolist/registry.d.ts +19 -0
  70. package/dist/components/infolist/registry.test.d.ts +1 -0
  71. package/dist/components/layouts/ColumnsLayout.vue.d.ts +13 -0
  72. package/dist/components/layouts/RowsLayout.vue.d.ts +10 -0
  73. package/dist/components/layouts/SectionLayout.vue.d.ts +11 -0
  74. package/dist/components/layouts/TabsLayout.vue.d.ts +22 -0
  75. package/dist/components/notifications/NotificationsDrawer.test.d.ts +1 -0
  76. package/dist/components/notifications/NotificationsDrawer.vue.d.ts +13 -0
  77. package/dist/components/notifications/index.d.ts +1 -0
  78. package/dist/components/profile/ProfilePage.test.d.ts +1 -0
  79. package/dist/components/profile/ProfilePage.vue.d.ts +50 -0
  80. package/dist/components/profile/index.d.ts +1 -0
  81. package/dist/components/render/FieldRenderer.test.d.ts +1 -0
  82. package/dist/components/render/FieldRenderer.vue.d.ts +9 -0
  83. package/dist/components/render/LayoutRenderer.test.d.ts +1 -0
  84. package/dist/components/render/LayoutRenderer.vue.d.ts +10 -0
  85. package/dist/components/render/builtin.d.ts +9 -0
  86. package/dist/components/render/formState.d.ts +36 -0
  87. package/dist/components/render/formState.test.d.ts +1 -0
  88. package/dist/components/render/index.d.ts +23 -0
  89. package/dist/components/render/registry.d.ts +35 -0
  90. package/dist/components/render/registry.test.d.ts +1 -0
  91. package/dist/components/resource/ResourceFormPage.test.d.ts +1 -0
  92. package/dist/components/resource/ResourceFormPage.vue.d.ts +13 -0
  93. package/dist/components/resource/ResourceIndexPage.test.d.ts +1 -0
  94. package/dist/components/resource/ResourceIndexPage.vue.d.ts +44 -0
  95. package/dist/components/resource/ResourceViewPage.test.d.ts +1 -0
  96. package/dist/components/resource/ResourceViewPage.vue.d.ts +13 -0
  97. package/dist/components/resource/index.d.ts +6 -0
  98. package/dist/components/shell/AdminShell.vue.d.ts +35 -0
  99. package/dist/components/shell/AdminSidebar.test.d.ts +1 -0
  100. package/dist/components/shell/AdminSidebar.vue.d.ts +27 -0
  101. package/dist/components/shell/AdminTopBar.test.d.ts +1 -0
  102. package/dist/components/shell/AdminTopBar.vue.d.ts +33 -0
  103. package/dist/components/shell/index.d.ts +18 -0
  104. package/dist/components/shell/widgets/LocaleSwitcher.test.d.ts +1 -0
  105. package/dist/components/shell/widgets/LocaleSwitcher.vue.d.ts +2 -0
  106. package/dist/components/shell/widgets/NotificationBell.vue.d.ts +2 -0
  107. package/dist/components/shell/widgets/ThemeToggle.test.d.ts +1 -0
  108. package/dist/components/shell/widgets/ThemeToggle.vue.d.ts +2 -0
  109. package/dist/components/shell/widgets/UserMenu.test.d.ts +1 -0
  110. package/dist/components/shell/widgets/UserMenu.vue.d.ts +2 -0
  111. package/dist/createAdminApp.d.ts +85 -0
  112. package/dist/createAdminApp.test.d.ts +1 -0
  113. package/dist/formState-DGNcH1XQ.js +40 -0
  114. package/dist/formState-DGNcH1XQ.js.map +1 -0
  115. package/dist/formState-GlJBphEn.cjs +2 -0
  116. package/dist/formState-GlJBphEn.cjs.map +1 -0
  117. package/dist/index.cjs +2 -0
  118. package/dist/index.cjs.map +1 -0
  119. package/dist/index.d.ts +62 -0
  120. package/dist/index.mjs +4345 -0
  121. package/dist/index.mjs.map +1 -0
  122. package/dist/quill.cjs +2 -0
  123. package/dist/quill.cjs.map +1 -0
  124. package/dist/quill.mjs +71 -0
  125. package/dist/quill.mjs.map +1 -0
  126. package/dist/router/builder.d.ts +52 -0
  127. package/dist/router/builder.test.d.ts +1 -0
  128. package/dist/router/guards.d.ts +56 -0
  129. package/dist/router/guards.test.d.ts +1 -0
  130. package/dist/router/index.d.ts +63 -0
  131. package/dist/router/index.test.d.ts +1 -0
  132. package/dist/stores/auth.d.ts +142 -0
  133. package/dist/stores/auth.test.d.ts +1 -0
  134. package/dist/stores/index.d.ts +21 -0
  135. package/dist/stores/locale.d.ts +29 -0
  136. package/dist/stores/locale.test.d.ts +1 -0
  137. package/dist/stores/manifest.d.ts +515 -0
  138. package/dist/stores/manifest.test.d.ts +1 -0
  139. package/dist/stores/menu.d.ts +215 -0
  140. package/dist/stores/menu.test.d.ts +1 -0
  141. package/dist/stores/notifications.d.ts +137 -0
  142. package/dist/stores/notifications.test.d.ts +1 -0
  143. package/dist/stores/registry.d.ts +16 -0
  144. package/dist/stores/registry.test.d.ts +1 -0
  145. package/dist/stores/resourceForm.d.ts +91 -0
  146. package/dist/stores/resourceForm.test.d.ts +1 -0
  147. package/dist/stores/resourceIndex.d.ts +149 -0
  148. package/dist/stores/resourceIndex.test.d.ts +1 -0
  149. package/dist/stores/theme.d.ts +29 -0
  150. package/dist/stores/theme.test.d.ts +1 -0
  151. package/dist/style.css +1 -0
  152. package/dist/tinymce.cjs +2 -0
  153. package/dist/tinymce.cjs.map +1 -0
  154. package/dist/tinymce.mjs +80 -0
  155. package/dist/tinymce.mjs.map +1 -0
  156. package/dist/types/bootstrap.d.ts +50 -0
  157. package/package.json +162 -0
  158. package/resources/fonts/InterDisplay-Bold.woff2 +0 -0
  159. package/resources/fonts/InterDisplay-ExtraBold.woff2 +0 -0
  160. package/resources/fonts/InterDisplay-SemiBold.woff2 +0 -0
  161. package/resources/fonts/InterVariable-Italic.woff2 +0 -0
  162. package/resources/fonts/InterVariable.woff2 +0 -0
  163. package/resources/fonts/fonts.css +69 -0
package/dist/quill.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),c=require("./formState-GlJBphEn.cjs"),u={key:0,class:"admin-field__label"},s={key:0,class:"admin-field__required","aria-hidden":"true"},m={class:"admin-field__control"},f={key:1,class:"admin-field__error"},h={key:2,class:"admin-field__help"},p=e.defineComponent({__name:"QuillField",props:{name:{},label:{default:null},help:{default:null},required:{type:Boolean,default:!1},placeholder:{default:null},toolbar:{default:"full"},theme:{default:"snow"},disabled:{type:Boolean,default:!1}},setup(l){const t=l,o=c.useFormState(),d=e.computed(()=>o.getField(t.name)??""),a=e.computed(()=>o.errors[t.name]?.[0]);function r(n){o.setField(t.name,n)}const i=e.defineComponent({props:{content:String,toolbar:[String,Array],theme:String,placeholder:String,readOnly:Boolean},setup(){return()=>e.h("div",{class:"quill-fallback"},"@vueup/vue-quill не загружен — host передаёт actual Editor через peer-dep")}});return(n,b)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["admin-field",{"admin-field--invalid":a.value!==void 0}])},[l.label?(e.openBlock(),e.createElementBlock("label",u,[e.createElementVNode("span",null,e.toDisplayString(l.label),1),l.required?(e.openBlock(),e.createElementBlock("span",s,"*")):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.createElementVNode("div",m,[e.createVNode(e.unref(i),{content:d.value,toolbar:l.toolbar,theme:l.theme,placeholder:l.placeholder??void 0,"read-only":l.disabled,"onUpdate:content":r},null,8,["content","toolbar","theme","placeholder","read-only"])]),a.value?(e.openBlock(),e.createElementBlock("p",f,e.toDisplayString(a.value),1)):l.help?(e.openBlock(),e.createElementBlock("p",h,e.toDisplayString(l.help),1)):e.createCommentVNode("",!0)],2))}});exports.QuillField=p;
2
+ //# sourceMappingURL=quill.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quill.cjs","sources":["../resources/ts/components/fields/wysiwyg/quill/QuillField.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * QuillField — wrapper над @vueup/vue-quill для использования в\n * field-registry admin-renderer'а.\n *\n * Подключение в host-проекте:\n *\n * import { registerField } from '@dskripchenko/laravel-admin'\n * import { QuillField } from '@dskripchenko/laravel-admin/quill'\n * registerField('wysiwyg', QuillField)\n *\n * Для image upload'ов host регистрирует кастомный handler в Quill Toolbar\n * (наша обёртка предоставляет default — POST /api/admin/uploads).\n */\nimport { computed, h, defineComponent } from 'vue'\nimport { useFormState } from '../../../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n /**\n * Quill toolbar config — string или array. См. https://quilljs.com/docs/modules/toolbar/.\n */\n toolbar?: string | unknown[]\n /**\n * Имя темы Quill ('snow' default | 'bubble' | 'core').\n */\n theme?: 'snow' | 'bubble' | 'core'\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n required: false,\n toolbar: 'full',\n theme: 'snow',\n disabled: false,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n\nconst Editor = defineComponent({\n props: {\n content: String,\n toolbar: [String, Array],\n theme: String,\n placeholder: String,\n readOnly: Boolean,\n },\n setup() {\n return () => h('div', {\n class: 'quill-fallback',\n }, '@vueup/vue-quill не загружен — host передаёт actual Editor через peer-dep')\n },\n})\n</script>\n\n<template>\n <div :class=\"['admin-field', { 'admin-field--invalid': errorMsg !== undefined }]\">\n <label v-if=\"label\" class=\"admin-field__label\">\n <span>{{ label }}</span>\n <span v-if=\"required\" class=\"admin-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <div class=\"admin-field__control\">\n <Editor\n :content=\"value\"\n :toolbar=\"toolbar\"\n :theme=\"theme\"\n :placeholder=\"placeholder ?? undefined\"\n :read-only=\"disabled\"\n @update:content=\"onUpdate\"\n />\n </div>\n <p v-if=\"errorMsg\" class=\"admin-field__error\">{{ errorMsg }}</p>\n <p v-else-if=\"help\" class=\"admin-field__help\">{{ help }}</p>\n </div>\n</template>\n"],"names":["props","__props","form","useFormState","value","computed","errorMsg","onUpdate","next","Editor","defineComponent","h","_createElementBlock","_normalizeClass","_openBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_createVNode","_unref","_hoisted_4","_toDisplayString","_hoisted_5"],"mappings":"qlBAkCA,MAAMA,EAAQC,EAURC,EAAOC,EAAAA,aAAA,EACPC,EAAQC,EAAAA,SAAiB,IAAOH,EAAK,SAASF,EAAM,IAAI,GAA4B,EAAE,EACtFM,EAAWD,EAAAA,SAA6B,IAAMH,EAAK,OAAOF,EAAM,IAAI,IAAI,CAAC,CAAC,EAEhF,SAASO,EAASC,EAAoB,CACpCN,EAAK,SAASF,EAAM,KAAMQ,CAAI,CAChC,CAEA,MAAMC,EAASC,EAAAA,gBAAgB,CAC7B,MAAO,CACL,QAAS,OACT,QAAS,CAAC,OAAQ,KAAK,EACvB,MAAO,OACP,YAAa,OACb,SAAU,OAAA,EAEZ,OAAQ,CACN,MAAO,IAAMC,EAAAA,EAAE,MAAO,CACpB,MAAO,gBAAA,EACN,2EAA2E,CAChF,CAAA,CACD,8BAICC,EAAAA,mBAiBM,MAAA,CAjBA,MAAKC,EAAAA,eAAA,CAAA,cAAA,CAAA,uBAA4CP,EAAA,QAAa,OAAS,CAAA,CAAA,GAC9DL,EAAA,OAAba,EAAAA,UAAA,EAAAF,EAAAA,mBAGQ,QAHRG,EAGQ,CAFNC,EAAAA,mBAAwB,8BAAff,EAAA,KAAK,EAAA,CAAA,EACFA,EAAA,wBAAZW,qBAA+E,OAA/EK,EAAuE,GAAC,8DAE1ED,EAAAA,mBASM,MATNE,EASM,CARJC,cAOEC,EAAAA,MAAAX,CAAA,EAAA,CANC,QAASL,EAAA,MACT,QAASH,EAAA,QACT,MAAOA,EAAA,MACP,YAAaA,EAAA,aAAe,OAC5B,YAAWA,EAAA,SACX,mBAAgBM,CAAA,oEAGZD,EAAA,qBAATM,EAAAA,mBAAgE,IAAhES,EAAgEC,EAAAA,gBAAfhB,EAAA,KAAQ,EAAA,CAAA,GAC3CL,EAAA,oBAAdW,EAAAA,mBAA4D,IAA5DW,EAA4DD,EAAAA,gBAAXrB,EAAA,IAAI,EAAA,CAAA"}
package/dist/quill.mjs ADDED
@@ -0,0 +1,71 @@
1
+ import { defineComponent as s, computed as u, h as p, openBlock as l, createElementBlock as t, normalizeClass as b, createElementVNode as c, toDisplayString as d, createCommentVNode as r, createVNode as v, unref as y } from "vue";
2
+ import { u as _ } from "./formState-DGNcH1XQ.js";
3
+ const g = {
4
+ key: 0,
5
+ class: "admin-field__label"
6
+ }, k = {
7
+ key: 0,
8
+ class: "admin-field__required",
9
+ "aria-hidden": "true"
10
+ }, S = { class: "admin-field__control" }, q = {
11
+ key: 1,
12
+ class: "admin-field__error"
13
+ }, B = {
14
+ key: 2,
15
+ class: "admin-field__help"
16
+ }, N = /* @__PURE__ */ s({
17
+ __name: "QuillField",
18
+ props: {
19
+ name: {},
20
+ label: { default: null },
21
+ help: { default: null },
22
+ required: { type: Boolean, default: !1 },
23
+ placeholder: { default: null },
24
+ toolbar: { default: "full" },
25
+ theme: { default: "snow" },
26
+ disabled: { type: Boolean, default: !1 }
27
+ },
28
+ setup(e) {
29
+ const a = e, n = _(), m = u(() => n.getField(a.name) ?? ""), o = u(() => n.errors[a.name]?.[0]);
30
+ function f(i) {
31
+ n.setField(a.name, i);
32
+ }
33
+ const h = s({
34
+ props: {
35
+ content: String,
36
+ toolbar: [String, Array],
37
+ theme: String,
38
+ placeholder: String,
39
+ readOnly: Boolean
40
+ },
41
+ setup() {
42
+ return () => p("div", {
43
+ class: "quill-fallback"
44
+ }, "@vueup/vue-quill не загружен — host передаёт actual Editor через peer-dep");
45
+ }
46
+ });
47
+ return (i, F) => (l(), t("div", {
48
+ class: b(["admin-field", { "admin-field--invalid": o.value !== void 0 }])
49
+ }, [
50
+ e.label ? (l(), t("label", g, [
51
+ c("span", null, d(e.label), 1),
52
+ e.required ? (l(), t("span", k, "*")) : r("", !0)
53
+ ])) : r("", !0),
54
+ c("div", S, [
55
+ v(y(h), {
56
+ content: m.value,
57
+ toolbar: e.toolbar,
58
+ theme: e.theme,
59
+ placeholder: e.placeholder ?? void 0,
60
+ "read-only": e.disabled,
61
+ "onUpdate:content": f
62
+ }, null, 8, ["content", "toolbar", "theme", "placeholder", "read-only"])
63
+ ]),
64
+ o.value ? (l(), t("p", q, d(o.value), 1)) : e.help ? (l(), t("p", B, d(e.help), 1)) : r("", !0)
65
+ ], 2));
66
+ }
67
+ });
68
+ export {
69
+ N as QuillField
70
+ };
71
+ //# sourceMappingURL=quill.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quill.mjs","sources":["../resources/ts/components/fields/wysiwyg/quill/QuillField.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * QuillField — wrapper над @vueup/vue-quill для использования в\n * field-registry admin-renderer'а.\n *\n * Подключение в host-проекте:\n *\n * import { registerField } from '@dskripchenko/laravel-admin'\n * import { QuillField } from '@dskripchenko/laravel-admin/quill'\n * registerField('wysiwyg', QuillField)\n *\n * Для image upload'ов host регистрирует кастомный handler в Quill Toolbar\n * (наша обёртка предоставляет default — POST /api/admin/uploads).\n */\nimport { computed, h, defineComponent } from 'vue'\nimport { useFormState } from '../../../render/formState'\n\ninterface Props {\n name: string\n label?: string | null\n help?: string | null\n required?: boolean\n placeholder?: string | null\n /**\n * Quill toolbar config — string или array. См. https://quilljs.com/docs/modules/toolbar/.\n */\n toolbar?: string | unknown[]\n /**\n * Имя темы Quill ('snow' default | 'bubble' | 'core').\n */\n theme?: 'snow' | 'bubble' | 'core'\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n label: null,\n help: null,\n placeholder: null,\n required: false,\n toolbar: 'full',\n theme: 'snow',\n disabled: false,\n})\n\nconst form = useFormState()\nconst value = computed<string>(() => (form.getField(props.name) as string | undefined) ?? '')\nconst errorMsg = computed<string | undefined>(() => form.errors[props.name]?.[0])\n\nfunction onUpdate(next: string): void {\n form.setField(props.name, next)\n}\n\nconst Editor = defineComponent({\n props: {\n content: String,\n toolbar: [String, Array],\n theme: String,\n placeholder: String,\n readOnly: Boolean,\n },\n setup() {\n return () => h('div', {\n class: 'quill-fallback',\n }, '@vueup/vue-quill не загружен — host передаёт actual Editor через peer-dep')\n },\n})\n</script>\n\n<template>\n <div :class=\"['admin-field', { 'admin-field--invalid': errorMsg !== undefined }]\">\n <label v-if=\"label\" class=\"admin-field__label\">\n <span>{{ label }}</span>\n <span v-if=\"required\" class=\"admin-field__required\" aria-hidden=\"true\">*</span>\n </label>\n <div class=\"admin-field__control\">\n <Editor\n :content=\"value\"\n :toolbar=\"toolbar\"\n :theme=\"theme\"\n :placeholder=\"placeholder ?? undefined\"\n :read-only=\"disabled\"\n @update:content=\"onUpdate\"\n />\n </div>\n <p v-if=\"errorMsg\" class=\"admin-field__error\">{{ errorMsg }}</p>\n <p v-else-if=\"help\" class=\"admin-field__help\">{{ help }}</p>\n </div>\n</template>\n"],"names":["props","__props","form","useFormState","value","computed","errorMsg","onUpdate","next","Editor","defineComponent","h","_createElementBlock","_normalizeClass","_openBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_createVNode","_unref","_hoisted_4","_toDisplayString","_hoisted_5"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,UAAMA,IAAQC,GAURC,IAAOC,EAAA,GACPC,IAAQC,EAAiB,MAAOH,EAAK,SAASF,EAAM,IAAI,KAA4B,EAAE,GACtFM,IAAWD,EAA6B,MAAMH,EAAK,OAAOF,EAAM,IAAI,IAAI,CAAC,CAAC;AAEhF,aAASO,EAASC,GAAoB;AACpC,MAAAN,EAAK,SAASF,EAAM,MAAMQ,CAAI;AAAA,IAChC;AAEA,UAAMC,IAASC,EAAgB;AAAA,MAC7B,OAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,QAAQ,KAAK;AAAA,QACvB,OAAO;AAAA,QACP,aAAa;AAAA,QACb,UAAU;AAAA,MAAA;AAAA,MAEZ,QAAQ;AACN,eAAO,MAAMC,EAAE,OAAO;AAAA,UACpB,OAAO;AAAA,QAAA,GACN,2EAA2E;AAAA,MAChF;AAAA,IAAA,CACD;2BAICC,EAiBM,OAAA;AAAA,MAjBA,OAAKC,EAAA,CAAA,eAAA,EAAA,wBAA4CP,EAAA,UAAa,QAAS,CAAA;AAAA,IAAA;MAC9DL,EAAA,SAAba,EAAA,GAAAF,EAGQ,SAHRG,GAGQ;AAAA,QAFNC,EAAwB,gBAAff,EAAA,KAAK,GAAA,CAAA;AAAA,QACFA,EAAA,iBAAZW,EAA+E,QAA/EK,GAAuE,GAAC;;MAE1ED,EASM,OATNE,GASM;AAAA,QARJC,EAOEC,EAAAX,CAAA,GAAA;AAAA,UANC,SAASL,EAAA;AAAA,UACT,SAASH,EAAA;AAAA,UACT,OAAOA,EAAA;AAAA,UACP,aAAaA,EAAA,eAAe;AAAA,UAC5B,aAAWA,EAAA;AAAA,UACX,oBAAgBM;AAAA,QAAA;;MAGZD,EAAA,cAATM,EAAgE,KAAhES,GAAgEC,EAAfhB,EAAA,KAAQ,GAAA,CAAA,KAC3CL,EAAA,aAAdW,EAA4D,KAA5DW,GAA4DD,EAAXrB,EAAA,IAAI,GAAA,CAAA;;;;"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * buildRoutesFromManifest — превращает AdminManifest в массив RouteRecordRaw.
3
+ *
4
+ * Маппинг:
5
+ * - resource{slug} → /r/{slug} (index)
6
+ * /r/{slug}/create (create)
7
+ * /r/{slug}/:id/edit (edit)
8
+ * /r/{slug}/:id (view, опционально)
9
+ * - screen{slug} → /screens/{slug}
10
+ * - settings{slug} → /settings/{slug}
11
+ * - dashboard{slug} → /dashboard/{slug}
12
+ *
13
+ * Component'ы передаются через resolver — host-проект решает, что отрисовать.
14
+ * Это позволяет library не тащить рендереры внутрь себя жёстко.
15
+ */
16
+ import type { RouteRecordRaw } from 'vue-router';
17
+ import type { Component } from 'vue';
18
+ import type { AdminManifest } from '../stores/manifest';
19
+ /** Vue Component либо async-loader (для code-splitting). */
20
+ export type AdminRouteComponent = Component | (() => Promise<Component>);
21
+ export interface RouteMeta {
22
+ /** Требует залогиненного пользователя. */
23
+ requiresAuth?: boolean;
24
+ /** Permissions, нужные для входа. ANY-логика (хотя бы одно совпадение). */
25
+ permissions?: string[];
26
+ /** Заголовок страницы (рендерим в <title> через router.afterEach). */
27
+ title?: string;
28
+ /** Тип админ-роута — для UI breadcrumbs/active-state. */
29
+ kind?: 'resource' | 'screen' | 'settings' | 'dashboard' | 'system' | 'auth';
30
+ /** Slug сущности из манифеста — для извлечения мета внутри компонента. */
31
+ slug?: string;
32
+ }
33
+ declare module 'vue-router' {
34
+ interface RouteMeta extends Record<string, unknown> {
35
+ }
36
+ }
37
+ /**
38
+ * Resolver компонентов для динамических роутов.
39
+ *
40
+ * Host-проект передаёт конкретные Vue-компоненты для каждой роли.
41
+ * Library не зависит от конкретных view'ов.
42
+ */
43
+ export interface RouteComponentResolver {
44
+ resourceIndex: AdminRouteComponent;
45
+ resourceCreate: AdminRouteComponent;
46
+ resourceEdit: AdminRouteComponent;
47
+ resourceView: AdminRouteComponent;
48
+ screen: AdminRouteComponent;
49
+ settings: AdminRouteComponent;
50
+ dashboard: AdminRouteComponent;
51
+ }
52
+ export declare function buildRoutesFromManifest(manifest: AdminManifest | null, components: RouteComponentResolver): RouteRecordRaw[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Router-guards: auth + permissions.
3
+ *
4
+ * Логика:
5
+ * 1. Если route.meta.requiresAuth и пользователь не залогинен → /login
6
+ * с ?redirect=...
7
+ * 2. Если у user'а есть pendingChallenge (2FA) — все защищённые роуты
8
+ * редиректят на /login (challenge-form там).
9
+ * 3. Если route.meta.permissions заданы — проверяем hasAnyPermission().
10
+ * Нет ни одного → /forbidden (или роут с name='admin.forbidden').
11
+ *
12
+ * Guards используют useAuthStore — но НЕ берут client напрямую: всё через
13
+ * permissions/isAuthenticated/pendingChallenge state. Stores должны быть
14
+ * захайдрейчены до setup'а router'а.
15
+ */
16
+ import type { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
17
+ /** Тип возвращаемого значения guard'а — true (passthrough) либо redirect-target. */
18
+ type GuardResult = boolean | RouteLocationRaw;
19
+ /**
20
+ * Простая 3-арг функция (то что router.beforeEach принимает).
21
+ * Не используем NavigationGuardWithThis<undefined>, т.к. она требует
22
+ * `this: undefined` что неудобно для прямого вызова в тестах.
23
+ */
24
+ type SimpleGuard = (to: RouteLocationNormalized, from: RouteLocationNormalized, next?: unknown) => GuardResult;
25
+ export interface AuthGuardOptions {
26
+ /** Имя login-роута. По умолчанию 'admin.login'. */
27
+ loginRouteName?: string;
28
+ /** Имя роута 403-страницы. По умолчанию 'admin.forbidden'. */
29
+ forbiddenRouteName?: string;
30
+ /**
31
+ * Имя query-параметра для возврата на исходную страницу после login.
32
+ * По умолчанию 'redirect'.
33
+ */
34
+ redirectQueryKey?: string;
35
+ }
36
+ /**
37
+ * Создаёт beforeEach guard. Pinia должна быть activeInstance к моменту
38
+ * вызова guard'а (router.beforeEach срабатывает на каждой навигации,
39
+ * включая первую — Pinia уже должна быть установлена).
40
+ */
41
+ export declare function createAuthGuard(opts?: AuthGuardOptions): SimpleGuard;
42
+ export interface TitleGuardOptions {
43
+ /** Шаблон заголовка. {title} — meta.title, {brand} — название бренда. */
44
+ template?: string;
45
+ /** Имя бренда. */
46
+ brand?: string;
47
+ /** Default title если в meta нет. */
48
+ fallback?: string;
49
+ }
50
+ /**
51
+ * Создаёт afterEach hook, обновляющий document.title.
52
+ *
53
+ * Шаблон по умолчанию: '{title} · {brand}' если оба, иначе один из.
54
+ */
55
+ export declare function createTitleGuard(opts?: TitleGuardOptions): (to: RouteLocationNormalized, from?: RouteLocationNormalized, failure?: unknown) => void;
56
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ /**
2
+ * createAdminRouter — фабрика admin-router'а.
3
+ *
4
+ * Использование:
5
+ *
6
+ * const router = createAdminRouter({
7
+ * base: '/admin',
8
+ * components: { ... },
9
+ * brand: 'My App',
10
+ * })
11
+ * await router.replaceManifestRoutes(manifestStore.manifest)
12
+ * app.use(router)
13
+ *
14
+ * Library намеренно не делает createWebHistory выбор за host'а — host передаёт
15
+ * объект history (createWebHistory / createWebHashHistory).
16
+ */
17
+ import { type Router, type RouteRecordRaw, type RouterHistory } from 'vue-router';
18
+ import type { AdminManifest } from '../stores/manifest';
19
+ import { type RouteComponentResolver, type AdminRouteComponent } from './builder';
20
+ import { type AuthGuardOptions, type TitleGuardOptions } from './guards';
21
+ export interface AdminRouterOptions {
22
+ /** Base URL admin-панели. По умолчанию '/admin'. */
23
+ base?: string;
24
+ /** History-implementation. По умолчанию createWebHistory(base). */
25
+ history?: RouterHistory;
26
+ /** Component resolver для resource/screen/settings/dashboard роутов. */
27
+ components: RouteComponentResolver & {
28
+ /** Login. */
29
+ login: AdminRouteComponent;
30
+ /** Главная (либо overview-dashboard). */
31
+ home: AdminRouteComponent;
32
+ /** 403 forbidden. */
33
+ forbidden: AdminRouteComponent;
34
+ /** 404 not found. */
35
+ notFound: AdminRouteComponent;
36
+ /** Страница профиля. */
37
+ profile?: AdminRouteComponent;
38
+ /** Страница уведомлений. */
39
+ notifications?: AdminRouteComponent;
40
+ };
41
+ /** Дополнительные руты сверху динамики. */
42
+ extraRoutes?: RouteRecordRaw[];
43
+ /** Опции auth-guard. */
44
+ authGuard?: AuthGuardOptions;
45
+ /** Опции title-guard. */
46
+ titleGuard?: TitleGuardOptions;
47
+ }
48
+ /**
49
+ * Расширенный Router с возможностью пере-построить динамические роуты.
50
+ */
51
+ export interface AdminRouter extends Router {
52
+ /**
53
+ * Пере-собрать динамические роуты из manifest'а.
54
+ * Удаляет старые admin.resource.* / admin.screen.* / admin.settings.* / admin.dashboard.*
55
+ * и заменяет на актуальные. Полезно при перезагрузке manifest'а.
56
+ */
57
+ replaceManifestRoutes(manifest: AdminManifest | null): void;
58
+ }
59
+ export declare function createAdminRouter(opts: AdminRouterOptions): AdminRouter;
60
+ export { buildRoutesFromManifest } from './builder';
61
+ export type { RouteComponentResolver, RouteMeta, AdminRouteComponent } from './builder';
62
+ export { createAuthGuard, createTitleGuard } from './guards';
63
+ export type { AuthGuardOptions, TitleGuardOptions } from './guards';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Auth store: текущий user, permissions, login/logout/2FA flow.
3
+ *
4
+ * Wildcard в permissions:
5
+ * - `*` — полный доступ ко всему.
6
+ * - `admin.users.*` — доступ ко всем admin.users.{view,create,update,delete}.
7
+ *
8
+ * 2FA flow:
9
+ * 1. login() с верными creds + 2FA включена → success: false +
10
+ * errorKey: 'two_factor_required' + challenge_token. State переходит в
11
+ * `pendingChallenge`.
12
+ * 2. UI показывает 2FA-форму. twoFactorChallenge(code) или
13
+ * twoFactorRecovery(recovery_code) → success login flow.
14
+ */
15
+ import type { AdminUser, AdminBootstrap } from '../types/bootstrap';
16
+ export interface PendingChallenge {
17
+ challengeToken: string;
18
+ remember: boolean;
19
+ }
20
+ export interface LoginPayload {
21
+ email: string;
22
+ password: string;
23
+ remember?: boolean;
24
+ }
25
+ export declare const useAuthStore: import("pinia").StoreDefinition<"admin-auth", Pick<{
26
+ user: import("vue").Ref<{
27
+ id: number | string;
28
+ name: string;
29
+ email: string;
30
+ avatar: string | null;
31
+ locale: string | null;
32
+ theme: string | null;
33
+ twoFactorEnabled: boolean;
34
+ } | null, AdminUser | {
35
+ id: number | string;
36
+ name: string;
37
+ email: string;
38
+ avatar: string | null;
39
+ locale: string | null;
40
+ theme: string | null;
41
+ twoFactorEnabled: boolean;
42
+ } | null>;
43
+ permissions: import("vue").Ref<string[], string[]>;
44
+ pendingChallenge: import("vue").Ref<{
45
+ challengeToken: string;
46
+ remember: boolean;
47
+ } | null, PendingChallenge | {
48
+ challengeToken: string;
49
+ remember: boolean;
50
+ } | null>;
51
+ isAuthenticated: import("vue").ComputedRef<boolean>;
52
+ isChallengePending: import("vue").ComputedRef<boolean>;
53
+ hydrate: (bootstrap: AdminBootstrap) => void;
54
+ hasPermission: (key: string) => boolean;
55
+ hasAnyPermission: (keys: string[]) => boolean;
56
+ hasAllPermissions: (keys: string[]) => boolean;
57
+ login: (payload: LoginPayload) => Promise<"authenticated" | "two_factor_required">;
58
+ twoFactorChallenge: (code: string) => Promise<void>;
59
+ twoFactorRecovery: (recoveryCode: string) => Promise<{
60
+ remaining: number;
61
+ }>;
62
+ cancelChallenge: () => void;
63
+ logout: () => Promise<void>;
64
+ }, "user" | "permissions" | "pendingChallenge">, Pick<{
65
+ user: import("vue").Ref<{
66
+ id: number | string;
67
+ name: string;
68
+ email: string;
69
+ avatar: string | null;
70
+ locale: string | null;
71
+ theme: string | null;
72
+ twoFactorEnabled: boolean;
73
+ } | null, AdminUser | {
74
+ id: number | string;
75
+ name: string;
76
+ email: string;
77
+ avatar: string | null;
78
+ locale: string | null;
79
+ theme: string | null;
80
+ twoFactorEnabled: boolean;
81
+ } | null>;
82
+ permissions: import("vue").Ref<string[], string[]>;
83
+ pendingChallenge: import("vue").Ref<{
84
+ challengeToken: string;
85
+ remember: boolean;
86
+ } | null, PendingChallenge | {
87
+ challengeToken: string;
88
+ remember: boolean;
89
+ } | null>;
90
+ isAuthenticated: import("vue").ComputedRef<boolean>;
91
+ isChallengePending: import("vue").ComputedRef<boolean>;
92
+ hydrate: (bootstrap: AdminBootstrap) => void;
93
+ hasPermission: (key: string) => boolean;
94
+ hasAnyPermission: (keys: string[]) => boolean;
95
+ hasAllPermissions: (keys: string[]) => boolean;
96
+ login: (payload: LoginPayload) => Promise<"authenticated" | "two_factor_required">;
97
+ twoFactorChallenge: (code: string) => Promise<void>;
98
+ twoFactorRecovery: (recoveryCode: string) => Promise<{
99
+ remaining: number;
100
+ }>;
101
+ cancelChallenge: () => void;
102
+ logout: () => Promise<void>;
103
+ }, "isAuthenticated" | "isChallengePending">, Pick<{
104
+ user: import("vue").Ref<{
105
+ id: number | string;
106
+ name: string;
107
+ email: string;
108
+ avatar: string | null;
109
+ locale: string | null;
110
+ theme: string | null;
111
+ twoFactorEnabled: boolean;
112
+ } | null, AdminUser | {
113
+ id: number | string;
114
+ name: string;
115
+ email: string;
116
+ avatar: string | null;
117
+ locale: string | null;
118
+ theme: string | null;
119
+ twoFactorEnabled: boolean;
120
+ } | null>;
121
+ permissions: import("vue").Ref<string[], string[]>;
122
+ pendingChallenge: import("vue").Ref<{
123
+ challengeToken: string;
124
+ remember: boolean;
125
+ } | null, PendingChallenge | {
126
+ challengeToken: string;
127
+ remember: boolean;
128
+ } | null>;
129
+ isAuthenticated: import("vue").ComputedRef<boolean>;
130
+ isChallengePending: import("vue").ComputedRef<boolean>;
131
+ hydrate: (bootstrap: AdminBootstrap) => void;
132
+ hasPermission: (key: string) => boolean;
133
+ hasAnyPermission: (keys: string[]) => boolean;
134
+ hasAllPermissions: (keys: string[]) => boolean;
135
+ login: (payload: LoginPayload) => Promise<"authenticated" | "two_factor_required">;
136
+ twoFactorChallenge: (code: string) => Promise<void>;
137
+ twoFactorRecovery: (recoveryCode: string) => Promise<{
138
+ remaining: number;
139
+ }>;
140
+ cancelChallenge: () => void;
141
+ logout: () => Promise<void>;
142
+ }, "hydrate" | "hasPermission" | "hasAnyPermission" | "hasAllPermissions" | "login" | "twoFactorChallenge" | "twoFactorRecovery" | "cancelChallenge" | "logout">>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Public API of admin stores.
3
+ *
4
+ * Использование:
5
+ *
6
+ * import { setAdminClient, useAuthStore, useThemeStore } from '@dskripchenko/laravel-admin'
7
+ *
8
+ * const client = createAdminClient({...})
9
+ * setAdminClient(client) // ОБЯЗАТЕЛЬНО до использования stores
10
+ * const auth = useAuthStore()
11
+ * const theme = useThemeStore()
12
+ */
13
+ export { setAdminClient, getAdminClient, hasAdminClient, clearAdminClient } from './registry';
14
+ export { useAuthStore } from './auth';
15
+ export type { LoginPayload, PendingChallenge } from './auth';
16
+ export { useManifestStore } from './manifest';
17
+ export type { AdminManifest, ManifestResourceMeta, ManifestScreenMeta, ManifestSettingsMeta, } from './manifest';
18
+ export { useThemeStore } from './theme';
19
+ export { useLocaleStore } from './locale';
20
+ export { useNotificationsStore } from './notifications';
21
+ export type { NotificationItem, NotificationFilter } from './notifications';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Locale store: текущая локаль + persist + sync с AdminClient.
3
+ *
4
+ * Side effects при смене:
5
+ * - `<html lang="...">` обновляется
6
+ * - AdminClient.setLocale() — все следующие запросы получат правильный
7
+ * X-Admin-Locale header
8
+ * - POST /system/setLocale → persist в user.locale + cookie
9
+ */
10
+ import type { AdminBootstrap } from '../types/bootstrap';
11
+ export declare const useLocaleStore: import("pinia").StoreDefinition<"admin-locale", Pick<{
12
+ current: import("vue").Ref<string, string>;
13
+ available: import("vue").Ref<string[], string[]>;
14
+ hydrate: (bootstrap: AdminBootstrap) => void;
15
+ applyLocal: (locale: string) => void;
16
+ setLocale: (locale: string) => Promise<void>;
17
+ }, "current" | "available">, Pick<{
18
+ current: import("vue").Ref<string, string>;
19
+ available: import("vue").Ref<string[], string[]>;
20
+ hydrate: (bootstrap: AdminBootstrap) => void;
21
+ applyLocal: (locale: string) => void;
22
+ setLocale: (locale: string) => Promise<void>;
23
+ }, never>, Pick<{
24
+ current: import("vue").Ref<string, string>;
25
+ available: import("vue").Ref<string[], string[]>;
26
+ hydrate: (bootstrap: AdminBootstrap) => void;
27
+ applyLocal: (locale: string) => void;
28
+ setLocale: (locale: string) => Promise<void>;
29
+ }, "hydrate" | "applyLocal" | "setLocale">>;
@@ -0,0 +1 @@
1
+ export {};