Capital/src/pages/posts/[...slug].astro
2024-12-19 23:11:13 +08:00

139 lines
4.4 KiB
Plaintext

---
export const prerender = false
import sanitizeHtml from 'sanitize-html'
import { Icon } from 'astro-icon/components'
import {SEO} from 'astro-seo'
import { marked } from 'marked'
import Layout from '@/layouts/Layout.astro'
import AttachmentRenderer from '@/components/AttachmentRenderer.astro'
import { getAttachmentUrl, fetchAttachmentMeta } from '@/scripts/attachment'
const { slug } = Astro.params
const baseUrl = import.meta.env.PUBLIC_SOLAR_NETWORK_URL
const resp = await fetch(`${baseUrl}/cgi/co/posts/${slug}`)
if (resp.status !== 200) {
return new Response(null, { status: 404 })
}
const data = await resp.json()
const rawContent = await marked(data.body.content as string, {
breaks: data.type == 'story',
})
const content = sanitizeHtml(rawContent)
const attachments = await fetchAttachmentMeta(data.body.attachments)
---
<head>
<SEO
title={data.body?.title ? data.body.title : `Post #${data.id}`}
description={data.body?.content}
openGraph={{
basic: {
title: data.body?.title ? data.body.title : `Post #${data.id}`,
type: "article",
image: data.body?.thumbnail ? getAttachmentUrl(data.body.thumbnail) : getAttachmentUrl(attachments.find(a => a.mimetype.startsWith('image'))?.rid),
url: `https://solsynth.dev/posts/${data.id}`
},
article: {
publishedTime: new Date(data.created_at).toISOString(),
modifiedTime: new Date(data.updated_at).toISOString(),
authors: ["@"+data.publisher.name],
}
}}
twitter={{
card: "summary_large_image",
title: data.body?.title ? data.body.title : `Post #${data.id}`,
description: data.body?.content,
creator: "@"+data.publisher.name,
image: data.body?.thumbnail ? getAttachmentUrl(data.body.thumbnail) : getAttachmentUrl(attachments.find(a => a.mimetype.startsWith('image'))?.rid),
}}
/>
</head>
<Layout title={data.body?.title ? data.body.title : `Post #${data.id}`} trailingTitle='Solar Network'>
<div role="alert" class="alert shadow-lg px-12 m-0 rounded-none mb-5">
<Icon
name="material-symbols:ungroup"
class="stroke-info fill-info h-6 w-6 shrink-0"
/>
<div>
<h3 class="font-bold">Open in the Solian</h3>
<div class="text-xs">
The most modern, user-friendly, and official Solar Network app.
</div>
</div>
<div class="flex gap-2">
<a class="btn btn-sm" href="/products/solar-network#downloads">Get</a>
<a class="btn btn-sm" href={`https://sn.solsynth.dev/posts/${data.id}`}
>Open</a
>
</div>
</div>
<div class="container lg:max-w-[75ch] px-8 mx-auto">
<div class="flex gap-4 items-center mb-5">
<div class="avatar">
<div class="w-12 rounded-full">
<img src={getAttachmentUrl(data.publisher.avatar)} alt="avatar" />
</div>
</div>
<div class="userinfo flex flex-col">
<span class="flex gap-2 items-baseline">
<span class="text-md font-bold">{data.publisher.nick}</span>
<span class="text-xs font-mono">@{data.publisher.name}</span>
</span>
<span class="text-sm line-clamp-2 overflow-ellipsis"
>{data.publisher.description}</span
>
</div>
</div>
{
data.repost_id && (
<div role="alert" class="alert mb-5 py-2 mx-[-4px]">
<Icon
name="material-symbols:format-quote"
class="stroke-info fill-info h-6 w-6 shrink-0"
/>
<span>
This post is reposting post{' '}
<span class="font-mono">#{data.repost_id}</span>
</span>
<div>
<a class="btn btn-sm" href={`/posts/${data.repost_id}`}>
See reposted post
</a>
</div>
</div>
)
}
<article>
<div class="prose max-w-none max-md:prose-lg" set:html={content} />
{
attachments && (
<div
class="attachment-list mt-5 gap-4 grid grid-cols-1"
class:list={
attachments.length >= 2 ? 'md:grid-cols-2' : 'md:grid-cols-1'
}
>
{attachments.map((attachment) => (
<div class="attachment">
<AttachmentRenderer data={attachment} />
</div>
))}
</div>
)
}
</article>
</div>
</Layout>