get routing working, add index for poetry, list first 6 poems on index, let each take you to their page with the poem's content

This commit is contained in:
2024-05-16 02:52:32 -04:00
parent 2cf484aa46
commit 3d22344e7f
44 changed files with 1134 additions and 178 deletions

View File

@@ -0,0 +1,63 @@
<script context="module">
import { tick } from 'svelte';
/**
* Usage: <div use:portal={'css selector'}> or <div use:portal={document.body}>
*
* @param {HTMLElement} el
* @param {HTMLElement|string} target DOM Element or CSS Selector
*/
export function portal(el, target = 'body') {
let targetEl;
/**
* @param {string | HTMLElement} newTarget
*/
async function update(newTarget) {
target = newTarget;
if (typeof target === 'string') {
targetEl = document.querySelector(target);
if (targetEl === null) {
await tick();
targetEl = document.querySelector(target);
}
if (targetEl === null) {
throw new Error(`No element found matching css selector: "${target}"`);
}
} else if (target instanceof HTMLElement) {
targetEl = target;
} else {
throw new TypeError(
`Unknown portal target type: ${
target === null ? 'null' : typeof target
}. Allowed types: string (CSS selector) or HTMLElement.`
);
}
targetEl.appendChild(el);
el.hidden = false;
}
function destroy() {
if (el.parentNode) {
el.parentNode.removeChild(el);
}
}
update(target);
return {
update,
destroy
};
}
</script>
<script>
/**
* DOM Element or CSS Selector
* @type { HTMLElement|string}
*/
export let target = 'body';
</script>
<div use:portal={target} hidden style="display: contents;">
<slot />
</div>

80
src/lib/utils/index.ts Normal file
View File

@@ -0,0 +1,80 @@
export interface Metadata {
title: string;
date: string;
content: string;
categories?: string[];
section?: SectionKey;
}
export interface Section {
poetry: 'poetry';
thoughts: 'thoughts';
projects: 'projects';
}
type SectionKey = keyof Section;
export interface Post {
meta: Metadata;
path: string;
}
interface Data {
metadata: Metadata;
}
function isData(obj: unknown): obj is Data {
if (typeof obj !== 'object' || obj === null) {
return false;
}
const dataObj = obj as Data;
return (
'metadata' in dataObj &&
typeof dataObj.metadata.title === 'string' &&
typeof dataObj.metadata.date === 'string'
);
}
export const fetchMarkdownPosts = async (
section: SectionKey,
limit: number,
offset: number
): Promise<Post[]> => {
let posts: Record<string, () => Promise<unknown>>;
switch (section) {
case 'poetry':
posts = import.meta.glob('/src/posts/poetry/*.md');
break;
case 'projects':
posts = import.meta.glob('/src/routes/(app)/projects/posts/*.md');
break;
case 'thoughts':
posts = import.meta.glob('/src/routes/(app)/thoughts/posts/*.md');
break;
default:
throw new Error('Could not find this section');
}
const iterablePostFiles = Object.entries(posts);
const allPosts = await Promise.all(
iterablePostFiles.map(async ([path, resolver]) => {
const data = await resolver();
if (isData(data)) {
const { metadata } = data;
const postPath = path.slice(11, -3);
return {
meta: { ...metadata, section: section },
path: postPath
};
} else {
throw new Error('Could not properly parse this post');
}
})
);
const paginatedPosts = allPosts.slice(offset, offset + limit);
return paginatedPosts;
};