diff --git a/.prettierrc b/.prettierrc index a77fdde..b7ef783 100644 --- a/.prettierrc +++ b/.prettierrc @@ -5,5 +5,6 @@ "printWidth": 100, "plugins": ["prettier-plugin-svelte"], "pluginSearchDirs": ["."], - "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }], + "tabWidth": 4 } diff --git a/src/config.yml b/src/config.yml index de9dbac..6613356 100644 --- a/src/config.yml +++ b/src/config.yml @@ -11,4 +11,5 @@ services: icon: 'fas fa-hard-drive' target: '_blank' url: '/NAS' + type: 'hello' keywords: 'cloud storage files' diff --git a/src/hooks.server.ts b/src/hooks.server.ts deleted file mode 100644 index 0aa0072..0000000 --- a/src/hooks.server.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { dev } from "$app/environment"; -import { clientConfig, stripPrivateFields, type Config } from "$lib/config"; -import type { Handle } from "@sveltejs/kit"; -import { readFile } from 'fs'; -import * as yml from 'js-yaml'; - -async function reloadConfig(): Promise { - try { - const dynamic = yml.load(await readFile('/dynamic/config.yml', 'utf8')); - return stripPrivateFields({ ...clientConfig, ...dynamic }); - } catch (err) { - return clientConfig; - } - -} - -export const handle: Handle = async ({ event, resolve }) => { - if ( dev == false ) { - Object.assign(event.locals,{config: await reloadConfig()}); - } - - const response = await resolve(event); - return response; -} diff --git a/src/lib/config.ts b/src/lib/config.ts index 7ab527d..fb48132 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,32 +1,33 @@ import configData from '../config.yml'; -export interface Brand { +export interface BrandConfig { logo?: string; icon?: string; usemask?: boolean; } -export interface Section extends Brand { +export interface SectionConfig extends BrandConfig { title: string; subtitle?: string; } -export interface Service extends Section { +export interface ServiceConfig extends SectionConfig { url: string; target?: string; type?: string; + data?: Record; [x: string]: unknown; } -export interface ServiceGroup extends Section { - items: Service[]; +export interface ServiceGroupConfig extends SectionConfig { + items: ServiceConfig[]; [x: string]: unknown; } -export interface Config extends Section { - services: ServiceGroup[]; +export interface Config extends SectionConfig { + services: ServiceGroupConfig[]; [x: string]: unknown; } @@ -46,9 +47,9 @@ const requiredConfig: DeepRequired = { items: [ { title: '', - url: '', + url: '' } - ], + ] } ] }; @@ -63,47 +64,44 @@ export const defaultConfig: Config = { services: [] }; +type SPOJO = Record; -type SPOJO = Record +function strip(toStrip: Type, reference: Type): Type { + const res: Type = { ...toStrip }; + const referenceNames = Object.entries(reference).map(([key, value]) => key); -function strip (toStrip: Type, reference: Type): Type { - const res: Type = {...toStrip} - const referenceNames = Object.entries(reference).map(([key,value]) => key) - - for ( const [key,value] of Object.entries(res) ) { - if ( referenceNames.includes(key) == false ) { + for (const [key, value] of Object.entries(res)) { + if (referenceNames.includes(key) == false) { // remove the object delete res[key]; - continue - } - - // strips further arrays - if ( value instanceof Array ) { - const stripped : SPOJO = {}; - const childRef = (reference[key] as Array)[0]; - stripped[key] = value.map((v: SPOJO) => strip(v,childRef)); - Object.assign(res,stripped); continue; } - if ( typeof value != "object") { - continue + // strips further arrays + if (value instanceof Array) { + const stripped: SPOJO = {}; + const childRef = (reference[key] as Array)[0]; + stripped[key] = value.map((v: SPOJO) => strip(v, childRef)); + Object.assign(res, stripped); + continue; + } + + if (typeof value != 'object') { + continue; } // it is a child object, we strip it further - const stripped : SPOJO = {}; - stripped[key] = strip(value as SPOJO,reference[key] as SPOJO); - Object.assign(res,stripped); - + const stripped: SPOJO = {}; + stripped[key] = strip(value as SPOJO, reference[key] as SPOJO); + Object.assign(res, stripped); } return res; } export function stripPrivateFields(config: Config): Config { - return strip(config,requiredConfig); + return strip(config, requiredConfig); } - export const config: Config = mergeConfig(defaultConfig, configData); -export const clientConfig :Config = stripPrivateFields(config) +export const clientConfig: Config = stripPrivateFields(config); diff --git a/src/lib/services/generic/GenericServiceCard.svelte b/src/lib/services/generic/GenericServiceCard.svelte new file mode 100644 index 0000000..dcb3c40 --- /dev/null +++ b/src/lib/services/generic/GenericServiceCard.svelte @@ -0,0 +1,9 @@ + + +
+ {data.title} +
diff --git a/src/lib/services/service.ts b/src/lib/services/service.ts new file mode 100644 index 0000000..a441996 --- /dev/null +++ b/src/lib/services/service.ts @@ -0,0 +1,27 @@ +import type { ServiceConfig } from '$lib/config'; + +interface ServiceHandlerArgs { + fetch: typeof fetch; + config: ServiceConfig; +} + +export type ServiceHandler = (input: Partial) => { + data: Record; + componentPath: string; +}; + +const services: Record = {}; + +export function registerService(type: string, handler: ServiceHandler) { + services[type] = handler; +} + +export function getService(type: string): ServiceHandler { + const handler = services[type]; + if (handler == undefined) { + return () => { + return { data: {}, componentPath: 'generic/GenericServiceCard.svelte' }; + }; + } + return handler; +} diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index d5a9976..3dc175b 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,12 +1,39 @@ import { dev } from '$app/environment'; -import { clientConfig, type Config } from '$lib/config'; +import { config, stripPrivateFields, type Config } from '$lib/config'; import type { PageServerLoad } from './$types'; +import * as yml from 'js-yaml'; +import { readFile } from 'fs/promises'; +import { getService } from '$lib/services/service'; - -export const load: PageServerLoad = ({locals}) => { +async function reloadConfig(): Promise { if (dev) { - return { config: clientConfig }; + return config; } + try { + const dynamic = yml.load(await readFile('/dynamic/config.yml', 'utf8')); + return { ...config, ...dynamic }; + } catch (err) { + return config; + } +} - return {config: (locals as Record).config || clientConfig}; +function zip(a: Array, b: Array): Array> { + const size = Math.min(a.length, b.length); + return a.slice(0, size).map((v, i) => [v, b[i]]); +} + +export const load: PageServerLoad = async ({ fetch, depends }) => { + depends('app:state'); + + const serverConfig = await reloadConfig(); + const clientConfig = stripPrivateFields(serverConfig); + + for (const [serverGroup, clientGroup] of zip(serverConfig.services, clientConfig.services)) { + for (const [serverService, clientService] of zip(serverGroup.items, clientGroup.items)) { + const handler = getService(serverService.type || ''); + Object.assign(clientService, handler({ fetch, config: serverService })); + } + } + clientConfig.timestamp = new Date(); + return { config: clientConfig }; }; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 94ee88f..0843d60 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,10 +1,20 @@

{data.config.title}

{#if data.config.subtitle}

{data.config.subtitle}

{/if} + +
 {JSON.stringify(data.config, null, 4)} 
diff --git a/src/routes/+page.ts b/src/routes/+page.ts new file mode 100644 index 0000000..0385991 --- /dev/null +++ b/src/routes/+page.ts @@ -0,0 +1,15 @@ +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ data }) => { + for (const group of data.config.services) { + for (const service of group.items) { + const path = + '../lib/services/' + (service.componentPath || 'generic/GenericServiceCard.svelte'); + const module = await import(/* @vite-ignore */ path); + + service.component = module.default; + delete service.componentPath; + } + } + return { config: data.config }; +};