mirror of
https://github.com/immich-app/static-pages.git
synced 2026-09-30 13:23:05 +08:00
refactor: site metadata
This commit is contained in:
@@ -4,6 +4,7 @@ pnpm-lock.yaml
|
||||
yarn.lock
|
||||
src/lib/assets
|
||||
dist/
|
||||
deployment/
|
||||
CHANGELOG.md
|
||||
.svelte-kit/
|
||||
.release-please-manifest.json
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
ControlBarHeader,
|
||||
ControlBarOverflow,
|
||||
getSiteProviders,
|
||||
globalManager,
|
||||
Logo,
|
||||
ThemeSwitcher,
|
||||
TooltipProvider,
|
||||
@@ -26,6 +27,7 @@
|
||||
|
||||
const { children }: Props = $props();
|
||||
|
||||
globalManager.setSiteMetadata(siteMetadata);
|
||||
commandPaletteManager.enable();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
let filteredCategories = $derived(filterProjects(query));
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} />
|
||||
<SiteMetadata />
|
||||
|
||||
<Heading size="giant">{siteMetadata.title}</Heading>
|
||||
<Text size="large" color="muted">{siteMetadata.description}</Text>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { siteMetadata } from '$lib';
|
||||
import { Card, CardBody, Container, Heading, SiteMetadata, Text } from '@immich/ui';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { Snippet } from 'svelte';
|
||||
@@ -22,7 +21,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} page={pageMetadata} />
|
||||
<SiteMetadata page={pageMetadata} />
|
||||
|
||||
<Container size="medium" center>
|
||||
<section class="flex flex-col gap-2">
|
||||
|
||||
@@ -4,13 +4,6 @@ import { defaultProvider, type ActionItem } from '@immich/ui';
|
||||
import fm from 'front-matter';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
export const siteMetadata = {
|
||||
title: 'Immich',
|
||||
description:
|
||||
'Self-hosted photo and video management solution. Easily back up, organize, and manage your photos on your own server. Immich helps you browse, search and organize your photos and videos with ease, without sacrificing your privacy.',
|
||||
imageUrl: '/img/social-preview.png',
|
||||
};
|
||||
|
||||
export const blogMetadata = {
|
||||
title: 'Immich Blog',
|
||||
description: 'Latest updates, announcements, and stories from the Immich team.',
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
CommandPaletteProvider,
|
||||
Constants,
|
||||
getSiteProviders,
|
||||
globalManager,
|
||||
IconButton,
|
||||
Link,
|
||||
Logo,
|
||||
@@ -77,6 +78,12 @@
|
||||
return active ? 'primary' : 'secondary';
|
||||
};
|
||||
|
||||
globalManager.setSiteMetadata({
|
||||
title: 'Immich',
|
||||
description:
|
||||
'Self-hosted photo and video management solution. Easily back up, organize, and manage your photos on your own server. Immich helps you browse, search and organize your photos and videos with ease, without sacrificing your privacy.',
|
||||
imageUrl: '/img/social-preview.png',
|
||||
});
|
||||
commandPaletteManager.enable();
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import qrCodeLight from '$common/img/app-qr-code-light.svg';
|
||||
import screenshotDark from '$common/img/screenshot-dark.webp';
|
||||
import screenshotLight from '$common/img/screenshot-light.webp';
|
||||
import { siteMetadata } from '$lib';
|
||||
import {
|
||||
appStoreBadge,
|
||||
Button,
|
||||
@@ -30,8 +29,7 @@
|
||||
];
|
||||
</script>
|
||||
|
||||
<!-- only SSR SiteMetadata -->
|
||||
<SiteMetadata site={siteMetadata} />
|
||||
<SiteMetadata />
|
||||
|
||||
{#if browser}
|
||||
<VStack gap={8} class="mt-4 text-center lg:mt-16">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { TimelineItem } from '$lib';
|
||||
import { posts, siteMetadata } from '$lib';
|
||||
import { posts } from '$lib';
|
||||
import Timeline from '$lib/components/Timeline.svelte';
|
||||
import { asGithubLink, Heading, SiteMetadata, Stack, Text } from '@immich/ui';
|
||||
import {
|
||||
@@ -234,7 +234,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} page={pageMetadata} />
|
||||
<SiteMetadata page={pageMetadata} />
|
||||
|
||||
<Stack class="text-center" gap={4}>
|
||||
<Heading size="title" tag="h1">{pageMetadata.title}</Heading>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import portainerIcon from '$common/img/portainer.svg';
|
||||
import truenasIcon from '$common/img/truenas-scale.svg';
|
||||
import unraidIcon from '$common/img/unraid.svg';
|
||||
import { siteMetadata } from '$lib';
|
||||
import {
|
||||
appStoreBadge,
|
||||
Button,
|
||||
@@ -30,7 +29,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} page={pageMetadata} />
|
||||
<SiteMetadata page={pageMetadata} />
|
||||
|
||||
<Heading size="title" class="mb-4" tag="h1">{pageMetadata.title}</Heading>
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { siteMetadata } from '$lib';
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
@@ -256,7 +255,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} page={pageMetadata} />
|
||||
<SiteMetadata page={pageMetadata} />
|
||||
|
||||
<Stack gap={8}>
|
||||
<Stack>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type { TimelineItem } from '$lib';
|
||||
import { siteMetadata } from '$lib';
|
||||
import Timeline from '$lib/components/Timeline.svelte';
|
||||
import { Heading, SiteMetadata, Stack, Text } from '@immich/ui';
|
||||
import {
|
||||
@@ -947,7 +946,7 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} page={pageMetadata} />
|
||||
<SiteMetadata page={pageMetadata} />
|
||||
|
||||
<Stack class="text-center" gap={4}>
|
||||
<Heading size="title" tag="h1">Roadmap</Heading>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<script lang="ts">
|
||||
import MarkdownPage from '$lib/components/MarkdownPage.svelte';
|
||||
import { type ContainerSize } from '@immich/ui';
|
||||
import { Markdown, type ContainerSize } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
description: string;
|
||||
descriptionBody?: Snippet;
|
||||
size?: ContainerSize;
|
||||
children?: Snippet;
|
||||
};
|
||||
|
||||
const { size, name, description, children }: Props = $props();
|
||||
const { size, name, description, descriptionBody, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<MarkdownPage attributes={{ title: name, description }} {size} {children} />
|
||||
<Markdown.Page attributes={{ title: name, description }} description={descriptionBody} {size} {children} />
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<script lang="ts">
|
||||
import PageDescription from '$lib/components/PageDescription.svelte';
|
||||
import { siteMetadata } from '$lib/constants.js';
|
||||
import { Container, Heading, SiteMetadata, type BreadcrumbItem, type ContainerSize } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
attributes: { title: string; description: string };
|
||||
size?: ContainerSize;
|
||||
breadcrumbs?: BreadcrumbItem[];
|
||||
children?: Snippet;
|
||||
};
|
||||
|
||||
const { attributes, size = 'medium', children }: Props = $props();
|
||||
const { title, description } = $derived(attributes);
|
||||
|
||||
const page = $derived({ title, description });
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} {page} />
|
||||
|
||||
<Container {size} center class="my-4 flex flex-col p-4 lg:my-8">
|
||||
<section class="mb-8">
|
||||
<Heading tag="h1" size="giant">{page.title}</Heading>
|
||||
{#if page.description}
|
||||
<PageDescription>{page.description}</PageDescription>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{@render children?.()}
|
||||
</Container>
|
||||
@@ -1,12 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Text } from '@immich/ui';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
children: Snippet;
|
||||
};
|
||||
|
||||
const { children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<Text color="muted" size="large" class="mt-2" {children} />
|
||||
@@ -106,11 +106,6 @@ export type ExampleItem = {
|
||||
|
||||
export type ExampleCardProps = ExampleItem;
|
||||
|
||||
export const siteMetadata = {
|
||||
title: 'Immich UI',
|
||||
description: 'A Svelte component library for Immich',
|
||||
};
|
||||
|
||||
export type ComponentItem = {
|
||||
name: string;
|
||||
title?: string;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts">
|
||||
import ComponentCard from '$lib/components/ComponentCard.svelte';
|
||||
import Grid from '$lib/components/Grid.svelte';
|
||||
import MarkdownPage from '$lib/components/MarkdownPage.svelte';
|
||||
import { components } from '$lib/constants.js';
|
||||
import { Markdown } from '@immich/ui';
|
||||
</script>
|
||||
|
||||
<MarkdownPage attributes={{ title: 'Components', description: 'A list of all the Immich UI components' }} size="large">
|
||||
<Markdown.Page attributes={{ title: 'Components', description: 'A list of all the Immich UI components' }} size="large">
|
||||
<Grid>
|
||||
{#each components as component (component.name)}
|
||||
<ComponentCard {component} />
|
||||
{/each}
|
||||
</Grid>
|
||||
</MarkdownPage>
|
||||
</Markdown.Page>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import ComponentExamples from '$lib/components/ComponentExamples.svelte';
|
||||
import ComponentLink from '$lib/components/ComponentLink.svelte';
|
||||
import ComponentPage from '$lib/components/ComponentPage.svelte';
|
||||
import PageDescription from '$lib/components/PageDescription.svelte';
|
||||
import BasicExample from './BasicExample.svelte';
|
||||
import basicExample from './BasicExample.svelte?raw';
|
||||
import ColorExample from './ColorExample.svelte';
|
||||
@@ -22,7 +21,9 @@
|
||||
</script>
|
||||
|
||||
<ComponentPage name="IconButton" description="An icon-only version of the Button component">
|
||||
<PageDescription>An icon-only version of the <ComponentLink name="Button" /> component</PageDescription>
|
||||
{#snippet descriptionBody()}
|
||||
An icon-only version of the <ComponentLink name="Button" /> component
|
||||
{/snippet}
|
||||
<ComponentExamples
|
||||
examples={[
|
||||
{ title: 'Basic', code: basicExample, component: BasicExample },
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import ComponentExamples from '$lib/components/ComponentExamples.svelte';
|
||||
import ComponentPage from '$lib/components/ComponentPage.svelte';
|
||||
import PageDescription from '$lib/components/PageDescription.svelte';
|
||||
import { asComponentHref } from '$lib/utilities.js';
|
||||
import { Link } from '@immich/ui';
|
||||
import { Link, Text } from '@immich/ui';
|
||||
import BasicExample from './BasicExample.svelte';
|
||||
import basicExample from './BasicExample.svelte?raw';
|
||||
import ExpandExample from './ExpandExample.svelte';
|
||||
@@ -15,10 +14,10 @@
|
||||
</script>
|
||||
|
||||
<ComponentPage name="Navbar" description="A component for creating navigation items in a sidebar">
|
||||
<PageDescription
|
||||
>This component exports a NavbarItem for creating navigation menus. This is usually used in conjunction with the <Link
|
||||
<Text>
|
||||
This component exports a NavbarItem for creating navigation menus. This is usually used in conjunction with the <Link
|
||||
href={asComponentHref('AppShell')}>AppSidebar</Link
|
||||
> component</PageDescription
|
||||
> component</Text
|
||||
>
|
||||
<ComponentExamples
|
||||
examples={[
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<script lang="ts">
|
||||
import ComponentExamples from '$lib/components/ComponentExamples.svelte';
|
||||
import ComponentPage from '$lib/components/ComponentPage.svelte';
|
||||
import PageDescription from '$lib/components/PageDescription.svelte';
|
||||
import BasicExample from './BasicExample.svelte';
|
||||
import basicExample from './BasicExample.svelte?raw';
|
||||
</script>
|
||||
|
||||
<ComponentPage name="Tooltip" description="A component for displaying tooltips on hover or focus">
|
||||
<PageDescription>
|
||||
Displays supplementary information when users hover over or interact with an element.
|
||||
</PageDescription>
|
||||
|
||||
<ComponentPage
|
||||
name="Tooltip"
|
||||
description="Display supplementary information when users hover over or interact with an element"
|
||||
>
|
||||
<ComponentExamples examples={[{ title: 'Basic', code: basicExample, component: BasicExample }]} />
|
||||
</ComponentPage>
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
<script lang="ts">
|
||||
import '$lib/app.css';
|
||||
import { getDocsProviders } from '$lib/constants.js';
|
||||
import {
|
||||
commandPaletteManager,
|
||||
CommandPaletteProvider,
|
||||
getSiteProviders,
|
||||
globalManager,
|
||||
ScreencastOverlay,
|
||||
toastManager,
|
||||
TooltipProvider,
|
||||
} from '@immich/ui';
|
||||
import '@immich/ui/theme/default.css';
|
||||
import '$lib/app.css';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
toastManager.setOptions({ class: 'top-[58px]' });
|
||||
|
||||
globalManager.setSiteMetadata({
|
||||
title: 'Immich UI',
|
||||
description: 'A Svelte component library for Immich',
|
||||
});
|
||||
commandPaletteManager.enable();
|
||||
commandPaletteManager.setTranslations({
|
||||
command_palette_prompt_default: 'Quickly find components, links, and commands',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import imageUrl from '$lib/assets/design_placeholder.svg';
|
||||
import { siteMetadata } from '$lib/constants.js';
|
||||
import {
|
||||
AppShell,
|
||||
AppShellHeader,
|
||||
@@ -23,7 +22,7 @@
|
||||
import { mdiCodeBraces, mdiOpenInNew } from '@mdi/js';
|
||||
</script>
|
||||
|
||||
<SiteMetadata site={siteMetadata} />
|
||||
<SiteMetadata />
|
||||
|
||||
<AppShell>
|
||||
<AppShellHeader class="w-full">
|
||||
|
||||
@@ -11,7 +11,7 @@ const config = {
|
||||
preprocess: [
|
||||
svelteMarkdownPreprocess({
|
||||
layouts: {
|
||||
default: '$lib/components/MarkdownPage.svelte',
|
||||
default: { name: 'Markdown.Page', source: '@immich/ui', import: false },
|
||||
},
|
||||
}),
|
||||
vitePreprocess(),
|
||||
|
||||
+2
-1
@@ -72,10 +72,11 @@ export default defineConfig([
|
||||
'apps/**/backend/dist',
|
||||
'apps/**/.wrangler',
|
||||
'apps/**/backend/worker-configuration.d.ts',
|
||||
'common/',
|
||||
'deployment/**',
|
||||
'packages/**/build/',
|
||||
'packages/**/.svelte-kit/',
|
||||
'packages/**/dist/',
|
||||
'common/',
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -9,7 +9,7 @@ export type FileWithContent = { filename: string; content: string };
|
||||
export type FileWithFrontMatter = { filename: string; attributes: FrontMatterAttributes; body: string };
|
||||
export type FileWithScriptBody = FileWithFrontMatter & { scriptBody: string };
|
||||
export type FileWithMarkup = FileWithScriptBody & { markup: string };
|
||||
export type FileWithLayout = FileWithMarkup & { layout?: string };
|
||||
export type FileWithLayout = FileWithMarkup & { layout?: SvelteMarkdownImport };
|
||||
export type FileWithSvelte = FileWithLayout & { svelte: string };
|
||||
|
||||
export type FrontMatterAttributes = {
|
||||
@@ -17,10 +17,14 @@ export type FrontMatterAttributes = {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
export type SvelteMarkdownLayoutHandler = (file: FileWithMarkup) => SvelteMarkdownImportLike;
|
||||
export type SvelteMarkdownImportLike = SvelteMarkdownImport | string;
|
||||
export type SvelteMarkdownImport = { name: string; import?: string | false; source: string };
|
||||
|
||||
export type SvelteMarkdownPreprocessLayouts = {
|
||||
_?: string;
|
||||
default?: string;
|
||||
[key: string]: string | undefined;
|
||||
_?: SvelteMarkdownImportLike | SvelteMarkdownLayoutHandler;
|
||||
default?: SvelteMarkdownImportLike | SvelteMarkdownLayoutHandler;
|
||||
[key: string]: SvelteMarkdownImportLike | SvelteMarkdownLayoutHandler | undefined;
|
||||
};
|
||||
|
||||
const SCRIPT_BODY_REGEX = /<script.*>(?<body>(.|\n)*?)<\/script>/;
|
||||
@@ -97,7 +101,21 @@ export class SvelteMarkdownPreprocess {
|
||||
|
||||
parseLayout(file: FileWithMarkup): MaybePromise<FileWithLayout> {
|
||||
const layoutKey = file.attributes.layout;
|
||||
const layout = layoutKey ? this.#layouts[layoutKey] : (this.#layouts.default ?? this.#layouts._);
|
||||
|
||||
let layout = layoutKey ? this.#layouts[layoutKey] : (this.#layouts.default ?? this.#layouts._);
|
||||
|
||||
if (layoutKey && !layout) {
|
||||
throw new Error(`File references unknown layout key: ${file.filename} => ${layoutKey} => ?`);
|
||||
}
|
||||
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(file);
|
||||
}
|
||||
|
||||
if (typeof layout === 'string') {
|
||||
layout = { name: 'Layout', source: layout };
|
||||
}
|
||||
|
||||
return { ...file, layout };
|
||||
}
|
||||
|
||||
@@ -108,10 +126,12 @@ export class SvelteMarkdownPreprocess {
|
||||
return { ...file, svelte };
|
||||
}
|
||||
|
||||
scriptImports(file: FileWithLayout): Array<string | undefined> {
|
||||
scriptImports({ layout }: FileWithLayout): Array<string | undefined> {
|
||||
return [
|
||||
` import { Markdown } from '@immich/ui';`,
|
||||
file.layout ? ` import Layout from '${file.layout}';` : undefined,
|
||||
layout && layout.import !== false
|
||||
? ` import ${layout.import ?? layout.name} from '${layout.source}';`
|
||||
: undefined,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -132,7 +152,9 @@ export class SvelteMarkdownPreprocess {
|
||||
}
|
||||
|
||||
createSvelteTemplate(file: FileWithLayout): string {
|
||||
return (file.layout ? [`<Layout {attributes}>`, file.markup, '</Layout>'] : [file.markup]).join('\n');
|
||||
return (
|
||||
file.layout ? [`<${file.layout.name} {attributes}>`, file.markup, `</${file.layout.name}>`] : [file.markup]
|
||||
).join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import Container from '$lib/components/Container/Container.svelte';
|
||||
import Heading from '$lib/components/Heading/Heading.svelte';
|
||||
import SiteMetadata from '$lib/components/SiteMetadata/SiteMetadata.svelte';
|
||||
import Text from '$lib/components/Text/Text.svelte';
|
||||
import { type BreadcrumbItem, type ContainerSize } from '$lib/types.js';
|
||||
import type { Metadata } from '$lib/utilities/common.js';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
attributes: Metadata;
|
||||
size?: ContainerSize;
|
||||
breadcrumbs?: BreadcrumbItem[];
|
||||
title?: Snippet;
|
||||
description?: Snippet;
|
||||
children?: Snippet;
|
||||
};
|
||||
|
||||
const { attributes: page, title, description, size = 'medium', children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<SiteMetadata {page} />
|
||||
|
||||
<Container {size} center class="my-4 flex flex-col p-4 lg:my-8">
|
||||
<section class="mb-8">
|
||||
<Heading tag="h1" size="giant">
|
||||
{#if title}
|
||||
{@render title()}
|
||||
{:else}
|
||||
{page.title}
|
||||
{/if}
|
||||
</Heading>
|
||||
{#if page.description || description}
|
||||
<Text color="muted" size="large" fontWeight="semi-bold" class="mt-2">
|
||||
{#if typeof description === 'function'}
|
||||
{@render description()}
|
||||
{:else}
|
||||
{page.description}
|
||||
{/if}
|
||||
</Text>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{@render children?.()}
|
||||
</Container>
|
||||
@@ -7,6 +7,7 @@ import LineBreak from './LineBreak.svelte';
|
||||
import Link from './Link.svelte';
|
||||
import List from './List.svelte';
|
||||
import ListItem from './ListItem.svelte';
|
||||
import Page from './Page.svelte';
|
||||
import Paragraph from './Paragraph.svelte';
|
||||
import Space from './Space.svelte';
|
||||
import Table from './Table.svelte';
|
||||
@@ -27,6 +28,7 @@ export const Markdown = {
|
||||
Image,
|
||||
ListItem,
|
||||
List,
|
||||
Page,
|
||||
Paragraph,
|
||||
Table,
|
||||
TableHeader,
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<button
|
||||
type="button"
|
||||
aria-label={expanded ? t('collapse') : t('expand')}
|
||||
class="hover:bg-subtle hover:text-primary absolute me-2 hidden h-full rounded-lg px-0.5 md:block"
|
||||
class="hover:bg-subtle hover:text-primary absolute me-2 h-full rounded-lg px-0.5 md:block"
|
||||
onclick={() => (expanded = !expanded)}
|
||||
>
|
||||
<Icon
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { globalManager } from '$lib/services/global-manager.svelte.js';
|
||||
import { resolveMetadata, resolveUrl, type ArticleMetadata, type Metadata } from '$lib/utilities/common.js';
|
||||
|
||||
type Props = {
|
||||
site: Metadata;
|
||||
site?: Metadata;
|
||||
page?: Metadata;
|
||||
article?: ArticleMetadata;
|
||||
};
|
||||
|
||||
const { site, page, article }: Props = $props();
|
||||
|
||||
let resolved = $derived(resolveMetadata(site, page, article));
|
||||
let resolved = $derived(resolveMetadata(site ?? globalManager.siteMetadata, page, article));
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
||||
@@ -109,6 +109,7 @@ export { default as TooltipProvider } from '$lib/components/Tooltip/TooltipProvi
|
||||
export * from '$lib/actions/shortcut.js';
|
||||
export * from '$lib/commands.js';
|
||||
export * from '$lib/services/command-palette-manager.svelte.js';
|
||||
export * from '$lib/services/global-manager.svelte.js';
|
||||
export * from '$lib/services/menu-manager.svelte.js';
|
||||
export * from '$lib/services/modal-manager.svelte.js';
|
||||
export * from '$lib/services/screencast-manager.svelte.js';
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { type Metadata } from '$lib/utilities/common.js';
|
||||
|
||||
class GlobalManager {
|
||||
#siteMetadata = $state<Metadata>();
|
||||
|
||||
get siteMetadata() {
|
||||
if (!this.#siteMetadata) {
|
||||
throw new Error('No site metadata!');
|
||||
}
|
||||
|
||||
return this.#siteMetadata;
|
||||
}
|
||||
|
||||
setSiteMetadata(site: Metadata) {
|
||||
this.#siteMetadata = site;
|
||||
}
|
||||
}
|
||||
|
||||
export const globalManager = new GlobalManager();
|
||||
Reference in New Issue
Block a user