40 lines
1.1 KiB
Vue
40 lines
1.1 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
import { useSlot } from '@/composables/useVanguard';
|
|
import { resolveSlot } from '@/vanguard';
|
|
|
|
const props = defineProps<{
|
|
/** Slot position name, e.g. "navbar:items". */
|
|
name: string;
|
|
/**
|
|
* Payloads for page scoped positions (e.g. "user:show"), which the owning
|
|
* controller resolves and passes as a page prop. Global positions such as
|
|
* "navbar:items" come from shared props and need nothing here.
|
|
*/
|
|
payloads?: Array<{ component: string; props: Record<string, unknown> }>;
|
|
}>();
|
|
|
|
const sharedPayloads = useSlot(props.name);
|
|
|
|
const entries = computed(() => {
|
|
const payloads = props.payloads ?? sharedPayloads.value;
|
|
|
|
return payloads
|
|
.map((payload) => ({
|
|
component: resolveSlot(payload.component),
|
|
props: payload.props,
|
|
key: payload.component,
|
|
}))
|
|
.filter((entry) => entry.component !== undefined);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<component
|
|
:is="entry.component"
|
|
v-for="entry in entries"
|
|
:key="entry.key"
|
|
v-bind="entry.props"
|
|
/>
|
|
</template>
|