✨ feat: added support for markdown pages
This commit is contained in:
66
app/page.tsx
66
app/page.tsx
@@ -1,50 +1,20 @@
|
||||
|
||||
import BlogArea from "../components/blogpost";
|
||||
|
||||
|
||||
// Mock data for blog posts
|
||||
const blogposts = [
|
||||
{
|
||||
label: "Оптимизация конвейера: как мы добились IPC 1.2 в нашем RISC-V ядре",
|
||||
body: "Разбираем как с помощью глубокого конвейера и точного предсказания переходов ускорили выполнение инструкций. Бенчмарки показывают прирост в 3.7x compared to naive implementation.",
|
||||
publish: "5 августа 2023",
|
||||
get_absolute_url: "/post/optimizatsiya-konveyera-risc-v",
|
||||
tags: ["risc-v", "microarchitecture", "optimization"]
|
||||
},
|
||||
{
|
||||
label: "RISC-V Custom Extensions: почему мы добавили свои инструкции в процессор",
|
||||
body: "После 6 месяцев анализа мы расширили базовый набор команд. В статье делимся болью верификации, разработкой компиляторной поддержки и тем, как это ускорило обработку AES в 17 раз.",
|
||||
publish: "12 августа 2023",
|
||||
get_absolute_url: "/risc-v-custom-extensions",
|
||||
tags: ["risc-v", "isa", "hardware"]
|
||||
},
|
||||
{
|
||||
label: "Кастомный memory-mapped периферийный контроллер для RISC-V SoC",
|
||||
body: "Как мы реализовали низколатентный доступ к периферии. Разбираем взаимодействие с шиной TileLink, arbitration и особенности работы с прерываниями.",
|
||||
publish: "19 августа 2023",
|
||||
get_absolute_url: "/memory-mapped-controller-risc-v-soc",
|
||||
tags: ["risc-v", "soc", "embedded"]
|
||||
},
|
||||
{
|
||||
label: "Hot-swap модулей в RISC-V системе: динамическая подгрузка ускорителей",
|
||||
body: "Реализовали runtime-конфигурацию процессорных расширений на ПЛИС. Теперь можно подгружать крипто-ускорители и DSP блоки без перезагрузки всей системы.",
|
||||
publish: "26 августа 2023",
|
||||
get_absolute_url: "/hot-swap-risc-v-modules",
|
||||
tags: ["risc-v", "fpga", "dynamic"]
|
||||
},
|
||||
{
|
||||
label: "Верификация RISC-V ядра: как мы покрыли 99.8% кода формальной проверкой",
|
||||
body: "Наша методология верификации с использованием UVM и SymbiYosys. Показываем как обнаружили 47 критических багов до tape-out и добились соответствия спецификации.",
|
||||
publish: "2 сентября 2023",
|
||||
get_absolute_url: "/verifikatsiya-risc-v-yadra",
|
||||
tags: ["risc-v", "verification", "formal"]
|
||||
}
|
||||
];
|
||||
import { getSortedPostsData } from '@/lib/posts';
|
||||
import BlogArea from '@/components/blogpost';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<BlogArea blogposts={blogposts} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
const blogposts = getSortedPostsData();
|
||||
|
||||
const formattedPosts = blogposts.map(post => ({
|
||||
label: post.title,
|
||||
body: post.description,
|
||||
publish: new Date(post.date).toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
}),
|
||||
get_absolute_url: `/post/${post.slug}`,
|
||||
tags: post.tags,
|
||||
}));
|
||||
|
||||
return <BlogArea blogposts={formattedPosts} />;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Post() {
|
||||
return (
|
||||
<>
|
||||
<main className="flex flex-col gap-[32px] row-start-2 items-center">
|
||||
<section className="space-y-1 text-center">
|
||||
<dl className="space-y-10">
|
||||
<div>
|
||||
<dt className="sr-only">Опубликовано</dt>
|
||||
<dd className="text-base leading-6 font-medium text-gray-500 dark:text-gray-400">
|
||||
Monday, December 21, 2025
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div>
|
||||
<h1 className="text-3xl leading-9 font-extrabold tracking-tight text-gray-900 sm:text-4xl sm:leading-10 md:text-5xl md:leading-14 lg:text-3xl dark:text-gray-100">
|
||||
Создание и интеграция собственного процессорного ядра на базе RISC-V с использованием языка Chisel
|
||||
</h1>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
98
app/post/[slug]/page.tsx
Normal file
98
app/post/[slug]/page.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import { getPostData, getAllPostSlugs } from '@/lib/posts';
|
||||
import { notFound } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface PostPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const slugs = getAllPostSlugs();
|
||||
console.log('Генерация статических путей для slugs:', slugs);
|
||||
|
||||
return slugs.map((slug) => ({
|
||||
slug,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PostPageProps) {
|
||||
const { slug } = await params;
|
||||
const post = await getPostData(slug);
|
||||
|
||||
if (!post) {
|
||||
return {
|
||||
title: 'Пост не найден',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: post.title,
|
||||
description: post.description,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function PostPage({ params }: PostPageProps) {
|
||||
const { slug } = await params;
|
||||
const post = await getPostData(slug);
|
||||
|
||||
console.log(`Загрузка поста: ${slug}, результат:`, post ? 'найден' : 'не найден');
|
||||
|
||||
if (!post) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const formatDate = (dateStr: string) => {
|
||||
try {
|
||||
const date = new Date(dateStr);
|
||||
return new Intl.DateTimeFormat('ru-RU', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
}).format(date);
|
||||
} catch {
|
||||
return dateStr;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="flex flex-col gap-[32px] row-start-2 items-center">
|
||||
<section className="space-y-1 text-center max-w-4xl w-full px-4 mt-2">
|
||||
<dl className="space-y-10">
|
||||
<div>
|
||||
<dt className="sr-only">Опубликовано</dt>
|
||||
<dd className="text-base leading-6 font-medium text-gray-500 dark:text-gray-400">
|
||||
{formatDate(post.date)}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div>
|
||||
<h1 className="text-3xl leading-9 font-extrabold tracking-tight text-gray-900 sm:text-4xl sm:leading-10 md:text-5xl md:leading-14 dark:text-gray-100">
|
||||
{post.title}
|
||||
</h1>
|
||||
</div>
|
||||
{post.tags.length > 0 && (
|
||||
<div className="flex flex-wrap justify-center gap-2 mt-4">
|
||||
{post.tags.map((tag) => (
|
||||
<Link
|
||||
key={tag}
|
||||
href={`/tags/${tag}`}
|
||||
className="inline-block border border-slate-400 px-3 py-1 rounded-full text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
||||
>
|
||||
{tag}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
<section className="mx-auto px-4 pb-[4em] w-full px-[3em]">
|
||||
<article
|
||||
className="prose prose-lg dark:prose-invert prose-headings:font-bold prose-a:text-blue-500 hover:prose-a:text-blue-700 prose-code:bg-gray-100 dark:prose-code:bg-gray-800 prose-pre:bg-gray-900 dark:prose-pre:bg-gray-900 prose-img:rounded-xl prose-blockquote:border-l-4 prose-blockquote:border-blue-500 prose-blockquote:bg-gray-50 dark:prose-blockquote:bg-gray-800 prose-blockquote:italic prose-blockquote:pl-4 max-w-none"
|
||||
dangerouslySetInnerHTML={{ __html: post.contentHtml }}
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user