breaking changes, major refactoring of Composite
This commit is contained in:
parent
858d21e7db
commit
0161f4ba4f
@ -1,147 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Composite from './Composite.svelte';
|
||||
import components from '$lib/componentLoader';
|
||||
import services from '$lib/servicesLoader';
|
||||
import { createComponentStore, getComponentStore } from '$lib/stores/componentStores.ts';
|
||||
|
||||
interface ICompositeLayout {
|
||||
areas: string;
|
||||
columns?: string;
|
||||
rows?: string;
|
||||
gap?: string;
|
||||
tailwindClasses?: string;
|
||||
}
|
||||
|
||||
export let componentsData: {
|
||||
layout: ICompositeLayout;
|
||||
children: Array<any>;
|
||||
};
|
||||
|
||||
$: layoutStyle = `
|
||||
grid-template-areas: ${componentsData.layout.areas};
|
||||
${componentsData.layout.gap ? `gap: ${componentsData.layout.gap};` : ''}
|
||||
${
|
||||
componentsData.layout.columns
|
||||
? `grid-template-columns: ${componentsData.layout.columns};`
|
||||
: ''
|
||||
}
|
||||
${componentsData.layout.rows ? `grid-template-rows: ${componentsData.layout.rows};` : ''}
|
||||
`;
|
||||
|
||||
function initializeComponentState(child) {
|
||||
child.store = createComponentStore(child.id, child.store || {});
|
||||
|
||||
if (child.children) {
|
||||
child.children.forEach(initializeComponentState);
|
||||
}
|
||||
}
|
||||
|
||||
$: if (componentsData && componentsData.children) {
|
||||
componentsData.children.forEach(initializeComponentState);
|
||||
}
|
||||
|
||||
function mapAndSubscribe(component) {
|
||||
console.log('Mapping and subscribing for:', component.id);
|
||||
|
||||
if (component.map) {
|
||||
const localStore = getComponentStore(component.id);
|
||||
|
||||
for (const [localKey, external] of Object.entries(component.map)) {
|
||||
const [externalID, externalKey] = external.split('.').map((item) => item.trim());
|
||||
const externalStore = getComponentStore(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 (componentsData && componentsData.children) {
|
||||
componentsData.children.forEach(mapAndSubscribe);
|
||||
}
|
||||
|
||||
async function getComponent(componentName) {
|
||||
if (components[componentName]) {
|
||||
const module = await components[componentName]();
|
||||
return module.default;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function loadService(serviceName) {
|
||||
if (services[serviceName]) {
|
||||
const module = await services[serviceName]();
|
||||
return module.default || module;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function getServiceProps(component) {
|
||||
const loadedServices = [];
|
||||
if (component.services) {
|
||||
for (const serviceName of component.services) {
|
||||
const loadedService = await loadService(serviceName);
|
||||
if (loadedService) {
|
||||
loadedServices.push(loadedService);
|
||||
}
|
||||
}
|
||||
}
|
||||
return loadedServices;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class={`grid w-full h-full ${componentsData.layout.tailwindClasses}`} style={layoutStyle}>
|
||||
{#each componentsData.children as component (component.id)}
|
||||
<div class={`w-full h-full overflow-hidden`} style={`grid-area: ${component.slot}`}>
|
||||
{#await Promise.all( [getComponent(component.componentName), getServiceProps(component)] ) then [Component, serviceProps]}
|
||||
{#if Component}
|
||||
<svelte:component
|
||||
this={Component}
|
||||
id={component.id}
|
||||
{...component.props}
|
||||
{...serviceProps.reduce((acc, currServiceModule, idx) => {
|
||||
acc[component.services[idx]] = currServiceModule;
|
||||
return acc;
|
||||
}, {})}
|
||||
/>
|
||||
|
||||
{#if component.actions}
|
||||
<div class="flex justify-end p-4">
|
||||
{#each component.actions as action}
|
||||
{#await getComponent(action) then ActionComponent}
|
||||
{#if ActionComponent}
|
||||
<svelte:component this={ActionComponent} {...component.props} />
|
||||
{:else}
|
||||
<p>Action {action} not found.</p>
|
||||
{/if}
|
||||
{/await}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if component.children && component.children.length}
|
||||
<Composite componentsData={component} />
|
||||
{/if}
|
||||
{:else}
|
||||
<p>Component {component.componentName} not found.</p>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
@ -8,7 +8,7 @@
|
||||
|
||||
const redirectUri = 'http://localhost:5173/';
|
||||
|
||||
export let setupLit;
|
||||
export let services;
|
||||
|
||||
let view = 'sign_in';
|
||||
let sessionSigs;
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
provider = await setupLit.connectProvider();
|
||||
provider = await services.setupLit.connectProvider();
|
||||
|
||||
logMessage('Component mounted.');
|
||||
|
||||
|
@ -1,16 +1,19 @@
|
||||
<script>
|
||||
export let id;
|
||||
|
||||
import { getComponentStore } from '$lib/stores/componentStores.ts';
|
||||
import { getCompositeStore } from '$lib/core/compositeStores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const store = getComponentStore(id);
|
||||
const store = getCompositeStore(id);
|
||||
|
||||
export let helloEarthAlert;
|
||||
export let services;
|
||||
|
||||
onMount(async () => {
|
||||
helloEarthAlert.alertMe();
|
||||
console.log('should alerted by now');
|
||||
if (services && services.helloEarthAlert) {
|
||||
console.log('Alerted by HelloEarthAlert');
|
||||
} else {
|
||||
console.error('Services or helloEarthAlert not loaded');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { messages } from '$lib/services/messages';
|
||||
import { onMount, afterUpdate } from 'svelte';
|
||||
import Composite from './Composite.svelte';
|
||||
import Composite from '$lib/core/Composite.svelte';
|
||||
|
||||
let latestMessages = [];
|
||||
|
||||
|
@ -13,16 +13,14 @@
|
||||
const match = text.match(appCommandPattern);
|
||||
if (match && match[1]) {
|
||||
message.composite = {
|
||||
layout: '',
|
||||
children: [
|
||||
{
|
||||
componentName: match[1], // Matched component name
|
||||
props: {},
|
||||
actions: ['ClearMessages']
|
||||
component: match[1] // Matched component name
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
console.log(message);
|
||||
|
||||
createMessage(message);
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { connectWallet } from '$lib/services/wallet/wallet';
|
||||
import { getComponentStore } from '$lib/stores/componentStores.ts';
|
||||
import { getCompositeStore } from '$lib/core/compositeStores';
|
||||
|
||||
export let id;
|
||||
const store = getComponentStore(id);
|
||||
const store = getCompositeStore(id);
|
||||
|
||||
onMount(async () => {
|
||||
$store.pkpWallet = await connectWallet($store.pkpPubKey, $store.rpcURL);
|
||||
|
144
src/lib/core/Composite.svelte
Normal file
144
src/lib/core/Composite.svelte
Normal file
@ -0,0 +1,144 @@
|
||||
<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;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={composite?.layout
|
||||
? `grid w-full h-full ${composite.layout.tailwindClasses}`
|
||||
: 'grid w-full h-full'}
|
||||
style={layoutStyle}
|
||||
>
|
||||
{#if composite && composite.children}
|
||||
{#each composite.children as child (child.id)}
|
||||
<div class={`w-full h-full overflow-hidden`} style={`grid-area: ${child.slot}`}>
|
||||
{#await Promise.all( [getComponent(child.component), getServiceProps(child)] ) then [Component, serviceProps]}
|
||||
{#if Component}
|
||||
<svelte:component
|
||||
this={Component}
|
||||
id={child.id}
|
||||
{...child.store}
|
||||
services={serviceProps}
|
||||
/>
|
||||
{#if child.children && child.children.length}
|
||||
<Composite composite={child} />
|
||||
{/if}
|
||||
{:else}
|
||||
<p>Component {child.component} not found.</p>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
16
src/lib/core/compositeStores.ts
Normal file
16
src/lib/core/compositeStores.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const compositeStores = new Map();
|
||||
|
||||
// Create or retrieve a composite store
|
||||
export function createCompositeStore(compositeId: string, initialState = {}) {
|
||||
if (!compositeStores.has(compositeId)) {
|
||||
compositeStores.set(compositeId, writable(initialState));
|
||||
}
|
||||
return compositeStores.get(compositeId);
|
||||
}
|
||||
|
||||
// Get composite store or create a default empty one if not exists
|
||||
export function getCompositeStore(compositeId: string) {
|
||||
return compositeStores.get(compositeId) || createCompositeStore(compositeId);
|
||||
}
|
16
src/lib/core/servicesLoader.ts
Normal file
16
src/lib/core/servicesLoader.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import serviceNames from 'virtual:services-list';
|
||||
|
||||
const services: { [key: string]: Function } = {};
|
||||
|
||||
serviceNames.forEach(path => {
|
||||
const serviceName = path.split('/').pop().replace('.ts', '');
|
||||
services[serviceName] = () => import(/* @vite-ignore */ `/src/lib/services/${path}`)
|
||||
.then(mod => {
|
||||
console.log(`Loaded service ${serviceName} with the following properties:`, Object.keys(mod));
|
||||
if (mod.default) return mod.default;
|
||||
return mod;
|
||||
});
|
||||
});
|
||||
|
||||
export default services;
|
||||
|
@ -4,7 +4,7 @@ import { LitAccessControlConditionResource, LitAbility } from '@lit-protocol/aut
|
||||
export async function createLitSession(
|
||||
provider: IProvider,
|
||||
pkpPublicKey: string,
|
||||
authMethod: any
|
||||
authMethod: any,
|
||||
): Promise<any> {
|
||||
const litResource = new LitAccessControlConditionResource('*');
|
||||
return await provider.getSessionSigs({
|
||||
|
@ -1,10 +0,0 @@
|
||||
import serviceNames from 'virtual:services-list';
|
||||
|
||||
const services = {};
|
||||
|
||||
serviceNames.forEach(path => {
|
||||
const name = path.split('/').pop().replace('.ts', ''); // Extract just the file name from the path without .ts
|
||||
services[name] = () => import(/* @vite-ignore */ `/src/lib/services/${path}`).then(mod => mod);
|
||||
});
|
||||
|
||||
export default services;
|
@ -1,16 +0,0 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const componentStores = new Map();
|
||||
|
||||
// Create or retrieve a component store
|
||||
export function createComponentStore(componentId, initialState = {}) {
|
||||
if (!componentStores.has(componentId)) {
|
||||
componentStores.set(componentId, writable(initialState));
|
||||
}
|
||||
return componentStores.get(componentId);
|
||||
}
|
||||
|
||||
// Get component store or create a default empty one if not exists
|
||||
export function getComponentStore(componentId) {
|
||||
return componentStores.get(componentId) || createComponentStore(componentId);
|
||||
}
|
@ -1,36 +1,24 @@
|
||||
<script>
|
||||
import Composite from '$lib/components/Composite.svelte';
|
||||
import Wallet from '$lib/Wallet.svelte';
|
||||
import HelloEarth from '$lib/components/HelloEarth/HelloEarth.svelte';
|
||||
import Composite from '$lib/core/Composite.svelte';
|
||||
|
||||
let componentsData = {
|
||||
let composite = {
|
||||
id: 'composite',
|
||||
layout: {
|
||||
areas: `
|
||||
"header main"
|
||||
"aside main"
|
||||
"footer footer";
|
||||
"top top top"
|
||||
"main main main"
|
||||
"footer footer footer";
|
||||
`,
|
||||
columns: '1fr 1fr',
|
||||
rows: 'auto 1fr auto'
|
||||
columns: '1fr 1fr 1fr',
|
||||
rows: '1fr 1fr auto'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: '1',
|
||||
componentName: 'GoogleAuth',
|
||||
slot: 'header',
|
||||
services: ['setupLit']
|
||||
},
|
||||
{
|
||||
id: 'messages',
|
||||
componentName: 'Messages',
|
||||
slot: 'main',
|
||||
store: {
|
||||
prop1: 'prop1',
|
||||
prop2: 'prop2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'wallet',
|
||||
componentName: 'Wallet',
|
||||
slot: 'aside',
|
||||
component: 'Wallet',
|
||||
slot: 'top',
|
||||
store: {
|
||||
pkpWallet: '',
|
||||
rpcURL: 'https://rpc.gnosischain.com/',
|
||||
@ -39,12 +27,17 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
componentName: 'Terminal',
|
||||
id: 'messages',
|
||||
component: 'Messages',
|
||||
slot: 'main'
|
||||
},
|
||||
{
|
||||
id: 'terminal',
|
||||
component: 'Terminal',
|
||||
slot: 'footer'
|
||||
}
|
||||
]
|
||||
};
|
||||
</script>
|
||||
|
||||
<Composite {componentsData} />
|
||||
<Composite {composite} />
|
||||
|
Loading…
Reference in New Issue
Block a user