rimelight-components 2.1.78 → 2.1.80
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/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/blocks/Block.vue +7 -7
- package/dist/runtime/components/blocks/BlockEditor.vue +5 -6
- package/dist/runtime/components/dashboard/QuickActions.vue +1 -1
- package/dist/runtime/components/page/PageEditor.d.vue.ts +13 -1
- package/dist/runtime/components/page/PageEditor.vue +72 -1
- package/dist/runtime/components/page/PageEditor.vue.d.ts +13 -1
- package/dist/runtime/components/page/index.d.ts +1 -0
- package/dist/runtime/components/page/index.js +1 -0
- package/dist/runtime/components/page/index.mjs +1 -0
- package/dist/runtime/components/page/modals/PageTreeModal.d.vue.ts +32 -0
- package/dist/runtime/components/page/modals/PageTreeModal.vue +139 -0
- package/dist/runtime/components/page/modals/PageTreeModal.vue.d.ts +32 -0
- package/dist/runtime/components/page/modals/index.d.ts +1 -0
- package/dist/runtime/components/page/modals/index.js +1 -0
- package/dist/runtime/components/page/modals/index.mjs +1 -0
- package/dist/runtime/types/pages.d.ts +11 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { readdirSync } from 'node:fs';
|
|
|
4
4
|
import { basename } from 'node:path';
|
|
5
5
|
|
|
6
6
|
const name = "rimelight-components";
|
|
7
|
-
const version = "2.1.
|
|
7
|
+
const version = "2.1.80";
|
|
8
8
|
const homepage = "https://rimelight.com/tools/rimelight-components";
|
|
9
9
|
|
|
10
10
|
const defaultOptions = {
|
|
@@ -30,37 +30,37 @@ const items = ref([
|
|
|
30
30
|
{
|
|
31
31
|
icon: "lucide:arrow-up",
|
|
32
32
|
label: "Move Block Up",
|
|
33
|
-
|
|
33
|
+
onSelect: onMoveUp
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
icon: "lucide:arrow-down",
|
|
37
37
|
label: "Move Block Down",
|
|
38
|
-
|
|
38
|
+
onSelect: onMoveDown
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
[
|
|
42
42
|
{
|
|
43
43
|
icon: "lucide:corner-right-up",
|
|
44
44
|
label: "Add Block Above"
|
|
45
|
-
//
|
|
45
|
+
//onSelect: handleAddBlockAbove
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
icon: "lucide:corner-right-down",
|
|
49
49
|
label: "Add Block Below"
|
|
50
|
-
//
|
|
50
|
+
//onSelect: handleAddBlockBelow
|
|
51
51
|
}
|
|
52
52
|
],
|
|
53
53
|
[
|
|
54
54
|
{
|
|
55
55
|
icon: "lucide:copy-plus",
|
|
56
56
|
label: "Duplicate Block",
|
|
57
|
-
|
|
57
|
+
onSelect: onDuplicate
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
|
-
color: "
|
|
60
|
+
color: "danger",
|
|
61
61
|
icon: "lucide:trash-2",
|
|
62
62
|
label: "Delete Block",
|
|
63
|
-
|
|
63
|
+
onSelect: onDelete
|
|
64
64
|
}
|
|
65
65
|
]
|
|
66
66
|
]);
|
|
@@ -36,7 +36,7 @@ const dropdownItems = computed(() => [
|
|
|
36
36
|
blockTypes.map((type) => ({
|
|
37
37
|
label: type.label,
|
|
38
38
|
icon: type.icon,
|
|
39
|
-
|
|
39
|
+
onSelect: () => insertBlock(type.value)
|
|
40
40
|
}))
|
|
41
41
|
]);
|
|
42
42
|
provide("block-editor-api", {
|
|
@@ -59,18 +59,17 @@ defineExpose({ undo, redo, canUndo, canRedo });
|
|
|
59
59
|
|
|
60
60
|
<div class="flex flex-col items-center justify-center p-4 border-t border-neutral-200 dark:border-neutral-800 border-dashed rounded-lg">
|
|
61
61
|
<span class="text-sm text-dimmed mb-2">Append new block to page</span>
|
|
62
|
-
<
|
|
62
|
+
<UDropdownMenu
|
|
63
63
|
:items="dropdownItems"
|
|
64
|
-
:popper="{ placement: 'bottom' }"
|
|
65
64
|
>
|
|
66
65
|
<UButton
|
|
67
|
-
color="
|
|
66
|
+
color="neutral"
|
|
68
67
|
label="Add Block"
|
|
69
68
|
trailing-icon="i-heroicons-chevron-down-20-solid"
|
|
70
|
-
variant="
|
|
69
|
+
variant="outline"
|
|
71
70
|
icon="i-lucide-plus"
|
|
72
71
|
/>
|
|
73
|
-
</
|
|
72
|
+
</UDropdownMenu>
|
|
74
73
|
</div>
|
|
75
74
|
</div>
|
|
76
75
|
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Page, type PageSurround, type PageDefinition } from "../../types/index.js";
|
|
1
|
+
import { type Page, type PageSurround, type PageDefinition, type PageVersion } from "../../types/index.js";
|
|
2
2
|
export interface PageEditorProps {
|
|
3
3
|
isSaving: boolean;
|
|
4
4
|
useSurround?: boolean;
|
|
@@ -8,6 +8,11 @@ export interface PageEditorProps {
|
|
|
8
8
|
pageDefinitions: Record<string, PageDefinition>;
|
|
9
9
|
onCreatePage?: (page: Partial<Page>) => Promise<void>;
|
|
10
10
|
onDeletePage?: (id: string) => Promise<void>;
|
|
11
|
+
onFetchPages?: () => Promise<Pick<Page, 'title' | 'slug'>[]>;
|
|
12
|
+
onNavigateToPage?: (slug: string) => void;
|
|
13
|
+
currentVersionId?: string | null;
|
|
14
|
+
isViewingVersion?: boolean;
|
|
15
|
+
isAdmin?: boolean;
|
|
11
16
|
rc?: {
|
|
12
17
|
header?: string;
|
|
13
18
|
headerGroup?: string;
|
|
@@ -31,12 +36,15 @@ export interface PageEditorProps {
|
|
|
31
36
|
type __VLS_Props = PageEditorProps;
|
|
32
37
|
export interface PageEditorEmits {
|
|
33
38
|
save: [value: Page];
|
|
39
|
+
'version-navigate': [version: PageVersion];
|
|
34
40
|
}
|
|
35
41
|
export interface PageEditorSlots {
|
|
42
|
+
'header-actions'?: (props: {}) => any;
|
|
36
43
|
}
|
|
37
44
|
type __VLS_Slots = PageEditorSlots;
|
|
38
45
|
type __VLS_ModelProps = {
|
|
39
46
|
modelValue: Page;
|
|
47
|
+
"currentVersionId"?: string | null;
|
|
40
48
|
};
|
|
41
49
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
42
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
@@ -53,6 +61,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
53
61
|
type: "Default";
|
|
54
62
|
properties: import("../../types/index.js").BasePageProperties;
|
|
55
63
|
} & import("../../types/index.js").BasePage) => any;
|
|
64
|
+
"version-navigate": (version: PageVersion) => any;
|
|
65
|
+
"update:currentVersionId": (value: string | null) => any;
|
|
56
66
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
57
67
|
onSave?: ((value: {
|
|
58
68
|
type: "Default";
|
|
@@ -62,6 +72,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
62
72
|
type: "Default";
|
|
63
73
|
properties: import("../../types/index.js").BasePageProperties;
|
|
64
74
|
} & import("../../types/index.js").BasePage) => any) | undefined;
|
|
75
|
+
"onVersion-navigate"?: ((version: PageVersion) => any) | undefined;
|
|
76
|
+
"onUpdate:currentVersionId"?: ((value: string | null) => any) | undefined;
|
|
65
77
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
66
78
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
67
79
|
declare const _default: typeof __VLS_export;
|
|
@@ -13,6 +13,11 @@ const {
|
|
|
13
13
|
resolvePage,
|
|
14
14
|
onCreatePage,
|
|
15
15
|
onDeletePage,
|
|
16
|
+
onFetchPages,
|
|
17
|
+
onNavigateToPage,
|
|
18
|
+
currentVersionId = null,
|
|
19
|
+
isViewingVersion = false,
|
|
20
|
+
isAdmin = false,
|
|
16
21
|
rc: rcProp
|
|
17
22
|
} = defineProps({
|
|
18
23
|
isSaving: { type: Boolean, required: true },
|
|
@@ -23,10 +28,16 @@ const {
|
|
|
23
28
|
pageDefinitions: { type: Object, required: true },
|
|
24
29
|
onCreatePage: { type: Function, required: false },
|
|
25
30
|
onDeletePage: { type: Function, required: false },
|
|
31
|
+
onFetchPages: { type: Function, required: false },
|
|
32
|
+
onNavigateToPage: { type: Function, required: false },
|
|
33
|
+
currentVersionId: { type: [String, null], required: false },
|
|
34
|
+
isViewingVersion: { type: Boolean, required: false },
|
|
35
|
+
isAdmin: { type: Boolean, required: false },
|
|
26
36
|
rc: { type: Object, required: false }
|
|
27
37
|
});
|
|
28
38
|
const page = defineModel({ type: null, ...{ required: true } });
|
|
29
|
-
const
|
|
39
|
+
const versionId = defineModel("currentVersionId", { type: [String, null], ...{ default: null } });
|
|
40
|
+
const emit = defineEmits(["save", "version-navigate"]);
|
|
30
41
|
const slots = defineSlots();
|
|
31
42
|
const { rc } = useRC("PageEditor", rcProp);
|
|
32
43
|
const pageEditorStyles = tv({
|
|
@@ -147,9 +158,46 @@ const handleDeleteConfirm = async () => {
|
|
|
147
158
|
isDeleting.value = false;
|
|
148
159
|
}
|
|
149
160
|
};
|
|
161
|
+
const isPageTreeModalOpen = ref(false);
|
|
162
|
+
const isFetchingTree = ref(false);
|
|
163
|
+
const treePages = ref([]);
|
|
164
|
+
const handleOpenTree = async () => {
|
|
165
|
+
if (!onFetchPages) return;
|
|
166
|
+
isFetchingTree.value = true;
|
|
167
|
+
try {
|
|
168
|
+
treePages.value = await onFetchPages();
|
|
169
|
+
isPageTreeModalOpen.value = true;
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.error("Failed to fetch pages for tree", e);
|
|
172
|
+
} finally {
|
|
173
|
+
isFetchingTree.value = false;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const handleTreeNavigate = (slug) => {
|
|
177
|
+
if (onNavigateToPage) {
|
|
178
|
+
onNavigateToPage(slug);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
150
181
|
</script>
|
|
151
182
|
|
|
152
183
|
<template>
|
|
184
|
+
<div
|
|
185
|
+
v-if="isViewingVersion"
|
|
186
|
+
class="fixed top-12 left-0 right-0 z-40 bg-warning-500 text-white px-4 py-2 text-sm text-center"
|
|
187
|
+
>
|
|
188
|
+
<div class="flex items-center justify-center gap-2">
|
|
189
|
+
<UIcon name="lucide:eye" />
|
|
190
|
+
<span>Viewing a previous version. Changes made here will create a new version.</span>
|
|
191
|
+
<UButton
|
|
192
|
+
icon="lucide:x"
|
|
193
|
+
color="neutral"
|
|
194
|
+
variant="ghost"
|
|
195
|
+
size="xs"
|
|
196
|
+
@click="versionId = null"
|
|
197
|
+
/>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
153
201
|
<RCHeaderLayer id="editor-header" :order="3">
|
|
154
202
|
<UHeader :class="header({ class: rc.header })">
|
|
155
203
|
<template #left>
|
|
@@ -191,6 +239,29 @@ const handleDeleteConfirm = async () => {
|
|
|
191
239
|
:loading="isSaving"
|
|
192
240
|
@click="handleSave"
|
|
193
241
|
/>
|
|
242
|
+
<UButton
|
|
243
|
+
icon="lucide:list-tree"
|
|
244
|
+
variant="outline"
|
|
245
|
+
color="neutral"
|
|
246
|
+
size="xs"
|
|
247
|
+
:loading="isFetchingTree"
|
|
248
|
+
:disabled="!onFetchPages"
|
|
249
|
+
@click="handleOpenTree"
|
|
250
|
+
/>
|
|
251
|
+
<RCPageTreeModal
|
|
252
|
+
v-model:open="isPageTreeModalOpen"
|
|
253
|
+
:pages="treePages"
|
|
254
|
+
:loading="isFetchingTree"
|
|
255
|
+
@navigate="handleTreeNavigate"
|
|
256
|
+
/>
|
|
257
|
+
<RCPageVersionSelector
|
|
258
|
+
v-if="page.id"
|
|
259
|
+
v-model:current-version-id="versionId"
|
|
260
|
+
:page-id="page.id"
|
|
261
|
+
:is-admin="isAdmin"
|
|
262
|
+
@version-selected="(v) => emit('version-navigate', v)"
|
|
263
|
+
/>
|
|
264
|
+
<slot name="header-actions" />
|
|
194
265
|
<RCCreatePageModal
|
|
195
266
|
:is-open="isCreateModalOpen"
|
|
196
267
|
:definitions="pageDefinitions"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Page, type PageSurround, type PageDefinition } from "../../types/index.js";
|
|
1
|
+
import { type Page, type PageSurround, type PageDefinition, type PageVersion } from "../../types/index.js";
|
|
2
2
|
export interface PageEditorProps {
|
|
3
3
|
isSaving: boolean;
|
|
4
4
|
useSurround?: boolean;
|
|
@@ -8,6 +8,11 @@ export interface PageEditorProps {
|
|
|
8
8
|
pageDefinitions: Record<string, PageDefinition>;
|
|
9
9
|
onCreatePage?: (page: Partial<Page>) => Promise<void>;
|
|
10
10
|
onDeletePage?: (id: string) => Promise<void>;
|
|
11
|
+
onFetchPages?: () => Promise<Pick<Page, 'title' | 'slug'>[]>;
|
|
12
|
+
onNavigateToPage?: (slug: string) => void;
|
|
13
|
+
currentVersionId?: string | null;
|
|
14
|
+
isViewingVersion?: boolean;
|
|
15
|
+
isAdmin?: boolean;
|
|
11
16
|
rc?: {
|
|
12
17
|
header?: string;
|
|
13
18
|
headerGroup?: string;
|
|
@@ -31,12 +36,15 @@ export interface PageEditorProps {
|
|
|
31
36
|
type __VLS_Props = PageEditorProps;
|
|
32
37
|
export interface PageEditorEmits {
|
|
33
38
|
save: [value: Page];
|
|
39
|
+
'version-navigate': [version: PageVersion];
|
|
34
40
|
}
|
|
35
41
|
export interface PageEditorSlots {
|
|
42
|
+
'header-actions'?: (props: {}) => any;
|
|
36
43
|
}
|
|
37
44
|
type __VLS_Slots = PageEditorSlots;
|
|
38
45
|
type __VLS_ModelProps = {
|
|
39
46
|
modelValue: Page;
|
|
47
|
+
"currentVersionId"?: string | null;
|
|
40
48
|
};
|
|
41
49
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
42
50
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
@@ -53,6 +61,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
53
61
|
type: "Default";
|
|
54
62
|
properties: import("../../types/index.js").BasePageProperties;
|
|
55
63
|
} & import("../../types/index.js").BasePage) => any;
|
|
64
|
+
"version-navigate": (version: PageVersion) => any;
|
|
65
|
+
"update:currentVersionId": (value: string | null) => any;
|
|
56
66
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
57
67
|
onSave?: ((value: {
|
|
58
68
|
type: "Default";
|
|
@@ -62,6 +72,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
62
72
|
type: "Default";
|
|
63
73
|
properties: import("../../types/index.js").BasePageProperties;
|
|
64
74
|
} & import("../../types/index.js").BasePage) => any) | undefined;
|
|
75
|
+
"onVersion-navigate"?: ((version: PageVersion) => any) | undefined;
|
|
76
|
+
"onUpdate:currentVersionId"?: ((value: string | null) => any) | undefined;
|
|
65
77
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
66
78
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
67
79
|
declare const _default: typeof __VLS_export;
|
|
@@ -5,4 +5,5 @@ export { default as PagePropertiesRenderer } from './PagePropertiesRenderer.vue.
|
|
|
5
5
|
export { default as PageRenderer } from './PageRenderer.vue.js';
|
|
6
6
|
export { default as PageSurround } from './PageSurround.vue.js';
|
|
7
7
|
export { default as PageTOC } from './PageTOC.vue.js';
|
|
8
|
+
export { default as PageVersionSelector } from './PageVersionSelector.vue.js';
|
|
8
9
|
export * from './modals/index.js';
|
|
@@ -5,4 +5,5 @@ export { default as PagePropertiesRenderer } from "./PagePropertiesRenderer.vue"
|
|
|
5
5
|
export { default as PageRenderer } from "./PageRenderer.vue";
|
|
6
6
|
export { default as PageSurround } from "./PageSurround.vue";
|
|
7
7
|
export { default as PageTOC } from "./PageTOC.vue";
|
|
8
|
+
export { default as PageVersionSelector } from "./PageVersionSelector.vue";
|
|
8
9
|
export * from "./modals/index.js";
|
|
@@ -5,4 +5,5 @@ export { default as PagePropertiesRenderer } from "./PagePropertiesRenderer.vue"
|
|
|
5
5
|
export { default as PageRenderer } from "./PageRenderer.vue";
|
|
6
6
|
export { default as PageSurround } from "./PageSurround.vue";
|
|
7
7
|
export { default as PageTOC } from "./PageTOC.vue";
|
|
8
|
+
export { default as PageVersionSelector } from "./PageVersionSelector.vue";
|
|
8
9
|
export * from "./modals/index.mjs";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Page } from "../../../types/index.js";
|
|
2
|
+
export interface PageTreeModalProps {
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
pages?: Pick<Page, "title" | "slug">[];
|
|
5
|
+
rc?: {
|
|
6
|
+
header?: string;
|
|
7
|
+
headerTitle?: string;
|
|
8
|
+
closeButton?: string;
|
|
9
|
+
body?: string;
|
|
10
|
+
footer?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
type __VLS_Props = PageTreeModalProps;
|
|
14
|
+
export interface PageTreeModalEmits {
|
|
15
|
+
close: [];
|
|
16
|
+
navigate: [slug: string];
|
|
17
|
+
}
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
"open"?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
navigate: (slug: string) => any;
|
|
24
|
+
close: () => any;
|
|
25
|
+
"update:open": (value: boolean) => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
27
|
+
onNavigate?: ((slug: string) => any) | undefined;
|
|
28
|
+
onClose?: (() => any) | undefined;
|
|
29
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
30
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
+
declare const _default: typeof __VLS_export;
|
|
32
|
+
export default _default;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { useRC } from "../../../composables";
|
|
4
|
+
import { tv } from "../../../internal/tv";
|
|
5
|
+
import { getLocalizedContent } from "../../../utils";
|
|
6
|
+
import { useI18n } from "vue-i18n";
|
|
7
|
+
const open = defineModel("open", { type: Boolean, ...{ default: false } });
|
|
8
|
+
const { loading, pages = [], rc: rcProp } = defineProps({
|
|
9
|
+
loading: { type: Boolean, required: false },
|
|
10
|
+
pages: { type: Array, required: false },
|
|
11
|
+
rc: { type: Object, required: false }
|
|
12
|
+
});
|
|
13
|
+
const emit = defineEmits(["close", "navigate"]);
|
|
14
|
+
const { rc } = useRC("PageTreeModal", rcProp);
|
|
15
|
+
const { t, locale } = useI18n();
|
|
16
|
+
const pageTreeModalStyles = tv({
|
|
17
|
+
slots: {
|
|
18
|
+
header: "flex items-center justify-between",
|
|
19
|
+
headerTitle: "text-base font-semibold leading-6",
|
|
20
|
+
closeButton: "-my-1",
|
|
21
|
+
body: "p-0 min-h-[300px] max-h-[60vh] overflow-y-auto",
|
|
22
|
+
footer: "flex justify-end gap-2"
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const { header: headerClass, headerTitle, closeButton, body, footer } = pageTreeModalStyles();
|
|
26
|
+
const treeItems = computed(() => {
|
|
27
|
+
if (!pages || pages.length === 0) return [];
|
|
28
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
29
|
+
const rootNodes = [];
|
|
30
|
+
const getNode = (path, partLabel, pageObj) => {
|
|
31
|
+
if (!nodeMap.has(path)) {
|
|
32
|
+
const label = pageObj ? getLocalizedContent(pageObj.title, locale.value) || partLabel : partLabel.charAt(0).toUpperCase() + partLabel.slice(1);
|
|
33
|
+
const newNode = {
|
|
34
|
+
label,
|
|
35
|
+
slug: pageObj ? pageObj.slug : void 0,
|
|
36
|
+
icon: pageObj ? "i-lucide-file" : "i-lucide-folder",
|
|
37
|
+
children: []
|
|
38
|
+
};
|
|
39
|
+
nodeMap.set(path, newNode);
|
|
40
|
+
} else if (pageObj) {
|
|
41
|
+
const node = nodeMap.get(path);
|
|
42
|
+
node.label = getLocalizedContent(pageObj.title, locale.value) || node.label;
|
|
43
|
+
node.slug = pageObj.slug;
|
|
44
|
+
node.icon = "i-lucide-file-text";
|
|
45
|
+
}
|
|
46
|
+
return nodeMap.get(path);
|
|
47
|
+
};
|
|
48
|
+
pages.forEach((page) => {
|
|
49
|
+
const parts = page.slug.split("/").filter(Boolean);
|
|
50
|
+
let currentPath = "";
|
|
51
|
+
let parent = null;
|
|
52
|
+
parts.forEach((part, index) => {
|
|
53
|
+
currentPath = currentPath ? `${currentPath}/${part}` : part;
|
|
54
|
+
const isLast = index === parts.length - 1;
|
|
55
|
+
const pageObj = isLast ? page : void 0;
|
|
56
|
+
const node = getNode(currentPath, part, pageObj);
|
|
57
|
+
if (index === 0) {
|
|
58
|
+
if (!rootNodes.includes(node)) {
|
|
59
|
+
rootNodes.push(node);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
if (parent && !parent.children?.includes(node)) {
|
|
63
|
+
if (!parent.children) parent.children = [];
|
|
64
|
+
parent.children.push(node);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
parent = node;
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
const sortNodes = (nodes) => {
|
|
71
|
+
nodes.sort((a, b) => a.label.localeCompare(b.label));
|
|
72
|
+
nodes.forEach((n) => {
|
|
73
|
+
if (n.children && n.children.length > 0) {
|
|
74
|
+
sortNodes(n.children);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
sortNodes(rootNodes);
|
|
79
|
+
return rootNodes;
|
|
80
|
+
});
|
|
81
|
+
const handleSelect = (node) => {
|
|
82
|
+
if (node.slug) {
|
|
83
|
+
emit("navigate", node.slug);
|
|
84
|
+
open.value = false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const getKey = (item) => item.slug || item.label;
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<UModal v-model:open="open" title="Page Hierarchy" description="Navigate through your pages">
|
|
92
|
+
<template #content>
|
|
93
|
+
<UCard :ui="{ body: 'p-0 sm:p-0' }">
|
|
94
|
+
<template #header>
|
|
95
|
+
<div :class="headerClass({ class: rc.header })">
|
|
96
|
+
<h3 :class="headerTitle({ class: rc.headerTitle })">Page Hierarchy</h3>
|
|
97
|
+
<UButton
|
|
98
|
+
color="neutral"
|
|
99
|
+
variant="ghost"
|
|
100
|
+
icon="i-heroicons-x-mark-20-solid"
|
|
101
|
+
:class="closeButton({ class: rc.closeButton })"
|
|
102
|
+
@click="open = false"
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<div :class="body({ class: rc.body })">
|
|
108
|
+
<div v-if="loading" class="p-4 flex justify-center">
|
|
109
|
+
<UIcon name="i-heroicons-arrow-path" class="w-5 h-5 animate-spin" />
|
|
110
|
+
</div>
|
|
111
|
+
<div v-else-if="treeItems.length === 0" class="p-4 text-center text-gray-500">
|
|
112
|
+
No pages found directly.
|
|
113
|
+
</div>
|
|
114
|
+
<UTree
|
|
115
|
+
v-else
|
|
116
|
+
:items="treeItems"
|
|
117
|
+
:ui="{ item: 'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800' }"
|
|
118
|
+
>
|
|
119
|
+
<template #item="{ item }">
|
|
120
|
+
<div class="flex items-center gap-2 py-1 w-full" @click="handleSelect(item)">
|
|
121
|
+
<UIcon :name="item.icon || (item.children?.length ? 'i-lucide-folder' : 'i-lucide-file')" class="w-4 h-4 text-gray-400" />
|
|
122
|
+
<span :class="{ 'text-gray-900 dark:text-gray-100': item.slug, 'text-gray-500 font-medium': !item.slug }">
|
|
123
|
+
{{ item.label }}
|
|
124
|
+
</span>
|
|
125
|
+
<UIcon v-if="item.slug" name="i-heroicons-arrow-right-20-solid" class="w-3 h-3 ml-auto text-gray-300 opacity-0 group-hover:opacity-100" />
|
|
126
|
+
</div>
|
|
127
|
+
</template>
|
|
128
|
+
</UTree>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<template #footer>
|
|
132
|
+
<div :class="footer({ class: rc.footer })">
|
|
133
|
+
<UButton color="neutral" variant="ghost" label="Close" @click="open = false" />
|
|
134
|
+
</div>
|
|
135
|
+
</template>
|
|
136
|
+
</UCard>
|
|
137
|
+
</template>
|
|
138
|
+
</UModal>
|
|
139
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Page } from "../../../types/index.js";
|
|
2
|
+
export interface PageTreeModalProps {
|
|
3
|
+
loading?: boolean;
|
|
4
|
+
pages?: Pick<Page, "title" | "slug">[];
|
|
5
|
+
rc?: {
|
|
6
|
+
header?: string;
|
|
7
|
+
headerTitle?: string;
|
|
8
|
+
closeButton?: string;
|
|
9
|
+
body?: string;
|
|
10
|
+
footer?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
type __VLS_Props = PageTreeModalProps;
|
|
14
|
+
export interface PageTreeModalEmits {
|
|
15
|
+
close: [];
|
|
16
|
+
navigate: [slug: string];
|
|
17
|
+
}
|
|
18
|
+
type __VLS_ModelProps = {
|
|
19
|
+
"open"?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
22
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
23
|
+
navigate: (slug: string) => any;
|
|
24
|
+
close: () => any;
|
|
25
|
+
"update:open": (value: boolean) => any;
|
|
26
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
27
|
+
onNavigate?: ((slug: string) => any) | undefined;
|
|
28
|
+
onClose?: (() => any) | undefined;
|
|
29
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
30
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
31
|
+
declare const _default: typeof __VLS_export;
|
|
32
|
+
export default _default;
|
|
@@ -67,3 +67,14 @@ export interface PageSurround {
|
|
|
67
67
|
previous: SurroundItem | null;
|
|
68
68
|
next: SurroundItem | null;
|
|
69
69
|
}
|
|
70
|
+
export interface PageVersion extends BasePage {
|
|
71
|
+
status: "pending" | "approved" | "rejected";
|
|
72
|
+
type: PageType;
|
|
73
|
+
content: {
|
|
74
|
+
blocks: Block[];
|
|
75
|
+
properties: RegisterPageTypes[PageType];
|
|
76
|
+
};
|
|
77
|
+
createdBy: string;
|
|
78
|
+
approvedBy?: string | null;
|
|
79
|
+
approvedAt?: Date | null;
|
|
80
|
+
}
|