@upsoftware_tech/svarium 1.0.7 → 1.0.9
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/index.d.ts +651 -284
- package/dist/src/pages/Auth/Method.vue +7 -1
- package/dist/src/pages/Auth/Register.vue +76 -0
- package/dist/src/pages/Svarium.vue +231 -19
- package/dist/svarium.css +1 -1
- package/dist/svarium.es.js +47659 -15907
- package/dist/svarium.umd.js +14 -5
- package/package.json +4 -2
- package/src/lib/appearance.ts +798 -0
- package/src/lib/block.ts +51 -0
- package/src/lib/utils.ts +7 -0
- package/src/pages/Auth/Method.vue +7 -1
- package/src/pages/Auth/Register.vue +76 -0
- package/src/pages/Svarium.vue +231 -19
package/src/lib/block.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const GRID_COLS = {
|
|
2
|
+
default: { 1: 'grid-cols-1', 2: 'grid-cols-2', 3: 'grid-cols-3', 4: 'grid-cols-4', 5: 'grid-cols-5', 6: 'grid-cols-6', 7: 'grid-cols-7', 8: 'grid-cols-8', 9: 'grid-cols-9', 10: 'grid-cols-10', 11: 'grid-cols-11', 12: 'grid-cols-12' },
|
|
3
|
+
sm: { 1: 'sm:grid-cols-1', 2: 'sm:grid-cols-2', 3: 'sm:grid-cols-3', 4: 'sm:grid-cols-4', 5: 'sm:grid-cols-5', 6: 'sm:grid-cols-6', 7: 'sm:grid-cols-7', 8: 'sm:grid-cols-8', 9: 'sm:grid-cols-9', 10: 'sm:grid-cols-10', 11: 'sm:grid-cols-11', 12: 'sm:grid-cols-12' },
|
|
4
|
+
md: { 1: 'md:grid-cols-1', 2: 'md:grid-cols-2', 3: 'md:grid-cols-3', 4: 'md:grid-cols-4', 5: 'md:grid-cols-5', 6: 'md:grid-cols-6', 7: 'md:grid-cols-7', 8: 'md:grid-cols-8', 9: 'md:grid-cols-9', 10: 'md:grid-cols-10', 11: 'md:grid-cols-11', 12: 'md:grid-cols-12' },
|
|
5
|
+
lg: { 1: 'lg:grid-cols-1', 2: 'lg:grid-cols-2', 3: 'lg:grid-cols-3', 4: 'lg:grid-cols-4', 5: 'lg:grid-cols-5', 6: 'lg:grid-cols-6', 7: 'lg:grid-cols-7', 8: 'lg:grid-cols-8', 9: 'lg:grid-cols-9', 10: 'lg:grid-cols-10', 11: 'lg:grid-cols-11', 12: 'lg:grid-cols-12' },
|
|
6
|
+
xl: { 1: 'xl:grid-cols-1', 2: 'xl:grid-cols-2', 3: 'xl:grid-cols-3', 4: 'xl:grid-cols-4', 5: 'xl:grid-cols-5', 6: 'xl:grid-cols-6', 7: 'xl:grid-cols-7', 8: 'xl:grid-cols-8', 9: 'xl:grid-cols-9', 10: 'xl:grid-cols-10', 11: 'xl:grid-cols-11', 12: 'xl:grid-cols-12' },
|
|
7
|
+
xxl: { 1: '2xl:grid-cols-1', 2: '2xl:grid-cols-2', 3: '2xl:grid-cols-3', 4: '2xl:grid-cols-4', 5: '2xl:grid-cols-5', 6: '2xl:grid-cols-6', 7: '2xl:grid-cols-7', 8: '2xl:grid-cols-8', 9: '2xl:grid-cols-9', 10: '2xl:grid-cols-10', 11: '2xl:grid-cols-11', 12: '2xl:grid-cols-12' }
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
const GAPS = { 0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 8: '8', 10: '10', 12: '12' } as const;
|
|
11
|
+
|
|
12
|
+
const generateGapMap = (prefix: string = 'gap') => ({
|
|
13
|
+
default: { 0: `${prefix}-0`, 1: `${prefix}-1`, 2: `${prefix}-2`, 3: `${prefix}-3`, 4: `${prefix}-4`, 5: `${prefix}-5`, 6: `${prefix}-6`, 8: `${prefix}-8`, 10: `${prefix}-10`, 12: `${prefix}-12` },
|
|
14
|
+
sm: { 0: `sm:${prefix}-0`, 1: `sm:${prefix}-1`, 2: `sm:${prefix}-2`, 3: `sm:${prefix}-3`, 4: `sm:${prefix}-4`, 5: `sm:${prefix}-5`, 6: `sm:${prefix}-6`, 8: `sm:${prefix}-8`, 10: `sm:${prefix}-10`, 12: `sm:${prefix}-12` },
|
|
15
|
+
md: { 0: `md:${prefix}-0`, 1: `md:${prefix}-1`, 2: `md:${prefix}-2`, 3: `md:${prefix}-3`, 4: `md:${prefix}-4`, 5: `md:${prefix}-5`, 6: `md:${prefix}-6`, 8: `md:${prefix}-8`, 10: `md:${prefix}-10`, 12: `md:${prefix}-12` },
|
|
16
|
+
lg: { 0: `lg:${prefix}-0`, 1: `lg:${prefix}-1`, 2: `lg:${prefix}-2`, 3: `lg:${prefix}-3`, 4: `lg:${prefix}-4`, 5: `lg:${prefix}-5`, 6: `lg:${prefix}-6`, 8: `lg:${prefix}-8`, 10: `lg:${prefix}-10`, 12: `lg:${prefix}-12` },
|
|
17
|
+
xl: { 0: `xl:${prefix}-0`, 1: `xl:${prefix}-1`, 2: `xl:${prefix}-2`, 3: `xl:${prefix}-3`, 4: `xl:${prefix}-4`, 5: `xl:${prefix}-5`, 6: `xl:${prefix}-6`, 8: `xl:${prefix}-8`, 10: `xl:${prefix}-10`, 12: `xl:${prefix}-12` },
|
|
18
|
+
xxl: { 0: `2xl:${prefix}-0`, 1: `2xl:${prefix}-1`, 2: `2xl:${prefix}-2`, 3: `2xl:${prefix}-3`, 4: `2xl:${prefix}-4`, 5: `2xl:${prefix}-5`, 6: `2xl:${prefix}-6`, 8: `2xl:${prefix}-8`, 10: `2xl:${prefix}-10`, 12: `2xl:${prefix}-12` }
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export const GRID_GAPS = generateGapMap('gap');
|
|
22
|
+
export const GRID_GAPS_X = generateGapMap('gap-x');
|
|
23
|
+
export const GRID_GAPS_Y = generateGapMap('gap-y');
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export type BreakpointValues = { default?: number; sm?: number; md?: number; lg?: number; xl?: number; xxl?: number; };
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
function resolveClasses(map: any, values?: BreakpointValues): string[] {
|
|
30
|
+
if (!values) return [];
|
|
31
|
+
const classes: string[] = [];
|
|
32
|
+
|
|
33
|
+
(Object.keys(map) as Array<keyof BreakpointValues>).forEach(bp => {
|
|
34
|
+
const val = values[bp];
|
|
35
|
+
if (val !== undefined && map[bp]?.[val as any]) {
|
|
36
|
+
classes.push(map[bp][val as any]);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return classes;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function getGridStyles(props: { cols?: BreakpointValues, gap?: BreakpointValues, gapX?: BreakpointValues, gapY?: BreakpointValues }): string {
|
|
44
|
+
return [
|
|
45
|
+
...resolveClasses(GRID_COLS, props.cols),
|
|
46
|
+
...resolveClasses(GRID_GAPS, props.gap),
|
|
47
|
+
...resolveClasses(GRID_GAPS_X, props.gapX),
|
|
48
|
+
...resolveClasses(GRID_GAPS_Y, props.gapY),
|
|
49
|
+
!props.cols?.default ? 'grid-cols-1' : ''
|
|
50
|
+
].filter(Boolean).join(' ');
|
|
51
|
+
}
|
package/src/lib/utils.ts
ADDED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<BlockFormLoginMethodVerification
|
|
2
|
+
<BlockFormLoginMethodVerification
|
|
3
|
+
:verification-methods="verificationMethods"
|
|
4
|
+
:session="session"
|
|
5
|
+
:type="type"
|
|
6
|
+
/>
|
|
3
7
|
</template>
|
|
4
8
|
|
|
5
9
|
<script setup lang="ts">
|
|
@@ -9,11 +13,13 @@ import { AuthLayout, BlockFormLoginMethodVerification } from '@upsoftware_tech/s
|
|
|
9
13
|
interface Props {
|
|
10
14
|
verificationMethods?: VerificationMethod[] | Record<string, VerificationMethod>;
|
|
11
15
|
session: string;
|
|
16
|
+
type?: string;
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
withDefaults(defineProps<Props>(), {
|
|
15
20
|
verificationMethods: () => [],
|
|
16
21
|
session: '',
|
|
22
|
+
type: 'login',
|
|
17
23
|
});
|
|
18
24
|
|
|
19
25
|
defineOptions({
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="resolvedLayout">
|
|
3
|
+
<BlockPageRegister v-bind="props" />
|
|
4
|
+
</component>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import { computed } from 'vue';
|
|
9
|
+
import { AuthLayout, BlockPageRegister, PanelLayout } from '@upsoftware_tech/svarium';
|
|
10
|
+
|
|
11
|
+
interface RegisterFieldOption {
|
|
12
|
+
value: string | number | boolean;
|
|
13
|
+
label: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface RegisterField {
|
|
17
|
+
name: string;
|
|
18
|
+
type?: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
hint?: string;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
autocomplete?: string;
|
|
24
|
+
value?: string | number | boolean;
|
|
25
|
+
options?: RegisterFieldOption[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Props {
|
|
29
|
+
title?: string;
|
|
30
|
+
subtitle?: string;
|
|
31
|
+
loginLabel?: string;
|
|
32
|
+
loginLinkLabel?: string;
|
|
33
|
+
loginLink?: string;
|
|
34
|
+
submitLabel?: string;
|
|
35
|
+
action?: string;
|
|
36
|
+
layout?: string;
|
|
37
|
+
schema?: Record<string, any>[];
|
|
38
|
+
fields?: RegisterField[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
42
|
+
title: 'Create account',
|
|
43
|
+
subtitle: 'Fill in the form to create your account',
|
|
44
|
+
loginLabel: 'Already have an account?',
|
|
45
|
+
loginLinkLabel: 'Sign in',
|
|
46
|
+
loginLink: 'panel.auth.login',
|
|
47
|
+
submitLabel: 'Create account',
|
|
48
|
+
action: 'panel.auth.register.set',
|
|
49
|
+
layout: 'AuthLayout',
|
|
50
|
+
fields: () => [
|
|
51
|
+
{ name: 'email', type: 'email', label: 'Email address', required: true, autocomplete: 'email' },
|
|
52
|
+
{ name: 'password', type: 'password', label: 'Password', required: true, autocomplete: 'new-password' },
|
|
53
|
+
{
|
|
54
|
+
name: 'password_confirmation',
|
|
55
|
+
type: 'password',
|
|
56
|
+
label: 'Confirm password',
|
|
57
|
+
required: true,
|
|
58
|
+
autocomplete: 'new-password',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const resolvedLayout = computed(() => {
|
|
64
|
+
const key = (props.layout ?? 'AuthLayout').trim();
|
|
65
|
+
|
|
66
|
+
if (key === 'PanelLayout') {
|
|
67
|
+
return PanelLayout;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (key === 'AuthLayout') {
|
|
71
|
+
return AuthLayout;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return key || AuthLayout;
|
|
75
|
+
});
|
|
76
|
+
</script>
|
package/src/pages/Svarium.vue
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<Head>
|
|
3
|
+
<link v-if="seo?.canonical" rel="canonical" :href="seo.canonical" />
|
|
4
|
+
<meta v-if="seo?.robots" name="robots" :content="seo.robots" />
|
|
5
|
+
</Head>
|
|
2
6
|
<pre class="hidden">{{ tree }}</pre>
|
|
3
|
-
<main class="
|
|
7
|
+
<main class="bg-slate-100 dark:bg-slate-950">
|
|
4
8
|
<template v-if="Array.isArray(tree)">
|
|
5
9
|
<component
|
|
6
10
|
:is="renderNode(node)"
|
|
@@ -17,7 +21,7 @@
|
|
|
17
21
|
</template>
|
|
18
22
|
|
|
19
23
|
<script setup lang="ts">
|
|
20
|
-
import { usePage } from '@inertiajs/vue3';
|
|
24
|
+
import { Head, usePage } from '@inertiajs/vue3';
|
|
21
25
|
import { computed, h, isRef, ref, resolveComponent, watch } from 'vue';
|
|
22
26
|
import { Toaster } from 'vue-sonner';
|
|
23
27
|
import { toast } from 'vue-sonner';
|
|
@@ -64,11 +68,44 @@ function updateModelValue(modelContext: any, value: any): void {
|
|
|
64
68
|
emit('update:modelValue', value);
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
function shouldRenderVueIf(value: any): boolean {
|
|
72
|
+
if (typeof value === 'boolean') {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof value === 'number') {
|
|
77
|
+
return value !== 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof value === 'string') {
|
|
81
|
+
const normalized = value.trim().toLowerCase();
|
|
82
|
+
|
|
83
|
+
if (normalized === '' || normalized === 'false' || normalized === '0' || normalized === 'null' || normalized === 'undefined') {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (value === null || value === undefined) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return Boolean(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
67
97
|
function renderNode(node: any, modelContext?: any) {
|
|
68
98
|
if (!node || typeof node !== 'object') {
|
|
69
99
|
return null;
|
|
70
100
|
}
|
|
71
101
|
|
|
102
|
+
const rawNodeProps = node.props && typeof node.props === 'object' ? node.props : {};
|
|
103
|
+
if (Object.prototype.hasOwnProperty.call(rawNodeProps, 'vIf')) {
|
|
104
|
+
if (!shouldRenderVueIf(rawNodeProps.vIf)) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
72
109
|
const componentName = node.component ?? node.type;
|
|
73
110
|
|
|
74
111
|
if (!componentName) {
|
|
@@ -78,10 +115,29 @@ function renderNode(node: any, modelContext?: any) {
|
|
|
78
115
|
|
|
79
116
|
const component = resolveComponent(componentName);
|
|
80
117
|
const slots: Record<string, (...args: any[]) => any> = {};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
118
|
+
const nodeProps = { ...(node.props ?? {}) };
|
|
119
|
+
delete nodeProps.vIf;
|
|
120
|
+
const slotPlacementRaw =
|
|
121
|
+
nodeProps.__slotPlacement && typeof nodeProps.__slotPlacement === 'object'
|
|
122
|
+
? nodeProps.__slotPlacement
|
|
123
|
+
: {};
|
|
124
|
+
|
|
125
|
+
delete nodeProps.__slotPlacement;
|
|
126
|
+
|
|
127
|
+
const resolveSlotContext = (slotProps: any = {}, fallbackModelContext: any = modelContext) => {
|
|
128
|
+
const hasSlotModel =
|
|
129
|
+
Object.prototype.hasOwnProperty.call(slotProps, 'modelValue') ||
|
|
130
|
+
Object.prototype.hasOwnProperty.call(slotProps, 'tab');
|
|
131
|
+
|
|
132
|
+
return hasSlotModel || typeof slotProps?.updateModelValue === 'function'
|
|
133
|
+
? {
|
|
134
|
+
value: slotProps?.modelValue ?? slotProps?.tab ?? resolveModelValue(fallbackModelContext),
|
|
135
|
+
update: slotProps?.updateModelValue,
|
|
136
|
+
}
|
|
137
|
+
: (slotProps?.model ?? fallbackModelContext);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const slotContentMap: Record<string, any[]> = {};
|
|
85
141
|
|
|
86
142
|
if (node.slots && !Array.isArray(node.slots)) {
|
|
87
143
|
for (const [name, content] of Object.entries(node.slots)) {
|
|
@@ -89,28 +145,180 @@ function renderNode(node: any, modelContext?: any) {
|
|
|
89
145
|
continue;
|
|
90
146
|
}
|
|
91
147
|
|
|
148
|
+
slotContentMap[name] = content;
|
|
92
149
|
slots[name] = (slotProps: any = {}) => {
|
|
93
|
-
const
|
|
94
|
-
Object.prototype.hasOwnProperty.call(slotProps, 'modelValue') ||
|
|
95
|
-
Object.prototype.hasOwnProperty.call(slotProps, 'tab');
|
|
96
|
-
|
|
97
|
-
const slotModelContext =
|
|
98
|
-
hasSlotModel || typeof slotProps?.updateModelValue === 'function'
|
|
99
|
-
? {
|
|
100
|
-
value: slotProps?.modelValue ?? slotProps?.tab ?? resolveModelValue(modelContext),
|
|
101
|
-
update: slotProps?.updateModelValue,
|
|
102
|
-
}
|
|
103
|
-
: (slotProps?.model ?? modelContext);
|
|
104
|
-
|
|
150
|
+
const slotModelContext = resolveSlotContext(slotProps);
|
|
105
151
|
return content.map((child: any) => renderNode(child, slotModelContext));
|
|
106
152
|
};
|
|
107
153
|
}
|
|
108
154
|
}
|
|
109
155
|
|
|
156
|
+
const renderDefaultChildren = (slotProps: any = {}) => {
|
|
157
|
+
if (!Array.isArray(node.children) || node.children.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const slotModelContext = resolveSlotContext(slotProps);
|
|
162
|
+
return node.children.map((child: any) => renderNode(child, slotModelContext));
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
type PlacedSlot = {
|
|
166
|
+
slotName: string;
|
|
167
|
+
anchor: 'header' | 'footer';
|
|
168
|
+
position: 'before' | 'after';
|
|
169
|
+
priority: number | null;
|
|
170
|
+
order: number;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const placedSlots: PlacedSlot[] = [];
|
|
174
|
+
let placementFallbackOrder = 0;
|
|
175
|
+
|
|
176
|
+
for (const [slotName, config] of Object.entries(slotPlacementRaw as Record<string, any>)) {
|
|
177
|
+
if (!Array.isArray(slotContentMap[slotName])) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const anchor = String(config?.anchor ?? 'header').toLowerCase();
|
|
182
|
+
const position = String(config?.position ?? 'after').toLowerCase();
|
|
183
|
+
const normalizedAnchor: 'header' | 'footer' = anchor === 'footer' ? 'footer' : 'header';
|
|
184
|
+
const normalizedPosition: 'before' | 'after' = position === 'before' ? 'before' : 'after';
|
|
185
|
+
|
|
186
|
+
let normalizedPriority: number | null = null;
|
|
187
|
+
const rawPriority = config?.priority;
|
|
188
|
+
if (typeof rawPriority === 'number' && Number.isFinite(rawPriority)) {
|
|
189
|
+
normalizedPriority = rawPriority;
|
|
190
|
+
} else if (typeof rawPriority === 'string' && rawPriority.trim() !== '' && Number.isFinite(Number(rawPriority))) {
|
|
191
|
+
normalizedPriority = Number(rawPriority);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const rawOrder = config?.order;
|
|
195
|
+
let normalizedOrder = placementFallbackOrder;
|
|
196
|
+
if (typeof rawOrder === 'number' && Number.isFinite(rawOrder)) {
|
|
197
|
+
normalizedOrder = rawOrder;
|
|
198
|
+
} else if (typeof rawOrder === 'string' && rawOrder.trim() !== '' && Number.isFinite(Number(rawOrder))) {
|
|
199
|
+
normalizedOrder = Number(rawOrder);
|
|
200
|
+
}
|
|
201
|
+
placementFallbackOrder += 1;
|
|
202
|
+
|
|
203
|
+
placedSlots.push({
|
|
204
|
+
slotName,
|
|
205
|
+
anchor: normalizedAnchor,
|
|
206
|
+
position: normalizedPosition,
|
|
207
|
+
priority: normalizedPriority,
|
|
208
|
+
order: normalizedOrder,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const sortPlacedSlots = (items: PlacedSlot[]): string[] => {
|
|
213
|
+
return [...items]
|
|
214
|
+
.sort((a, b) => {
|
|
215
|
+
const aHasPriority = a.priority !== null;
|
|
216
|
+
const bHasPriority = b.priority !== null;
|
|
217
|
+
|
|
218
|
+
if (aHasPriority && bHasPriority) {
|
|
219
|
+
if (a.priority !== b.priority) {
|
|
220
|
+
return (a.priority as number) - (b.priority as number);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return a.order - b.order;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (aHasPriority !== bHasPriority) {
|
|
227
|
+
return aHasPriority ? -1 : 1;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return a.order - b.order;
|
|
231
|
+
})
|
|
232
|
+
.map((item) => item.slotName);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const beforeHeader = sortPlacedSlots(
|
|
236
|
+
placedSlots.filter((item) => item.anchor === 'header' && item.position === 'before'),
|
|
237
|
+
);
|
|
238
|
+
const afterHeader = sortPlacedSlots(
|
|
239
|
+
placedSlots.filter((item) => item.anchor === 'header' && item.position === 'after'),
|
|
240
|
+
);
|
|
241
|
+
const beforeFooter = sortPlacedSlots(
|
|
242
|
+
placedSlots.filter((item) => item.anchor === 'footer' && item.position === 'before'),
|
|
243
|
+
);
|
|
244
|
+
const afterFooter = sortPlacedSlots(
|
|
245
|
+
placedSlots.filter((item) => item.anchor === 'footer' && item.position === 'after'),
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
const placedSlotNames = new Set(placedSlots.map((item) => item.slotName));
|
|
249
|
+
|
|
250
|
+
if (placedSlotNames.size > 0) {
|
|
251
|
+
for (const slotName of placedSlotNames) {
|
|
252
|
+
delete slots[slotName];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const renderPlacedSlotNames = (slotNames: string[], slotProps: any = {}) => {
|
|
257
|
+
const slotModelContext = resolveSlotContext(slotProps);
|
|
258
|
+
const rendered: any[] = [];
|
|
259
|
+
|
|
260
|
+
for (const slotName of slotNames) {
|
|
261
|
+
const content = slotContentMap[slotName];
|
|
262
|
+
if (!Array.isArray(content) || content.length === 0) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
rendered.push(...content.map((child: any) => renderNode(child, slotModelContext)));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return rendered;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const hasMainHeader = !placedSlotNames.has('header') && Array.isArray(slotContentMap.header) && slotContentMap.header.length > 0;
|
|
273
|
+
const hasMainFooter = !placedSlotNames.has('footer') && Array.isArray(slotContentMap.footer) && slotContentMap.footer.length > 0;
|
|
274
|
+
const hasMainBody = !placedSlotNames.has('body') && Array.isArray(slotContentMap.body) && slotContentMap.body.length > 0;
|
|
275
|
+
|
|
276
|
+
const headerSlotOrder = [...beforeHeader, ...(hasMainHeader ? ['header'] : []), ...afterHeader];
|
|
277
|
+
const footerSlotOrder = [...beforeFooter, ...(hasMainFooter ? ['footer'] : []), ...afterFooter];
|
|
278
|
+
|
|
279
|
+
const hasStructuredSlots =
|
|
280
|
+
placedSlots.length > 0 || hasMainHeader || hasMainFooter || hasMainBody;
|
|
281
|
+
|
|
282
|
+
if (hasStructuredSlots) {
|
|
283
|
+
slots.header = (slotProps: any = {}) => renderPlacedSlotNames(headerSlotOrder, slotProps);
|
|
284
|
+
slots.footer = (slotProps: any = {}) => renderPlacedSlotNames(footerSlotOrder, slotProps);
|
|
285
|
+
slots.body = (slotProps: any = {}) => {
|
|
286
|
+
if (hasMainBody) {
|
|
287
|
+
return renderPlacedSlotNames(['body'], slotProps);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return renderDefaultChildren(slotProps);
|
|
291
|
+
};
|
|
292
|
+
if (placedSlots.length > 0) {
|
|
293
|
+
slots.default = (slotProps: any = {}) => {
|
|
294
|
+
const rendered: any[] = [];
|
|
295
|
+
|
|
296
|
+
rendered.push(...renderPlacedSlotNames(headerSlotOrder, slotProps));
|
|
297
|
+
if (hasMainBody) {
|
|
298
|
+
rendered.push(...renderPlacedSlotNames(['body'], slotProps));
|
|
299
|
+
} else {
|
|
300
|
+
rendered.push(...renderDefaultChildren(slotProps));
|
|
301
|
+
}
|
|
302
|
+
rendered.push(...renderPlacedSlotNames(footerSlotOrder, slotProps));
|
|
303
|
+
|
|
304
|
+
return rendered;
|
|
305
|
+
};
|
|
306
|
+
} else if (Array.isArray(node.children) && node.children.length) {
|
|
307
|
+
slots.default = (slotProps: any = {}) => renderDefaultChildren(slotProps);
|
|
308
|
+
}
|
|
309
|
+
} else if (Array.isArray(node.children) && node.children.length) {
|
|
310
|
+
slots.default = (slotProps: any = {}) => renderDefaultChildren(slotProps);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const normalizedProps = normalizeNodeProps(nodeProps);
|
|
314
|
+
if (Object.prototype.hasOwnProperty.call(normalizedProps, 'appearance')) {
|
|
315
|
+
delete normalizedProps.appearance;
|
|
316
|
+
}
|
|
317
|
+
|
|
110
318
|
return h(
|
|
111
319
|
component,
|
|
112
320
|
{
|
|
113
|
-
...
|
|
321
|
+
...normalizedProps,
|
|
114
322
|
modelValue: resolveModelValue(modelContext),
|
|
115
323
|
'onUpdate:modelValue': (value: any) => {
|
|
116
324
|
updateModelValue(modelContext, value);
|
|
@@ -130,6 +338,10 @@ type FlashMessages = {
|
|
|
130
338
|
|
|
131
339
|
const page = usePage();
|
|
132
340
|
const lastFlashFingerprint = ref('');
|
|
341
|
+
const seo = computed(() => {
|
|
342
|
+
const currentPage = page as unknown as { props?: { seo?: Record<string, any> } };
|
|
343
|
+
return currentPage.props?.seo ?? {};
|
|
344
|
+
});
|
|
133
345
|
|
|
134
346
|
const flash = computed<FlashMessages>(() => {
|
|
135
347
|
const currentPage = page as unknown as { flash?: unknown; props?: { flash?: unknown } };
|