rimelight-components 2.0.98 → 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.
Files changed (53) hide show
  1. package/README.md +44 -45
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +8 -7
  4. package/dist/runtime/app.config.d.ts +4 -2
  5. package/dist/runtime/components/app/ScrollToTop.vue +1 -3
  6. package/dist/runtime/components/blocks/Block.vue +1 -3
  7. package/dist/runtime/components/blocks/TextRenderer.vue +3 -5
  8. package/dist/runtime/components/blocks/editor/ImageBlockEditor.vue +2 -6
  9. package/dist/runtime/components/blocks/editor/ParagraphBlockEditor.vue +6 -7
  10. package/dist/runtime/components/blocks/editor/SectionBlockEditor.d.vue.ts +1 -1
  11. package/dist/runtime/components/blocks/editor/SectionBlockEditor.vue +21 -24
  12. package/dist/runtime/components/blocks/editor/SectionBlockEditor.vue.d.ts +1 -1
  13. package/dist/runtime/components/blocks/renderer/SectionBlockRenderer.vue +1 -6
  14. package/dist/runtime/components/blocks/renderer/TestBlockRenderer.vue +1 -1
  15. package/dist/runtime/components/content/Callout.vue +1 -4
  16. package/dist/runtime/components/content/Section.vue +8 -10
  17. package/dist/runtime/components/page/PageEditor.d.vue.ts +2 -2
  18. package/dist/runtime/components/page/PageEditor.vue +64 -26
  19. package/dist/runtime/components/page/PageEditor.vue.d.ts +2 -2
  20. package/dist/runtime/components/page/PageMention.d.vue.ts +6 -0
  21. package/dist/runtime/components/page/PageMention.vue +42 -0
  22. package/dist/runtime/components/page/PageMention.vue.d.ts +6 -0
  23. package/dist/runtime/components/page/PagePropertiesEditor.d.vue.ts +1 -1
  24. package/dist/runtime/components/page/PagePropertiesEditor.vue +23 -37
  25. package/dist/runtime/components/page/PagePropertiesEditor.vue.d.ts +1 -1
  26. package/dist/runtime/components/page/PagePropertiesRenderer.d.vue.ts +12 -2
  27. package/dist/runtime/components/page/PagePropertiesRenderer.vue +215 -78
  28. package/dist/runtime/components/page/PagePropertiesRenderer.vue.d.ts +12 -2
  29. package/dist/runtime/components/page/PageRenderer.d.vue.ts +25 -0
  30. package/dist/runtime/components/page/PageRenderer.vue +123 -0
  31. package/dist/runtime/components/page/PageRenderer.vue.d.ts +25 -0
  32. package/dist/runtime/components/page/PageSurround.vue +9 -9
  33. package/dist/runtime/components/{blocks/TOC.d.vue.ts → page/PageTOC.d.vue.ts} +5 -8
  34. package/dist/runtime/components/page/PageTOC.vue +107 -0
  35. package/dist/runtime/components/{blocks/TOC.vue.d.ts → page/PageTOC.vue.d.ts} +5 -8
  36. package/dist/runtime/components/swatches/ColorSwatch.vue +1 -4
  37. package/dist/runtime/composables/index.d.ts +1 -0
  38. package/dist/runtime/composables/index.js +1 -0
  39. package/dist/runtime/composables/useBlockEditor.d.ts +173 -517
  40. package/dist/runtime/composables/usePageEditor.js +7 -3
  41. package/dist/runtime/composables/usePageRegistry.d.ts +33 -0
  42. package/dist/runtime/composables/usePageRegistry.js +16 -0
  43. package/dist/runtime/types/blocks.d.ts +1 -3
  44. package/dist/runtime/types/pages.d.ts +18 -9
  45. package/dist/runtime/types/schemas.d.ts +6 -0
  46. package/dist/runtime/types/schemas.js +3 -1
  47. package/dist/runtime/utils/page.d.ts +17 -3
  48. package/dist/runtime/utils/richTextHelpers.js +9 -1
  49. package/package.json +17 -17
  50. package/dist/runtime/components/blocks/TOC.vue +0 -95
  51. package/dist/runtime/components/nodes/MentionNode.d.vue.ts +0 -8
  52. package/dist/runtime/components/nodes/MentionNode.vue +0 -22
  53. package/dist/runtime/components/nodes/MentionNode.vue.d.ts +0 -8
@@ -1,13 +1,11 @@
1
1
  <script setup>
2
- import { computed } from "vue";
3
2
  import { useI18n } from "vue-i18n";
3
+ import { usePageRegistry } from "../../composables";
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().locale;
7
- const properties = computed(() => page.value.properties);
8
- const groups = computed(() => {
9
- return page.value.properties;
10
- });
8
+ const { locale, t } = useI18n();
11
9
  const isFieldVisible = (fieldSchema) => {
12
10
  if (!fieldSchema.visibleIf) return true;
13
11
  return fieldSchema.visibleIf(page.value.properties);
@@ -18,17 +16,18 @@ const getSortedFields = (fields) => {
18
16
  </script>
19
17
 
20
18
  <template>
21
- <div class="flex flex-col gap-y-8 pr-2 pb-12">
22
- <div class="flex items-center justify-between border-b border-border pb-4">
23
- <h3 class="text-xs font-black uppercase tracking-widest text-muted-foreground">
24
- {{ page.type }} Metadata
19
+ <UCard
20
+ variant="soft"
21
+ :ui="{ root: 'divide-none', header: 'bg-elevated text-center', body: 'bg-muted' }"
22
+ >
23
+ <template #header>
24
+ <h3>
25
+ {{ getLocalizedContent(page.title, locale) }}
25
26
  </h3>
26
- <UBadge variant="subtle" size="sm" color="primary">
27
- {{ page.slug }}
28
- </UBadge>
29
- </div>
27
+ <UBadge variant="subtle" size="sm" color="primary" :label="t(getTypeLabelKey(page.type))" />
28
+ </template>
30
29
 
31
- <div v-for="(group, groupId) in groups" :key="groupId" class="space-y-4">
30
+ <div v-for="(group, groupId) in page.properties" :key="groupId">
32
31
  <div class="flex items-center gap-3">
33
32
  <span class="text-[10px] font-bold uppercase tracking-widest text-primary">
34
33
  {{ group.label[locale] }}
@@ -38,36 +37,36 @@ const getSortedFields = (fields) => {
38
37
 
39
38
  <div class="grid gap-y-4 px-1">
40
39
  <template v-for="[fieldKey, schema] in getSortedFields(group.fields)" :key="fieldKey">
41
-
42
40
  <UFormField
43
41
  v-if="isFieldVisible(schema)"
44
- :label="schema.label"
42
+ :label="getLocalizedContent(schema.label, locale)"
45
43
  :name="fieldKey"
46
44
  >
47
45
  <UInput
48
46
  v-if="schema.type === 'text'"
49
- v-model="properties[groupId].fields[fieldKey].value[locale]"
47
+ v-model="schema.value[locale]"
50
48
  variant="subtle"
51
49
  placeholder="..."
52
50
  />
53
51
 
54
52
  <UInput
55
53
  v-else-if="schema.type === 'number'"
56
- v-model.number="properties[groupId].fields[fieldKey].value"
54
+ v-model.number="schema.value"
57
55
  type="number"
58
56
  variant="subtle"
59
57
  />
60
58
 
61
59
  <USelect
62
60
  v-else-if="schema.type === 'enum'"
63
- v-model="properties[groupId].fields[fieldKey].value"
61
+ v-model="schema.value"
64
62
  :items="schema.options || []"
65
63
  variant="subtle"
66
64
  />
67
65
 
68
66
  <UInputMenu
69
67
  v-else-if="schema.type === 'text-array'"
70
- v-model="properties[groupId].fields[fieldKey].value[locale]"
68
+ :model-value="schema.value.map((v) => v[locale])"
69
+ @update:model-value="(vals) => schema.value = vals.map((str) => ({ [locale]: str }))"
71
70
  multiple
72
71
  creatable
73
72
  variant="subtle"
@@ -76,7 +75,7 @@ const getSortedFields = (fields) => {
76
75
 
77
76
  <UInput
78
77
  v-else-if="schema.type === 'page'"
79
- v-model="properties[groupId].fields[fieldKey].value"
78
+ v-model="schema.value"
80
79
  icon="lucide:link-2"
81
80
  variant="subtle"
82
81
  :placeholder="`Select ${schema.allowedPageTypes?.join('/')}`"
@@ -86,7 +85,7 @@ const getSortedFields = (fields) => {
86
85
  </div>
87
86
  </div>
88
87
 
89
- <USeparator />
88
+ <USeparator class="my-6" />
90
89
 
91
90
  <UFormField label="Global Search Tags">
92
91
  <UInputMenu
@@ -98,18 +97,5 @@ const getSortedFields = (fields) => {
98
97
  placeholder="Add tags..."
99
98
  />
100
99
  </UFormField>
101
-
102
- <div class="mt-auto pt-6 text-[9px] font-mono text-muted-foreground/60 space-y-1">
103
- <div class="flex justify-between">
104
- <span>ID:</span>
105
- <span>{{ page.id }}</span>
106
- </div>
107
- <ClientOnly>
108
- <div class="flex justify-between">
109
- <span>Last Updated:</span>
110
- <span>{{ page.updated_at }}</span>
111
- </div>
112
- </ClientOnly>
113
- </div>
114
- </div>
100
+ </UCard>
115
101
  </template>
@@ -1,4 +1,4 @@
1
- import { type Page } from '../../types/index.js';
1
+ import { type Page } from "../../types/index.js";
2
2
  type __VLS_ModelProps = {
3
3
  modelValue: Page;
4
4
  };
@@ -1,7 +1,17 @@
1
1
  import { type Page } from '../../types/index.js';
2
- type __VLS_Props = {
2
+ type __VLS_ModelProps = {
3
3
  modelValue: Page;
4
4
  };
5
- declare const __VLS_export: 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
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:modelValue": (value: {
7
+ type: "Default";
8
+ properties: import("../../types/index.js").BasePageProperties;
9
+ } & import("../../types/index.js").BasePage) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
11
+ "onUpdate:modelValue"?: ((value: {
12
+ type: "Default";
13
+ properties: import("../../types/index.js").BasePageProperties;
14
+ } & import("../../types/index.js").BasePage) => any) | undefined;
15
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
16
  declare const _default: typeof __VLS_export;
7
17
  export default _default;
@@ -1,99 +1,236 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
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";
6
- const props = defineProps({
7
- modelValue: { type: null, required: true }
8
- });
9
- const locale = useI18n().locale;
10
- const properties = computed(() => props.modelValue.properties);
11
- const displayGroups = computed(() => {
12
- return Object.entries(properties.value || {}).map(([groupId, group]) => {
13
- const visibleFields = Object.entries(group.fields || {}).filter(([fieldKey, schema]) => {
14
- const value = schema.type === "text" || schema.type === "text-array" ? schema.value?.[locale.value] : schema.value;
15
- const isVisible = !schema.visibleIf || schema.visibleIf(props.modelValue.properties);
16
- if (!isVisible) return false;
17
- if (Array.isArray(value)) return value.length > 0;
18
- return value !== void 0 && value !== null && value !== "";
19
- }).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
8
+ import { useShare, useClipboard } from "@vueuse/core";
9
+ import {} from "../../types";
10
+ const { getTypeLabelKey } = usePageRegistry();
11
+ const page = defineModel({ type: null, ...{ required: true } });
12
+ const { t, locale } = useI18n();
13
+ const { share } = useShare();
14
+ const { copy } = useClipboard();
15
+ const toast = useToast();
16
+ const shouldRenderField = (schema) => {
17
+ const isVisible = !schema.visibleIf || schema.visibleIf(page.value.properties);
18
+ if (!isVisible) return false;
19
+ const val = schema.value;
20
+ if (schema.type === "text") {
21
+ return !!val?.[locale.value];
22
+ }
23
+ if (schema.type === "text-array") {
24
+ return Array.isArray(val) && val.length > 0;
25
+ }
26
+ return val !== void 0 && val !== null && val !== "";
27
+ };
28
+ const shouldRenderGroup = (group) => {
29
+ return Object.values(group.fields || {}).some((schema) => shouldRenderField(schema));
30
+ };
31
+ const getSortedFields = (fields) => {
32
+ return Object.entries(fields).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
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);
20
72
  return {
21
- ...group,
22
- groupId,
23
- visibleFields
73
+ label: localizedName || `${t("label_image")} ${index + 1}`,
74
+ value: `image-${index}`,
75
+ img
24
76
  };
25
- }).filter((group) => group.visibleFields.length > 0);
77
+ });
26
78
  });
27
79
  </script>
28
80
 
29
81
  <template>
30
- <div class="wiki-renderer flex flex-col border border-border rounded-lg bg-muted/20 overflow-hidden shadow-sm">
31
- <div class="bg-muted/50 p-4 border-b border-border text-center">
32
- <div class="text-[10px] font-bold uppercase tracking-widest text-muted-foreground/70 mb-1">
33
- {{ props.modelValue.type }}
34
- </div>
35
- <h2 class="text-xl font-serif font-bold italic text-foreground">
36
- {{ properties.name?.value?.[locale] || props.modelValue.slug }}
37
- </h2>
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()" />
38
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
+ >
91
+ <template #header>
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
+
100
+ <h3>
101
+ {{ getLocalizedContent(page.title, locale) }}
102
+ </h3>
39
103
 
40
- <div v-for="group in displayGroups" :key="group.groupId" class="border-b last:border-b-0 border-border/40">
41
- <div class="bg-muted/30 px-3 py-1.5 text-[10px] font-black text-primary uppercase tracking-tighter border-b border-border/10">
42
- {{ group.label[locale] }}
43
- </div>
104
+ <span class="text-sm">{{ t(getTypeLabelKey(page.type)) }}</span>
44
105
 
45
- <dl class="p-3 space-y-2.5">
46
- <div
47
- v-for="[fieldKey, schema] in group.visibleFields"
48
- :key="fieldKey"
49
- class="grid grid-cols-3 gap-x-3 items-baseline"
50
- >
51
- <dt class="text-[11px] font-semibold text-muted-foreground leading-tight">
52
- {{ schema.label }}
53
- </dt>
106
+ <div v-if="page.tags?.length" class="flex flex-row flex-wrap gap-xs">
107
+ <UBadge
108
+ v-for="tag in page.tags"
109
+ :key="tag[locale]"
110
+ variant="soft"
111
+ size="xs"
112
+ color="neutral"
113
+ >
114
+ {{ tag[locale] }}
115
+ </UBadge>
116
+ </div>
54
117
 
55
- <dd class="text-xs col-span-2 text-foreground leading-snug">
56
- <div v-if="schema.type === 'text-array'" class="flex flex-wrap gap-1">
57
- <template v-for="(item, index) in properties[group.groupId].fields[fieldKey].value[locale]" :key="index">
58
- <span class="font-medium">{{ item }}</span>
59
- <span v-if="index < properties[group.groupId].fields[fieldKey].value[locale].length - 1" class="text-muted-foreground/50">, </span>
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" />
60
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
+ />
61
139
  </div>
140
+ </div>
141
+ </div>
142
+ </template>
62
143
 
63
- <span v-else-if="schema.type === 'page'" class="text-primary font-bold hover:underline cursor-pointer">
64
- {{ properties[group.groupId].fields[fieldKey].value }}
65
- </span>
144
+ <template #default>
145
+ <template v-for="(group, groupId) in page.properties" :key="groupId">
146
+ <UCollapsible v-if="shouldRenderGroup(group)" :default-open="group.defaultOpen">
147
+ <template #default>
148
+ <UButton
149
+ :label="getLocalizedContent(group.label, locale)"
150
+ variant="soft"
151
+ trailing-icon="lucide:chevron-down"
152
+ :ui="{
153
+ trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
154
+ }"
155
+ block
156
+ class="group rounded-none bg-elevated text-default"
157
+ />
158
+ </template>
66
159
 
67
- <span v-else-if="schema.type === 'text'" class="font-medium">
68
- {{ properties[group.groupId].fields[fieldKey].value[locale] }}
69
- </span>
160
+ <template #content>
161
+ <dl class="p-sm flex flex-col gap-xs">
162
+ <template
163
+ v-for="[fieldKey, schema] in getSortedFields(group.fields)"
164
+ :key="fieldKey"
165
+ >
166
+ <div
167
+ v-if="shouldRenderField(schema)"
168
+ class="grid grid-cols-3 gap-xs items-baseline"
169
+ >
170
+ <dt class="text-xs font-semibold text-dimmed">
171
+ {{ getLocalizedContent(schema.label, locale) }}
172
+ </dt>
70
173
 
71
- <span v-else class="font-medium">
72
- {{ properties[group.groupId].fields[fieldKey].value }}
73
- </span>
74
- </dd>
75
- </div>
76
- </dl>
77
- </div>
174
+ <dd class="text-xs col-span-2">
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
+ >
182
+ <li v-for="(item, index) in schema.value" :key="index">
183
+ <span class="font-medium">
184
+ {{ getLocalizedContent(item, locale) }}
185
+ </span>
186
+ </li>
187
+ </ul>
188
+ <RCPageMention
189
+ v-else-if="schema.type === 'page' && schema.value"
190
+ :page-id="schema.value"
191
+ />
78
192
 
79
- <div v-if="props.modelValue.tags?.length" class="p-3 bg-background/50 border-t border-border">
80
- <div class="flex flex-wrap gap-1.5">
81
- <UBadge
82
- v-for="tag in props.modelValue.tags"
83
- :key="String(tag[locale])"
84
- variant="subtle"
85
- size="sm"
86
- color="neutral"
87
- class="text-[9px] font-bold uppercase tracking-tight"
88
- >
89
- #{{ tag[locale] }}
90
- </UBadge>
91
- </div>
92
- </div>
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
+ />
93
202
 
94
- </div>
95
- </template>
203
+ <RCPageMention :page-id="id" />
204
+ </li>
205
+ </ul>
96
206
 
97
- <style scoped>
98
- .font-serif{font-family:Georgia,Times New Roman,Times,serif}
99
- </style>
207
+ <span v-else>
208
+ {{ schema.value }}
209
+ </span>
210
+ </dd>
211
+ </div>
212
+ </template>
213
+ </dl>
214
+ </template>
215
+ </UCollapsible>
216
+ </template>
217
+ </template>
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>
235
+ </aside>
236
+ </template>
@@ -1,7 +1,17 @@
1
1
  import { type Page } from '../../types/index.js';
2
- type __VLS_Props = {
2
+ type __VLS_ModelProps = {
3
3
  modelValue: Page;
4
4
  };
5
- declare const __VLS_export: 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
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ "update:modelValue": (value: {
7
+ type: "Default";
8
+ properties: import("../../types/index.js").BasePageProperties;
9
+ } & import("../../types/index.js").BasePage) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
11
+ "onUpdate:modelValue"?: ((value: {
12
+ type: "Default";
13
+ properties: import("../../types/index.js").BasePageProperties;
14
+ } & import("../../types/index.js").BasePage) => any) | undefined;
15
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
16
  declare const _default: typeof __VLS_export;
7
17
  export default _default;
@@ -0,0 +1,25 @@
1
+ import { type Page, type PageSurround } from "../../types/index.js";
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'>>;
7
+ }
8
+ type __VLS_Props = PageRendererProps;
9
+ type __VLS_ModelProps = {
10
+ modelValue: Page;
11
+ };
12
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ "update:modelValue": (value: {
15
+ type: "Default";
16
+ properties: import("../../types/index.js").BasePageProperties;
17
+ } & import("../../types/index.js").BasePage) => any;
18
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
19
+ "onUpdate:modelValue"?: ((value: {
20
+ type: "Default";
21
+ properties: import("../../types/index.js").BasePageProperties;
22
+ } & import("../../types/index.js").BasePage) => any) | undefined;
23
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;
@@ -0,0 +1,123 @@
1
+ <script setup>
2
+ import { computed, provide } from "vue";
3
+ import {} from "../../types";
4
+ import { getLocalizedContent } from "../../utils";
5
+ import { useI18n } from "vue-i18n";
6
+ import { usePageRegistry } from "../../composables";
7
+ const { getTypeLabelKey } = usePageRegistry();
8
+ const page = defineModel({ type: null, ...{ required: true } });
9
+ const { t, locale } = useI18n();
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
+ });
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));
21
+ </script>
22
+
23
+ <template>
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"
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>
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>
120
+ </div>
121
+ </div>
122
+ </UContainer>
123
+ </template>