mirror of
https://github.com/youwen5/site.git
synced 2024-11-24 17:33:51 -08:00
feat: schema validation + article format improvements
This commit is contained in:
parent
4a11f11e54
commit
f26765dda5
15 changed files with 277 additions and 16 deletions
|
@ -1,3 +1,5 @@
|
|||
#:schema ../../../post.schema.json
|
||||
|
||||
title = "A Brief Introduction to Taylor Series"
|
||||
|
||||
[manifest]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#:schema ../../../post.schema.json
|
||||
title = "My Awesome Blog Post"
|
||||
|
||||
[manifest]
|
||||
|
@ -12,6 +13,6 @@ primary = ["Rust", "WebAssembly"]
|
|||
secondary = ["Web Development", "Frontend"]
|
||||
|
||||
[cover]
|
||||
src = "cover.jpg"
|
||||
src = "https://machinelearningmastery.com/wp-content/uploads/2021/07/tayloreq6.png"
|
||||
alt = "A Rust and WebAssembly logo"
|
||||
caption = "Rust and WebAssembly"
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"@types/node": "^20.12.5",
|
||||
"bits-ui": "^0.21.2",
|
||||
"clsx": "^2.1.0",
|
||||
"coredump": "link:",
|
||||
"dayjs": "^1.11.10",
|
||||
"mode-watcher": "^0.3.0",
|
||||
"rehype-katex": "^7.0.0",
|
||||
|
|
|
@ -32,6 +32,9 @@ dependencies:
|
|||
clsx:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
coredump:
|
||||
specifier: 'link:'
|
||||
version: 'link:'
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.10
|
||||
|
|
69
post.schema.json
Normal file
69
post.schema.json
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"manifest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"blurb": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"authors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"primary": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"secondary": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["primary", "secondary"]
|
||||
}
|
||||
},
|
||||
"required": ["date", "blurb", "description", "type", "authors", "tags"]
|
||||
},
|
||||
"cover": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"alt": {
|
||||
"type": "string"
|
||||
},
|
||||
"caption": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["src", "alt", "caption"]
|
||||
}
|
||||
},
|
||||
"required": ["title", "manifest", "cover"]
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { ChevronRight } from 'svelte-radix';
|
||||
import * as Breadcrumb from '../ui/breadcrumb';
|
||||
|
||||
export let slug: string;
|
||||
export let title: string;
|
||||
|
@ -7,14 +7,18 @@
|
|||
$: trail = slug.split('/').slice(0, slug.split('/').length - 1);
|
||||
</script>
|
||||
|
||||
<div class="mb-4 flex items-center space-x-1 text-sm text-muted-foreground">
|
||||
<a class="overflow-hidden text-ellipsis whitespace-nowrap hover:underline" href="/blog"
|
||||
>The Coredump</a
|
||||
>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
<Breadcrumb.Root class="mb-4">
|
||||
<Breadcrumb.List>
|
||||
<Breadcrumb.Item><Breadcrumb.Link href="/blog">The Coredump</Breadcrumb.Link></Breadcrumb.Item>
|
||||
<Breadcrumb.Separator />
|
||||
{#each trail as crumb, i}
|
||||
<div class="text-muted-foreground">{crumb}</div>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
<Breadcrumb.Item>{crumb}</Breadcrumb.Item>
|
||||
<Breadcrumb.Separator />
|
||||
{/each}
|
||||
<div class="font-medium text-foreground">{title}</div>
|
||||
</div>
|
||||
<Breadcrumb.Item>
|
||||
<Breadcrumb.Page>
|
||||
{title}
|
||||
</Breadcrumb.Page>
|
||||
</Breadcrumb.Item>
|
||||
</Breadcrumb.List>
|
||||
</Breadcrumb.Root>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import Placeholder from '$lib/assets/img/galaxy.jpg';
|
||||
import Button from '../ui/button/button.svelte';
|
||||
import PostMetadata from './PostMetadata.svelte';
|
||||
|
||||
|
@ -26,8 +25,8 @@
|
|||
</Card.Header>
|
||||
<Card.Content class="grid grid-cols-3 gap-6">
|
||||
<img
|
||||
src={Placeholder}
|
||||
alt="Placeholder"
|
||||
src={doc.metadata.cover.src}
|
||||
alt={doc.metadata.cover.alt}
|
||||
class="col-span-3 md:col-span-1 rounded-2xl shadow-md"
|
||||
/>
|
||||
<div class="flex flex-col justify-around col-span-3 md:col-span-2 gap-4">
|
||||
|
|
24
src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte
Normal file
24
src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte
Normal file
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import DotsHorizontal from "svelte-radix/DotsHorizontal.svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement> & {
|
||||
el?: HTMLSpanElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<span
|
||||
bind:this={el}
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
class={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<DotsHorizontal class="h-4 w-4 outline-none" tabindex="-1" />
|
||||
<span class="sr-only">More</span>
|
||||
</span>
|
16
src/lib/components/ui/breadcrumb/breadcrumb-item.svelte
Normal file
16
src/lib/components/ui/breadcrumb/breadcrumb-item.svelte
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLLiAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLLiAttributes & {
|
||||
el?: HTMLLIElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<li bind:this={el} class={cn("inline-flex items-center gap-1.5", className)}>
|
||||
<slot />
|
||||
</li>
|
31
src/lib/components/ui/breadcrumb/breadcrumb-link.svelte
Normal file
31
src/lib/components/ui/breadcrumb/breadcrumb-link.svelte
Normal file
|
@ -0,0 +1,31 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAnchorAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAnchorAttributes & {
|
||||
el?: HTMLAnchorElement;
|
||||
asChild?: boolean;
|
||||
};
|
||||
|
||||
export let href: $$Props["href"] = undefined;
|
||||
export let el: $$Props["el"] = undefined;
|
||||
export let asChild: $$Props["asChild"] = false;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
|
||||
let attrs: Record<string, unknown>;
|
||||
|
||||
$: attrs = {
|
||||
class: cn("transition-colors hover:text-foreground", className),
|
||||
href,
|
||||
...$$restProps,
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if asChild}
|
||||
<slot {attrs} />
|
||||
{:else}
|
||||
<a bind:this={el} {...attrs} {href}>
|
||||
<slot {attrs} />
|
||||
</a>
|
||||
{/if}
|
23
src/lib/components/ui/breadcrumb/breadcrumb-list.svelte
Normal file
23
src/lib/components/ui/breadcrumb/breadcrumb-list.svelte
Normal file
|
@ -0,0 +1,23 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLOlAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLOlAttributes & {
|
||||
el?: HTMLOListElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<ol
|
||||
bind:this={el}
|
||||
class={cn(
|
||||
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</ol>
|
23
src/lib/components/ui/breadcrumb/breadcrumb-page.svelte
Normal file
23
src/lib/components/ui/breadcrumb/breadcrumb-page.svelte
Normal file
|
@ -0,0 +1,23 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement> & {
|
||||
el?: HTMLSpanElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
export let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<span
|
||||
bind:this={el}
|
||||
role="link"
|
||||
aria-disabled="true"
|
||||
aria-current="page"
|
||||
class={cn("font-normal text-foreground", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</span>
|
25
src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte
Normal file
25
src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte
Normal file
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLLiAttributes } from "svelte/elements";
|
||||
import ChevronRight from "svelte-radix/ChevronRight.svelte";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
type $$Props = HTMLLiAttributes & {
|
||||
el?: HTMLLIElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<li
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
class={cn("[&>svg]:size-3.5", className)}
|
||||
bind:this={el}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot>
|
||||
<ChevronRight tabindex="-1" />
|
||||
</slot>
|
||||
</li>
|
15
src/lib/components/ui/breadcrumb/breadcrumb.svelte
Normal file
15
src/lib/components/ui/breadcrumb/breadcrumb.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLElement> & {
|
||||
el?: HTMLElement;
|
||||
};
|
||||
|
||||
export let el: $$Props["el"] = undefined;
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<nav class={className} bind:this={el} aria-label="breadcrumb" {...$$restProps}>
|
||||
<slot />
|
||||
</nav>
|
25
src/lib/components/ui/breadcrumb/index.ts
Normal file
25
src/lib/components/ui/breadcrumb/index.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Root from "./breadcrumb.svelte";
|
||||
import Ellipsis from "./breadcrumb-ellipsis.svelte";
|
||||
import Item from "./breadcrumb-item.svelte";
|
||||
import Separator from "./breadcrumb-separator.svelte";
|
||||
import Link from "./breadcrumb-link.svelte";
|
||||
import List from "./breadcrumb-list.svelte";
|
||||
import Page from "./breadcrumb-page.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Ellipsis,
|
||||
Item,
|
||||
Separator,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
//
|
||||
Root as Breadcrumb,
|
||||
Ellipsis as BreadcrumbEllipsis,
|
||||
Item as BreadcrumbItem,
|
||||
Separator as BreadcrumbSeparator,
|
||||
Link as BreadcrumbLink,
|
||||
List as BreadcrumbList,
|
||||
Page as BreadcrumbPage,
|
||||
};
|
Loading…
Reference in a new issue