@vigilkids/section-renderer-vue 0.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.
- package/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/assets/images/article/arrow.svg +3 -0
- package/dist/assets/images/article/hot.svg +3 -0
- package/dist/assets/images/article/notice-info-icon.svg +5 -0
- package/dist/assets/images/article/notice-info.svg +3 -0
- package/dist/assets/images/article/notice-warning-icon.svg +5 -0
- package/dist/assets/images/article/notice-warning.svg +10 -0
- package/dist/assets/images/article/question.svg +10 -0
- package/dist/composables/useInlineEdit.d.ts +30 -0
- package/dist/composables/useInlineEdit.mjs +94 -0
- package/dist/composables/useLazyRender.d.ts +18 -0
- package/dist/composables/useLazyRender.mjs +33 -0
- package/dist/composables/useRegistry.d.ts +38 -0
- package/dist/composables/useRegistry.mjs +60 -0
- package/dist/composables/useSectionSEO.d.ts +26 -0
- package/dist/composables/useSectionSEO.mjs +122 -0
- package/dist/composables/useSectionStyle.d.ts +23 -0
- package/dist/composables/useSectionStyle.mjs +111 -0
- package/dist/editor.d.ts +4 -0
- package/dist/editor.mjs +9 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.mjs +14 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.mjs +14 -0
- package/dist/preview/createPreviewApp.d.ts +20 -0
- package/dist/preview/createPreviewApp.mjs +161 -0
- package/dist/renderer/FallbackSection.d.vue.ts +8 -0
- package/dist/renderer/FallbackSection.vue +17 -0
- package/dist/renderer/FallbackSection.vue.d.ts +8 -0
- package/dist/renderer/LazySection.d.vue.ts +60 -0
- package/dist/renderer/LazySection.vue +115 -0
- package/dist/renderer/LazySection.vue.d.ts +60 -0
- package/dist/renderer/SectionErrorBoundary.d.vue.ts +16 -0
- package/dist/renderer/SectionErrorBoundary.vue +38 -0
- package/dist/renderer/SectionErrorBoundary.vue.d.ts +16 -0
- package/dist/renderer/SectionRenderer.d.vue.ts +29 -0
- package/dist/renderer/SectionRenderer.vue +99 -0
- package/dist/renderer/SectionRenderer.vue.d.ts +29 -0
- package/dist/renderer/SectionWrapper.d.vue.ts +24 -0
- package/dist/renderer/SectionWrapper.vue +52 -0
- package/dist/renderer/SectionWrapper.vue.d.ts +24 -0
- package/dist/sections/RichTextSection.d.vue.ts +9 -0
- package/dist/sections/RichTextSection.vue +135 -0
- package/dist/sections/RichTextSection.vue.d.ts +9 -0
- package/dist/sections/article/index.d.ts +2 -0
- package/dist/sections/article/index.mjs +174 -0
- package/dist/sections/article/prosemirror.d.ts +2 -0
- package/dist/sections/article/prosemirror.mjs +65 -0
- package/dist/sections/article/shared/ArticleCustomHtml.d.vue.ts +9 -0
- package/dist/sections/article/shared/ArticleCustomHtml.vue +32 -0
- package/dist/sections/article/shared/ArticleCustomHtml.vue.d.ts +9 -0
- package/dist/sections/article/shared/ArticleImage.d.vue.ts +21 -0
- package/dist/sections/article/shared/ArticleImage.vue +53 -0
- package/dist/sections/article/shared/ArticleImage.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleBulletList.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleBulletList.vue +48 -0
- package/dist/sections/article/vigilkids/ArticleBulletList.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleCta.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleCta.vue +126 -0
- package/dist/sections/article/vigilkids/ArticleCta.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleFaq.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleFaq.vue +62 -0
- package/dist/sections/article/vigilkids/ArticleFaq.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleFaqItem.d.vue.ts +5 -0
- package/dist/sections/article/vigilkids/ArticleFaqItem.vue +24 -0
- package/dist/sections/article/vigilkids/ArticleFaqItem.vue.d.ts +5 -0
- package/dist/sections/article/vigilkids/ArticleFeature.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleFeature.vue +77 -0
- package/dist/sections/article/vigilkids/ArticleFeature.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleHeading.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleHeading.vue +53 -0
- package/dist/sections/article/vigilkids/ArticleHeading.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleNotice.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleNotice.vue +81 -0
- package/dist/sections/article/vigilkids/ArticleNotice.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleProsCons.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleProsCons.vue +74 -0
- package/dist/sections/article/vigilkids/ArticleProsCons.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleQuestion.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleQuestion.vue +58 -0
- package/dist/sections/article/vigilkids/ArticleQuestion.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleQuote.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleQuote.vue +50 -0
- package/dist/sections/article/vigilkids/ArticleQuote.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleStepList.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleStepList.vue +49 -0
- package/dist/sections/article/vigilkids/ArticleStepList.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleSubheading.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleSubheading.vue +56 -0
- package/dist/sections/article/vigilkids/ArticleSubheading.vue.d.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleTable.d.vue.ts +9 -0
- package/dist/sections/article/vigilkids/ArticleTable.vue +75 -0
- package/dist/sections/article/vigilkids/ArticleTable.vue.d.ts +9 -0
- package/dist/sections/article/vigilkids/ArticleToc.d.vue.ts +21 -0
- package/dist/sections/article/vigilkids/ArticleToc.vue +102 -0
- package/dist/sections/article/vigilkids/ArticleToc.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleBulletList.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleBulletList.vue +48 -0
- package/dist/sections/article/visiva/ArticleBulletList.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleCta.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleCta.vue +148 -0
- package/dist/sections/article/visiva/ArticleCta.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleFaq.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleFaq.vue +76 -0
- package/dist/sections/article/visiva/ArticleFaq.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleFeature.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleFeature.vue +79 -0
- package/dist/sections/article/visiva/ArticleFeature.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleHeading.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleHeading.vue +61 -0
- package/dist/sections/article/visiva/ArticleHeading.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleNotice.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleNotice.vue +102 -0
- package/dist/sections/article/visiva/ArticleNotice.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleProsCons.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleProsCons.vue +98 -0
- package/dist/sections/article/visiva/ArticleProsCons.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleQuestion.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleQuestion.vue +80 -0
- package/dist/sections/article/visiva/ArticleQuestion.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleQuote.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleQuote.vue +50 -0
- package/dist/sections/article/visiva/ArticleQuote.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleStepList.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleStepList.vue +48 -0
- package/dist/sections/article/visiva/ArticleStepList.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleSubheading.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleSubheading.vue +91 -0
- package/dist/sections/article/visiva/ArticleSubheading.vue.d.ts +21 -0
- package/dist/sections/article/visiva/ArticleTable.d.vue.ts +9 -0
- package/dist/sections/article/visiva/ArticleTable.vue +140 -0
- package/dist/sections/article/visiva/ArticleTable.vue.d.ts +9 -0
- package/dist/sections/article/visiva/ArticleToc.d.vue.ts +21 -0
- package/dist/sections/article/visiva/ArticleToc.vue +116 -0
- package/dist/sections/article/visiva/ArticleToc.vue.d.ts +21 -0
- package/dist/shims-css.d.ts +4 -0
- package/dist/styles/products/vigilkids.css +1 -0
- package/dist/styles/products/visiva.css +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function renderNode(node) {
|
|
2
|
+
switch (node.type) {
|
|
3
|
+
case "blockquote":
|
|
4
|
+
return `<blockquote>${renderChildren(node)}</blockquote>`;
|
|
5
|
+
case "bulletList":
|
|
6
|
+
return `<ul>${renderChildren(node)}</ul>`;
|
|
7
|
+
case "codeBlock":
|
|
8
|
+
return `<pre><code>${renderChildren(node)}</code></pre>`;
|
|
9
|
+
case "hardBreak":
|
|
10
|
+
return "<br />";
|
|
11
|
+
case "heading": {
|
|
12
|
+
const level = node.attrs?.level ?? 2;
|
|
13
|
+
return `<h${level}>${renderChildren(node)}</h${level}>`;
|
|
14
|
+
}
|
|
15
|
+
case "horizontalRule":
|
|
16
|
+
return "<hr />";
|
|
17
|
+
case "listItem":
|
|
18
|
+
return `<li>${renderChildren(node)}</li>`;
|
|
19
|
+
case "orderedList":
|
|
20
|
+
return `<ol>${renderChildren(node)}</ol>`;
|
|
21
|
+
case "paragraph":
|
|
22
|
+
return `<p>${renderChildren(node)}</p>`;
|
|
23
|
+
case "text":
|
|
24
|
+
return applyMarks(node.text ?? "", node.marks);
|
|
25
|
+
default:
|
|
26
|
+
return renderChildren(node);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function renderChildren(node) {
|
|
30
|
+
if (!node.content) return node.text ?? "";
|
|
31
|
+
return node.content.map(renderNode).join("");
|
|
32
|
+
}
|
|
33
|
+
function applyMarks(text, marks) {
|
|
34
|
+
if (!marks) return text;
|
|
35
|
+
let result = text;
|
|
36
|
+
for (const mark of marks) {
|
|
37
|
+
switch (mark.type) {
|
|
38
|
+
case "bold":
|
|
39
|
+
result = `<strong>${result}</strong>`;
|
|
40
|
+
break;
|
|
41
|
+
case "code":
|
|
42
|
+
result = `<code>${result}</code>`;
|
|
43
|
+
break;
|
|
44
|
+
case "italic":
|
|
45
|
+
result = `<em>${result}</em>`;
|
|
46
|
+
break;
|
|
47
|
+
case "link":
|
|
48
|
+
result = `<a href="${mark.attrs?.href ?? "#"}">${result}</a>`;
|
|
49
|
+
break;
|
|
50
|
+
case "underline":
|
|
51
|
+
result = `<span class="underline">${result}</span>`;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
export function renderContent(content) {
|
|
58
|
+
if (typeof content === "string") return content;
|
|
59
|
+
if (content && typeof content === "object" && content.type === "doc") {
|
|
60
|
+
const doc = content;
|
|
61
|
+
if (!doc.content) return "";
|
|
62
|
+
return doc.content.map(renderNode).join("");
|
|
63
|
+
}
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BlockData } from '@vigilkids/section-core'
|
|
3
|
+
import type { Ref } from 'vue'
|
|
4
|
+
|
|
5
|
+
import { computed, inject } from 'vue'
|
|
6
|
+
|
|
7
|
+
import { renderContent } from '../prosemirror'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
blockOrder: string[]
|
|
11
|
+
blocks: Record<string, BlockData>
|
|
12
|
+
editorMode?: boolean
|
|
13
|
+
settings: Record<string, unknown>
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
// 从 createPreviewApp 注入当前产品标识,用于加载对应产品的 CSS
|
|
17
|
+
const currentProduct = inject<Ref<string>>('currentProduct')
|
|
18
|
+
const productClass = computed(() => {
|
|
19
|
+
const code = currentProduct?.value || 'vigilkids'
|
|
20
|
+
return `article-content--${code}`
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/* 兼容 article-prose 的 settings.content 字段(可能是 ProseMirror JSON) */
|
|
24
|
+
const htmlContent = computed(() => {
|
|
25
|
+
const raw = props.settings.html_content ?? props.settings.content ?? ''
|
|
26
|
+
return renderContent(raw)
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div :class="['article-custom-html', 'article-content', productClass]" v-html="htmlContent" />
|
|
32
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BlockData } from '@vigilkids/section-core'
|
|
3
|
+
|
|
4
|
+
import { safeUrl } from '@vigilkids/section-core'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
|
|
7
|
+
import { useInlineEdit } from '../../../composables/useInlineEdit'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
blockOrder: string[]
|
|
11
|
+
blocks: Record<string, BlockData>
|
|
12
|
+
editorMode?: boolean
|
|
13
|
+
settings: Record<string, unknown>
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits<{
|
|
17
|
+
(e: 'update:setting', key: string, value: unknown): void
|
|
18
|
+
(e: 'update:block-setting', blockId: string, key: string, value: unknown): void
|
|
19
|
+
(e: 'inline-edit-start', key: string): void
|
|
20
|
+
(e: 'inline-edit-end'): void
|
|
21
|
+
(e: 'undo-redo', action: 'redo' | 'undo'): void
|
|
22
|
+
}>()
|
|
23
|
+
|
|
24
|
+
const s = computed(() => props.settings)
|
|
25
|
+
|
|
26
|
+
const { editableAttrs } = useInlineEdit({
|
|
27
|
+
editorMode: () => !!props.editorMode,
|
|
28
|
+
onSettingUpdate: (key, value) => emit('update:setting', key, value),
|
|
29
|
+
onBlockSettingUpdate: (blockId, key, value) => emit('update:block-setting', blockId, key, value),
|
|
30
|
+
onEditStart: (key) => emit('inline-edit-start', key),
|
|
31
|
+
onEditEnd: () => emit('inline-edit-end'),
|
|
32
|
+
onUndoRedo: (action) => emit('undo-redo', action),
|
|
33
|
+
})
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<figure class="article-image">
|
|
38
|
+
<img
|
|
39
|
+
v-if="s.src"
|
|
40
|
+
:alt="String(s.alt || '')"
|
|
41
|
+
:src="safeUrl(String(s.src))"
|
|
42
|
+
class="article-image__img"
|
|
43
|
+
loading="lazy"
|
|
44
|
+
/>
|
|
45
|
+
<figcaption v-if="s.caption" class="article-image__caption" v-bind="editableAttrs('caption')">
|
|
46
|
+
{{ s.caption }}
|
|
47
|
+
</figcaption>
|
|
48
|
+
</figure>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<style scoped>
|
|
52
|
+
.article-image{text-align:center}.article-image__img{height:auto;margin:10px auto 30px;max-width:500px;-o-object-fit:cover;object-fit:cover;width:auto}.article-image__caption{color:#999;font-size:14px;margin-bottom:10px;margin-top:-20px;text-align:center}@media (max-width:515px){.article-image__img{max-width:100%;width:auto}}
|
|
53
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BlockData } from '@vigilkids/section-core'
|
|
3
|
+
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
|
|
6
|
+
import { useInlineEdit } from '../../../composables/useInlineEdit'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
blockOrder: string[]
|
|
10
|
+
blocks: Record<string, BlockData>
|
|
11
|
+
editorMode?: boolean
|
|
12
|
+
settings: Record<string, unknown>
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
(e: 'update:setting', key: string, value: unknown): void
|
|
17
|
+
(e: 'update:block-setting', blockId: string, key: string, value: unknown): void
|
|
18
|
+
(e: 'inline-edit-start', key: string): void
|
|
19
|
+
(e: 'inline-edit-end'): void
|
|
20
|
+
(e: 'undo-redo', action: 'redo' | 'undo'): void
|
|
21
|
+
}>()
|
|
22
|
+
|
|
23
|
+
const blockOrder = computed(() => props.blockOrder)
|
|
24
|
+
const blocks = computed(() => props.blocks)
|
|
25
|
+
|
|
26
|
+
const { blockEditableAttrs } = useInlineEdit({
|
|
27
|
+
editorMode: () => !!props.editorMode,
|
|
28
|
+
onSettingUpdate: (key, value) => emit('update:setting', key, value),
|
|
29
|
+
onBlockSettingUpdate: (blockId, key, value) => emit('update:block-setting', blockId, key, value),
|
|
30
|
+
onEditStart: (key) => emit('inline-edit-start', key),
|
|
31
|
+
onEditEnd: () => emit('inline-edit-end'),
|
|
32
|
+
onUndoRedo: (action) => emit('undo-redo', action),
|
|
33
|
+
})
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<ul class="article-bullet-list">
|
|
38
|
+
<template v-for="blockId in blockOrder" :key="blockId">
|
|
39
|
+
<li v-if="blocks[blockId]" v-bind="blockEditableAttrs(blockId, 'text')">
|
|
40
|
+
{{ blocks[blockId]!.settings.text }}
|
|
41
|
+
</li>
|
|
42
|
+
</template>
|
|
43
|
+
</ul>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style scoped>
|
|
47
|
+
.article-bullet-list{color:var(--article-text,#3a4259);list-style-type:disc;margin-top:10px;padding-left:20px}
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BlockData } from '@vigilkids/section-core'
|
|
3
|
+
|
|
4
|
+
import { safeUrl } from '@vigilkids/section-core'
|
|
5
|
+
import { computed } from 'vue'
|
|
6
|
+
|
|
7
|
+
import { useInlineEdit } from '../../../composables/useInlineEdit'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
blockOrder: string[]
|
|
11
|
+
blocks: Record<string, BlockData>
|
|
12
|
+
editorMode?: boolean
|
|
13
|
+
settings: Record<string, unknown>
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits<{
|
|
17
|
+
(e: 'update:setting', key: string, value: unknown): void
|
|
18
|
+
(e: 'update:block-setting', blockId: string, key: string, value: unknown): void
|
|
19
|
+
(e: 'inline-edit-start', key: string): void
|
|
20
|
+
(e: 'inline-edit-end'): void
|
|
21
|
+
(e: 'undo-redo', action: 'redo' | 'undo'): void
|
|
22
|
+
}>()
|
|
23
|
+
|
|
24
|
+
const s = computed(() => props.settings)
|
|
25
|
+
const variant = computed(() => String(s.value.variant || 'button'))
|
|
26
|
+
|
|
27
|
+
const { editableAttrs } = useInlineEdit({
|
|
28
|
+
editorMode: () => !!props.editorMode,
|
|
29
|
+
onSettingUpdate: (key, value) => emit('update:setting', key, value),
|
|
30
|
+
onBlockSettingUpdate: (blockId, key, value) => emit('update:block-setting', blockId, key, value),
|
|
31
|
+
onEditStart: (key) => emit('inline-edit-start', key),
|
|
32
|
+
onEditEnd: () => emit('inline-edit-end'),
|
|
33
|
+
onUndoRedo: (action) => emit('undo-redo', action),
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<!-- button variant: 单个居中按钮 -->
|
|
39
|
+
<a
|
|
40
|
+
v-if="variant === 'button'"
|
|
41
|
+
:href="safeUrl(String(s.button_url || ''))"
|
|
42
|
+
class="btn btn-primary"
|
|
43
|
+
v-bind="editableAttrs('button_text')"
|
|
44
|
+
>
|
|
45
|
+
{{ s.button_text }}
|
|
46
|
+
</a>
|
|
47
|
+
|
|
48
|
+
<!-- button-group variant: 两个按钮并排 -->
|
|
49
|
+
<div v-else-if="variant === 'button-group'" class="btn-group">
|
|
50
|
+
<a
|
|
51
|
+
:href="safeUrl(String(s.button_url || ''))"
|
|
52
|
+
class="btn btn-primary"
|
|
53
|
+
v-bind="editableAttrs('button_text')"
|
|
54
|
+
>
|
|
55
|
+
{{ s.button_text }}
|
|
56
|
+
</a>
|
|
57
|
+
<a
|
|
58
|
+
v-if="s.secondary_button_text"
|
|
59
|
+
:href="safeUrl(String(s.secondary_button_url || ''))"
|
|
60
|
+
class="btn outline-btn"
|
|
61
|
+
v-bind="editableAttrs('secondary_button_text')"
|
|
62
|
+
>
|
|
63
|
+
{{ s.secondary_button_text }}
|
|
64
|
+
</a>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<!-- card variant: 左文字右按钮 -->
|
|
68
|
+
<div v-else-if="variant === 'card'" class="article-try">
|
|
69
|
+
<div class="article-try-content">
|
|
70
|
+
<p v-if="s.title" class="article-try-title" v-bind="editableAttrs('title')">{{ s.title }}</p>
|
|
71
|
+
<p v-if="s.description" class="article-try-description" v-bind="editableAttrs('description')">{{ s.description }}</p>
|
|
72
|
+
</div>
|
|
73
|
+
<a
|
|
74
|
+
v-if="s.button_text"
|
|
75
|
+
:href="safeUrl(String(s.button_url || ''))"
|
|
76
|
+
class="btn btn-primary"
|
|
77
|
+
v-bind="editableAttrs('button_text')"
|
|
78
|
+
>
|
|
79
|
+
{{ s.button_text }}
|
|
80
|
+
</a>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<!-- showcase variant: 左文字+按钮,右图片 -->
|
|
84
|
+
<div v-else-if="variant === 'showcase'" class="article-show">
|
|
85
|
+
<div class="article-show-content">
|
|
86
|
+
<p v-if="s.title" class="article-show-title" v-bind="editableAttrs('title')">{{ s.title }}</p>
|
|
87
|
+
<p v-if="s.description" class="article-show-description" v-bind="editableAttrs('description')">{{ s.description }}</p>
|
|
88
|
+
<a
|
|
89
|
+
v-if="s.button_text"
|
|
90
|
+
:href="safeUrl(String(s.button_url || ''))"
|
|
91
|
+
class="btn btn-primary"
|
|
92
|
+
v-bind="editableAttrs('button_text')"
|
|
93
|
+
>
|
|
94
|
+
{{ s.button_text }}
|
|
95
|
+
</a>
|
|
96
|
+
</div>
|
|
97
|
+
<img
|
|
98
|
+
v-if="s.image_src"
|
|
99
|
+
:src="String(s.image_src)"
|
|
100
|
+
alt=""
|
|
101
|
+
loading="lazy"
|
|
102
|
+
>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<!-- button-group-dark variant: 黑底容器+白边主按钮+渐变次按钮 (Visiva) -->
|
|
106
|
+
<div v-else-if="variant === 'button-group-dark'" class="btn-group-dark">
|
|
107
|
+
<div class="btn-group-dark__buttons">
|
|
108
|
+
<div v-if="s.button_text" class="btn-group-dark__item">
|
|
109
|
+
<a :href="safeUrl(String(s.button_url || ''))" class="btn btn-outline-white" v-bind="editableAttrs('button_text')">
|
|
110
|
+
{{ s.button_text }}
|
|
111
|
+
</a>
|
|
112
|
+
<p v-if="s.button_caption" class="btn-group-dark__caption" v-bind="editableAttrs('button_caption')">{{ s.button_caption }}</p>
|
|
113
|
+
</div>
|
|
114
|
+
<div v-if="s.secondary_button_text" class="btn-group-dark__item">
|
|
115
|
+
<a :href="safeUrl(String(s.secondary_button_url || ''))" class="btn btn-gradient" v-bind="editableAttrs('secondary_button_text')">
|
|
116
|
+
{{ s.secondary_button_text }}
|
|
117
|
+
</a>
|
|
118
|
+
<p v-if="s.secondary_button_caption" class="btn-group-dark__caption" v-bind="editableAttrs('secondary_button_caption')">{{ s.secondary_button_caption }}</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</template>
|
|
123
|
+
|
|
124
|
+
<style scoped>
|
|
125
|
+
.btn{align-items:center;border:none;border-radius:var(--article-btn-radius,10px);box-sizing:border-box;cursor:pointer;display:flex;font-size:16px;font-weight:700;height:var(--article-btn-height,52px);justify-content:center;line-height:24px;padding:10px 20px;text-decoration:none;transition:all .3s ease;width:220px}.btn.btn-primary{background:var(--article-primary,#24c790);color:var(--article-btn-color,#fff);margin:20px auto 30px}.btn.btn-primary:active,.btn.btn-primary:hover{background:var(--article-primary-hover,#1ba97a)}.btn.outline-btn{background:#fff;border:2px solid var(--article-primary,#24c790);border-radius:var(--article-btn-radius,10px);color:var(--article-primary-hover,#1ba97a);height:var(--article-btn-height,52px);margin:20px auto 30px}.btn.outline-btn:hover{background:var(--article-primary,#24c790);color:#fff}.btn.outline-btn:active{background:var(--article-primary-hover,#1ba97a);color:#fff}.btn-group{align-items:center;display:flex;gap:40px;justify-content:center;margin-bottom:30px}.btn-group .btn{margin:0}.article-try{align-items:center;background:var(--article-bg-gray,#f3f5f7);border-radius:10px;color:var(--article-text,#3a4259);margin-top:30px;padding:40px 60px}.article-try,.article-try-content{display:flex;justify-content:space-between}.article-try-content{flex-direction:column}.article-try-title{font-size:20px;font-weight:700;line-height:23px;margin-bottom:10px;margin-top:0}.article-try-description{line-height:32px;margin-bottom:0;margin-top:0}.article-try .btn{margin:0 0 0 10px;min-width:220px}.article-show{align-items:center;background:var(--article-bg-gray,#f3f5f7);border-radius:10px;color:var(--article-text,#3a4259);margin-top:30px;padding:40px 30px 40px 60px}.article-show,.article-show-content{display:flex;justify-content:space-between}.article-show-content{flex-direction:column}.article-show-title{font-size:24px;font-weight:700;line-height:28px;margin-bottom:14px;margin-top:0}.article-show-description{line-height:30px;margin-bottom:0;margin-top:0}.article-show .btn{margin-left:0;margin-top:20px;min-width:220px}.article-show img{border-radius:10px;height:auto;margin-left:32px;max-width:368px;-o-object-fit:cover;object-fit:cover;width:100%}.btn-group-dark{background:#000;border-radius:20px;margin-top:40px;padding:16px 40px}.btn-group-dark__buttons{align-items:center;display:flex;flex-direction:column;gap:16px;justify-content:center}.btn-group-dark__item{text-align:center}.btn-group-dark__caption{color:#9ca3af;font-size:14px;font-weight:500;margin:16px 0 0}.btn.btn-outline-white{background:transparent;border:1px solid #fff;color:#fff;margin:0}.btn.btn-outline-white:hover{background:#fff;color:#000}.btn.btn-gradient{background:linear-gradient(to right,var(--article-gradient-start,#24c790),var(--article-gradient-end,#1ba97a));border:none;color:#000;margin:0}.btn.btn-gradient:hover{opacity:.9}@media (min-width:769px){.btn-group-dark{padding:40px}.btn-group-dark__buttons{flex-direction:row;gap:24px}}@media (max-width:768px){.btn-group{flex-direction:column;gap:10px}.article-try{align-items:center;flex-direction:column;padding:20px 16px;text-align:center}.article-try-description{line-height:21px}.article-try .btn{margin:20px 0}.article-show{flex-direction:column;padding:20px 16px;text-align:center}.article-show,.article-show-content{align-items:center}.article-show-description{line-height:21px}.article-show .btn,.article-show img{margin:20px 0}.btn-group-dark__buttons{gap:16px}}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BlockData } from '@vigilkids/section-core'
|
|
3
|
+
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
|
|
6
|
+
import { useInlineEdit } from '../../../composables/useInlineEdit'
|
|
7
|
+
import ArticleFaqItem from './ArticleFaqItem.vue'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
blockOrder: string[]
|
|
11
|
+
blocks: Record<string, BlockData>
|
|
12
|
+
editorMode?: boolean
|
|
13
|
+
settings: Record<string, unknown>
|
|
14
|
+
}>()
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits<{
|
|
17
|
+
(e: 'update:setting', key: string, value: unknown): void
|
|
18
|
+
(e: 'update:block-setting', blockId: string, key: string, value: unknown): void
|
|
19
|
+
(e: 'inline-edit-start', key: string): void
|
|
20
|
+
(e: 'inline-edit-end'): void
|
|
21
|
+
(e: 'undo-redo', action: 'redo' | 'undo'): void
|
|
22
|
+
}>()
|
|
23
|
+
|
|
24
|
+
const s = computed(() => props.settings)
|
|
25
|
+
|
|
26
|
+
const { editableAttrs, blockEditableAttrs } = useInlineEdit({
|
|
27
|
+
editorMode: () => !!props.editorMode,
|
|
28
|
+
onSettingUpdate: (key, value) => emit('update:setting', key, value),
|
|
29
|
+
onBlockSettingUpdate: (blockId, key, value) => emit('update:block-setting', blockId, key, value),
|
|
30
|
+
onEditStart: (key) => emit('inline-edit-start', key),
|
|
31
|
+
onEditEnd: () => emit('inline-edit-end'),
|
|
32
|
+
onUndoRedo: (action) => emit('undo-redo', action),
|
|
33
|
+
})
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<!-- Visiva 风格:浅绿卡片 + 绿色标题 + 静态列表 -->
|
|
38
|
+
<div v-if="s.title" class="faq-card">
|
|
39
|
+
<div class="faq-card__header">
|
|
40
|
+
<h2 class="faq-card__title" v-bind="editableAttrs('title')">{{ s.title }}</h2>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="faq-card__list">
|
|
43
|
+
<template v-for="blockId in blockOrder" :key="blockId">
|
|
44
|
+
<div v-if="blocks[blockId]" class="faq-card__item">
|
|
45
|
+
<h3 class="faq-card__question" v-bind="blockEditableAttrs(blockId, 'question')">{{ blocks[blockId]!.settings.question }}</h3>
|
|
46
|
+
<p class="faq-card__answer" v-bind="blockEditableAttrs(blockId, 'answer')">{{ blocks[blockId]!.settings.answer }}</p>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- VigilKids 风格:手风琴折叠 -->
|
|
53
|
+
<div v-else class="faq-list">
|
|
54
|
+
<template v-for="blockId in blockOrder" :key="blockId">
|
|
55
|
+
<ArticleFaqItem v-if="blocks[blockId]" :settings="blocks[blockId]!.settings" />
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style scoped>
|
|
61
|
+
.faq-list{background:var(--article-bg-gray,#f3f5f7);border-radius:10px;color:#333;margin-bottom:50px;margin-top:20px;padding:26px 20px}.faq-list :deep(.faq-item:not(:last-child)){margin-bottom:10px}.faq-card{background:var(--article-bg-faq,#f9fafb);border-radius:10px;font-size:14px;margin-top:40px;padding:28px 16px}.faq-card__header{align-items:center;display:flex;gap:8px;margin-bottom:16px}.faq-card__title{color:var(--article-primary,#24c790);font-size:18px;font-weight:700;margin:0}.faq-card__list{display:flex;flex-direction:column;gap:16px}.faq-card__question{font-size:14px;font-weight:700;margin:0 0 6px}.faq-card__answer{line-height:1.6;margin:0}@media (min-width:769px){.faq-card{border-radius:15px;font-size:16px;padding:28px 20px}.faq-card__title{font-size:20px}.faq-card__list{gap:24px}.faq-card__question{font-size:16px;margin-bottom:12px}}
|
|
62
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BlockData } from '@vigilkids/section-core';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
blockOrder: string[];
|
|
4
|
+
blocks: Record<string, BlockData>;
|
|
5
|
+
editorMode?: boolean;
|
|
6
|
+
settings: Record<string, unknown>;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
+
"update:setting": (key: string, value: unknown) => any;
|
|
10
|
+
"update:block-setting": (blockId: string, key: string, value: unknown) => any;
|
|
11
|
+
"inline-edit-start": (key: string) => any;
|
|
12
|
+
"inline-edit-end": () => any;
|
|
13
|
+
"undo-redo": (action: "redo" | "undo") => any;
|
|
14
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
15
|
+
"onUpdate:setting"?: ((key: string, value: unknown) => any) | undefined;
|
|
16
|
+
"onUpdate:block-setting"?: ((blockId: string, key: string, value: unknown) => any) | undefined;
|
|
17
|
+
"onInline-edit-start"?: ((key: string) => any) | undefined;
|
|
18
|
+
"onInline-edit-end"?: (() => any) | undefined;
|
|
19
|
+
"onUndo-redo"?: ((action: "redo" | "undo") => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
settings: Record<string, unknown>;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
settings: Record<string, unknown>
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
const active = ref(false)
|
|
9
|
+
|
|
10
|
+
function toggle() {
|
|
11
|
+
active.value = !active.value
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div class="faq-item" :class="{ active }" @click="toggle">
|
|
17
|
+
<p class="faq-item-title">{{ settings.question }}</p>
|
|
18
|
+
<p class="faq-item-answer">{{ settings.answer }}</p>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<style scoped>
|
|
23
|
+
.faq-item{background:#fff;border-radius:10px;cursor:pointer;padding:32px 26px 32px 18px;position:relative;transition:all .3s ease}.faq-item:hover{transform:translateY(-2px)}.faq-item-title{cursor:pointer;font-size:18px;font-weight:700;line-height:26px;margin-bottom:0;margin-top:0;padding-right:74px;transition:margin-bottom .3s ease}.faq-item-title:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='%23333' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:cover;content:"";height:26px;position:absolute;right:26px;top:30px;transition:transform .3s ease;width:26px}.faq-item.active .faq-item-title{margin-bottom:18px}.faq-item.active .faq-item-title:before{transform:rotate(180deg)}.faq-item-answer{color:#666;font-size:18px;line-height:27px;margin:0;max-height:0;opacity:0;overflow:hidden;padding:0 74px 0 22px;transition:max-height .4s ease,opacity .3s ease,padding .3s ease}.faq-item.active .faq-item-answer{max-height:500px;opacity:1;padding-bottom:0;padding-top:0}@media (max-width:768px){.faq-item{padding:20px 16px}.faq-item-title{font-size:14px;line-height:16px;padding-right:40px}.faq-item-title:before{height:16px;right:16px;top:20px;width:16px}.faq-item-answer{font-size:14px;line-height:16px;padding-left:0;padding-right:0}.faq-item.active .faq-item-title{margin-bottom:10px}}
|
|
24
|
+
</style>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
settings: Record<string, unknown>;
|
|
3
|
+
};
|
|
4
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
|
+
export default _default;
|