rimelight-components 2.0.59 → 2.0.61
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/app.config.d.ts +4 -0
- package/dist/runtime/app.config.js +4 -0
- package/dist/runtime/components/blocks/BlockEditor.vue +1 -1
- package/dist/runtime/components/content/Section.vue +1 -1
- package/dist/runtime/components/page/PageEditor.d.vue.ts +0 -24
- package/dist/runtime/components/page/PageEditor.vue +1 -1
- package/dist/runtime/components/page/PageEditor.vue.d.ts +0 -24
- package/dist/runtime/components/page/PagePropertiesEditor.d.vue.ts +0 -11
- package/dist/runtime/components/page/PagePropertiesEditor.vue +16 -12
- package/dist/runtime/components/page/PagePropertiesEditor.vue.d.ts +0 -11
- package/dist/runtime/components/page/PagePropertiesRenderer.vue +25 -17
- package/dist/runtime/components/swatches/ColorSwatch.vue +1 -1
- package/dist/runtime/types/app.config.d.ts +10 -2
- package/dist/runtime/types/index.d.ts +0 -1
- package/dist/runtime/types/index.js +0 -1
- package/dist/runtime/types/pages.d.ts +28 -105
- package/dist/runtime/types/pages.js +3 -58
- package/dist/runtime/utils/page.d.ts +7 -4
- package/dist/runtime/utils/page.js +64 -13
- package/package.json +5 -3
- package/dist/runtime/types/pageTemplates.d.ts +0 -3
- package/dist/runtime/types/pageTemplates.js +0 -170
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { basename } from 'node:path';
|
|
|
5
5
|
export * from '../dist/runtime/types/index.js';
|
|
6
6
|
|
|
7
7
|
const name = "rimelight-components";
|
|
8
|
-
const version = "2.0.
|
|
8
|
+
const version = "2.0.61";
|
|
9
9
|
const homepage = "https://rimelight.com/tools/rimelight-components";
|
|
10
10
|
|
|
11
11
|
const defaultOptions = {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useRoute } from "#imports";
|
|
3
3
|
import { computed } from "vue";
|
|
4
4
|
import { useClipboard } from "@vueuse/core";
|
|
5
|
-
import { useToast } from "
|
|
5
|
+
import { useToast } from "@nuxt/ui/composables";
|
|
6
6
|
import { tv } from "tailwind-variants";
|
|
7
7
|
import { slugify } from "../../utils";
|
|
8
8
|
const { copy } = useClipboard();
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Page } from "../../types/pages.js";
|
|
2
|
-
interface Props {
|
|
3
|
-
isSaving: boolean;
|
|
4
|
-
}
|
|
5
|
-
type __VLS_Props = Props;
|
|
6
|
-
type __VLS_ModelProps = {
|
|
7
|
-
modelValue: Page;
|
|
8
|
-
};
|
|
9
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
11
|
-
undo: () => void;
|
|
12
|
-
redo: () => void;
|
|
13
|
-
canUndo: import("vue").ComputedRef<boolean>;
|
|
14
|
-
canRedo: import("vue").ComputedRef<boolean>;
|
|
15
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
-
"update:modelValue": (value: Page) => any;
|
|
17
|
-
} & {
|
|
18
|
-
save: (value: Page) => any;
|
|
19
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
-
onSave?: ((value: Page) => any) | undefined;
|
|
21
|
-
"onUpdate:modelValue"?: ((value: Page) => any) | undefined;
|
|
22
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
-
declare const _default: typeof __VLS_export;
|
|
24
|
-
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, computed, useTemplateRef } from "vue";
|
|
3
3
|
import { usePageEditor } from "../../composables/usePageEditor";
|
|
4
|
-
const page = defineModel({ type:
|
|
4
|
+
const page = defineModel({ type: null, ...{ required: true } });
|
|
5
5
|
const { undo, redo, canUndo, canRedo, captureSnapshot } = usePageEditor(page);
|
|
6
6
|
const emit = defineEmits(["save"]);
|
|
7
7
|
const handleSave = () => {
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Page } from "../../types/pages.js";
|
|
2
|
-
interface Props {
|
|
3
|
-
isSaving: boolean;
|
|
4
|
-
}
|
|
5
|
-
type __VLS_Props = Props;
|
|
6
|
-
type __VLS_ModelProps = {
|
|
7
|
-
modelValue: Page;
|
|
8
|
-
};
|
|
9
|
-
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
11
|
-
undo: () => void;
|
|
12
|
-
redo: () => void;
|
|
13
|
-
canUndo: import("vue").ComputedRef<boolean>;
|
|
14
|
-
canRedo: import("vue").ComputedRef<boolean>;
|
|
15
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
|
-
"update:modelValue": (value: Page) => any;
|
|
17
|
-
} & {
|
|
18
|
-
save: (value: Page) => any;
|
|
19
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
-
onSave?: ((value: Page) => any) | undefined;
|
|
21
|
-
"onUpdate:modelValue"?: ((value: Page) => any) | undefined;
|
|
22
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
-
declare const _default: typeof __VLS_export;
|
|
24
|
-
export default _default;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type Page } from '../../types/pages.js';
|
|
2
|
-
type __VLS_ModelProps = {
|
|
3
|
-
modelValue: Page;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
-
"update:modelValue": (value: Page) => any;
|
|
7
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
-
"onUpdate:modelValue"?: ((value: Page) => any) | undefined;
|
|
9
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
-
declare const _default: typeof __VLS_export;
|
|
11
|
-
export default _default;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { useAppConfig } from "#imports";
|
|
4
|
+
import { useI18n } from "vue-i18n";
|
|
5
|
+
import {} from "../../types/pages";
|
|
6
|
+
const page = defineModel({ type: null, ...{ required: true } });
|
|
7
|
+
const appConfig = useAppConfig();
|
|
8
|
+
const locale = useI18n().locale;
|
|
5
9
|
const properties = computed(() => page.value.properties);
|
|
6
10
|
const groups = computed(() => {
|
|
7
|
-
return
|
|
11
|
+
return page.value.properties;
|
|
8
12
|
});
|
|
9
13
|
const isFieldVisible = (fieldSchema) => {
|
|
10
14
|
if (!fieldSchema.visibleIf) return true;
|
|
@@ -26,46 +30,46 @@ const getSortedFields = (fields) => {
|
|
|
26
30
|
</UBadge>
|
|
27
31
|
</div>
|
|
28
32
|
|
|
29
|
-
<div v-for="group in groups" :key="
|
|
33
|
+
<div v-for="(group, groupId) in groups" :key="groupId" class="space-y-4">
|
|
30
34
|
<div class="flex items-center gap-3">
|
|
31
35
|
<span class="text-[10px] font-bold uppercase tracking-widest text-primary">
|
|
32
|
-
{{ group.label }}
|
|
36
|
+
{{ group.label[locale] }}
|
|
33
37
|
</span>
|
|
34
38
|
<div class="h-px flex-1 bg-border/50"></div>
|
|
35
39
|
</div>
|
|
36
40
|
|
|
37
41
|
<div class="grid gap-y-4 px-1">
|
|
38
|
-
<template v-for="[
|
|
42
|
+
<template v-for="[fieldKey, schema] in getSortedFields(group.fields)" :key="fieldKey">
|
|
39
43
|
|
|
40
44
|
<UFormField
|
|
41
45
|
v-if="isFieldVisible(schema)"
|
|
42
46
|
:label="schema.label"
|
|
43
|
-
:name="
|
|
47
|
+
:name="fieldKey"
|
|
44
48
|
>
|
|
45
49
|
<UInput
|
|
46
50
|
v-if="schema.type === 'text'"
|
|
47
|
-
v-model="properties[
|
|
51
|
+
v-model="properties[groupId].fields[fieldKey].value[locale]"
|
|
48
52
|
variant="subtle"
|
|
49
53
|
placeholder="..."
|
|
50
54
|
/>
|
|
51
55
|
|
|
52
56
|
<UInput
|
|
53
57
|
v-else-if="schema.type === 'number'"
|
|
54
|
-
v-model.number="properties[
|
|
58
|
+
v-model.number="properties[groupId].fields[fieldKey].value"
|
|
55
59
|
type="number"
|
|
56
60
|
variant="subtle"
|
|
57
61
|
/>
|
|
58
62
|
|
|
59
63
|
<USelect
|
|
60
64
|
v-else-if="schema.type === 'enum'"
|
|
61
|
-
v-model="properties[
|
|
65
|
+
v-model="properties[groupId].fields[fieldKey].value"
|
|
62
66
|
:items="schema.options || []"
|
|
63
67
|
variant="subtle"
|
|
64
68
|
/>
|
|
65
69
|
|
|
66
70
|
<UInputMenu
|
|
67
71
|
v-else-if="schema.type === 'text-array'"
|
|
68
|
-
v-model="properties[
|
|
72
|
+
v-model="properties[groupId].fields[fieldKey].value[locale]"
|
|
69
73
|
multiple
|
|
70
74
|
creatable
|
|
71
75
|
variant="subtle"
|
|
@@ -74,7 +78,7 @@ const getSortedFields = (fields) => {
|
|
|
74
78
|
|
|
75
79
|
<UInput
|
|
76
80
|
v-else-if="schema.type === 'page'"
|
|
77
|
-
v-model="properties[
|
|
81
|
+
v-model="properties[groupId].fields[fieldKey].value"
|
|
78
82
|
icon="lucide:link-2"
|
|
79
83
|
variant="subtle"
|
|
80
84
|
:placeholder="`Select ${schema.allowedPageTypes?.join('/')}`"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type Page } from '../../types/pages.js';
|
|
2
|
-
type __VLS_ModelProps = {
|
|
3
|
-
modelValue: Page;
|
|
4
|
-
};
|
|
5
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
-
"update:modelValue": (value: Page) => any;
|
|
7
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
8
|
-
"onUpdate:modelValue"?: ((value: Page) => any) | undefined;
|
|
9
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
-
declare const _default: typeof __VLS_export;
|
|
11
|
-
export default _default;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
+
import { useAppConfig } from "#imports";
|
|
4
|
+
import { useI18n } from "vue-i18n";
|
|
3
5
|
import {
|
|
4
|
-
PAGE_SCHEMAS
|
|
5
6
|
} from "../../types/pages";
|
|
6
7
|
const props = defineProps({
|
|
7
|
-
modelValue: { type:
|
|
8
|
+
modelValue: { type: null, required: true }
|
|
8
9
|
});
|
|
10
|
+
const appConfig = useAppConfig();
|
|
11
|
+
const locale = useI18n().locale;
|
|
9
12
|
const properties = computed(() => props.modelValue.properties);
|
|
10
13
|
const displayGroups = computed(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const value = properties.value[key];
|
|
14
|
+
return Object.entries(properties.value || {}).map(([groupId, group]) => {
|
|
15
|
+
const visibleFields = Object.entries(group.fields || {}).filter(([fieldKey, schema]) => {
|
|
16
|
+
const value = schema.type === "text" || schema.type === "text-array" ? schema.value?.[locale.value] : schema.value;
|
|
15
17
|
const isVisible = !schema.visibleIf || schema.visibleIf(props.modelValue.properties);
|
|
16
18
|
if (!isVisible) return false;
|
|
17
19
|
if (Array.isArray(value)) return value.length > 0;
|
|
@@ -19,6 +21,7 @@ const displayGroups = computed(() => {
|
|
|
19
21
|
}).sort(([, a], [, b]) => (a.order ?? 0) - (b.order ?? 0));
|
|
20
22
|
return {
|
|
21
23
|
...group,
|
|
24
|
+
groupId,
|
|
22
25
|
visibleFields
|
|
23
26
|
};
|
|
24
27
|
}).filter((group) => group.visibleFields.length > 0);
|
|
@@ -32,19 +35,19 @@ const displayGroups = computed(() => {
|
|
|
32
35
|
{{ props.modelValue.type }}
|
|
33
36
|
</div>
|
|
34
37
|
<h2 class="text-xl font-serif font-bold italic text-foreground">
|
|
35
|
-
{{ properties.name || props.modelValue.slug }}
|
|
38
|
+
{{ properties.name?.value?.[locale] || props.modelValue.slug }}
|
|
36
39
|
</h2>
|
|
37
40
|
</div>
|
|
38
41
|
|
|
39
|
-
<div v-for="group in displayGroups" :key="group.
|
|
42
|
+
<div v-for="group in displayGroups" :key="group.groupId" class="border-b last:border-b-0 border-border/40">
|
|
40
43
|
<div class="bg-muted/30 px-3 py-1.5 text-[10px] font-black text-primary uppercase tracking-tighter border-b border-border/10">
|
|
41
|
-
{{ group.label }}
|
|
44
|
+
{{ group.label[locale] }}
|
|
42
45
|
</div>
|
|
43
46
|
|
|
44
47
|
<dl class="p-3 space-y-2.5">
|
|
45
48
|
<div
|
|
46
|
-
v-for="[
|
|
47
|
-
:key="
|
|
49
|
+
v-for="[fieldKey, schema] in group.visibleFields"
|
|
50
|
+
:key="fieldKey"
|
|
48
51
|
class="grid grid-cols-3 gap-x-3 items-baseline"
|
|
49
52
|
>
|
|
50
53
|
<dt class="text-[11px] font-semibold text-muted-foreground leading-tight">
|
|
@@ -53,18 +56,22 @@ const displayGroups = computed(() => {
|
|
|
53
56
|
|
|
54
57
|
<dd class="text-xs col-span-2 text-foreground leading-snug">
|
|
55
58
|
<div v-if="schema.type === 'text-array'" class="flex flex-wrap gap-1">
|
|
56
|
-
<template v-for="(item, index) in properties[
|
|
59
|
+
<template v-for="(item, index) in properties[group.groupId].fields[fieldKey].value[locale]" :key="index">
|
|
57
60
|
<span class="font-medium">{{ item }}</span>
|
|
58
|
-
<span v-if="index < properties[
|
|
61
|
+
<span v-if="index < properties[group.groupId].fields[fieldKey].value[locale].length - 1" class="text-muted-foreground/50">, </span>
|
|
59
62
|
</template>
|
|
60
63
|
</div>
|
|
61
64
|
|
|
62
65
|
<span v-else-if="schema.type === 'page'" class="text-primary font-bold hover:underline cursor-pointer">
|
|
63
|
-
{{ properties[
|
|
66
|
+
{{ properties[group.groupId].fields[fieldKey].value }}
|
|
67
|
+
</span>
|
|
68
|
+
|
|
69
|
+
<span v-else-if="schema.type === 'text'" class="font-medium">
|
|
70
|
+
{{ properties[group.groupId].fields[fieldKey].value[locale] }}
|
|
64
71
|
</span>
|
|
65
72
|
|
|
66
73
|
<span v-else class="font-medium">
|
|
67
|
-
{{ properties[
|
|
74
|
+
{{ properties[group.groupId].fields[fieldKey].value }}
|
|
68
75
|
</span>
|
|
69
76
|
</dd>
|
|
70
77
|
</div>
|
|
@@ -75,16 +82,17 @@ const displayGroups = computed(() => {
|
|
|
75
82
|
<div class="flex flex-wrap gap-1.5">
|
|
76
83
|
<UBadge
|
|
77
84
|
v-for="tag in props.modelValue.tags"
|
|
78
|
-
:key="tag"
|
|
85
|
+
:key="String(tag[locale])"
|
|
79
86
|
variant="subtle"
|
|
80
87
|
size="sm"
|
|
81
88
|
color="neutral"
|
|
82
89
|
class="text-[9px] font-bold uppercase tracking-tight"
|
|
83
90
|
>
|
|
84
|
-
#{{ tag }}
|
|
91
|
+
#{{ tag[locale] }}
|
|
85
92
|
</UBadge>
|
|
86
93
|
</div>
|
|
87
94
|
</div>
|
|
95
|
+
|
|
88
96
|
</div>
|
|
89
97
|
</template>
|
|
90
98
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
import { useClipboard } from "@vueuse/core";
|
|
4
|
-
import { useToast } from "
|
|
4
|
+
import { useToast } from "@nuxt/ui/composables";
|
|
5
5
|
const { copy } = useClipboard();
|
|
6
6
|
const toast = useToast();
|
|
7
7
|
const { name, hex, rgb, hsl, oklch, cmyk } = defineProps({
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
declare module '#build/app.config' {
|
|
2
2
|
import type { AppConfig } from '@nuxt/schema'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
interface RimelightComponentsConfig {
|
|
5
|
+
[key: string]: any
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface CustomAppConfig extends AppConfig {
|
|
9
|
+
rimelightComponents?: RimelightComponentsConfig
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const _default: CustomAppConfig
|
|
5
13
|
export default _default
|
|
6
|
-
}
|
|
14
|
+
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { type Image } from "../types/schemas.js";
|
|
2
2
|
import { type Block } from "./blocks.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
declare global {
|
|
4
|
+
interface RimelightRegisterPageTypes {
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export type PageType = keyof RegisterPageTypes;
|
|
8
|
+
export interface Property<T = any> {
|
|
9
|
+
value: T;
|
|
5
10
|
label: string;
|
|
6
11
|
type: "number" | "text" | "text-array" | "enum" | "page" | "page-array";
|
|
7
12
|
options?: string[];
|
|
@@ -9,66 +14,29 @@ export interface Property {
|
|
|
9
14
|
order?: number;
|
|
10
15
|
visibleIf?: (properties: any) => boolean;
|
|
11
16
|
}
|
|
17
|
+
export type Localized<T = string> = Record<string, T>;
|
|
12
18
|
export interface PropertyGroup {
|
|
13
|
-
|
|
14
|
-
label: string;
|
|
19
|
+
label: Localized<string>;
|
|
15
20
|
order?: number;
|
|
16
21
|
fields: Record<string, Property>;
|
|
17
22
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export interface PatchNoteProperties extends BasePageProperties {
|
|
25
|
-
}
|
|
26
|
-
export interface LocationProperties extends BasePageProperties {
|
|
27
|
-
}
|
|
28
|
-
export interface SpeciesProperties extends BasePageProperties {
|
|
29
|
-
}
|
|
30
|
-
export interface CharacterProperties extends BasePageProperties {
|
|
31
|
-
name: string;
|
|
32
|
-
title?: string;
|
|
33
|
-
aliases?: string[];
|
|
34
|
-
flavourText?: string;
|
|
35
|
-
species?: string;
|
|
36
|
-
sex?: string;
|
|
37
|
-
pronouns?: string;
|
|
38
|
-
height?: number;
|
|
39
|
-
weight?: number;
|
|
40
|
-
dateOfBirth?: string;
|
|
41
|
-
dateOfDeath?: string;
|
|
42
|
-
placeOfBirth?: string;
|
|
43
|
-
placeOfDeath?: string;
|
|
44
|
-
formerAffiliations?: string[];
|
|
45
|
-
currentAffiliations?: string[];
|
|
46
|
-
equipment?: string[];
|
|
47
|
-
pets?: string[];
|
|
48
|
-
mounts?: string[];
|
|
49
|
-
favouriteFood?: string;
|
|
50
|
-
}
|
|
51
|
-
export interface ObjectProperties extends BasePageProperties {
|
|
52
|
-
}
|
|
53
|
-
export interface TaleProperties extends BasePageProperties {
|
|
54
|
-
}
|
|
55
|
-
export interface ItemProperties extends BasePageProperties {
|
|
56
|
-
}
|
|
57
|
-
export interface SkillProperties extends BasePageProperties {
|
|
58
|
-
}
|
|
59
|
-
export interface HeroProperties extends BasePageProperties {
|
|
60
|
-
}
|
|
61
|
-
export interface CardProperties extends BasePageProperties {
|
|
62
|
-
name: string;
|
|
63
|
-
alignment: string;
|
|
64
|
-
type: string;
|
|
65
|
-
flavourText: string;
|
|
23
|
+
/**
|
|
24
|
+
* A PageTemplate is the single definition for a page's properties and initial blocks.
|
|
25
|
+
*/
|
|
26
|
+
export interface PageDefinition {
|
|
27
|
+
properties: Record<string, PropertyGroup>;
|
|
28
|
+
initialBlocks?: () => Block[];
|
|
66
29
|
}
|
|
67
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Helper to define a page with full type safety and literal preservation.
|
|
32
|
+
* This is used by consuming apps to define their custom page types.
|
|
33
|
+
*/
|
|
34
|
+
export declare function definePageDefinition<T extends PageDefinition>(def: T): T;
|
|
35
|
+
export interface BasePageProperties {
|
|
68
36
|
}
|
|
69
|
-
export interface
|
|
37
|
+
export interface RegisterPageTypes extends RimelightRegisterPageTypes {
|
|
38
|
+
Default: BasePageProperties;
|
|
70
39
|
}
|
|
71
|
-
export type Localized<T = string> = Record<string, T>;
|
|
72
40
|
/**
|
|
73
41
|
* Common fields shared by every page regardless of type.
|
|
74
42
|
*/
|
|
@@ -89,54 +57,9 @@ interface BasePage {
|
|
|
89
57
|
* Discriminated Union for Page Data structure
|
|
90
58
|
*/
|
|
91
59
|
export type Page = {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
} & BasePage | {
|
|
98
|
-
type: "BlogPost";
|
|
99
|
-
properties: BlogPostProperties;
|
|
100
|
-
} & BasePage | {
|
|
101
|
-
type: "PatchNote";
|
|
102
|
-
properties: PatchNoteProperties;
|
|
103
|
-
} & BasePage | {
|
|
104
|
-
type: "Character";
|
|
105
|
-
properties: CharacterProperties;
|
|
106
|
-
} & BasePage | {
|
|
107
|
-
type: "Card";
|
|
108
|
-
properties: CardProperties;
|
|
109
|
-
} & BasePage | {
|
|
110
|
-
type: "Location";
|
|
111
|
-
properties: BasePageProperties;
|
|
112
|
-
} & BasePage | {
|
|
113
|
-
type: "Species";
|
|
114
|
-
properties: BasePageProperties;
|
|
115
|
-
} & BasePage | {
|
|
116
|
-
type: "Object";
|
|
117
|
-
properties: BasePageProperties;
|
|
118
|
-
} & BasePage | {
|
|
119
|
-
type: "Tale";
|
|
120
|
-
properties: BasePageProperties;
|
|
121
|
-
} & BasePage | {
|
|
122
|
-
type: "Item";
|
|
123
|
-
properties: BasePageProperties;
|
|
124
|
-
} & BasePage | {
|
|
125
|
-
type: "Skill";
|
|
126
|
-
properties: BasePageProperties;
|
|
127
|
-
} & BasePage | {
|
|
128
|
-
type: "Hero";
|
|
129
|
-
properties: BasePageProperties;
|
|
130
|
-
} & BasePage | {
|
|
131
|
-
type: "Series";
|
|
132
|
-
properties: BasePageProperties;
|
|
133
|
-
} & BasePage | {
|
|
134
|
-
type: "Episode";
|
|
135
|
-
properties: BasePageProperties;
|
|
136
|
-
} & BasePage;
|
|
137
|
-
/**
|
|
138
|
-
* Registry mapping PageTypes to their UI schema.
|
|
139
|
-
* This drives the dynamic form generation in the Sidebar.
|
|
140
|
-
*/
|
|
141
|
-
export declare const PAGE_SCHEMAS: Record<PageType, PropertyGroup[]>;
|
|
60
|
+
[K in PageType]: {
|
|
61
|
+
type: K;
|
|
62
|
+
properties: RegisterPageTypes[K];
|
|
63
|
+
} & BasePage;
|
|
64
|
+
}[PageType];
|
|
142
65
|
export {};
|
|
@@ -1,58 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
BlogPost: [],
|
|
5
|
-
PatchNote: [],
|
|
6
|
-
Character: [
|
|
7
|
-
{
|
|
8
|
-
id: "identity",
|
|
9
|
-
label: "Identity",
|
|
10
|
-
fields: {
|
|
11
|
-
name: { label: "Name", type: "text" },
|
|
12
|
-
title: { label: "Social Title", type: "text" },
|
|
13
|
-
aliases: { label: "Aliases", type: "text-array" }
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
id: "characteristics",
|
|
18
|
-
label: "Characteristics",
|
|
19
|
-
fields: {
|
|
20
|
-
species: { label: "Species", type: "page", allowedPageTypes: ["Species"] },
|
|
21
|
-
sex: { label: "Sex", type: "enum", options: ["Male", "Female", "Other", "Unknown"] },
|
|
22
|
-
height: { label: "Height", type: "number" },
|
|
23
|
-
weight: { label: "Weight", type: "number" }
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
id: "timeline",
|
|
28
|
-
label: "Timeline",
|
|
29
|
-
fields: {
|
|
30
|
-
dateOfBirth: { label: "Date of Birth", type: "text" },
|
|
31
|
-
dateOfDeath: { label: "Date of Death", type: "text" },
|
|
32
|
-
placeOfDeath: {
|
|
33
|
-
label: "Place of Death",
|
|
34
|
-
type: "text",
|
|
35
|
-
visibleIf: (props) => !!props.dateOfDeath
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: "other",
|
|
41
|
-
label: "Other",
|
|
42
|
-
order: 3,
|
|
43
|
-
fields: {
|
|
44
|
-
flavourText: { label: "Flavour Text", type: "text" }
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
Location: [],
|
|
49
|
-
Species: [],
|
|
50
|
-
Object: [],
|
|
51
|
-
Tale: [],
|
|
52
|
-
Item: [],
|
|
53
|
-
Skill: [],
|
|
54
|
-
Hero: [],
|
|
55
|
-
Card: [],
|
|
56
|
-
Series: [],
|
|
57
|
-
Episode: []
|
|
58
|
-
};
|
|
1
|
+
export function definePageDefinition(def) {
|
|
2
|
+
return def;
|
|
3
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type { Page, Localized } from "../types/pages.js";
|
|
1
|
+
import type { Page, Localized, PageDefinition } from "../types/pages.js";
|
|
2
2
|
export declare const getLocalizedContent: (field: Localized | undefined, currentLocale: string) => string;
|
|
3
3
|
/**
|
|
4
|
-
* Ensures
|
|
5
|
-
*
|
|
4
|
+
* Ensures a page strictly adheres to its PageDefinition.
|
|
5
|
+
* - Adds missing properties and groups in the correct order.
|
|
6
|
+
* - Removes properties and groups no longer in the definition.
|
|
7
|
+
* - Adds missing templated blocks in the correct relative position.
|
|
8
|
+
* - Removes templated blocks no longer in the definition.
|
|
6
9
|
*/
|
|
7
|
-
export declare function
|
|
10
|
+
export declare function syncPageWithDefinition(page: Page, definition?: PageDefinition): Page;
|
|
@@ -1,20 +1,71 @@
|
|
|
1
|
-
import { PAGE_TEMPLATES } from "../types/pageTemplates.js";
|
|
2
1
|
export const getLocalizedContent = (field, currentLocale) => {
|
|
3
2
|
if (!field) return "";
|
|
4
3
|
return field[currentLocale] || field["en"] || "";
|
|
5
4
|
};
|
|
6
|
-
export function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
export function syncPageWithDefinition(page, definition) {
|
|
6
|
+
if (!definition) return page;
|
|
7
|
+
let hasChanged = false;
|
|
8
|
+
const updatedProperties = {};
|
|
9
|
+
const definitionGroups = definition.properties;
|
|
10
|
+
for (const [groupId, definitionGroup] of Object.entries(definitionGroups)) {
|
|
11
|
+
const existingGroup = page.properties[groupId];
|
|
12
|
+
const updatedGroupFields = {};
|
|
13
|
+
for (const [fieldId, definitionField] of Object.entries(definitionGroup.fields)) {
|
|
14
|
+
if (existingGroup?.fields[fieldId]) {
|
|
15
|
+
updatedGroupFields[fieldId] = {
|
|
16
|
+
...definitionField,
|
|
17
|
+
value: existingGroup.fields[fieldId].value
|
|
18
|
+
};
|
|
19
|
+
} else {
|
|
20
|
+
updatedGroupFields[fieldId] = { ...definitionField };
|
|
21
|
+
hasChanged = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
updatedProperties[groupId] = {
|
|
25
|
+
...definitionGroup,
|
|
26
|
+
fields: updatedGroupFields
|
|
27
|
+
};
|
|
28
|
+
if (!existingGroup) {
|
|
29
|
+
hasChanged = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (Object.keys(page.properties).length !== Object.keys(updatedProperties).length) {
|
|
33
|
+
hasChanged = true;
|
|
34
|
+
} else {
|
|
35
|
+
for (const groupId in updatedProperties) {
|
|
36
|
+
const pageGroup = page.properties[groupId];
|
|
37
|
+
if (Object.keys(pageGroup?.fields || {}).length !== Object.keys(updatedProperties[groupId].fields).length) {
|
|
38
|
+
hasChanged = true;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
page.properties = updatedProperties;
|
|
44
|
+
if (definition.initialBlocks) {
|
|
45
|
+
const idealBlocks = definition.initialBlocks();
|
|
46
|
+
const currentBlocks = [...page.blocks];
|
|
47
|
+
const idealBlocksMap = new Map(idealBlocks.map((b) => [b.id, b]));
|
|
48
|
+
const filteredCurrent = currentBlocks.filter((b) => {
|
|
49
|
+
if (!b.isTemplated) return true;
|
|
50
|
+
return idealBlocksMap.has(b.id);
|
|
51
|
+
});
|
|
52
|
+
if (filteredCurrent.length !== currentBlocks.length) {
|
|
53
|
+
hasChanged = true;
|
|
54
|
+
}
|
|
55
|
+
let lastExistingIdealIndex = -1;
|
|
56
|
+
for (const idealBlock of idealBlocks) {
|
|
57
|
+
const existingIndex = filteredCurrent.findIndex((b) => b.id === idealBlock.id);
|
|
58
|
+
if (existingIndex !== -1) {
|
|
59
|
+
lastExistingIdealIndex = existingIndex;
|
|
60
|
+
} else {
|
|
61
|
+
filteredCurrent.splice(lastExistingIdealIndex + 1, 0, { ...idealBlock });
|
|
62
|
+
lastExistingIdealIndex++;
|
|
63
|
+
hasChanged = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
page.blocks = filteredCurrent;
|
|
67
|
+
}
|
|
68
|
+
if (hasChanged) {
|
|
18
69
|
page.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19
70
|
}
|
|
20
71
|
return page;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rimelight-components",
|
|
3
3
|
"description": "A component library by Rimelight Entertainment.",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.61",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -78,8 +78,10 @@
|
|
|
78
78
|
"typecheck": "vue-tsc --noEmit && nuxt typecheck",
|
|
79
79
|
"lint": "oxlint .",
|
|
80
80
|
"lint:fix": "oxlint . --fix",
|
|
81
|
-
"format": "
|
|
82
|
-
"format:fix": "
|
|
81
|
+
"format": "oxfmt --check",
|
|
82
|
+
"format:fix": "oxfmt .",
|
|
83
|
+
"check": "bun run typecheck && bun run lint && bun run format",
|
|
84
|
+
"fix": "bun run lint:fix && bun run format:fix",
|
|
83
85
|
"test": "vitest",
|
|
84
86
|
"release": "release-it --ci"
|
|
85
87
|
},
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import { v7 as uuidv7 } from "uuid";
|
|
2
|
-
export const PAGE_TEMPLATES = {
|
|
3
|
-
Default: () => [],
|
|
4
|
-
Character: () => [
|
|
5
|
-
{
|
|
6
|
-
id: uuidv7(),
|
|
7
|
-
type: "SectionBlock",
|
|
8
|
-
isTemplated: true,
|
|
9
|
-
props: { level: 2, title: "Appearance", children: [] }
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
id: uuidv7(),
|
|
13
|
-
type: "SectionBlock",
|
|
14
|
-
isTemplated: true,
|
|
15
|
-
props: { level: 2, title: "Abilities", children: [] }
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
id: uuidv7(),
|
|
19
|
-
type: "SectionBlock",
|
|
20
|
-
isTemplated: true,
|
|
21
|
-
props: { level: 2, title: "History", children: [] }
|
|
22
|
-
}
|
|
23
|
-
],
|
|
24
|
-
Location: () => [
|
|
25
|
-
{
|
|
26
|
-
id: uuidv7(),
|
|
27
|
-
type: "SectionBlock",
|
|
28
|
-
isTemplated: true,
|
|
29
|
-
props: { level: 2, title: "Geography", children: [] }
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: uuidv7(),
|
|
33
|
-
type: "SectionBlock",
|
|
34
|
-
isTemplated: true,
|
|
35
|
-
props: { level: 2, title: "Points of Interest", children: [] }
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: uuidv7(),
|
|
39
|
-
type: "SectionBlock",
|
|
40
|
-
isTemplated: true,
|
|
41
|
-
props: { level: 2, title: "History", children: [] }
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
Species: () => [
|
|
45
|
-
{
|
|
46
|
-
id: uuidv7(),
|
|
47
|
-
type: "SectionBlock",
|
|
48
|
-
isTemplated: true,
|
|
49
|
-
props: { level: 2, title: "Biology", children: [] }
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
id: uuidv7(),
|
|
53
|
-
type: "SectionBlock",
|
|
54
|
-
isTemplated: true,
|
|
55
|
-
props: { level: 2, title: "Culture", children: [] }
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
|
-
Object: () => [
|
|
59
|
-
{
|
|
60
|
-
id: uuidv7(),
|
|
61
|
-
type: "SectionBlock",
|
|
62
|
-
isTemplated: true,
|
|
63
|
-
props: { level: 2, title: "Description", children: [] }
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
id: uuidv7(),
|
|
67
|
-
type: "SectionBlock",
|
|
68
|
-
isTemplated: true,
|
|
69
|
-
props: { level: 2, title: "Properties", children: [] }
|
|
70
|
-
}
|
|
71
|
-
],
|
|
72
|
-
Tale: () => [
|
|
73
|
-
{
|
|
74
|
-
id: uuidv7(),
|
|
75
|
-
type: "SectionBlock",
|
|
76
|
-
isTemplated: true,
|
|
77
|
-
props: { level: 2, title: "Summary", children: [] }
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
id: uuidv7(),
|
|
81
|
-
type: "SectionBlock",
|
|
82
|
-
isTemplated: true,
|
|
83
|
-
props: { level: 2, title: "The Story", children: [] }
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
Item: () => [
|
|
87
|
-
{
|
|
88
|
-
id: uuidv7(),
|
|
89
|
-
type: "SectionBlock",
|
|
90
|
-
isTemplated: true,
|
|
91
|
-
props: { level: 2, title: "Statistics", children: [] }
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
id: uuidv7(),
|
|
95
|
-
type: "SectionBlock",
|
|
96
|
-
isTemplated: true,
|
|
97
|
-
props: { level: 2, title: "Lore", children: [] }
|
|
98
|
-
}
|
|
99
|
-
],
|
|
100
|
-
Skill: () => [
|
|
101
|
-
{
|
|
102
|
-
id: uuidv7(),
|
|
103
|
-
type: "SectionBlock",
|
|
104
|
-
isTemplated: true,
|
|
105
|
-
props: { level: 2, title: "Effects", children: [] }
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
id: uuidv7(),
|
|
109
|
-
type: "SectionBlock",
|
|
110
|
-
isTemplated: true,
|
|
111
|
-
props: { level: 2, title: "Acquisition", children: [] }
|
|
112
|
-
}
|
|
113
|
-
],
|
|
114
|
-
Hero: () => [
|
|
115
|
-
{
|
|
116
|
-
id: uuidv7(),
|
|
117
|
-
type: "SectionBlock",
|
|
118
|
-
isTemplated: true,
|
|
119
|
-
props: { level: 2, title: "Background", children: [] }
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
id: uuidv7(),
|
|
123
|
-
type: "SectionBlock",
|
|
124
|
-
isTemplated: true,
|
|
125
|
-
props: { level: 2, title: "Legacy", children: [] }
|
|
126
|
-
}
|
|
127
|
-
],
|
|
128
|
-
Card: () => [
|
|
129
|
-
{
|
|
130
|
-
id: uuidv7(),
|
|
131
|
-
type: "SectionBlock",
|
|
132
|
-
isTemplated: true,
|
|
133
|
-
props: { level: 2, title: "Card Art", children: [] }
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
id: uuidv7(),
|
|
137
|
-
type: "SectionBlock",
|
|
138
|
-
isTemplated: true,
|
|
139
|
-
props: { level: 2, title: "Game Mechanics", children: [] }
|
|
140
|
-
}
|
|
141
|
-
],
|
|
142
|
-
Series: () => [
|
|
143
|
-
{
|
|
144
|
-
id: uuidv7(),
|
|
145
|
-
type: "SectionBlock",
|
|
146
|
-
isTemplated: true,
|
|
147
|
-
props: { level: 2, title: "Synopsis", children: [] }
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: uuidv7(),
|
|
151
|
-
type: "SectionBlock",
|
|
152
|
-
isTemplated: true,
|
|
153
|
-
props: { level: 2, title: "List of Episodes", children: [] }
|
|
154
|
-
}
|
|
155
|
-
],
|
|
156
|
-
Episode: () => [
|
|
157
|
-
{
|
|
158
|
-
id: uuidv7(),
|
|
159
|
-
type: "SectionBlock",
|
|
160
|
-
isTemplated: true,
|
|
161
|
-
props: { level: 2, title: "Plot Summary", children: [] }
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
id: uuidv7(),
|
|
165
|
-
type: "SectionBlock",
|
|
166
|
-
isTemplated: true,
|
|
167
|
-
props: { level: 2, title: "Characters Appearing", children: [] }
|
|
168
|
-
}
|
|
169
|
-
]
|
|
170
|
-
};
|