@hywax/cms 3.0.1 → 3.2.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.
- package/.nuxt/cms/form-panel-section.ts +3 -2
- package/.nuxt/cms/form-panel.ts +6 -1
- package/.nuxt/cms/form-uplora-image.ts +1 -1
- package/.nuxt/cms.css +1 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +11 -5
- package/dist/runtime/components/EditorFull.d.vue.ts +1 -0
- package/dist/runtime/components/EditorFull.vue +17 -3
- package/dist/runtime/components/EditorFull.vue.d.ts +1 -0
- package/dist/runtime/components/FormPanel.d.vue.ts +1 -0
- package/dist/runtime/components/FormPanel.vue +5 -1
- package/dist/runtime/components/FormPanel.vue.d.ts +1 -0
- package/dist/runtime/components/FormPanelSection.vue +7 -5
- package/dist/runtime/components/FormUploraImage.vue +10 -1
- package/dist/runtime/components/TablePreviewSeo.d.vue.ts +8 -0
- package/dist/runtime/components/TablePreviewSeo.vue +23 -0
- package/dist/runtime/components/TablePreviewSeo.vue.d.ts +8 -0
- package/dist/runtime/composables/useSeoStats.d.ts +1 -0
- package/dist/runtime/composables/useSeoStats.js +2 -1
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/index.js +1 -0
- package/package.json +3 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"slots": {
|
|
3
|
-
"root": "",
|
|
3
|
+
"root": "flex flex-col gap-2",
|
|
4
|
+
"header": "",
|
|
4
5
|
"title": "text-base text-pretty font-semibold text-highlighted",
|
|
5
|
-
"description": "text-[15px] text-pretty text-muted
|
|
6
|
+
"description": "text-[15px] text-pretty text-muted",
|
|
6
7
|
"body": "relative rounded-lg bg-elevated/50 ring ring-default grid gap-x-8 gap-y-4 p-4 sm:p-6"
|
|
7
8
|
}
|
|
8
9
|
}
|
package/.nuxt/cms/form-panel.ts
CHANGED
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
"slots": {
|
|
3
3
|
"root": "",
|
|
4
4
|
"form": "flex flex-1 flex-row",
|
|
5
|
-
"body": "flex-1
|
|
5
|
+
"body": "flex-1 w-full mx-auto p-4 sm:p-6 overflow-y-auto",
|
|
6
6
|
"sidebar": "flex-1 overflow-y-auto border-l border-default w-full max-w-xs p-4 sm:p-4"
|
|
7
7
|
},
|
|
8
8
|
"variants": {
|
|
@@ -10,6 +10,11 @@ export default {
|
|
|
10
10
|
"true": {
|
|
11
11
|
"sidebar": "*:not-last:after:absolute *:not-last:after:inset-x-1 *:not-last:after:bottom-0 *:not-last:after:bg-border *:not-last:after:h-px *:not-last:relative *:not-last:pb-4 flex flex-col gap-4"
|
|
12
12
|
}
|
|
13
|
+
},
|
|
14
|
+
"bodyFit": {
|
|
15
|
+
"true": {
|
|
16
|
+
"body": "lg:max-w-2xl mx-auto"
|
|
17
|
+
}
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"slots": {
|
|
3
3
|
"root": "relative w-full gap-1",
|
|
4
|
-
"base": "rounded-md overflow-hidden
|
|
4
|
+
"base": "rounded-md overflow-hidden ring-1 ring-inset ring-accented bg-default aspect-3/2",
|
|
5
5
|
"uploader": "flex flex-col items-center justify-center w-full h-full",
|
|
6
6
|
"uploaderPendingIcon": "size-6 animate-spin",
|
|
7
7
|
"uploaderIdleButton": "cursor-pointer h-full w-full",
|
package/.nuxt/cms.css
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
@source "./cms/table-panel.ts";
|
|
12
12
|
@source "./cms/modal-confirm.ts";
|
|
13
13
|
@source "./cms/table-search-input.ts";
|
|
14
|
+
@source "./cms/table-preview-seo.ts";
|
|
14
15
|
@source "./cms/ms-core-options.ts";
|
|
15
16
|
@source "./cms/ms-nuxt-context.ts";
|
|
16
17
|
@source "./cms/date-picker.ts";
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { pascalCase, kebabCase } from 'scule';
|
|
|
7
7
|
import { globSync } from 'tinyglobby';
|
|
8
8
|
|
|
9
9
|
const name = "@hywax/cms";
|
|
10
|
-
const version = "3.0
|
|
10
|
+
const version = "3.2.0";
|
|
11
11
|
|
|
12
12
|
function createContext(options, nuxt) {
|
|
13
13
|
const { resolve } = createResolver(import.meta.url);
|
|
@@ -437,7 +437,7 @@ const formPanel = {
|
|
|
437
437
|
slots: {
|
|
438
438
|
root: "",
|
|
439
439
|
form: "flex flex-1 flex-row",
|
|
440
|
-
body: "flex-1
|
|
440
|
+
body: "flex-1 w-full mx-auto p-4 sm:p-6 overflow-y-auto",
|
|
441
441
|
sidebar: "flex-1 overflow-y-auto border-l border-default w-full max-w-xs p-4 sm:p-4"
|
|
442
442
|
},
|
|
443
443
|
variants: {
|
|
@@ -445,6 +445,11 @@ const formPanel = {
|
|
|
445
445
|
true: {
|
|
446
446
|
sidebar: "*:not-last:after:absolute *:not-last:after:inset-x-1 *:not-last:after:bottom-0 *:not-last:after:bg-border *:not-last:after:h-px *:not-last:relative *:not-last:pb-4 flex flex-col gap-4"
|
|
447
447
|
}
|
|
448
|
+
},
|
|
449
|
+
bodyFit: {
|
|
450
|
+
true: {
|
|
451
|
+
body: "lg:max-w-2xl mx-auto"
|
|
452
|
+
}
|
|
448
453
|
}
|
|
449
454
|
}
|
|
450
455
|
};
|
|
@@ -461,9 +466,10 @@ const formPanelAsideSection = {
|
|
|
461
466
|
|
|
462
467
|
const formPanelSection = {
|
|
463
468
|
slots: {
|
|
464
|
-
root: "",
|
|
469
|
+
root: "flex flex-col gap-2",
|
|
470
|
+
header: "",
|
|
465
471
|
title: "text-base text-pretty font-semibold text-highlighted",
|
|
466
|
-
description: "text-[15px] text-pretty text-muted
|
|
472
|
+
description: "text-[15px] text-pretty text-muted",
|
|
467
473
|
body: "relative rounded-lg bg-elevated/50 ring ring-default grid gap-x-8 gap-y-4 p-4 sm:p-6"
|
|
468
474
|
}
|
|
469
475
|
};
|
|
@@ -483,7 +489,7 @@ const formSlug = {
|
|
|
483
489
|
const formUploraImage = {
|
|
484
490
|
slots: {
|
|
485
491
|
root: "relative w-full gap-1",
|
|
486
|
-
base: "rounded-md overflow-hidden
|
|
492
|
+
base: "rounded-md overflow-hidden ring-1 ring-inset ring-accented bg-default aspect-3/2",
|
|
487
493
|
uploader: "flex flex-col items-center justify-center w-full h-full",
|
|
488
494
|
uploaderPendingIcon: "size-6 animate-spin",
|
|
489
495
|
uploaderIdleButton: "cursor-pointer h-full w-full",
|
|
@@ -2,6 +2,7 @@ import type { EditorCustomHandlers, EditorEmits, EditorProps } from '@nuxt/ui';
|
|
|
2
2
|
import type { HTMLContent } from '@tiptap/vue-3';
|
|
3
3
|
export interface EditorFullProps extends Omit<EditorProps<HTMLContent>, 'autofocus' | 'contentType' | 'placeholder'> {
|
|
4
4
|
customHandlers?: EditorCustomHandlers;
|
|
5
|
+
madeRaw?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface EditorFullEmits extends EditorEmits<HTMLContent> {
|
|
7
8
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<UTextarea
|
|
3
|
+
v-if="madeRaw"
|
|
4
|
+
v-bind="forwardedTextarea"
|
|
5
|
+
:ui="{
|
|
6
|
+
root: 'w-full px-6',
|
|
7
|
+
base: 'text-md text-default min-h-screen'
|
|
8
|
+
}"
|
|
9
|
+
variant="none"
|
|
10
|
+
placeholder="Введите текст..."
|
|
11
|
+
autoresize
|
|
12
|
+
/>
|
|
2
13
|
<UEditor
|
|
14
|
+
v-else
|
|
3
15
|
v-slot="{ editor, handlers }"
|
|
4
|
-
v-bind="
|
|
16
|
+
v-bind="forwardedEditor"
|
|
5
17
|
class="min-h-screen"
|
|
6
18
|
content-type="markdown"
|
|
7
19
|
placeholder="Введите '/' для выбора блока..."
|
|
@@ -74,7 +86,7 @@
|
|
|
74
86
|
|
|
75
87
|
<script>
|
|
76
88
|
import { useAppConfig } from "#imports";
|
|
77
|
-
import { reactiveOmit } from "@vueuse/core";
|
|
89
|
+
import { reactiveOmit, reactivePick } from "@vueuse/core";
|
|
78
90
|
import { useForwardPropsEmits } from "reka-ui";
|
|
79
91
|
import { computed } from "vue";
|
|
80
92
|
import { useEditorDragHandle } from "../composables/useEditorDragHandle";
|
|
@@ -87,6 +99,7 @@ import EditorLinkPopover from "./EditorLinkPopover.vue";
|
|
|
87
99
|
<script setup>
|
|
88
100
|
const props = defineProps({
|
|
89
101
|
customHandlers: { type: Object, required: false },
|
|
102
|
+
madeRaw: { type: Boolean, required: false },
|
|
90
103
|
as: { type: null, required: false },
|
|
91
104
|
modelValue: { type: String, required: false },
|
|
92
105
|
starterKit: { type: Object, required: false },
|
|
@@ -125,7 +138,8 @@ const props = defineProps({
|
|
|
125
138
|
onDelete: { type: Function, required: false }
|
|
126
139
|
});
|
|
127
140
|
const emit = defineEmits(["update:modelValue"]);
|
|
128
|
-
const
|
|
141
|
+
const forwardedEditor = useForwardPropsEmits(reactiveOmit(props, "extensions", "customHandlers", "handlers", "madeRaw"), emit);
|
|
142
|
+
const forwardedTextarea = useForwardPropsEmits(reactivePick(props, "modelValue"), emit);
|
|
129
143
|
const appConfig = useAppConfig();
|
|
130
144
|
const extensions = computed(() => [
|
|
131
145
|
UploraImageExtension,
|
|
@@ -2,6 +2,7 @@ import type { EditorCustomHandlers, EditorEmits, EditorProps } from '@nuxt/ui';
|
|
|
2
2
|
import type { HTMLContent } from '@tiptap/vue-3';
|
|
3
3
|
export interface EditorFullProps extends Omit<EditorProps<HTMLContent>, 'autofocus' | 'contentType' | 'placeholder'> {
|
|
4
4
|
customHandlers?: EditorCustomHandlers;
|
|
5
|
+
madeRaw?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface EditorFullEmits extends EditorEmits<HTMLContent> {
|
|
7
8
|
}
|
|
@@ -13,6 +13,7 @@ export interface FormPanelProps<S extends FormSchema, T extends FormData<S> = Fo
|
|
|
13
13
|
loading?: boolean;
|
|
14
14
|
handler: (event: FormSubmitEvent<T>) => Promise<void>;
|
|
15
15
|
asideDivide?: boolean;
|
|
16
|
+
bodyFit?: boolean;
|
|
16
17
|
showReset?: boolean;
|
|
17
18
|
class?: any;
|
|
18
19
|
ui?: FormPanel['slots'];
|
|
@@ -60,6 +60,7 @@ const props = defineProps({
|
|
|
60
60
|
loading: { type: Boolean, required: false },
|
|
61
61
|
handler: { type: Function, required: true },
|
|
62
62
|
asideDivide: { type: Boolean, required: false },
|
|
63
|
+
bodyFit: { type: Boolean, required: false, default: true },
|
|
63
64
|
showReset: { type: Boolean, required: false },
|
|
64
65
|
class: { type: null, required: false },
|
|
65
66
|
ui: { type: null, required: false }
|
|
@@ -71,5 +72,8 @@ const formId = computed(() => props.formId ?? `form-${useId()}`);
|
|
|
71
72
|
async function submitHandler(event) {
|
|
72
73
|
await props.handler?.(event);
|
|
73
74
|
}
|
|
74
|
-
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.formPanel || {} })(
|
|
75
|
+
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.cms?.formPanel || {} })({
|
|
76
|
+
bodyFit: props.bodyFit,
|
|
77
|
+
asideDivide: props.asideDivide
|
|
78
|
+
}));
|
|
75
79
|
</script>
|
|
@@ -13,6 +13,7 @@ export interface FormPanelProps<S extends FormSchema, T extends FormData<S> = Fo
|
|
|
13
13
|
loading?: boolean;
|
|
14
14
|
handler: (event: FormSubmitEvent<T>) => Promise<void>;
|
|
15
15
|
asideDivide?: boolean;
|
|
16
|
+
bodyFit?: boolean;
|
|
16
17
|
showReset?: boolean;
|
|
17
18
|
class?: any;
|
|
18
19
|
ui?: FormPanel['slots'];
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="ui.root({ class: [props.ui?.root, props.class] })">
|
|
3
|
-
<div v-if="title" :class="ui.
|
|
4
|
-
{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{
|
|
3
|
+
<div v-if="title || description" :class="ui.header({ class: props.ui?.header })">
|
|
4
|
+
<div v-if="title" :class="ui.title({ class: props.ui?.title })">
|
|
5
|
+
{{ title }}
|
|
6
|
+
</div>
|
|
7
|
+
<div v-if="description" :class="ui.description({ class: props.ui?.description })">
|
|
8
|
+
{{ description }}
|
|
9
|
+
</div>
|
|
8
10
|
</div>
|
|
9
11
|
<div :class="ui.body({ class: props.ui?.body })">
|
|
10
12
|
<slot />
|
|
@@ -89,7 +89,8 @@
|
|
|
89
89
|
placeholder="Введите описание..."
|
|
90
90
|
variant="none"
|
|
91
91
|
size="xs"
|
|
92
|
-
:ui="{ base: 'text-center' }"
|
|
92
|
+
:ui="{ base: 'text-center text-toned' }"
|
|
93
|
+
@update:model-value="onAltInput"
|
|
93
94
|
/>
|
|
94
95
|
</UFormField>
|
|
95
96
|
</UForm>
|
|
@@ -140,6 +141,14 @@ const { open, execute: uploadExecute, status: uploadStatus, reset: resetUpload,
|
|
|
140
141
|
accept: "image/*"
|
|
141
142
|
});
|
|
142
143
|
const { execute: deleteExecute, onDeleted } = useUploraDelete();
|
|
144
|
+
function onAltInput(alt) {
|
|
145
|
+
modelValue.value = {
|
|
146
|
+
...modelValue.value,
|
|
147
|
+
alt: alt || void 0
|
|
148
|
+
};
|
|
149
|
+
emitFormChange();
|
|
150
|
+
emitFormInput();
|
|
151
|
+
}
|
|
143
152
|
function resetState() {
|
|
144
153
|
modelValue.value = {
|
|
145
154
|
image: void 0,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SEO } from '../types/seo';
|
|
2
|
+
export interface TableCellSeoProps {
|
|
3
|
+
seo: SEO;
|
|
4
|
+
as?: any;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<TableCellSeoProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TableCellSeoProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UBadge
|
|
3
|
+
:color="computeColor(rating)"
|
|
4
|
+
:label="`${rating}/100`"
|
|
5
|
+
variant="subtle"
|
|
6
|
+
/>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import { computed } from "#imports";
|
|
11
|
+
import { useSeoStats } from "../composables/useSeoStats";
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
const props = defineProps({
|
|
16
|
+
seo: { type: Object, required: true },
|
|
17
|
+
as: { type: null, required: false }
|
|
18
|
+
});
|
|
19
|
+
const { title, description, computeColor } = useSeoStats(props.seo);
|
|
20
|
+
const rating = computed(() => {
|
|
21
|
+
return Math.round((title.value.progress + description.value.progress) / 2);
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SEO } from '../types/seo';
|
|
2
|
+
export interface TableCellSeoProps {
|
|
3
|
+
seo: SEO;
|
|
4
|
+
as?: any;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: typeof __VLS_export;
|
|
7
|
+
export default _default;
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<TableCellSeoProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<TableCellSeoProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -7,6 +7,7 @@ interface SEOStats {
|
|
|
7
7
|
interface UseSeoStatsReturn {
|
|
8
8
|
title: ComputedRef<SEOStats>;
|
|
9
9
|
description: ComputedRef<SEOStats>;
|
|
10
|
+
computeColor: (score: number) => 'error' | 'warning' | 'success';
|
|
10
11
|
}
|
|
11
12
|
export declare function useSeoStats(options: MaybeRefOrGetter<SEO>): UseSeoStatsReturn;
|
|
12
13
|
export {};
|
|
@@ -16,6 +16,7 @@ export * from '../components/prose/UploraImage.vue';
|
|
|
16
16
|
export * from '../components/TableColumnSorting.vue';
|
|
17
17
|
export * from '../components/TableFilters.vue';
|
|
18
18
|
export * from '../components/TablePanel.vue';
|
|
19
|
+
export * from '../components/TablePreviewSeo.vue';
|
|
19
20
|
export * from '../components/TableSearchInput.vue';
|
|
20
21
|
export * from '../components/UploraImage.vue';
|
|
21
22
|
export * from '../composables/useAdmin';
|
|
@@ -16,6 +16,7 @@ export * from "../components/prose/UploraImage.vue";
|
|
|
16
16
|
export * from "../components/TableColumnSorting.vue";
|
|
17
17
|
export * from "../components/TableFilters.vue";
|
|
18
18
|
export * from "../components/TablePanel.vue";
|
|
19
|
+
export * from "../components/TablePreviewSeo.vue";
|
|
19
20
|
export * from "../components/TableSearchInput.vue";
|
|
20
21
|
export * from "../components/UploraImage.vue";
|
|
21
22
|
export * from "../composables/useAdmin.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hywax/cms",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0
|
|
4
|
+
"version": "3.2.0",
|
|
5
5
|
"description": "Hywax CMS. ⚠️ This package is intended for internal use only.",
|
|
6
6
|
"imports": {
|
|
7
7
|
"#build/cms/*": "./.nuxt/cms/*.ts",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@dicebear/collection": "^9.2.4",
|
|
64
64
|
"@dicebear/core": "^9.2.4",
|
|
65
|
+
"@iconify-json/lucide": "^1.2.83",
|
|
65
66
|
"@nuxt/kit": "^4.2.2",
|
|
66
67
|
"@nuxt/ui": "^4.3.0",
|
|
67
68
|
"@nuxtjs/mdc": "^0.19.2",
|
|
@@ -94,7 +95,7 @@
|
|
|
94
95
|
"@vue/test-utils": "^2.4.6",
|
|
95
96
|
"changelogen-monorepo": "^0.5.0",
|
|
96
97
|
"eslint": "^9.39.2",
|
|
97
|
-
"happy-dom": "^20.0
|
|
98
|
+
"happy-dom": "^20.1.0",
|
|
98
99
|
"husky": "^9.1.7",
|
|
99
100
|
"lint-staged": "^16.2.7",
|
|
100
101
|
"nuxt": "^4.2.2",
|