Inital commit of Astro Website
This commit is contained in:
112
src/pages/book/[...slug].astro
Normal file
112
src/pages/book/[...slug].astro
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
import { getCollection, render } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import BookNavigation from '../../components/BookNavigation.astro';
|
||||
import "katex/dist/katex.min.css";
|
||||
import "rehype-callouts/theme/obsidian";
|
||||
import "../../styles/md-custom.css";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const pages = await getCollection('book');
|
||||
pages.sort((a, b) => a.id.localeCompare(b.id));
|
||||
|
||||
return pages.map((page, index) => {
|
||||
return {
|
||||
params: { slug: page.id },
|
||||
props: {
|
||||
page,
|
||||
prevPage: index > 0 ? pages[index - 1] : null,
|
||||
nextPage: index < pages.length - 1 ? pages[index + 1] : null,
|
||||
allPages: pages
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { page, prevPage, nextPage, allPages } = Astro.props;
|
||||
const { Content } = await render(page);
|
||||
|
||||
const chapters = allPages.reduce((acc, p) => {
|
||||
const [chapter] = p.id.split('/');
|
||||
if (!acc[chapter]) acc[chapter] = [];
|
||||
acc[chapter].push(p);
|
||||
return acc;
|
||||
}, {} as Record<string, typeof allPages>);
|
||||
---
|
||||
<BaseLayout title={page.data.title} theme="book">
|
||||
<div class="glass-container content prose">
|
||||
<h1>{page.data.title}</h1>
|
||||
<Content />
|
||||
</div>
|
||||
|
||||
<BookNavigation
|
||||
prevUrl={prevPage ? `/book/${prevPage.id}` : undefined}
|
||||
prevTitle={prevPage?.data.title}
|
||||
nextUrl={nextPage ? `/book/${nextPage.id}` : undefined}
|
||||
nextTitle={nextPage?.data.title}
|
||||
>
|
||||
<div slot="toc" class="mini-toc">
|
||||
{Object.entries(chapters).map(([chapter, items]) => (
|
||||
<div class="mini-chapter">
|
||||
<h4>{chapter.replace(/-/g, ' ').toUpperCase()}</h4>
|
||||
<ul>
|
||||
{items.map(item => (
|
||||
<li>
|
||||
<a
|
||||
href={`/book/${item.id}`}
|
||||
class={item.id === page.id ? 'active' : ''}
|
||||
>
|
||||
{item.data.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</BookNavigation>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
line-height: 1.8;
|
||||
padding: 2rem 3rem;
|
||||
}
|
||||
.mini-toc {
|
||||
text-align: left;
|
||||
}
|
||||
.mini-chapter {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.mini-chapter h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.7;
|
||||
color: var(--text-main);
|
||||
}
|
||||
.mini-chapter ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.mini-chapter li {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.mini-chapter a {
|
||||
display: block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
}
|
||||
.mini-chapter a:hover {
|
||||
background: rgba(var(--accent-base), 0.1);
|
||||
color: rgb(var(--accent-base));
|
||||
}
|
||||
.mini-chapter a.active {
|
||||
background: rgba(var(--accent-base), 0.2);
|
||||
color: rgb(var(--accent-base));
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
44
src/pages/book/index.astro
Normal file
44
src/pages/book/index.astro
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
const pages = await getCollection('book');
|
||||
pages.sort((a, b) => a.data.part - b.data.part);
|
||||
|
||||
const chapters = pages.reduce((acc, page) => {
|
||||
const chapter = page.data.chapter["id"];
|
||||
if (!acc[chapter]) acc[chapter] = [];
|
||||
acc[chapter].push(page);
|
||||
return acc;
|
||||
}, {} as Record<string, typeof pages>);
|
||||
---
|
||||
<BaseLayout title="Das Buch" theme="book" description="Ein fortlaufendes Werk über Software, Design und Architektur von c0ntroller.de.">
|
||||
<div class="glass-container header">
|
||||
<h1>Das Buch</h1>
|
||||
<p>Ein fortlaufendes Werk über Software, Design und Architektur.</p>
|
||||
</div>
|
||||
|
||||
<div class="glass-container toc">
|
||||
<h2>Inhaltsverzeichnis</h2>
|
||||
{Object.entries(chapters).map(([chapter, items]) => (
|
||||
<div class="chapter">
|
||||
<h3>{chapter.replace(/-/g, ' ').toUpperCase()}</h3>
|
||||
<ul class="page-list">
|
||||
{items.map(item => (
|
||||
<li><a href={`/book/${item.id}`}>{item.data.title}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</BaseLayout>
|
||||
<style>
|
||||
.header { margin-bottom: 2rem; }
|
||||
.toc { padding: 2rem; }
|
||||
.chapter { margin-bottom: 1.5rem; }
|
||||
.chapter h3 { margin-top: 0; margin-bottom: 0.5rem; font-size: 1.1rem; opacity: 0.8; }
|
||||
.page-list { list-style: none; padding-left: 0; margin: 0; }
|
||||
.page-list li { margin-bottom: 0.5rem; }
|
||||
.page-list a { display: block; padding: 0.5rem; border-radius: 0.25rem; transition: background 0.2s; }
|
||||
.page-list a:hover { background: rgba(59, 130, 246, 0.1); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user