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:
63
src/lib/utils/DomPortal.svelte
Normal file
63
src/lib/utils/DomPortal.svelte
Normal 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
80
src/lib/utils/index.ts
Normal 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;
|
||||
};
|
Reference in New Issue
Block a user