big style update
This commit is contained in:
98
app/blog/DjBlogEntry.tsx
Normal file
98
app/blog/DjBlogEntry.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import { computed, createTextVNode, defineComponent, h, type VNode } from "vue";
|
||||
import useHead from "@/useHead.ts";
|
||||
import useAsyncState from "@/useAsyncState.ts";
|
||||
import getDjAPI from "@/api.ts";
|
||||
import getDomParser from "@/domParse.ts";
|
||||
import { addCSS, css } from "../util.ts";
|
||||
|
||||
const style = css`
|
||||
.byline {
|
||||
font-style: italic;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--dj-palette1);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
`;
|
||||
|
||||
export default defineComponent({
|
||||
name: "DjBlogEntry",
|
||||
props: {
|
||||
slug: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
async setup(props) {
|
||||
addCSS('DjBlogEntry', style);
|
||||
|
||||
const parseDom = getDomParser();
|
||||
|
||||
const blogpostContent = useAsyncState(
|
||||
`dj-blog-article-content-${ props.slug }`,
|
||||
async ({ hostUrl }) => {
|
||||
const blogpostResponse = await fetch(`${hostUrl}/blog/content/${ props.slug }.html`);
|
||||
const result = await blogpostResponse.text();
|
||||
return result;
|
||||
},
|
||||
);
|
||||
|
||||
const blogpostsMetadata = useAsyncState('article-metadata', ({ hostUrl }) => getDjAPI(hostUrl, '/blog-entries'));
|
||||
|
||||
const blogpostMetadata = computed(() => blogpostsMetadata.result.value?.find(_ => _.slug === props.slug));
|
||||
|
||||
useHead({
|
||||
title: () => blogpostMetadata.value?.title ?? '',
|
||||
metatags: () => blogpostMetadata.value ? [
|
||||
{ name: 'title', content: blogpostMetadata.value.title },
|
||||
{ name: 'author', content: 'Daniel Ledda' },
|
||||
] : [],
|
||||
});
|
||||
|
||||
function transformPostNode(node: Node): VNode | string {
|
||||
if (node.nodeType === node.ELEMENT_NODE) {
|
||||
const el = node as Element;
|
||||
const attrs: Record<string, string> = {};
|
||||
const children = [...node.childNodes].map((_) => transformPostNode(_));
|
||||
|
||||
for (let i = 0; i < el.attributes.length; i++) {
|
||||
const item = el.attributes.item(i);
|
||||
if (item) {
|
||||
attrs[item.name] = item.value;
|
||||
}
|
||||
}
|
||||
|
||||
return h((node as Element).tagName, attrs, children);
|
||||
} else {
|
||||
return createTextVNode(node.textContent ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
function PostContentTransformed() {
|
||||
if (blogpostContent.result.value) {
|
||||
const dom = parseDom(blogpostContent.result.value);
|
||||
return h("div", {}, [...dom.children].map((_) => transformPostNode(_)));
|
||||
}
|
||||
return <div>Blog post loading...</div>;
|
||||
}
|
||||
|
||||
await Promise.allSettled([ blogpostContent.done, blogpostsMetadata.done ]);
|
||||
|
||||
return () => <>
|
||||
{ blogpostMetadata.value
|
||||
? <>
|
||||
<h1>{ blogpostMetadata.value.title }</h1>
|
||||
<div class="byline">by Daniel Ledda, first published { new Date(blogpostMetadata.value.createdAt).toLocaleDateString() }</div>
|
||||
<PostContentTransformed />
|
||||
</>
|
||||
: "Sorry, this blog post doesn't seem to exist."
|
||||
}
|
||||
</>;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user