164 lines
4.5 KiB
Svelte
164 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import Composite from './Composite.svelte';
|
|
import components from '$lib/core/componentLoader';
|
|
import services from '$lib/core/servicesLoader';
|
|
import { createCompositeStore, getCompositeStore } from '$lib/core/compositeStores';
|
|
|
|
interface IComposite {
|
|
layout?: ICompositeLayout;
|
|
id: string;
|
|
slot?: string;
|
|
component: string;
|
|
services?: string[];
|
|
map?: Record<string, string>;
|
|
store?: Record<string, any>;
|
|
children?: IComposite[];
|
|
}
|
|
|
|
interface ICompositeLayout {
|
|
areas: string;
|
|
columns?: string;
|
|
rows?: string;
|
|
gap?: string;
|
|
tailwindClasses?: string;
|
|
}
|
|
|
|
export let composite: IComposite;
|
|
|
|
$: layoutStyle = composite?.layout
|
|
? `
|
|
grid-template-areas: ${composite.layout.areas};
|
|
${composite.layout.gap ? `gap: ${composite.layout.gap};` : ''}
|
|
${composite.layout.columns ? `grid-template-columns: ${composite.layout.columns};` : ''}
|
|
${composite.layout.rows ? `grid-template-rows: ${composite.layout.rows};` : ''}
|
|
`
|
|
: '';
|
|
|
|
function initializeCompositeState(child: IComposite) {
|
|
if (child.id) {
|
|
child.store = createCompositeStore(child.id, child.store || {});
|
|
}
|
|
|
|
if (child.children) {
|
|
child.children.forEach(initializeCompositeState);
|
|
}
|
|
}
|
|
|
|
$: if (composite && composite.children) {
|
|
composite.children.forEach(initializeCompositeState);
|
|
}
|
|
|
|
function mapAndSubscribe(component: IComposite) {
|
|
console.log('Mapping and subscribing for:', component.id);
|
|
|
|
if (component.map) {
|
|
const localStore = getCompositeStore(component.id);
|
|
|
|
for (const [localKey, external] of Object.entries(component.map)) {
|
|
const [externalID, externalKey] = external.split('.').map((item) => item.trim());
|
|
const externalStore = getCompositeStore(externalID);
|
|
if (externalStore) {
|
|
externalStore.subscribe((externalState) => {
|
|
console.log('External state:', externalState);
|
|
if (externalState && externalKey in externalState) {
|
|
localStore.update((storeValue) => {
|
|
storeValue = storeValue || {};
|
|
if (storeValue[localKey] !== externalState[externalKey]) {
|
|
storeValue[localKey] = externalState[externalKey];
|
|
return storeValue;
|
|
}
|
|
return storeValue;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (component.children) {
|
|
component.children.forEach(mapAndSubscribe);
|
|
}
|
|
}
|
|
|
|
$: if (composite && composite.children) {
|
|
composite.children.forEach(mapAndSubscribe);
|
|
}
|
|
|
|
async function getComponent(componentName: string) {
|
|
if (components[componentName]) {
|
|
const module = await components[componentName]();
|
|
return module.default;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function loadService(serviceName: string) {
|
|
if (services[serviceName]) {
|
|
const module = await services[serviceName]();
|
|
return module.default || module;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
async function getServiceProps(component: IComposite) {
|
|
const loadedServices = {};
|
|
if (component.services) {
|
|
for (const serviceName of component.services) {
|
|
const loadedService = await loadService(serviceName);
|
|
if (loadedService) {
|
|
loadedServices[serviceName] = loadedService;
|
|
}
|
|
}
|
|
}
|
|
return loadedServices;
|
|
}
|
|
// Additional utility function to get component and service props
|
|
async function loadComponentAndService(component: IComposite) {
|
|
return await Promise.all([getComponent(component.component), getServiceProps(component)]);
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
class={composite?.layout
|
|
? `grid w-full h-full ${composite.layout.tailwindClasses}`
|
|
: 'grid w-full h-full'}
|
|
style={layoutStyle}
|
|
>
|
|
{#if composite && 'component' in composite}
|
|
{#await loadComponentAndService(composite) then [Component, serviceProps]}
|
|
{#if Component}
|
|
<svelte:component
|
|
this={Component}
|
|
id={composite.id}
|
|
store={getCompositeStore(composite.id)}
|
|
services={serviceProps}
|
|
/>
|
|
{:else if composite.component}
|
|
<p>Component {composite.component} not found.</p>
|
|
{/if}
|
|
{/await}
|
|
{/if}
|
|
|
|
{#if composite?.children}
|
|
{#each composite.children as child (child.id)}
|
|
<div class={`w-full h-full overflow-hidden`} style={`grid-area: ${child.slot}`}>
|
|
{#await loadComponentAndService(child) then [ChildComponent, childServiceProps]}
|
|
{#if ChildComponent}
|
|
<svelte:component
|
|
this={ChildComponent}
|
|
id={child.id}
|
|
store={getCompositeStore(child.id)}
|
|
services={childServiceProps}
|
|
/>
|
|
{#if child.children && child.children.length}
|
|
<Composite composite={child} />
|
|
{/if}
|
|
{:else if child.component}
|
|
<p>Component {child.component} not found.</p>
|
|
{/if}
|
|
{/await}
|
|
</div>
|
|
{/each}
|
|
{/if}
|
|
</div>
|