@hywax/cms 1.10.1 → 2.0.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 (91) hide show
  1. package/.nuxt/cms/config.ts +6 -0
  2. package/.nuxt/cms/editor/uplora-image.ts +5 -0
  3. package/.nuxt/cms/index.ts +4 -1
  4. package/.nuxt/cms/input-seo.ts +5 -0
  5. package/.nuxt/cms/input-slug.ts +5 -0
  6. package/.nuxt/cms/input-uplora-image.ts +27 -0
  7. package/.nuxt/cms.css +1 -29
  8. package/dist/module.d.mts +20 -5
  9. package/dist/module.json +2 -2
  10. package/dist/module.mjs +288 -99
  11. package/dist/runtime/components/AutocompleteSelect.d.vue.ts +3 -3
  12. package/dist/runtime/components/AutocompleteSelect.vue.d.ts +3 -3
  13. package/dist/runtime/components/ButtonCopyText.d.vue.ts +2 -2
  14. package/dist/runtime/components/ButtonCopyText.vue.d.ts +2 -2
  15. package/dist/runtime/components/ButtonDeleteConfirm.vue +3 -3
  16. package/dist/runtime/components/DatePicker.d.vue.ts +3 -3
  17. package/dist/runtime/components/DatePicker.vue +1 -2
  18. package/dist/runtime/components/DatePicker.vue.d.ts +3 -3
  19. package/dist/runtime/components/EditorFull.d.vue.ts +7 -6
  20. package/dist/runtime/components/EditorFull.vue +23 -8
  21. package/dist/runtime/components/EditorFull.vue.d.ts +7 -6
  22. package/dist/runtime/components/FormPanelAsideSection.vue +2 -1
  23. package/dist/runtime/components/FormPanelSection.vue +2 -1
  24. package/dist/runtime/components/InputSeo.d.vue.ts +20 -0
  25. package/dist/runtime/components/InputSeo.vue +74 -0
  26. package/dist/runtime/components/InputSeo.vue.d.ts +20 -0
  27. package/dist/runtime/components/InputSlug.d.vue.ts +30 -0
  28. package/dist/runtime/components/InputSlug.vue +71 -0
  29. package/dist/runtime/components/InputSlug.vue.d.ts +30 -0
  30. package/dist/runtime/components/InputUploraImage.d.vue.ts +40 -0
  31. package/dist/runtime/components/InputUploraImage.vue +181 -0
  32. package/dist/runtime/components/InputUploraImage.vue.d.ts +40 -0
  33. package/dist/runtime/components/ModalConfirm.d.vue.ts +0 -1
  34. package/dist/runtime/components/ModalConfirm.vue +2 -4
  35. package/dist/runtime/components/ModalConfirm.vue.d.ts +0 -1
  36. package/dist/runtime/components/TableColumnVisibility.vue +1 -2
  37. package/dist/runtime/components/TableFilters.d.vue.ts +1 -1
  38. package/dist/runtime/components/TableFilters.vue +12 -11
  39. package/dist/runtime/components/TableFilters.vue.d.ts +1 -1
  40. package/dist/runtime/components/TablePanel.vue +6 -6
  41. package/dist/runtime/components/UploraImage.d.vue.ts +2 -1
  42. package/dist/runtime/components/UploraImage.vue +7 -4
  43. package/dist/runtime/components/UploraImage.vue.d.ts +2 -1
  44. package/dist/runtime/components/prose/UploraImage.d.vue.ts +3 -3
  45. package/dist/runtime/components/prose/UploraImage.vue +11 -5
  46. package/dist/runtime/components/prose/UploraImage.vue.d.ts +3 -3
  47. package/dist/runtime/composables/useEditorDragHandle.d.ts +2 -1
  48. package/dist/runtime/composables/useEditorDragHandle.js +2 -2
  49. package/dist/runtime/composables/useEditorSuggestions.d.ts +7 -1
  50. package/dist/runtime/composables/useEditorSuggestions.js +2 -1
  51. package/dist/runtime/composables/useEditorToolbar.d.ts +2 -1
  52. package/dist/runtime/composables/useFormState.js +2 -2
  53. package/dist/runtime/composables/useModal.js +1 -1
  54. package/dist/runtime/composables/useSeoStats.d.ts +12 -0
  55. package/dist/runtime/composables/useSeoStats.js +44 -0
  56. package/dist/runtime/composables/useTable.d.ts +1 -2
  57. package/dist/runtime/composables/useTable.js +2 -2
  58. package/dist/runtime/composables/useTableColumns.js +1 -2
  59. package/dist/runtime/editor/uplora-image/EditorUploraImage.d.ts +18 -0
  60. package/dist/runtime/editor/uplora-image/EditorUploraImage.js +43 -0
  61. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.d.vue.ts +9 -0
  62. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.vue +28 -0
  63. package/dist/runtime/editor/uplora-image/EditorUploraImageNode.vue.d.ts +9 -0
  64. package/dist/runtime/editor/utils.d.ts +13 -0
  65. package/dist/runtime/editor/utils.js +73 -0
  66. package/dist/runtime/index.css +1 -1
  67. package/dist/runtime/server/api/uplora/index.post.d.ts +1 -0
  68. package/dist/runtime/server/api/uplora/index.post.js +1 -0
  69. package/dist/runtime/types/index.d.ts +36 -3
  70. package/dist/runtime/types/index.js +36 -1
  71. package/dist/runtime/types/tv.d.ts +1 -1
  72. package/dist/runtime/utils/date.d.ts +0 -4
  73. package/dist/runtime/utils/date.js +0 -15
  74. package/dist/runtime/utils/formatters.d.ts +2 -1
  75. package/dist/runtime/utils/index.d.ts +0 -1
  76. package/dist/runtime/utils/index.js +0 -1
  77. package/dist/runtime/utils/slugify.js +2 -1
  78. package/dist/types.d.mts +2 -0
  79. package/package.json +19 -25
  80. package/cli/commands/make/component.mjs +0 -75
  81. package/cli/commands/make/index.mjs +0 -12
  82. package/cli/index.mjs +0 -15
  83. package/cli/package.json +0 -13
  84. package/cli/templates.mjs +0 -102
  85. package/cli/utils.mjs +0 -31
  86. package/dist/runtime/composables/useRowSelection.d.ts +0 -8
  87. package/dist/runtime/composables/useRowSelection.js +0 -46
  88. package/dist/runtime/types/dictionaries.d.ts +0 -1
  89. package/dist/runtime/types/dictionaries.js +0 -0
  90. package/dist/runtime/utils/features.d.ts +0 -4
  91. package/dist/runtime/utils/features.js +0 -13
package/dist/module.mjs CHANGED
@@ -1,12 +1,13 @@
1
- import { createResolver, addComponentsDir, addPlugin, addImports, addImportsDir, addServerImports, addServerImportsDir, addServerHandler, addTypeTemplate, addTemplate, addServerTemplate, defineNuxtModule } from '@nuxt/kit';
1
+ import { createResolver, addComponentsDir, addPlugin, addImports, addImportsDir, addServerImports, addServerImportsDir, addServerHandler, addTypeTemplate, addTemplate, addServerTemplate, updateTemplates, getLayerDirectories, logger, defineNuxtModule } from '@nuxt/kit';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { dirname, join } from 'pathe';
4
- import { defu } from 'defu';
5
- import { snakeCase, kebabCase } from 'scule';
4
+ import { snakeCase, pascalCase, kebabCase } from 'scule';
6
5
  import { readFile, writeFile } from 'node:fs/promises';
6
+ import { defu } from 'defu';
7
+ import { globSync } from 'tinyglobby';
7
8
 
8
9
  const name = "@hywax/cms";
9
- const version = "1.10.1";
10
+ const version = "2.0.0";
10
11
 
11
12
  function createContext(options, nuxt) {
12
13
  const { resolve } = createResolver(import.meta.url);
@@ -21,17 +22,14 @@ function createContext(options, nuxt) {
21
22
  };
22
23
  }
23
24
 
24
- function defaultCMSConfig(options) {
25
- return {
26
- features: options.features
27
- };
28
- }
29
25
  const defaultModuleOptions = {
30
26
  name: "cms",
31
27
  componentsPrefix: "C",
32
28
  uploraUrl: "http://uplora.ru",
33
29
  fluxorUrl: "https://fluxor.uplora.ru",
34
30
  envPrefix: "APP_",
31
+ unovis: false,
32
+ componentDetection: true,
35
33
  httpCodes: {
36
34
  badRequest: "400: \u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441",
37
35
  unauthorized: "401: \u041D\u0435 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u043E\u0432\u0430\u043D",
@@ -42,9 +40,14 @@ const defaultModuleOptions = {
42
40
  badGateway: "502: \u041E\u0448\u0438\u0431\u043A\u0430 \u0448\u043B\u044E\u0437\u0430",
43
41
  serviceUnavailable: "503: \u0421\u0435\u0440\u0432\u0438\u0441 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D"
44
42
  },
45
- features: {},
46
43
  formats: {
47
44
  serverDateTime: "YYYY-MM-DD HH:mm:ss"
45
+ },
46
+ prose: {
47
+ uploraImage: {
48
+ formats: [],
49
+ sizes: []
50
+ }
48
51
  }
49
52
  };
50
53
 
@@ -59,25 +62,23 @@ function prepareAutoImports({ resolve, options, nuxt }) {
59
62
  const cmsConfigPath = resolve(nuxt.options.buildDir, "cms/config");
60
63
  const httpCodesPath = resolve(nuxt.options.buildDir, "cms/http-codes");
61
64
  const httpCodesImports = transformHttpCodes(options.httpCodes).map(({ code }) => ({ name: code, from: httpCodesPath }));
62
- addComponentsDir({
63
- path: resolve("./runtime/components"),
64
- pathPrefix: false,
65
- prefix: options.componentsPrefix,
66
- ignore: ["prose/**"]
67
- });
68
65
  addComponentsDir({
69
66
  path: resolve("./runtime/components/prose"),
70
67
  prefix: "Prose",
71
68
  pathPrefix: false,
72
69
  global: true
73
70
  });
71
+ addComponentsDir({
72
+ path: resolve("./runtime/components"),
73
+ pathPrefix: false,
74
+ prefix: options.componentsPrefix,
75
+ ignore: ["prose/**"]
76
+ });
74
77
  addPlugin(resolve("./runtime/plugins/api"));
75
78
  addPlugin(resolve("./runtime/plugins/zod"));
76
79
  addImports([
77
80
  ...httpCodesImports,
78
81
  { name: "getCmsConfig", from: cmsConfigPath }
79
- // { name: 'docToMarkdown', from: resolve('./runtime/editor/markdown') },
80
- // { name: 'markdownToDoc', from: resolve('./runtime/editor/markdown') },
81
82
  ]);
82
83
  addImportsDir([
83
84
  resolve("./runtime/utils"),
@@ -86,8 +87,6 @@ function prepareAutoImports({ resolve, options, nuxt }) {
86
87
  addServerImports([
87
88
  ...httpCodesImports,
88
89
  { name: "getCmsConfig", from: cmsConfigPath }
89
- // { name: 'docToMarkdown', from: resolve('./runtime/editor/markdown') },
90
- // { name: 'markdownToDoc', from: resolve('./runtime/editor/markdown') },
91
90
  ]);
92
91
  addServerImportsDir([
93
92
  resolve("./runtime/utils"),
@@ -96,7 +95,6 @@ function prepareAutoImports({ resolve, options, nuxt }) {
96
95
  nuxt.options.nitro.alias ||= {};
97
96
  nuxt.options.nitro.alias["#cms/http-codes"] = httpCodesPath;
98
97
  nuxt.options.alias["#cms"] = resolve("./runtime");
99
- nuxt.options.appConfig.cms = defu(nuxt.options.appConfig.cms || {}, defaultCMSConfig(options));
100
98
  }
101
99
 
102
100
  async function prepareGenerateEnv({ nuxt }) {
@@ -117,35 +115,38 @@ async function prepareGenerateEnv({ nuxt }) {
117
115
  }
118
116
 
119
117
  const icons = {
120
- calendar: "lucide:calendar",
121
- sort: "lucide:arrow-down-up",
122
- sortAsc: "lucide:arrow-up-wide-narrow",
123
- sortDesc: "lucide:arrow-down-wide-narrow",
124
- columns: "lucide:columns-3-cog",
125
- filter: "lucide:filter",
126
- ellipsisVertical: "lucide:ellipsis-vertical",
127
- repeat: "lucide:repeat-2",
128
- clipboard: "lucide:clipboard",
129
- trash: "lucide:trash",
130
- paragraph: "lucide:type",
131
- heading1: "lucide:heading-1",
132
- heading2: "lucide:heading-2",
133
- heading3: "lucide:heading-3",
134
- heading4: "lucide:heading-4",
135
- list: "lucide:list",
136
- listOrdered: "lucide:list-ordered",
137
- blockquote: "lucide:text-quote",
138
- codeBlock: "lucide:square-code",
139
- horizontalRule: "lucide:separator-horizontal",
140
- enter: "lucide:corner-down-left",
141
- link: "lucide:link",
142
- download: "lucide:download",
143
- bold: "lucide:bold",
144
- italic: "lucide:italic",
145
- underline: "lucide:underline",
146
- strikethrough: "lucide:strikethrough",
147
- code: "lucide:code",
148
- image: "lucide:image"
118
+ loading: "i-lucide-loader",
119
+ refresh: "i-lucide-refresh-cw",
120
+ calendar: "i-lucide-calendar",
121
+ sort: "i-lucide-arrow-down-up",
122
+ sortAsc: "i-lucide-arrow-up-wide-narrow",
123
+ sortDesc: "i-lucide-arrow-down-wide-narrow",
124
+ columns: "i-lucide-columns-3-cog",
125
+ filter: "i-lucide-filter",
126
+ ellipsisVertical: "i-lucide-ellipsis-vertical",
127
+ repeat: "i-lucide-repeat-2",
128
+ clipboard: "i-lucide-clipboard",
129
+ trash: "i-lucide-trash",
130
+ paragraph: "i-lucide-type",
131
+ heading1: "i-lucide-heading-1",
132
+ heading2: "i-lucide-heading-2",
133
+ heading3: "i-lucide-heading-3",
134
+ heading4: "i-lucide-heading-4",
135
+ list: "i-lucide-list",
136
+ listOrdered: "i-lucide-list-ordered",
137
+ blockquote: "i-lucide-text-quote",
138
+ codeBlock: "i-lucide-square-code",
139
+ horizontalRule: "i-lucide-separator-horizontal",
140
+ enter: "i-lucide-corner-down-left",
141
+ link: "i-lucide-link",
142
+ download: "i-lucide-download",
143
+ bold: "i-lucide-bold",
144
+ italic: "i-lucide-italic",
145
+ underline: "i-lucide-underline",
146
+ strikethrough: "i-lucide-strikethrough",
147
+ code: "i-lucide-code",
148
+ image: "i-lucide-image",
149
+ editLine: "i-lucide-pen-line"
149
150
  };
150
151
 
151
152
  function prepareMergeConfigs({ nuxt, options }) {
@@ -212,7 +213,7 @@ function prepareMergeConfigs({ nuxt, options }) {
212
213
  pinned: {
213
214
  true: {
214
215
  th: "bg-unset",
215
- td: "bg-unset"
216
+ td: "bg-default"
216
217
  }
217
218
  }
218
219
  }
@@ -220,7 +221,11 @@ function prepareMergeConfigs({ nuxt, options }) {
220
221
  });
221
222
  nuxt.options.ui = defu(nuxt.options.ui || {}, {
222
223
  colorMode: true,
223
- fonts: true
224
+ fonts: true,
225
+ mdc: true,
226
+ experimental: {
227
+ componentDetection: true
228
+ }
224
229
  });
225
230
  nuxt.options.colorMode = defu(nuxt.options.colorMode || {}, {
226
231
  storageKey: `${options.name}:color-mode`
@@ -242,17 +247,31 @@ function prepareMergeConfigs({ nuxt, options }) {
242
247
  nuxt.options.vite = defu(nuxt.options.vite || {}, {
243
248
  optimizeDeps: {
244
249
  include: [
250
+ "@unovis/vue",
251
+ "@tanstack/vue-table",
252
+ "@uplora/formats",
253
+ "@nuxt/ui/utils/editor",
245
254
  "@vue/devtools-core",
246
255
  "@vue/devtools-kit",
247
256
  "@nuxt/ui/locale",
248
- "@uplora/formats",
257
+ "@tiptap/core",
258
+ "@tiptap/vue-3",
259
+ "@sindresorhus/slugify",
260
+ "@vueuse/integrations/useSortable",
261
+ "@dicebear/collection",
262
+ "@dicebear/core",
249
263
  "@uplora/serializer",
250
- "@unovis/ts",
251
- "@unovis/vue",
252
- "plural-ru",
253
- "object-to-formdata",
264
+ "@internationalized/date",
265
+ "tailwind-variants",
266
+ "fast-equals",
267
+ "fast-copy",
268
+ "reka-ui",
254
269
  "zod",
255
- "zod/locales"
270
+ "zod/locales",
271
+ "prosemirror-state",
272
+ "prosemirror-model",
273
+ "prosemirror-view",
274
+ "prosemirror-transform"
256
275
  ]
257
276
  }
258
277
  });
@@ -332,6 +351,46 @@ const formPanelSection = {
332
351
  }
333
352
  };
334
353
 
354
+ const inputSeo = {
355
+ slots: {
356
+ root: "flex flex-col gap-4"
357
+ }
358
+ };
359
+
360
+ const inputSlug = {
361
+ slots: {
362
+ root: "flex flex-col gap-4"
363
+ }
364
+ };
365
+
366
+ const inputUploraImage = {
367
+ slots: {
368
+ root: "relative w-full rounded-md overflow-hidden border-1 border-default aspect-3/2 text-sm bg-default",
369
+ image: "",
370
+ imageActions: "absolute top-4 right-4 flex gap-2",
371
+ imageActionsWarning: "absolute top-0 right-0 size-6 bg-linear-to-bl from-error/90 to-transparent rounded-bl-lg text-error flex items-center justify-center",
372
+ uploader: "flex flex-col items-center justify-center w-full h-full",
373
+ uploaderPendingIcon: "size-6 animate-spin",
374
+ uploaderIdleButton: "cursor-pointer h-full w-full",
375
+ uploaderIdleText: "mt-2 font-medium",
376
+ uploaderIdleExtensions: "mt-2 text-xs text-muted uppercase",
377
+ uploaderErrorText: "text-center font-medium p-2",
378
+ uploaderErrorActions: "flex gap-2 mt-4"
379
+ },
380
+ variants: {
381
+ disabled: {
382
+ true: {
383
+ root: "cursor-not-allowed opacity-75"
384
+ }
385
+ },
386
+ uploaded: {
387
+ false: {
388
+ root: "border-dashed"
389
+ }
390
+ }
391
+ }
392
+ };
393
+
335
394
  const modalConfirm = {
336
395
  slots: {
337
396
  root: ""
@@ -370,10 +429,13 @@ const theme = {
370
429
  FormPanel: formPanel,
371
430
  FormPanelAsideSection: formPanelAsideSection,
372
431
  FormPanelSection: formPanelSection,
432
+ InputSeo: inputSeo,
433
+ InputUploraImage: inputUploraImage,
373
434
  ModalConfirm: modalConfirm,
374
435
  TablePanel: tablePanel,
375
436
  TableSearchInput: tableSearchInput,
376
- UploraImage: uploraImage$1
437
+ UploraImage: uploraImage$1,
438
+ inputSlug: inputSlug
377
439
  };
378
440
 
379
441
  const themeEditor = {
@@ -391,8 +453,88 @@ const themeProse = {
391
453
  uploraImage: uploraImage
392
454
  };
393
455
 
394
- function getAppTemplates({ options }) {
456
+ async function buildComponentDependencyGraph(componentDir, componentPattern) {
457
+ const dependencyGraph = /* @__PURE__ */ new Map();
458
+ const componentFiles = globSync(["**/*.vue"], {
459
+ cwd: componentDir,
460
+ absolute: true
461
+ });
462
+ for (const componentFile of componentFiles) {
463
+ try {
464
+ const content = await readFile(componentFile, "utf-8");
465
+ const componentName = pascalCase(componentFile.split("/").pop().replace(".vue", ""));
466
+ const dependencies = /* @__PURE__ */ new Set();
467
+ const matches = content.matchAll(componentPattern);
468
+ for (const match of matches) {
469
+ const depName = match[1] || match[2];
470
+ if (depName && depName !== componentName) {
471
+ dependencies.add(depName);
472
+ }
473
+ }
474
+ dependencyGraph.set(componentName, dependencies);
475
+ } catch {
476
+ }
477
+ }
478
+ return dependencyGraph;
479
+ }
480
+ function resolveComponentDependencies(component, dependencyGraph, resolved = /* @__PURE__ */ new Set()) {
481
+ if (resolved.has(component)) {
482
+ return resolved;
483
+ }
484
+ resolved.add(component);
485
+ const dependencies = dependencyGraph.get(component);
486
+ if (dependencies) {
487
+ for (const dep of dependencies) {
488
+ resolveComponentDependencies(dep, dependencyGraph, resolved);
489
+ }
490
+ }
491
+ return resolved;
492
+ }
493
+ async function detectUsedComponents(dirs, prefix, componentDir, includeComponents) {
494
+ const detectedComponents = /* @__PURE__ */ new Set();
495
+ if (includeComponents && includeComponents.length > 0) {
496
+ for (const component of includeComponents) {
497
+ detectedComponents.add(component);
498
+ }
499
+ }
500
+ const componentPattern = new RegExp(`<(?:Lazy)?${prefix}([A-Z][a-zA-Z]+)|\\b(?:Lazy)?${prefix}([A-Z][a-zA-Z]+)\\b`, "g");
501
+ for (const dir of dirs) {
502
+ const appFiles = globSync(["**/*.{vue,ts,js,tsx,jsx}"], {
503
+ cwd: dir,
504
+ ignore: ["node_modules/**", ".nuxt/**", "dist/**"]
505
+ });
506
+ for (const file of appFiles) {
507
+ try {
508
+ const filePath = join(dir, file);
509
+ const content = await readFile(filePath, "utf-8");
510
+ const matches = content.matchAll(componentPattern);
511
+ for (const match of matches) {
512
+ const componentName = match[1] || match[2];
513
+ if (componentName) {
514
+ detectedComponents.add(componentName);
515
+ }
516
+ }
517
+ } catch {
518
+ }
519
+ }
520
+ }
521
+ if (detectedComponents.size === 0) {
522
+ return void 0;
523
+ }
524
+ const dependencyGraph = await buildComponentDependencyGraph(componentDir, componentPattern);
525
+ const allComponents = /* @__PURE__ */ new Set();
526
+ for (const component of detectedComponents) {
527
+ const resolved = resolveComponentDependencies(component, dependencyGraph);
528
+ for (const resolvedComponent of resolved) {
529
+ allComponents.add(resolvedComponent);
530
+ }
531
+ }
532
+ return allComponents;
533
+ }
534
+
535
+ function getAppTemplates({ options, resolve, nuxt }) {
395
536
  const templates = [];
537
+ let previousDetectedComponents;
396
538
  function writeThemeTemplate(theme2, path) {
397
539
  for (const component in theme2) {
398
540
  templates.push({
@@ -427,8 +569,46 @@ function getAppTemplates({ options }) {
427
569
  });
428
570
  }
429
571
  }
572
+ async function generateSources() {
573
+ const sources = [];
574
+ const layers = getLayerDirectories(nuxt).map((layer) => layer.app);
575
+ if (options.componentDetection) {
576
+ const detectedComponents = await detectUsedComponents(
577
+ layers,
578
+ options.componentsPrefix,
579
+ resolve("./runtime/components"),
580
+ Array.isArray(options.componentDetection) ? options.componentDetection : void 0
581
+ );
582
+ if (detectedComponents && detectedComponents.size > 0) {
583
+ if (previousDetectedComponents) {
584
+ const newComponents = Array.from(detectedComponents).filter(
585
+ (component) => !previousDetectedComponents.has(component)
586
+ );
587
+ if (newComponents.length > 0) {
588
+ logger.success(`CMS detected new components: ${newComponents.join(", ")}`);
589
+ }
590
+ } else {
591
+ logger.success(`CMS detected ${detectedComponents.size} components in use (including dependencies)`);
592
+ }
593
+ previousDetectedComponents = detectedComponents;
594
+ for (const component of detectedComponents) {
595
+ const kebabComponent = kebabCase(component);
596
+ sources.push(`@source "./cms/${kebabComponent}.ts";`);
597
+ }
598
+ } else {
599
+ if (!previousDetectedComponents || previousDetectedComponents.size > 0) {
600
+ logger.info("CMS detected no components in use, including all components");
601
+ }
602
+ previousDetectedComponents = /* @__PURE__ */ new Set();
603
+ sources.push('@source "./cms";');
604
+ }
605
+ } else {
606
+ sources.push('@source "./cms";');
607
+ }
608
+ return sources.join("\n");
609
+ }
430
610
  writeThemeTemplate(themeProse, "prose");
431
- writeThemeTemplate(themeEditor, "editor");
611
+ writeThemeTemplate(themeProse, "editor");
432
612
  writeThemeTemplate(theme);
433
613
  templates.push({
434
614
  filename: `cms/prose/index.ts`,
@@ -443,37 +623,41 @@ function getAppTemplates({ options }) {
443
623
  templates.push({
444
624
  filename: "cms.css",
445
625
  write: true,
446
- getContents: () => `@source "./cms";
447
-
448
- @layer components {
449
- .unvois {
450
- --vis-crosshair-line-stroke-color: var(--ui-bg-elevated);
451
- --vis-crosshair-circle-stroke-color: transparent;
452
-
453
- --vis-axis-grid-color: var(--ui-border);
454
- --vis-axis-tick-color: var(--ui-border);
455
- --vis-axis-tick-label-color: var(--ui-text-dimmed);
456
-
457
- --vis-tooltip-background-color: var(--ui-bg);
458
- --vis-tooltip-border-color: var(--ui-border);
459
- --vis-tooltip-text-color: var(--ui-text-highlighted);
460
-
461
- --vis-color0: var(--ui-primary);
462
- --vis-color1: var(--ui-secondary);
463
- --vis-color2: var(--ui-info);
464
- --vis-color3: var(--ui-warning);
465
- --vis-color4: var(--ui-error);
466
- --vis-color5: var(--ui-success);
467
-
468
- --vis-dark-color0: var(--ui-primary);
469
- --vis-dark-color1: var(--ui-secondary);
470
- --vis-dark-color2: var(--ui-info);
471
- --vis-dark-color3: var(--ui-warning);
472
- --vis-dark-color4: var(--ui-error);
473
- --vis-dark-color5: var(--ui-success);
474
- }
475
- }
476
- `
626
+ getContents: async () => {
627
+ const sources = await generateSources();
628
+ return `${sources}
629
+ ${options.unovis ? `
630
+ @layer components {
631
+ .unvois {
632
+ --vis-crosshair-line-stroke-color: var(--ui-bg-elevated);
633
+ --vis-crosshair-circle-stroke-color: transparent;
634
+
635
+ --vis-axis-grid-color: var(--ui-border);
636
+ --vis-axis-tick-color: var(--ui-border);
637
+ --vis-axis-tick-label-color: var(--ui-text-dimmed);
638
+
639
+ --vis-tooltip-background-color: var(--ui-bg);
640
+ --vis-tooltip-border-color: var(--ui-border);
641
+ --vis-tooltip-text-color: var(--ui-text-highlighted);
642
+
643
+ --vis-color0: var(--ui-primary);
644
+ --vis-color1: var(--ui-secondary);
645
+ --vis-color2: var(--ui-info);
646
+ --vis-color3: var(--ui-warning);
647
+ --vis-color4: var(--ui-error);
648
+ --vis-color5: var(--ui-success);
649
+
650
+ --vis-dark-color0: var(--ui-primary);
651
+ --vis-dark-color1: var(--ui-secondary);
652
+ --vis-dark-color2: var(--ui-info);
653
+ --vis-dark-color3: var(--ui-warning);
654
+ --vis-dark-color4: var(--ui-error);
655
+ --vis-dark-color5: var(--ui-success);
656
+ }
657
+ }
658
+ ` : ""}
659
+ `;
660
+ }
477
661
  });
478
662
  templates.push({
479
663
  filename: "cms/index.ts",
@@ -488,16 +672,14 @@ function getAppTemplates({ options }) {
488
672
  import type { TVConfig } from '@nuxt/ui'
489
673
  import type { RouteLocationRaw } from 'vue-router'
490
674
 
491
- type AppConfigCMS = {
492
- features: Record<string, boolean>
493
- } & TVConfig<typeof cms>
675
+ type AppConfigCMS = TVConfig<typeof cms>
494
676
 
495
677
  declare module '@nuxt/schema' {
496
678
  interface AppConfigInput {
497
679
  /**
498
680
  * CMS theme configuration
499
681
  */
500
- cms?: AppConfigCMS
682
+ cmsRuntime?: AppConfigCMS
501
683
  }
502
684
  }
503
685
 
@@ -520,7 +702,8 @@ export {}
520
702
  getContents: () => {
521
703
  const config = {
522
704
  name: options.name,
523
- formats: options.formats
705
+ formats: options.formats,
706
+ prose: options.prose
524
707
  };
525
708
  return `const cmsConfig = ${JSON.stringify(config, null, 2)}
526
709
 
@@ -550,18 +733,24 @@ function prepareTemplates(context) {
550
733
  addServerTemplate(template);
551
734
  }
552
735
  }
736
+ if (context.options?.componentDetection && context.nuxt.options.dev) {
737
+ context.nuxt.hook("builder:watch", async (_, path) => {
738
+ if (/\.(?:vue|ts|js|tsx|jsx)$/.test(path)) {
739
+ await updateTemplates({ filter: (template) => template.filename === "cms.css" });
740
+ }
741
+ });
742
+ }
553
743
  }
554
744
 
555
745
  const module$1 = defineNuxtModule({
556
746
  meta: {
557
747
  name,
558
748
  version,
559
- configKey: "cms"
749
+ configKey: "cmsRuntime"
560
750
  },
561
751
  moduleDependencies: {
562
752
  "@nuxt/ui": {},
563
753
  "@nuxtjs/mdc": {},
564
- "@nuxtjs/seo": {},
565
754
  "@vueuse/nuxt": {},
566
755
  "nuxt-auth-utils": {}
567
756
  },
@@ -14,7 +14,7 @@ export type Handler<T extends AutocompleteSelectItem = AutocompleteSelectItem> =
14
14
  items: T[];
15
15
  pagination: Pagination;
16
16
  }>;
17
- export interface Props<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
17
+ export interface AutocompleteSelectProps<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
18
18
  modelValue?: GetModelValue<T, VK, M>;
19
19
  cacheKey: string;
20
20
  handler: Handler<T>;
@@ -26,7 +26,7 @@ export interface Props<T extends AutocompleteSelectItem = AutocompleteSelectItem
26
26
  placeholder?: string;
27
27
  initSelected?: boolean;
28
28
  }
29
- export interface Emits<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
29
+ export interface AutocompleteSelectEmits<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
30
30
  'update:modelValue': [payload: GetModelValue<T, VK, M>];
31
31
  }
32
32
  export interface Slots<T extends AutocompleteSelectItem = AutocompleteSelectItem> {
@@ -37,7 +37,7 @@ export interface Slots<T extends AutocompleteSelectItem = AutocompleteSelectItem
37
37
  declare const _default: typeof __VLS_export;
38
38
  export default _default;
39
39
  declare const __VLS_export: <T extends AutocompleteSelectItem, VK extends keyof T = "id", M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
40
- props: import("vue").PublicProps & __VLS_PrettifyLocal<Props<T, VK, M> & {
40
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<AutocompleteSelectProps<T, VK, M> & {
41
41
  "onUpdate:modelValue"?: ((payload: GetModelValue<T, VK, M>) => any) | undefined;
42
42
  }> & (typeof globalThis extends {
43
43
  __VLS_PROPS_FALLBACK: infer P;
@@ -14,7 +14,7 @@ export type Handler<T extends AutocompleteSelectItem = AutocompleteSelectItem> =
14
14
  items: T[];
15
15
  pagination: Pagination;
16
16
  }>;
17
- export interface Props<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
17
+ export interface AutocompleteSelectProps<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
18
18
  modelValue?: GetModelValue<T, VK, M>;
19
19
  cacheKey: string;
20
20
  handler: Handler<T>;
@@ -26,7 +26,7 @@ export interface Props<T extends AutocompleteSelectItem = AutocompleteSelectItem
26
26
  placeholder?: string;
27
27
  initSelected?: boolean;
28
28
  }
29
- export interface Emits<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
29
+ export interface AutocompleteSelectEmits<T extends AutocompleteSelectItem = AutocompleteSelectItem, VK extends keyof T = 'id', M extends boolean = false> {
30
30
  'update:modelValue': [payload: GetModelValue<T, VK, M>];
31
31
  }
32
32
  export interface Slots<T extends AutocompleteSelectItem = AutocompleteSelectItem> {
@@ -37,7 +37,7 @@ export interface Slots<T extends AutocompleteSelectItem = AutocompleteSelectItem
37
37
  declare const _default: typeof __VLS_export;
38
38
  export default _default;
39
39
  declare const __VLS_export: <T extends AutocompleteSelectItem, VK extends keyof T = "id", M extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
40
- props: import("vue").PublicProps & __VLS_PrettifyLocal<Props<T, VK, M> & {
40
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<AutocompleteSelectProps<T, VK, M> & {
41
41
  "onUpdate:modelValue"?: ((payload: GetModelValue<T, VK, M>) => any) | undefined;
42
42
  }> & (typeof globalThis extends {
43
43
  __VLS_PROPS_FALLBACK: infer P;
@@ -4,7 +4,7 @@ import type { RouteLocationRaw } from 'vue-router';
4
4
  import type { ComponentConfig } from '../types';
5
5
  import theme from '#build/cms/button-copy-text';
6
6
  type ButtonCopyText = ComponentConfig<typeof theme, AppConfig, 'buttonCopyText'>;
7
- export interface Props extends Pick<ButtonProps, 'target' | 'external' | 'label'> {
7
+ export interface ButtonCopyTextProps extends Pick<ButtonProps, 'target' | 'external' | 'label'> {
8
8
  text?: string | number | null;
9
9
  showAction?: boolean;
10
10
  alwaysShowTooltip?: boolean;
@@ -14,7 +14,7 @@ export interface Props extends Pick<ButtonProps, 'target' | 'external' | 'label'
14
14
  }
15
15
  declare const _default: typeof __VLS_export;
16
16
  export default _default;
17
- declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
17
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ButtonCopyTextProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ButtonCopyTextProps> & Readonly<{}>, {
18
18
  showAction: boolean;
19
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
20
20
  default?: (props: {}) => any;
@@ -4,7 +4,7 @@ import type { RouteLocationRaw } from 'vue-router';
4
4
  import type { ComponentConfig } from '../types';
5
5
  import theme from '#build/cms/button-copy-text';
6
6
  type ButtonCopyText = ComponentConfig<typeof theme, AppConfig, 'buttonCopyText'>;
7
- export interface Props extends Pick<ButtonProps, 'target' | 'external' | 'label'> {
7
+ export interface ButtonCopyTextProps extends Pick<ButtonProps, 'target' | 'external' | 'label'> {
8
8
  text?: string | number | null;
9
9
  showAction?: boolean;
10
10
  alwaysShowTooltip?: boolean;
@@ -14,7 +14,7 @@ export interface Props extends Pick<ButtonProps, 'target' | 'external' | 'label'
14
14
  }
15
15
  declare const _default: typeof __VLS_export;
16
16
  export default _default;
17
- declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
17
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ButtonCopyTextProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ButtonCopyTextProps> & Readonly<{}>, {
18
18
  showAction: boolean;
19
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, {
20
20
  default?: (props: {}) => any;
@@ -11,7 +11,7 @@
11
11
  :variant="variant"
12
12
  :size="size"
13
13
  :icon="icon"
14
- :label="label"
14
+ :label="label === '' ? void 0 : label"
15
15
  :class="ui.root({ class: [props.ui?.root, props.class] })"
16
16
  auto-loading
17
17
  @click="handleDeleteClick()"
@@ -21,7 +21,8 @@
21
21
 
22
22
  <script>
23
23
  import theme from "#build/cms/button-delete-confirm";
24
- import { computed, useAppConfig, useOverlay } from "#imports";
24
+ import { useAppConfig, useOverlay } from "#imports";
25
+ import { computed } from "vue";
25
26
  import { tv } from "../tv";
26
27
  import ModalConfirm from "./ModalConfirm.vue";
27
28
  </script>
@@ -52,7 +53,6 @@ function handleDeleteClick() {
52
53
  title: props.title ?? "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435",
53
54
  message: props.message ?? "\u0412\u044B \u0434\u0435\u0438\u0306\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C?",
54
55
  color: "error",
55
- variant: props.variant,
56
56
  confirmLabel: props.confirmLabel,
57
57
  confirmText: props.confirmText,
58
58
  onConfirm: props.onConfirm