feat: schema validation + article format improvements

This commit is contained in:
Youwen Wu 2024-04-12 22:43:17 -07:00
parent 4a11f11e54
commit f26765dda5
Signed by: youwen5
GPG key ID: 865658ED1FE61EC3
15 changed files with 277 additions and 16 deletions

View file

@ -1,3 +1,5 @@
#:schema ../../../post.schema.json
title = "A Brief Introduction to Taylor Series" title = "A Brief Introduction to Taylor Series"
[manifest] [manifest]

View file

@ -1,3 +1,4 @@
#:schema ../../../post.schema.json
title = "My Awesome Blog Post" title = "My Awesome Blog Post"
[manifest] [manifest]
@ -12,6 +13,6 @@ primary = ["Rust", "WebAssembly"]
secondary = ["Web Development", "Frontend"] secondary = ["Web Development", "Frontend"]
[cover] [cover]
src = "cover.jpg" src = "https://machinelearningmastery.com/wp-content/uploads/2021/07/tayloreq6.png"
alt = "A Rust and WebAssembly logo" alt = "A Rust and WebAssembly logo"
caption = "Rust and WebAssembly" caption = "Rust and WebAssembly"

View file

@ -51,6 +51,7 @@
"@types/node": "^20.12.5", "@types/node": "^20.12.5",
"bits-ui": "^0.21.2", "bits-ui": "^0.21.2",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"coredump": "link:",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"mode-watcher": "^0.3.0", "mode-watcher": "^0.3.0",
"rehype-katex": "^7.0.0", "rehype-katex": "^7.0.0",

View file

@ -32,6 +32,9 @@ dependencies:
clsx: clsx:
specifier: ^2.1.0 specifier: ^2.1.0
version: 2.1.0 version: 2.1.0
coredump:
specifier: 'link:'
version: 'link:'
dayjs: dayjs:
specifier: ^1.11.10 specifier: ^1.11.10
version: 1.11.10 version: 1.11.10

69
post.schema.json Normal file
View 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"]
}

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { ChevronRight } from 'svelte-radix'; import * as Breadcrumb from '../ui/breadcrumb';
export let slug: string; export let slug: string;
export let title: string; export let title: string;
@ -7,14 +7,18 @@
$: trail = slug.split('/').slice(0, slug.split('/').length - 1); $: trail = slug.split('/').slice(0, slug.split('/').length - 1);
</script> </script>
<div class="mb-4 flex items-center space-x-1 text-sm text-muted-foreground"> <Breadcrumb.Root class="mb-4">
<a class="overflow-hidden text-ellipsis whitespace-nowrap hover:underline" href="/blog" <Breadcrumb.List>
>The Coredump</a <Breadcrumb.Item><Breadcrumb.Link href="/blog">The Coredump</Breadcrumb.Link></Breadcrumb.Item>
> <Breadcrumb.Separator />
<ChevronRight class="h-4 w-4" /> {#each trail as crumb, i}
{#each trail as crumb, i} <Breadcrumb.Item>{crumb}</Breadcrumb.Item>
<div class="text-muted-foreground">{crumb}</div> <Breadcrumb.Separator />
<ChevronRight class="h-4 w-4" /> {/each}
{/each} <Breadcrumb.Item>
<div class="font-medium text-foreground">{title}</div> <Breadcrumb.Page>
</div> {title}
</Breadcrumb.Page>
</Breadcrumb.Item>
</Breadcrumb.List>
</Breadcrumb.Root>

View file

@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import Placeholder from '$lib/assets/img/galaxy.jpg';
import Button from '../ui/button/button.svelte'; import Button from '../ui/button/button.svelte';
import PostMetadata from './PostMetadata.svelte'; import PostMetadata from './PostMetadata.svelte';
@ -26,8 +25,8 @@
</Card.Header> </Card.Header>
<Card.Content class="grid grid-cols-3 gap-6"> <Card.Content class="grid grid-cols-3 gap-6">
<img <img
src={Placeholder} src={doc.metadata.cover.src}
alt="Placeholder" alt={doc.metadata.cover.alt}
class="col-span-3 md:col-span-1 rounded-2xl shadow-md" 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"> <div class="flex flex-col justify-around col-span-3 md:col-span-2 gap-4">

View 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>

View 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>

View 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}

View 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>

View 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>

View 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>

View 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>

View 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,
};