rimelight-components 2.0.99 → 2.1.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/README.md +44 -45
- package/dist/module.json +1 -1
- package/dist/module.mjs +8 -7
- package/dist/runtime/app.config.d.ts +4 -2
- package/dist/runtime/components/app/ScrollToTop.vue +1 -3
- package/dist/runtime/components/blocks/Block.vue +1 -3
- package/dist/runtime/components/blocks/TextRenderer.vue +3 -5
- package/dist/runtime/components/blocks/editor/ImageBlockEditor.vue +2 -6
- package/dist/runtime/components/blocks/editor/ParagraphBlockEditor.vue +6 -7
- package/dist/runtime/components/blocks/editor/SectionBlockEditor.d.vue.ts +1 -1
- package/dist/runtime/components/blocks/editor/SectionBlockEditor.vue +21 -24
- package/dist/runtime/components/blocks/editor/SectionBlockEditor.vue.d.ts +1 -1
- package/dist/runtime/components/blocks/renderer/SectionBlockRenderer.vue +1 -6
- package/dist/runtime/components/blocks/renderer/TestBlockRenderer.vue +1 -1
- package/dist/runtime/components/content/Callout.vue +1 -4
- package/dist/runtime/components/content/Section.vue +8 -10
- package/dist/runtime/components/page/PageEditor.vue +18 -6
- package/dist/runtime/components/page/PageMention.d.vue.ts +6 -0
- package/dist/runtime/components/page/PageMention.vue +42 -0
- package/dist/runtime/components/page/PageMention.vue.d.ts +6 -0
- package/dist/runtime/components/page/PagePropertiesEditor.d.vue.ts +1 -1
- package/dist/runtime/components/page/PagePropertiesEditor.vue +42 -41
- package/dist/runtime/components/page/PagePropertiesEditor.vue.d.ts +1 -1
- package/dist/runtime/components/page/PagePropertiesRenderer.vue +157 -23
- package/dist/runtime/components/page/PageRenderer.d.vue.ts +9 -5
- package/dist/runtime/components/page/PageRenderer.vue +109 -43
- package/dist/runtime/components/page/PageRenderer.vue.d.ts +9 -5
- package/dist/runtime/components/page/PageSurround.vue +9 -9
- package/dist/runtime/components/{blocks/TOC.d.vue.ts → page/PageTOC.d.vue.ts} +5 -8
- package/dist/runtime/components/page/PageTOC.vue +107 -0
- package/dist/runtime/components/{blocks/TOC.vue.d.ts → page/PageTOC.vue.d.ts} +5 -8
- package/dist/runtime/components/swatches/ColorSwatch.vue +1 -4
- package/dist/runtime/composables/index.d.ts +1 -0
- package/dist/runtime/composables/index.js +1 -0
- package/dist/runtime/composables/useBlockEditor.d.ts +173 -517
- package/dist/runtime/composables/usePageEditor.js +7 -3
- package/dist/runtime/composables/usePageRegistry.d.ts +33 -0
- package/dist/runtime/composables/usePageRegistry.js +16 -0
- package/dist/runtime/types/blocks.d.ts +1 -3
- package/dist/runtime/types/pages.d.ts +16 -8
- package/dist/runtime/types/schemas.d.ts +6 -0
- package/dist/runtime/types/schemas.js +3 -1
- package/dist/runtime/utils/page.d.ts +4 -4
- package/dist/runtime/utils/richTextHelpers.js +9 -1
- package/package.json +17 -17
- package/dist/runtime/components/blocks/TOC.vue +0 -95
- package/dist/runtime/components/nodes/MentionNode.d.vue.ts +0 -8
- package/dist/runtime/components/nodes/MentionNode.vue +0 -22
- package/dist/runtime/components/nodes/MentionNode.vue.d.ts +0 -8
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useI18n } from "vue-i18n";
|
|
3
|
+
import { usePageRegistry } from "../../composables";
|
|
3
4
|
import { getLocalizedContent } from "../../utils";
|
|
4
5
|
import {} from "../../types";
|
|
6
|
+
const { getTypeLabelKey } = usePageRegistry();
|
|
5
7
|
const page = defineModel({ type: null, ...{ required: true } });
|
|
6
|
-
const locale = useI18n()
|
|
8
|
+
const { locale, t } = useI18n();
|
|
7
9
|
const isFieldVisible = (fieldSchema) => {
|
|
8
10
|
if (!fieldSchema.visibleIf) return true;
|
|
9
11
|
return fieldSchema.visibleIf(page.value.properties);
|
|
@@ -14,18 +16,18 @@ const getSortedFields = (fields) => {
|
|
|
14
16
|
</script>
|
|
15
17
|
|
|
16
18
|
<template>
|
|
17
|
-
<UCard
|
|
19
|
+
<UCard
|
|
20
|
+
variant="soft"
|
|
21
|
+
:ui="{ root: 'divide-none', header: 'bg-elevated text-center', body: 'bg-muted' }"
|
|
22
|
+
>
|
|
18
23
|
<template #header>
|
|
19
24
|
<h3>
|
|
20
25
|
{{ getLocalizedContent(page.title, locale) }}
|
|
21
26
|
</h3>
|
|
22
|
-
<UBadge variant="subtle" size="sm" color="primary" :label="page.type"/>
|
|
27
|
+
<UBadge variant="subtle" size="sm" color="primary" :label="t(getTypeLabelKey(page.type))" />
|
|
23
28
|
</template>
|
|
24
29
|
|
|
25
|
-
<div
|
|
26
|
-
v-for="(group, groupId) in page.properties"
|
|
27
|
-
:key="groupId"
|
|
28
|
-
>
|
|
30
|
+
<div v-for="(group, groupId) in page.properties" :key="groupId">
|
|
29
31
|
<div class="flex items-center gap-3">
|
|
30
32
|
<span class="text-[10px] font-bold uppercase tracking-widest text-primary">
|
|
31
33
|
{{ group.label[locale] }}
|
|
@@ -35,49 +37,48 @@ const getSortedFields = (fields) => {
|
|
|
35
37
|
|
|
36
38
|
<div class="grid gap-y-4 px-1">
|
|
37
39
|
<template v-for="[fieldKey, schema] in getSortedFields(group.fields)" :key="fieldKey">
|
|
38
|
-
|
|
39
40
|
<UFormField
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
v-if="isFieldVisible(schema)"
|
|
42
|
+
:label="getLocalizedContent(schema.label, locale)"
|
|
43
|
+
:name="fieldKey"
|
|
43
44
|
>
|
|
44
45
|
<UInput
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
v-if="schema.type === 'text'"
|
|
47
|
+
v-model="schema.value[locale]"
|
|
48
|
+
variant="subtle"
|
|
49
|
+
placeholder="..."
|
|
49
50
|
/>
|
|
50
51
|
|
|
51
52
|
<UInput
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
v-else-if="schema.type === 'number'"
|
|
54
|
+
v-model.number="schema.value"
|
|
55
|
+
type="number"
|
|
56
|
+
variant="subtle"
|
|
56
57
|
/>
|
|
57
58
|
|
|
58
59
|
<USelect
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
v-else-if="schema.type === 'enum'"
|
|
61
|
+
v-model="schema.value"
|
|
62
|
+
:items="schema.options || []"
|
|
63
|
+
variant="subtle"
|
|
63
64
|
/>
|
|
64
65
|
|
|
65
66
|
<UInputMenu
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
v-else-if="schema.type === 'text-array'"
|
|
68
|
+
:model-value="schema.value.map((v) => v[locale])"
|
|
69
|
+
@update:model-value="(vals) => schema.value = vals.map((str) => ({ [locale]: str }))"
|
|
70
|
+
multiple
|
|
71
|
+
creatable
|
|
72
|
+
variant="subtle"
|
|
73
|
+
placeholder="Add item..."
|
|
73
74
|
/>
|
|
74
75
|
|
|
75
76
|
<UInput
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
v-else-if="schema.type === 'page'"
|
|
78
|
+
v-model="schema.value"
|
|
79
|
+
icon="lucide:link-2"
|
|
80
|
+
variant="subtle"
|
|
81
|
+
:placeholder="`Select ${schema.allowedPageTypes?.join('/')}`"
|
|
81
82
|
/>
|
|
82
83
|
</UFormField>
|
|
83
84
|
</template>
|
|
@@ -88,12 +89,12 @@ const getSortedFields = (fields) => {
|
|
|
88
89
|
|
|
89
90
|
<UFormField label="Global Search Tags">
|
|
90
91
|
<UInputMenu
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
v-model="page.tags"
|
|
93
|
+
multiple
|
|
94
|
+
creatable
|
|
95
|
+
icon="lucide:tag"
|
|
96
|
+
variant="subtle"
|
|
97
|
+
placeholder="Add tags..."
|
|
97
98
|
/>
|
|
98
99
|
</UFormField>
|
|
99
100
|
</UCard>
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
2
3
|
import { getLocalizedContent } from "../../utils";
|
|
4
|
+
import { usePageRegistry } from "../../composables";
|
|
5
|
+
import { useToast } from "@nuxt/ui/composables";
|
|
6
|
+
import {} from "@nuxt/ui/components/Tabs.vue";
|
|
3
7
|
import { useI18n } from "vue-i18n";
|
|
4
|
-
import {
|
|
5
|
-
} from "../../types";
|
|
8
|
+
import { useShare, useClipboard } from "@vueuse/core";
|
|
9
|
+
import {} from "../../types";
|
|
10
|
+
const { getTypeLabelKey } = usePageRegistry();
|
|
6
11
|
const page = defineModel({ type: null, ...{ required: true } });
|
|
7
12
|
const { t, locale } = useI18n();
|
|
13
|
+
const { share } = useShare();
|
|
14
|
+
const { copy } = useClipboard();
|
|
15
|
+
const toast = useToast();
|
|
8
16
|
const shouldRenderField = (schema) => {
|
|
9
17
|
const isVisible = !schema.visibleIf || schema.visibleIf(page.value.properties);
|
|
10
18
|
if (!isVisible) return false;
|
|
@@ -23,28 +31,113 @@ const shouldRenderGroup = (group) => {
|
|
|
23
31
|
const getSortedFields = (fields) => {
|
|
24
32
|
return Object.entries(fields).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
|
|
25
33
|
};
|
|
34
|
+
const sharePage = async () => {
|
|
35
|
+
if (!page.value) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
await share({
|
|
40
|
+
title: getLocalizedContent(page.value.title, locale),
|
|
41
|
+
text: getLocalizedContent(page.value.description, locale),
|
|
42
|
+
url: typeof location !== "undefined" ? location.href : ""
|
|
43
|
+
});
|
|
44
|
+
} catch {
|
|
45
|
+
toast.add({
|
|
46
|
+
color: "error",
|
|
47
|
+
title: "toast_share-page_error_title",
|
|
48
|
+
description: "toast_share-page_error_description"
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const copyLink = async () => {
|
|
53
|
+
try {
|
|
54
|
+
await copy(typeof location !== "undefined" ? location.href : "");
|
|
55
|
+
toast.add({
|
|
56
|
+
color: "success",
|
|
57
|
+
title: "toast_copy-page-link_success_title",
|
|
58
|
+
description: typeof location !== "undefined" ? location.href : ""
|
|
59
|
+
});
|
|
60
|
+
} catch {
|
|
61
|
+
toast.add({
|
|
62
|
+
color: "error",
|
|
63
|
+
title: "toast_copy-page-link_error_title",
|
|
64
|
+
description: "toast_copy-page-link_error_description"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const imageTabs = computed(() => {
|
|
69
|
+
if (!page.value.images?.length) return [];
|
|
70
|
+
return page.value.images.map((img, index) => {
|
|
71
|
+
const localizedName = getLocalizedContent(img.name, locale.value);
|
|
72
|
+
return {
|
|
73
|
+
label: localizedName || `${t("label_image")} ${index + 1}`,
|
|
74
|
+
value: `image-${index}`,
|
|
75
|
+
img
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
});
|
|
26
79
|
</script>
|
|
27
80
|
|
|
28
81
|
<template>
|
|
29
|
-
<aside class="flex flex-col gap-
|
|
30
|
-
<
|
|
82
|
+
<aside class="flex flex-col gap-md">
|
|
83
|
+
<div class="flex flex-row flex-wrap gap-sm">
|
|
84
|
+
<UButton variant="soft" color="neutral" icon="lucide:share" size="sm" @click="sharePage()" />
|
|
85
|
+
<UButton variant="soft" color="neutral" icon="lucide:link" size="sm" @click="copyLink()" />
|
|
86
|
+
</div>
|
|
87
|
+
<UCard
|
|
88
|
+
variant="soft"
|
|
89
|
+
:ui="{ root: 'divide-none', header: 'bg-accented text-center', body: 'p-0 sm:p-0 bg-muted' }"
|
|
90
|
+
>
|
|
31
91
|
<template #header>
|
|
32
92
|
<div class="flex flex-col gap-xs items-center">
|
|
93
|
+
<NuxtImg
|
|
94
|
+
v-if="page.icon?.src"
|
|
95
|
+
:src="page.icon?.src"
|
|
96
|
+
:alt="page.icon?.alt"
|
|
97
|
+
class="rounded-full w-12 h-12 object-cover"
|
|
98
|
+
/>
|
|
99
|
+
|
|
33
100
|
<h3>
|
|
34
101
|
{{ getLocalizedContent(page.title, locale) }}
|
|
35
102
|
</h3>
|
|
36
|
-
|
|
103
|
+
|
|
104
|
+
<span class="text-sm">{{ t(getTypeLabelKey(page.type)) }}</span>
|
|
105
|
+
|
|
37
106
|
<div v-if="page.tags?.length" class="flex flex-row flex-wrap gap-xs">
|
|
38
107
|
<UBadge
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
108
|
+
v-for="tag in page.tags"
|
|
109
|
+
:key="tag[locale]"
|
|
110
|
+
variant="soft"
|
|
111
|
+
size="xs"
|
|
112
|
+
color="neutral"
|
|
44
113
|
>
|
|
45
114
|
{{ tag[locale] }}
|
|
46
115
|
</UBadge>
|
|
47
116
|
</div>
|
|
117
|
+
|
|
118
|
+
<div v-if="page.images?.length" class="w-full">
|
|
119
|
+
<UTabs
|
|
120
|
+
v-if="page.images.length > 1"
|
|
121
|
+
:items="imageTabs"
|
|
122
|
+
default-value="image-0"
|
|
123
|
+
variant="link"
|
|
124
|
+
size="xs"
|
|
125
|
+
color="neutral"
|
|
126
|
+
class="w-full"
|
|
127
|
+
>
|
|
128
|
+
<template #content="{ item }">
|
|
129
|
+
<NuxtImg :src="item.img.src" :alt="item.img.alt" class="w-full object-cover" />
|
|
130
|
+
</template>
|
|
131
|
+
</UTabs>
|
|
132
|
+
|
|
133
|
+
<div v-else-if="page.images[0]">
|
|
134
|
+
<NuxtImg
|
|
135
|
+
:src="page.images[0].src"
|
|
136
|
+
:alt="page.images[0].alt"
|
|
137
|
+
class="w-full object-cover"
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
48
141
|
</div>
|
|
49
142
|
</template>
|
|
50
143
|
|
|
@@ -53,39 +146,64 @@ const getSortedFields = (fields) => {
|
|
|
53
146
|
<UCollapsible v-if="shouldRenderGroup(group)" :default-open="group.defaultOpen">
|
|
54
147
|
<template #default>
|
|
55
148
|
<UButton
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
149
|
+
:label="getLocalizedContent(group.label, locale)"
|
|
150
|
+
variant="soft"
|
|
151
|
+
trailing-icon="lucide:chevron-down"
|
|
152
|
+
:ui="{
|
|
60
153
|
trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
|
|
61
154
|
}"
|
|
62
|
-
|
|
63
|
-
|
|
155
|
+
block
|
|
156
|
+
class="group rounded-none bg-elevated text-default"
|
|
64
157
|
/>
|
|
65
158
|
</template>
|
|
66
159
|
|
|
67
160
|
<template #content>
|
|
68
161
|
<dl class="p-sm flex flex-col gap-xs">
|
|
69
|
-
<template
|
|
162
|
+
<template
|
|
163
|
+
v-for="[fieldKey, schema] in getSortedFields(group.fields)"
|
|
164
|
+
:key="fieldKey"
|
|
165
|
+
>
|
|
70
166
|
<div
|
|
71
|
-
|
|
72
|
-
|
|
167
|
+
v-if="shouldRenderField(schema)"
|
|
168
|
+
class="grid grid-cols-3 gap-xs items-baseline"
|
|
73
169
|
>
|
|
74
170
|
<dt class="text-xs font-semibold text-dimmed">
|
|
75
171
|
{{ getLocalizedContent(schema.label, locale) }}
|
|
76
172
|
</dt>
|
|
77
173
|
|
|
78
174
|
<dd class="text-xs col-span-2">
|
|
79
|
-
<
|
|
175
|
+
<span v-if="schema.type === 'text'">
|
|
176
|
+
{{ getLocalizedContent(schema.value, locale) }}
|
|
177
|
+
</span>
|
|
178
|
+
<ul
|
|
179
|
+
v-else-if="schema.type === 'text-array'"
|
|
180
|
+
class="flex flex-wrap list-disc list-inside"
|
|
181
|
+
>
|
|
80
182
|
<li v-for="(item, index) in schema.value" :key="index">
|
|
81
183
|
<span class="font-medium">
|
|
82
184
|
{{ getLocalizedContent(item, locale) }}
|
|
83
185
|
</span>
|
|
84
186
|
</li>
|
|
85
187
|
</ul>
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
188
|
+
<RCPageMention
|
|
189
|
+
v-else-if="schema.type === 'page' && schema.value"
|
|
190
|
+
:page-id="schema.value"
|
|
191
|
+
/>
|
|
192
|
+
|
|
193
|
+
<ul
|
|
194
|
+
v-else-if="schema.type === 'page-array' && Array.isArray(schema.value)"
|
|
195
|
+
class="flex flex-col gap-y-1"
|
|
196
|
+
>
|
|
197
|
+
<li v-for="id in schema.value" :key="id" class="flex items-center gap-x-2">
|
|
198
|
+
<span
|
|
199
|
+
class="w-1 h-1 rounded-full bg-inverted shrink-0"
|
|
200
|
+
aria-hidden="true"
|
|
201
|
+
/>
|
|
202
|
+
|
|
203
|
+
<RCPageMention :page-id="id" />
|
|
204
|
+
</li>
|
|
205
|
+
</ul>
|
|
206
|
+
|
|
89
207
|
<span v-else>
|
|
90
208
|
{{ schema.value }}
|
|
91
209
|
</span>
|
|
@@ -98,5 +216,21 @@ const getSortedFields = (fields) => {
|
|
|
98
216
|
</template>
|
|
99
217
|
</template>
|
|
100
218
|
</UCard>
|
|
219
|
+
<div class="flex flex-col gap-xs">
|
|
220
|
+
<h6>Links</h6>
|
|
221
|
+
<UButton
|
|
222
|
+
v-for="(link, index) in page.links"
|
|
223
|
+
:key="index"
|
|
224
|
+
:label="link.label"
|
|
225
|
+
:icon="link.icon"
|
|
226
|
+
:to="link.to"
|
|
227
|
+
:target="link.to ? '_blank' : void 0"
|
|
228
|
+
:external="!!link.to"
|
|
229
|
+
:variant="link.variant || 'link'"
|
|
230
|
+
:color="link.color || 'neutral'"
|
|
231
|
+
size="sm"
|
|
232
|
+
:ui="{ base: 'pl-0' }"
|
|
233
|
+
/>
|
|
234
|
+
</div>
|
|
101
235
|
</aside>
|
|
102
236
|
</template>
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Page, type PageSurround } from "../../types/index.js";
|
|
2
2
|
interface PageRendererProps {
|
|
3
|
+
useSurround?: boolean;
|
|
4
|
+
surround?: PageSurround | null;
|
|
5
|
+
surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
|
|
6
|
+
resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
|
|
3
7
|
}
|
|
4
8
|
type __VLS_Props = PageRendererProps;
|
|
5
9
|
type __VLS_ModelProps = {
|
|
@@ -9,13 +13,13 @@ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
|
9
13
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
14
|
"update:modelValue": (value: {
|
|
11
15
|
type: "Default";
|
|
12
|
-
properties: import("
|
|
13
|
-
} & import("
|
|
16
|
+
properties: import("../../types/index.js").BasePageProperties;
|
|
17
|
+
} & import("../../types/index.js").BasePage) => any;
|
|
14
18
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
15
19
|
"onUpdate:modelValue"?: ((value: {
|
|
16
20
|
type: "Default";
|
|
17
|
-
properties: import("
|
|
18
|
-
} & import("
|
|
21
|
+
properties: import("../../types/index.js").BasePageProperties;
|
|
22
|
+
} & import("../../types/index.js").BasePage) => any) | undefined;
|
|
19
23
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
24
|
declare const _default: typeof __VLS_export;
|
|
21
25
|
export default _default;
|
|
@@ -1,57 +1,123 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed, provide } from "vue";
|
|
3
|
+
import {} from "../../types";
|
|
2
4
|
import { getLocalizedContent } from "../../utils";
|
|
3
|
-
import { useI18n } from "
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
6
|
+
import { usePageRegistry } from "../../composables";
|
|
7
|
+
const { getTypeLabelKey } = usePageRegistry();
|
|
4
8
|
const page = defineModel({ type: null, ...{ required: true } });
|
|
5
9
|
const { t, locale } = useI18n();
|
|
6
|
-
const {} = defineProps({
|
|
10
|
+
const { useSurround = false, surroundStatus = "idle", surround = null, resolvePage } = defineProps({
|
|
11
|
+
useSurround: { type: Boolean, required: false },
|
|
12
|
+
surround: { type: [Object, null], required: false },
|
|
13
|
+
surroundStatus: { type: String, required: false },
|
|
14
|
+
resolvePage: { type: Function, required: false }
|
|
15
|
+
});
|
|
7
16
|
const emit = defineEmits([]);
|
|
17
|
+
provide("page-resolver", resolvePage);
|
|
18
|
+
const previousPage = computed(() => surround?.previous);
|
|
19
|
+
const nextPage = computed(() => surround?.next);
|
|
20
|
+
const hasSurround = computed(() => !!(surround?.previous || surround?.next));
|
|
8
21
|
</script>
|
|
9
22
|
|
|
10
23
|
<template>
|
|
11
|
-
<UContainer class="flex flex-col">
|
|
12
|
-
<div class="grid grid-cols-1 lg:grid-cols-
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
<UContainer class="flex flex-col py-16">
|
|
25
|
+
<div class="grid grid-cols-1 lg:grid-cols-24 gap-xl items-start">
|
|
26
|
+
<RCPageTOC
|
|
27
|
+
:page-blocks="page.blocks"
|
|
28
|
+
:levels="[2, 3, 4]"
|
|
29
|
+
class="hidden lg:flex lg:col-span-4 sticky top-32"
|
|
30
|
+
>
|
|
31
|
+
<template #bottom> </template>
|
|
32
|
+
</RCPageTOC>
|
|
33
|
+
<RCPagePropertiesRenderer v-model="page" class="order-1 lg:order-2 lg:col-span-6" />
|
|
34
|
+
<div class="order-2 lg:order-1 lg:col-span-14 flex flex-col gap-xl">
|
|
35
|
+
<NuxtImg
|
|
36
|
+
v-if="page.banner?.src"
|
|
37
|
+
:src="page.banner?.src"
|
|
38
|
+
:alt="page.banner?.alt"
|
|
39
|
+
class="rounded-xl w-full object-cover"
|
|
18
40
|
/>
|
|
41
|
+
<UPageHeader
|
|
42
|
+
:headline="t(getTypeLabelKey(page.type))"
|
|
43
|
+
:description="getLocalizedContent(page.description, 'en') ?? ''"
|
|
44
|
+
:ui="{ root: 'pt-0' }"
|
|
45
|
+
>
|
|
46
|
+
<template #title>
|
|
47
|
+
<div class="flex flex-row gap-sm">
|
|
48
|
+
<NuxtImg
|
|
49
|
+
v-if="page.icon?.src"
|
|
50
|
+
:src="page.icon?.src"
|
|
51
|
+
:alt="page.icon?.alt"
|
|
52
|
+
class="rounded-full w-12 h-12 object-cover"
|
|
53
|
+
/>
|
|
54
|
+
<h1>{{ getLocalizedContent(page.title, locale) }}</h1>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
</UPageHeader>
|
|
19
58
|
<RCBlockViewRenderer :blocks="page.blocks" />
|
|
59
|
+
<template v-if="useSurround">
|
|
60
|
+
<div v-if="surroundStatus === 'pending'" class="grid grid-cols-1 gap-md sm:grid-cols-2">
|
|
61
|
+
<USkeleton class="h-48 w-full rounded-xl" />
|
|
62
|
+
<USkeleton class="h-48 w-full rounded-xl" />
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<LazyRCPageSurround
|
|
66
|
+
v-else-if="surroundStatus === 'success' && hasSurround"
|
|
67
|
+
hydrate-on-visible
|
|
68
|
+
:pageType="getTypeLabelKey(page.type)"
|
|
69
|
+
:previousTitle="getLocalizedContent(previousPage?.title, locale)"
|
|
70
|
+
:previousDescription="getLocalizedContent(previousPage?.description, locale)"
|
|
71
|
+
:previousTo="`/${previousPage?.slug}`"
|
|
72
|
+
:nextTitle="getLocalizedContent(nextPage?.title, locale)"
|
|
73
|
+
:nextDescription="getLocalizedContent(nextPage?.description, locale)"
|
|
74
|
+
:nextTo="`/${nextPage?.slug}`"
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
<USeparator />
|
|
78
|
+
|
|
79
|
+
<div class="flex flex-col gap-xs text-xs text-dimmed p-xl">
|
|
80
|
+
<h6>Metadata</h6>
|
|
81
|
+
<span>Page ID: {{ page.id }}</span>
|
|
82
|
+
<span
|
|
83
|
+
>Created At:
|
|
84
|
+
<NuxtTime
|
|
85
|
+
:datetime="page.created_at ?? ''"
|
|
86
|
+
year="numeric"
|
|
87
|
+
month="numeric"
|
|
88
|
+
day="numeric"
|
|
89
|
+
hour="numeric"
|
|
90
|
+
minute="numeric"
|
|
91
|
+
second="numeric"
|
|
92
|
+
time-zone-name="short"
|
|
93
|
+
/></span>
|
|
94
|
+
<span
|
|
95
|
+
>Posted At:
|
|
96
|
+
<NuxtTime
|
|
97
|
+
:datetime="page.created_at ?? ''"
|
|
98
|
+
year="numeric"
|
|
99
|
+
month="numeric"
|
|
100
|
+
day="numeric"
|
|
101
|
+
hour="numeric"
|
|
102
|
+
minute="numeric"
|
|
103
|
+
second="numeric"
|
|
104
|
+
time-zone-name="short"
|
|
105
|
+
/></span>
|
|
106
|
+
<span
|
|
107
|
+
>Updated At:
|
|
108
|
+
<NuxtTime
|
|
109
|
+
:datetime="page.created_at ?? ''"
|
|
110
|
+
year="numeric"
|
|
111
|
+
month="numeric"
|
|
112
|
+
day="numeric"
|
|
113
|
+
hour="numeric"
|
|
114
|
+
minute="numeric"
|
|
115
|
+
second="numeric"
|
|
116
|
+
time-zone-name="short"
|
|
117
|
+
/></span>
|
|
118
|
+
</div>
|
|
119
|
+
</template>
|
|
20
120
|
</div>
|
|
21
121
|
</div>
|
|
22
|
-
<div class="flex flex-col gap-xs text-xs p-xl">
|
|
23
|
-
<h6>Metadata</h6>
|
|
24
|
-
<span>Page ID: {{ page.id }}</span>
|
|
25
|
-
<span>Created At: <NuxtTime
|
|
26
|
-
:datetime="page.created_at ?? ''"
|
|
27
|
-
year="numeric"
|
|
28
|
-
month="numeric"
|
|
29
|
-
day="numeric"
|
|
30
|
-
hour="numeric"
|
|
31
|
-
minute="numeric"
|
|
32
|
-
second="numeric"
|
|
33
|
-
time-zone-name="short"
|
|
34
|
-
/></span>
|
|
35
|
-
<span>Posted At: <NuxtTime
|
|
36
|
-
:datetime="page.created_at ?? ''"
|
|
37
|
-
year="numeric"
|
|
38
|
-
month="numeric"
|
|
39
|
-
day="numeric"
|
|
40
|
-
hour="numeric"
|
|
41
|
-
minute="numeric"
|
|
42
|
-
second="numeric"
|
|
43
|
-
time-zone-name="short"
|
|
44
|
-
/></span>
|
|
45
|
-
<span>Updated At: <NuxtTime
|
|
46
|
-
:datetime="page.created_at ?? ''"
|
|
47
|
-
year="numeric"
|
|
48
|
-
month="numeric"
|
|
49
|
-
day="numeric"
|
|
50
|
-
hour="numeric"
|
|
51
|
-
minute="numeric"
|
|
52
|
-
second="numeric"
|
|
53
|
-
time-zone-name="short"
|
|
54
|
-
/></span>
|
|
55
|
-
</div>
|
|
56
122
|
</UContainer>
|
|
57
123
|
</template>
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Page, type PageSurround } from "../../types/index.js";
|
|
2
2
|
interface PageRendererProps {
|
|
3
|
+
useSurround?: boolean;
|
|
4
|
+
surround?: PageSurround | null;
|
|
5
|
+
surroundStatus?: 'idle' | 'pending' | 'success' | 'error';
|
|
6
|
+
resolvePage?: (id: string) => Promise<Pick<Page, 'title' | 'icon' | 'slug'>>;
|
|
3
7
|
}
|
|
4
8
|
type __VLS_Props = PageRendererProps;
|
|
5
9
|
type __VLS_ModelProps = {
|
|
@@ -9,13 +13,13 @@ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
|
9
13
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
14
|
"update:modelValue": (value: {
|
|
11
15
|
type: "Default";
|
|
12
|
-
properties: import("
|
|
13
|
-
} & import("
|
|
16
|
+
properties: import("../../types/index.js").BasePageProperties;
|
|
17
|
+
} & import("../../types/index.js").BasePage) => any;
|
|
14
18
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
15
19
|
"onUpdate:modelValue"?: ((value: {
|
|
16
20
|
type: "Default";
|
|
17
|
-
properties: import("
|
|
18
|
-
} & import("
|
|
21
|
+
properties: import("../../types/index.js").BasePageProperties;
|
|
22
|
+
} & import("../../types/index.js").BasePage) => any) | undefined;
|
|
19
23
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
24
|
declare const _default: typeof __VLS_export;
|
|
21
25
|
export default _default;
|