Страница заметки в блоге

This commit is contained in:
Иван Кузьменко 2025-09-29 03:22:58 +03:00 committed by Иван Кузьменко
parent 68c331f146
commit 4d65b30005
4 changed files with 124 additions and 1 deletions

1
src/app.d.ts vendored
View file

@ -23,6 +23,7 @@ declare global {
title: string;
thumbnail?: string;
date?: string;
dateChanged?: string;
description: string;
publisher: string;
published?: boolean;

View file

@ -1,5 +1,7 @@
import path from 'path';
export const THUMBNAIL_DEFAULT = "https://teasanctuary.ru/common/background-day.webp";
export async function fetchPostsSorted() {
const allPosts = await fetchPosts();
@ -8,7 +10,7 @@ export async function fetchPostsSorted() {
.filter((a) => !!a.date)
.sort((a, b) => {
return new Date(b.date!).valueOf() - new Date(a.date!).valueOf();
});
});
return sortedPosts;
};
@ -31,3 +33,11 @@ export async function fetchPosts() {
return allPosts;
};
export function resolveBlogPath(slug?: string, src?: string) {
if (!src) return null;
return src.startsWith('http://') || src.startsWith('https://')
? src
: `/blog/${slug}/${src}`;
}

View file

@ -0,0 +1,95 @@
<script lang="ts">
import { page } from '$app/state';
import InfoBlock from '$src/lib/components/InfoBlock.svelte';
import type { PageData } from './$types';
import Icon from '@iconify/svelte';
export let data: PageData;
const imageFallback = (event: any) => {
if (!event.target) return;
event.target.src = '/team/profiles/none.jpg';
};
const isPublic = !!data.blogPost.date;
</script>
<base target="_blank" />
<svelte:head>
<meta name="twitter:card" content="summary_large_image" />
</svelte:head>
<section class="hero flex shrink-0 flex-col items-center justify-center gap-5 overflow-hidden p-4">
<div
class="flex flex-col flex-nowrap items-center justify-center gap-3 lg:flex-row lg:flex-nowrap"
>
<div class="text-left">
<h1>{data.blogPost.title}</h1>
{#if data.blogPost.description}
<h2 class="text-gray">{data.blogPost.description}</h2>
{/if}
</div>
</div>
</section>
<section
class="flex shrink-0 flex-col items-center justify-center p-4 font-bold {isPublic
? 'bg-amber-50 text-slate-950'
: 'bg-red-500 text-slate-50'} sm:flex-row sm:flex-nowrap sm:gap-5"
>
<div class="flex items-center">
<Icon icon="material-symbols:calendar-today" class="mr-3" style="transform: scale( 1.4 )" />
<p>
{data.blogPost.date
? new Date(data.blogPost.date).toLocaleString(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric'
})
: 'Не опубликован!'}
</p>
</div>
{#if data.blogPost.dateChanged}
<div class="flex items-center font-bold">
<Icon icon="material-symbols:update" class="mr-3" style="transform: scale( 1.4 )" />
<p>
{new Date(data.blogPost.dateChanged).toLocaleString(undefined, {
month: 'short',
day: 'numeric',
year: 'numeric'
})}
</p>
</div>
{/if}
</section>
{#if page.data.blogPost.projects?.length > 0}
<InfoBlock>
<p>В данной заметке упоминаются наши проекты:</p>
<ul>
{#each page.data.blogPost.projects as project}
<li>{project}</li>
{/each}
</ul>
</InfoBlock>
{/if}
<article
class="prose
lg:prose-lg
prose-a:text-blue
prose-a:decoration-2
prose-a:underline-offset-2
hover:prose-a:text-lightblue
hover:prose-a:transition-all
prose-code:break-words
prose-pre:drop-shadow-md
bg-white
p-4 lg:p-8"
>
<svelte:component this={data.content} />
</article>
<style>
@import '$src/app.css';
</style>

View file

@ -0,0 +1,17 @@
import { resolveBlogPath, THUMBNAIL_DEFAULT } from "$src/lib/util/Blogs.js";
export async function load({ params }) {
const post = await import(`$src/blogs/${params.slug}.md`);
const blogPost: App.BlogPost = post.metadata;
const thumbnail = resolveBlogPath(params.slug, blogPost.thumbnail ?? THUMBNAIL_DEFAULT);
return {
title: `${blogPost.title} — Блог`,
description: blogPost.description,
thumbnail: thumbnail,
content: post.default,
blogPost: {
...blogPost
}
};
};