mdsvex fixes

This commit is contained in:
Benjamin Palko 2026-01-27 09:38:29 -05:00
parent 832ef7f411
commit a515a2a687
26 changed files with 585 additions and 179 deletions

View file

@ -1,4 +1,5 @@
@import "tailwindcss"; @import "tailwindcss";
@plugin "daisyui" { @plugin "daisyui" {
themes: nord --default, forest --prefersdark; themes: nord --default, forest --prefersdark;
} }

View file

@ -1,15 +1,12 @@
import { logger } from '$lib/server/logger'; import { logger } from '$lib/server/logger';
import type { HandleServerError } from '@sveltejs/kit'; import type { HandleServerError } from '@sveltejs/kit';
import { randomUUID } from 'crypto';
export const handleError: HandleServerError = async ({ error, event, message, status }) => { export const handleError: HandleServerError = async ({ error, event, message, status }) => {
const errorId = randomUUID();
logger.error({ error, errorId, event, message, status }, 'Blyat'); logger.error({ error, event, message, status });
return { return {
message: 'An Internal Error Occurred', message: 'An Internal Error Occurred',
errorId
}; };
}; };

View file

@ -0,0 +1,11 @@
<script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements';
type Props = Omit<SvelteHTMLElements['blockquote'], 'class'>;
const { children, ...props }: Props = $props();
</script>
<blockquote {...props} class="alert alert-soft my-4">
{@render children?.()}
</blockquote>

View file

@ -0,0 +1,193 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['code'];
const { children, class: className, ...props }: Props = $props();
</script>
<code {...props} class={twMerge('text-pink-500', clsx(className))}>
{@render children?.()}
</code>
<style scoped>
@reference "../../../app.css";
blockquote {
@apply alert my-3 text-xs leading-loose italic;
}
/**
** code block styling
**/
code[class*='language-'],
pre[class*='language-'] {
color: #ebdbb2;
/* fg1 / fg */
font-family: 'JetBrains Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
@apply text-neutral-content;
}
pre[class*='language-']::-moz-selection,
pre[class*='language-'] ::-moz-selection,
code[class*='language-']::-moz-selection,
code[class*='language-'] ::-moz-selection {
color: #fbf1c7;
/* fg0 */
background: #7c6f64;
/* bg4 */
@apply bg-accent/80 text-accent-content/80;
}
pre[class*='language-']::selection,
pre[class*='language-'] ::selection,
code[class*='language-']::selection,
code[class*='language-'] ::selection {
color: #fbf1c7;
/* fg0 */
background: #7c6f64;
/* bg4 */
@apply bg-accent text-accent-content;
}
/* Code blocks */
pre[class*='language-'] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*='language-'],
pre[class*='language-'] {
@apply rounded-box bg-neutral;
/* bg0_h */
}
/* Inline code */
:not(pre) > code[class*='language-'] {
padding: 0.1em;
border-radius: 0.3em;
}
.token.comment,
.token.prolog,
.token.cdata {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.delimiter,
.token.boolean,
.token.keyword,
.token.selector,
.token.important,
.token.atrule {
color: #fb4934;
/* red2 */
@apply text-error/80;
}
.token.operator,
.token.punctuation,
.token.attr-name {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.tag,
.token.tag .punctuation,
.token.doctype,
.token.builtin {
color: #fabd2f;
/* yellow2 */
@apply text-warning/80;
}
.token.entity,
.token.number,
.token.symbol {
color: #d3869b;
/* purple2 */
@apply text-secondary;
}
.token.property,
.token.constant,
.token.variable {
color: #fb4934;
/* red2 */
@apply text-error/80;
}
.token.string,
.token.char {
color: #b8bb26;
/* green2 */
@apply text-primary;
}
.token.attr-value,
.token.attr-value .punctuation {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.url {
color: #b8bb26;
/* green2 */
text-decoration: underline;
@apply text-secondary/80;
}
.token.function {
color: #fabd2f;
/* yellow2 */
@apply text-accent/90;
}
.token.regex {
background: #b8bb26;
/* green2 */
@apply bg-secondary/40;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.inserted {
background: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.deleted {
background: #fb4934;
/* red2 */
@apply text-error;
}
</style>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['h1'];
const { children, class: className, ...props }: Props = $props();
</script>
<h1
{...props}
class={twMerge(
'before:border-l-primary bg-base-200/60 my-3 w-full overflow-hidden rounded-lg py-2 text-3xl font-light before:mr-4 before:border-l-6 before:py-8',
clsx(className)
)}
>
{@render children?.()}
</h1>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['h2'];
const { children, class: className, ...props }: Props = $props();
</script>
<h2
{...props}
class={twMerge(
'before:border-l-secondary bg-base-200/60 my-3 w-full overflow-hidden rounded-lg py-2 text-2xl font-light before:mr-4 before:border-l-6 before:py-8',
clsx(className)
)}
>
{@render children?.()}
</h2>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['h3'];
const { children, class: className, ...props }: Props = $props();
</script>
<h3
{...props}
class={twMerge(
'before:border-l-accent bg-base-200/60 my-3 w-full overflow-hidden rounded-lg py-2 text-xl font-light before:mr-4 before:border-l-6 before:py-8',
clsx(className)
)}
>
{@render children?.()}
</h3>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['h4'];
const { children, class: className, ...props }: Props = $props();
</script>
<h4
{...props}
class={twMerge(
'before:border-l-neutral bg-base-200/60 my-3 w-full overflow-hidden rounded-lg py-2 text-lg before:mr-4 before:border-l-6 before:py-8',
clsx(className)
)}
>
{@render children?.()}
</h4>

View file

@ -0,0 +1,19 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['h5'];
const { children, class: className, ...props }: Props = $props();
</script>
<h5
{...props}
class={twMerge(
'before:border-l-neutral bg-base-200/60 my-3 w-full overflow-hidden rounded-lg py-2 before:mr-4 before:border-l-6 before:py-8',
clsx(className)
)}
>
{@render children?.()}
</h5>

View file

@ -0,0 +1,11 @@
<script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements';
type Props = Omit<SvelteHTMLElements['a'], 'class'>;
const { href, children }: Props = $props();
</script>
<a {href} target="_blank" class="link link-primary">
{@render children?.()}
</a>

View file

@ -0,0 +1,11 @@
<script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements';
type Props = SvelteHTMLElements['ol'];
const { children, ...props }: Props = $props();
</script>
<ol {...props} class="ml-8 list-decimal">
{@render children?.()}
</ol>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['p'];
const { children, class: className, ...props }: Props = $props();
</script>
<p {...props} class={twMerge('text-base-content my-3', clsx(className))}>
{@render children?.()}
</p>

View file

@ -0,0 +1,191 @@
<script lang="ts">
import clsx from 'clsx';
import type { SvelteHTMLElements } from 'svelte/elements';
import { twMerge } from 'tailwind-merge';
type Props = SvelteHTMLElements['div'] & {
code: string;
lang: string;
};
const { code, lang, class: className, ...props }: Props = $props();
</script>
<div {...props} class={twMerge('mockup-code', `before:content-['${lang}']`, clsx(className))}>
{#each code.split('\n') as row, index (row)}
<pre data-prefix={index + 1} class={lang}><code>{row}</code></pre>
{/each}
</div>
<style scoped>
@reference "../../../app.css";
code[class*='language-'],
pre[class*='language-'] {
color: #ebdbb2;
/* fg1 / fg */
font-family: 'JetBrains Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
@apply text-neutral-content;
}
pre[class*='language-']::-moz-selection,
pre[class*='language-'] ::-moz-selection,
code[class*='language-']::-moz-selection,
code[class*='language-'] ::-moz-selection {
color: #fbf1c7;
/* fg0 */
background: #7c6f64;
/* bg4 */
@apply bg-accent/80 text-accent-content/80;
}
pre[class*='language-']::selection,
pre[class*='language-'] ::selection,
code[class*='language-']::selection,
code[class*='language-'] ::selection {
color: #fbf1c7;
/* fg0 */
background: #7c6f64;
/* bg4 */
@apply bg-accent text-accent-content;
}
/* Code blocks */
pre[class*='language-'] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*='language-'],
pre[class*='language-'] {
@apply rounded-box bg-neutral;
/* bg0_h */
}
/* Inline code */
:not(pre) > code[class*='language-'] {
padding: 0.1em;
border-radius: 0.3em;
}
.token.comment,
.token.prolog,
.token.cdata {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.delimiter,
.token.boolean,
.token.keyword,
.token.selector,
.token.important,
.token.atrule {
color: #fb4934;
/* red2 */
@apply text-error/80;
}
.token.operator,
.token.punctuation,
.token.attr-name {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.tag,
.token.tag .punctuation,
.token.doctype,
.token.builtin {
color: #fabd2f;
/* yellow2 */
@apply text-warning/80;
}
.token.entity,
.token.number,
.token.symbol {
color: #d3869b;
/* purple2 */
@apply text-secondary;
}
.token.property,
.token.constant,
.token.variable {
color: #fb4934;
/* red2 */
@apply text-error/80;
}
.token.string,
.token.char {
color: #b8bb26;
/* green2 */
@apply text-primary;
}
.token.attr-value,
.token.attr-value .punctuation {
color: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.url {
color: #b8bb26;
/* green2 */
text-decoration: underline;
@apply text-secondary/80;
}
.token.function {
color: #fabd2f;
/* yellow2 */
@apply text-accent/90;
}
.token.regex {
background: #b8bb26;
/* green2 */
@apply bg-secondary/40;
}
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.inserted {
background: #a89984;
/* fg4 / gray1 */
@apply text-neutral-content/60;
}
.token.deleted {
background: #fb4934;
/* red2 */
@apply text-error;
}
</style>

View file

@ -0,0 +1,11 @@
<script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements';
type Props = SvelteHTMLElements['ul'];
const { children, ...props }: Props = $props();
</script>
<ul {...props} class="ml-8 list-disc">
{@render children?.()}
</ul>

View file

@ -0,0 +1,18 @@
<script lang="ts" context="module">
import a from '$lib/components/markdown/Link.svelte';
import blockquote from '$lib/components/markdown/BlockQuote.svelte';
import code from '$lib/components/markdown/Code.svelte';
import h1 from '$lib/components/markdown/Heading1.svelte';
import h2 from '$lib/components/markdown/Heading2.svelte';
import h3 from '$lib/components/markdown/Heading3.svelte';
import h4 from '$lib/components/markdown/Heading4.svelte';
import h5 from '$lib/components/markdown/Heading5.svelte';
import p from '$lib/components/markdown/Paragraph.svelte';
import pre from '$lib/components/markdown/Pre.svelte';
import ol from '$lib/components/markdown/OrderedListItem.svelte';
import ul from '$lib/components/markdown/UnorderedList.svelte';
export { a, blockquote, code, h1, h2, h3, h4, h5, p, pre, ol, ul };
</script>
<slot />

View file

@ -1,11 +0,0 @@
<script lang="ts">
interface Props {
text?: string;
}
const { text }: Props = $props();
</script>
<blockquote class="bg-base-200 border-base-300 text-base-content rounded-lg border-l-4 p-4">
<p class="text-gray-700">{text}</p>
</blockquote>

View file

@ -1,14 +0,0 @@
<script lang="ts">
interface Props {
lang?: string;
text?: string;
}
const { text = '' }: Props = $props();
</script>
<div class="mockup-code w-full">
{#each text.split('\n') as line, index (index)}
<pre data-prefix={index + 1}><code>{line}</code></pre>
{/each}
</div>

View file

@ -1,22 +0,0 @@
<script lang="ts">
interface Props {
depth: number;
text: string;
}
const { depth, text }: Props = $props();
</script>
{#if depth === 1}
<h1 class="my-3 text-4xl font-bold">{text}</h1>
{:else if depth === 2}
<h2 class="my-2 text-3xl font-bold">{text}</h2>
{:else if depth === 3}
<h3 class="my-2 text-2xl font-semibold">{text}</h3>
{:else if depth === 4}
<h4 class="my-1 text-xl font-semibold">{text}</h4>
{:else if depth === 5}
<h5 class="my-1 text-lg font-medium underline">{text}</h5>
{:else if depth === 6}
<h6 class="my-1 font-medium underline">{text}</h6>
{/if}

View file

@ -1,15 +0,0 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children?: Snippet;
href?: string;
title?: string;
}
const { href = '', title = '', children }: Props = $props();
</script>
<a {href} {title} class="link link-primary">
{@render children?.()}
</a>

View file

@ -1,22 +0,0 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children?: Snippet;
ordered?: boolean;
loose?: boolean;
start?: number;
}
const { children, ordered }: Props = $props();
</script>
{#if ordered}
<ol class="my-2">
{@render children?.()}
</ol>
{:else}
<ul class="my-2">
{@render children?.()}
</ul>
{/if}

View file

@ -1,27 +0,0 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children?: Snippet;
task?: boolean;
checked?: boolean;
listItemIndex: number;
}
const { children, task, checked: initial = false, listItemIndex, ...rest }: Props = $props();
let checked = $derived(initial);
</script>
<li class="ml-2">
{listItemIndex + 1}. {#if task}
<input
type="checkbox"
class="mr-2"
class:hidden={!task}
{checked}
onclick={() => {
checked = !checked;
}}
/>{/if}{@render children?.()}
</li>

View file

@ -1,11 +0,0 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children?: Snippet;
}
const { children }: Props = $props();
</script>
<p class="my-3">{@render children?.()}</p>

View file

@ -1,30 +0,0 @@
<script lang="ts">
import type { Snippet } from 'svelte';
interface Props {
children?: Snippet;
task?: boolean;
checked?: boolean;
listItemIndex?: number;
}
const { children, task, checked: initial = false }: Props = $props();
let checked = $derived(initial);
</script>
<li class="ml-2">
{#if task}
<input
type="checkbox"
class="mr-2"
class:hidden={!task}
{checked}
onclick={() => {
checked = !checked;
}}
/>
{:else}
🞄
{/if}{@render children?.()}
</li>

View file

@ -1,4 +1,5 @@
--- ---
layout: blog
title: Godot .NET with SpacetimeDB title: Godot .NET with SpacetimeDB
description: First post. description: First post.
image: image:

View file

@ -8,23 +8,17 @@
<div class="flex flex-col items-center gap-4"> <div class="flex flex-col items-center gap-4">
<div class="w-full max-w-5xl px-4"> <div class="w-full max-w-5xl px-4">
<p class="text-gray-500">{dayjs(data.meta.date).format('DD MMMM YYYY')}</p>
<h1 class="text-4xl font-light">{data.meta.title}</h1> <h1 class="text-4xl font-light">{data.meta.title}</h1>
<p class="text-neutral-content/40 text-lg font-thin">
{dayjs(data.meta.date).format('DD MMMM YYYY')}
</p>
</div> </div>
<Image <Image
src={data.meta.image.url} src={data.meta.image.url}
alt={data.meta.image.alt} alt={data.meta.image.alt}
class="aspect-4/2 w-full object-cover" class="aspect-4/2 w-full object-cover"
/> />
<div class="w-full max-w-5xl px-4"> <div class="w-full max-w-5xl">
<data.content class="content" /> <data.content />
</div> </div>
</div> </div>
<style>
.content {
* code {
@apply bg-base-200 border-base-300 text-base-content rounded-lg border-l-4 p-4 text-gray-700;
}
}
</style>

View file

@ -1,12 +1,23 @@
import { mdsvex } from 'mdsvex'; import { mdsvex } from 'mdsvex';
import adapter from '@sveltejs/adapter-netlify'; import adapter from '@sveltejs/adapter-netlify';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { join } from 'path';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
// Consult https://svelte.dev/docs/kit/integrations // Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors // for more information about preprocessors
preprocess: [vitePreprocess(), mdsvex({ extensions: ['.md'] })], preprocess: [vitePreprocess(), mdsvex({
extensions: ['.md'], layout: {
blog: join(import.meta.dirname, './src/lib/layout/Blog.svelte')
},
highlight: {
highlighter: (code, lang, meta) => {
console.log(meta);
return `<Components.pre code={\`${code}\`} lang={\`${lang}\`} />`;
}
}
})],
kit: { kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list. // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.