@hywax/cms 1.10.1 → 2.0.1

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 +18 -30
  8. package/dist/module.d.mts +20 -5
  9. package/dist/module.json +1 -1
  10. package/dist/module.mjs +287 -96
  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.1";
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,33 @@ 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",
264
+ "@internationalized/date",
265
+ "tailwind-variants",
252
266
  "plural-ru",
253
267
  "object-to-formdata",
268
+ "fast-equals",
269
+ "fast-copy",
270
+ "reka-ui",
254
271
  "zod",
255
- "zod/locales"
272
+ "zod/locales",
273
+ "prosemirror-state",
274
+ "prosemirror-model",
275
+ "prosemirror-view",
276
+ "prosemirror-transform"
256
277
  ]
257
278
  }
258
279
  });
@@ -332,6 +353,46 @@ const formPanelSection = {
332
353
  }
333
354
  };
334
355
 
356
+ const inputSeo = {
357
+ slots: {
358
+ root: "flex flex-col gap-4"
359
+ }
360
+ };
361
+
362
+ const inputSlug = {
363
+ slots: {
364
+ root: "flex flex-col gap-4"
365
+ }
366
+ };
367
+
368
+ const inputUploraImage = {
369
+ slots: {
370
+ root: "relative w-full rounded-md overflow-hidden border-1 border-default aspect-3/2 text-sm bg-default",
371
+ image: "",
372
+ imageActions: "absolute top-4 right-4 flex gap-2",
373
+ 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",
374
+ uploader: "flex flex-col items-center justify-center w-full h-full",
375
+ uploaderPendingIcon: "size-6 animate-spin",
376
+ uploaderIdleButton: "cursor-pointer h-full w-full",
377
+ uploaderIdleText: "mt-2 font-medium",
378
+ uploaderIdleExtensions: "mt-2 text-xs text-muted uppercase",
379
+ uploaderErrorText: "text-center font-medium p-2",
380
+ uploaderErrorActions: "flex gap-2 mt-4"
381
+ },
382
+ variants: {
383
+ disabled: {
384
+ true: {
385
+ root: "cursor-not-allowed opacity-75"
386
+ }
387
+ },
388
+ uploaded: {
389
+ false: {
390
+ root: "border-dashed"
391
+ }
392
+ }
393
+ }
394
+ };
395
+
335
396
  const modalConfirm = {
336
397
  slots: {
337
398
  root: ""
@@ -370,10 +431,13 @@ const theme = {
370
431
  FormPanel: formPanel,
371
432
  FormPanelAsideSection: formPanelAsideSection,
372
433
  FormPanelSection: formPanelSection,
434
+ InputSeo: inputSeo,
435
+ InputUploraImage: inputUploraImage,
373
436
  ModalConfirm: modalConfirm,
374
437
  TablePanel: tablePanel,
375
438
  TableSearchInput: tableSearchInput,
376
- UploraImage: uploraImage$1
439
+ UploraImage: uploraImage$1,
440
+ inputSlug: inputSlug
377
441
  };
378
442
 
379
443
  const themeEditor = {
@@ -391,8 +455,88 @@ const themeProse = {
391
455
  uploraImage: uploraImage
392
456
  };
393
457
 
394
- function getAppTemplates({ options }) {
458
+ async function buildComponentDependencyGraph(componentDir, componentPattern) {
459
+ const dependencyGraph = /* @__PURE__ */ new Map();
460
+ const componentFiles = globSync(["**/*.vue"], {
461
+ cwd: componentDir,
462
+ absolute: true
463
+ });
464
+ for (const componentFile of componentFiles) {
465
+ try {
466
+ const content = await readFile(componentFile, "utf-8");
467
+ const componentName = pascalCase(componentFile.split("/").pop().replace(".vue", ""));
468
+ const dependencies = /* @__PURE__ */ new Set();
469
+ const matches = content.matchAll(componentPattern);
470
+ for (const match of matches) {
471
+ const depName = match[1] || match[2];
472
+ if (depName && depName !== componentName) {
473
+ dependencies.add(depName);
474
+ }
475
+ }
476
+ dependencyGraph.set(componentName, dependencies);
477
+ } catch {
478
+ }
479
+ }
480
+ return dependencyGraph;
481
+ }
482
+ function resolveComponentDependencies(component, dependencyGraph, resolved = /* @__PURE__ */ new Set()) {
483
+ if (resolved.has(component)) {
484
+ return resolved;
485
+ }
486
+ resolved.add(component);
487
+ const dependencies = dependencyGraph.get(component);
488
+ if (dependencies) {
489
+ for (const dep of dependencies) {
490
+ resolveComponentDependencies(dep, dependencyGraph, resolved);
491
+ }
492
+ }
493
+ return resolved;
494
+ }
495
+ async function detectUsedComponents(dirs, prefix, componentDir, includeComponents) {
496
+ const detectedComponents = /* @__PURE__ */ new Set();
497
+ if (includeComponents && includeComponents.length > 0) {
498
+ for (const component of includeComponents) {
499
+ detectedComponents.add(component);
500
+ }
501
+ }
502
+ const componentPattern = new RegExp(`<(?:Lazy)?${prefix}([A-Z][a-zA-Z]+)|\\b(?:Lazy)?${prefix}([A-Z][a-zA-Z]+)\\b`, "g");
503
+ for (const dir of dirs) {
504
+ const appFiles = globSync(["**/*.{vue,ts,js,tsx,jsx}"], {
505
+ cwd: dir,
506
+ ignore: ["node_modules/**", ".nuxt/**", "dist/**"]
507
+ });
508
+ for (const file of appFiles) {
509
+ try {
510
+ const filePath = join(dir, file);
511
+ const content = await readFile(filePath, "utf-8");
512
+ const matches = content.matchAll(componentPattern);
513
+ for (const match of matches) {
514
+ const componentName = match[1] || match[2];
515
+ if (componentName) {
516
+ detectedComponents.add(componentName);
517
+ }
518
+ }
519
+ } catch {
520
+ }
521
+ }
522
+ }
523
+ if (detectedComponents.size === 0) {
524
+ return void 0;
525
+ }
526
+ const dependencyGraph = await buildComponentDependencyGraph(componentDir, componentPattern);
527
+ const allComponents = /* @__PURE__ */ new Set();
528
+ for (const component of detectedComponents) {
529
+ const resolved = resolveComponentDependencies(component, dependencyGraph);
530
+ for (const resolvedComponent of resolved) {
531
+ allComponents.add(resolvedComponent);
532
+ }
533
+ }
534
+ return allComponents;
535
+ }
536
+
537
+ function getAppTemplates({ options, resolve, nuxt }) {
395
538
  const templates = [];
539
+ let previousDetectedComponents;
396
540
  function writeThemeTemplate(theme2, path) {
397
541
  for (const component in theme2) {
398
542
  templates.push({
@@ -427,8 +571,46 @@ function getAppTemplates({ options }) {
427
571
  });
428
572
  }
429
573
  }
574
+ async function generateSources() {
575
+ const sources = [];
576
+ const layers = getLayerDirectories(nuxt).map((layer) => layer.app);
577
+ if (options.componentDetection) {
578
+ const detectedComponents = await detectUsedComponents(
579
+ layers,
580
+ options.componentsPrefix,
581
+ resolve("./runtime/components"),
582
+ Array.isArray(options.componentDetection) ? options.componentDetection : void 0
583
+ );
584
+ if (detectedComponents && detectedComponents.size > 0) {
585
+ if (previousDetectedComponents) {
586
+ const newComponents = Array.from(detectedComponents).filter(
587
+ (component) => !previousDetectedComponents.has(component)
588
+ );
589
+ if (newComponents.length > 0) {
590
+ logger.success(`CMS detected new components: ${newComponents.join(", ")}`);
591
+ }
592
+ } else {
593
+ logger.success(`CMS detected ${detectedComponents.size} components in use (including dependencies)`);
594
+ }
595
+ previousDetectedComponents = detectedComponents;
596
+ for (const component of detectedComponents) {
597
+ const kebabComponent = kebabCase(component);
598
+ sources.push(`@source "./cms/${kebabComponent}.ts";`);
599
+ }
600
+ } else {
601
+ if (!previousDetectedComponents || previousDetectedComponents.size > 0) {
602
+ logger.info("CMS detected no components in use, including all components");
603
+ }
604
+ previousDetectedComponents = /* @__PURE__ */ new Set();
605
+ sources.push('@source "./cms";');
606
+ }
607
+ } else {
608
+ sources.push('@source "./cms";');
609
+ }
610
+ return sources.join("\n");
611
+ }
430
612
  writeThemeTemplate(themeProse, "prose");
431
- writeThemeTemplate(themeEditor, "editor");
613
+ writeThemeTemplate(themeProse, "editor");
432
614
  writeThemeTemplate(theme);
433
615
  templates.push({
434
616
  filename: `cms/prose/index.ts`,
@@ -443,37 +625,41 @@ function getAppTemplates({ options }) {
443
625
  templates.push({
444
626
  filename: "cms.css",
445
627
  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
- `
628
+ getContents: async () => {
629
+ const sources = await generateSources();
630
+ return `${sources}
631
+ ${options.unovis ? `
632
+ @layer components {
633
+ .unvois {
634
+ --vis-crosshair-line-stroke-color: var(--ui-bg-elevated);
635
+ --vis-crosshair-circle-stroke-color: transparent;
636
+
637
+ --vis-axis-grid-color: var(--ui-border);
638
+ --vis-axis-tick-color: var(--ui-border);
639
+ --vis-axis-tick-label-color: var(--ui-text-dimmed);
640
+
641
+ --vis-tooltip-background-color: var(--ui-bg);
642
+ --vis-tooltip-border-color: var(--ui-border);
643
+ --vis-tooltip-text-color: var(--ui-text-highlighted);
644
+
645
+ --vis-color0: var(--ui-primary);
646
+ --vis-color1: var(--ui-secondary);
647
+ --vis-color2: var(--ui-info);
648
+ --vis-color3: var(--ui-warning);
649
+ --vis-color4: var(--ui-error);
650
+ --vis-color5: var(--ui-success);
651
+
652
+ --vis-dark-color0: var(--ui-primary);
653
+ --vis-dark-color1: var(--ui-secondary);
654
+ --vis-dark-color2: var(--ui-info);
655
+ --vis-dark-color3: var(--ui-warning);
656
+ --vis-dark-color4: var(--ui-error);
657
+ --vis-dark-color5: var(--ui-success);
658
+ }
659
+ }
660
+ ` : ""}
661
+ `;
662
+ }
477
663
  });
478
664
  templates.push({
479
665
  filename: "cms/index.ts",
@@ -488,16 +674,14 @@ function getAppTemplates({ options }) {
488
674
  import type { TVConfig } from '@nuxt/ui'
489
675
  import type { RouteLocationRaw } from 'vue-router'
490
676
 
491
- type AppConfigCMS = {
492
- features: Record<string, boolean>
493
- } & TVConfig<typeof cms>
677
+ type AppConfigCMS = TVConfig<typeof cms>
494
678
 
495
679
  declare module '@nuxt/schema' {
496
680
  interface AppConfigInput {
497
681
  /**
498
682
  * CMS theme configuration
499
683
  */
500
- cms?: AppConfigCMS
684
+ cmsRuntime?: AppConfigCMS
501
685
  }
502
686
  }
503
687
 
@@ -520,7 +704,8 @@ export {}
520
704
  getContents: () => {
521
705
  const config = {
522
706
  name: options.name,
523
- formats: options.formats
707
+ formats: options.formats,
708
+ prose: options.prose
524
709
  };
525
710
  return `const cmsConfig = ${JSON.stringify(config, null, 2)}
526
711
 
@@ -550,6 +735,13 @@ function prepareTemplates(context) {
550
735
  addServerTemplate(template);
551
736
  }
552
737
  }
738
+ if (context.options?.componentDetection && context.nuxt.options.dev) {
739
+ context.nuxt.hook("builder:watch", async (_, path) => {
740
+ if (/\.(?:vue|ts|js|tsx|jsx)$/.test(path)) {
741
+ await updateTemplates({ filter: (template) => template.filename === "cms.css" });
742
+ }
743
+ });
744
+ }
553
745
  }
554
746
 
555
747
  const module$1 = defineNuxtModule({
@@ -561,7 +753,6 @@ const module$1 = defineNuxtModule({
561
753
  moduleDependencies: {
562
754
  "@nuxt/ui": {},
563
755
  "@nuxtjs/mdc": {},
564
- "@nuxtjs/seo": {},
565
756
  "@vueuse/nuxt": {},
566
757
  "nuxt-auth-utils": {}
567
758
  },
@@ -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