This commit is contained in:
2025-11-25 19:53:38 +08:00
parent 2c4ed896e8
commit db55d8fd83
6 changed files with 116 additions and 28 deletions

56
src/apps/menu.tsx Normal file
View File

@@ -0,0 +1,56 @@
import { useMemo } from "react";
export type MenuProps = {
items: MenuItem[];
basename?: string;
};
export type MenuItem = {
id: string;
data: {
title: string;
tags: string[];
hideInMenu?: boolean;
}
}
export const Menu = (props: MenuProps) => {
const { items, basename = '' } = props;
const list = useMemo(() => {
return items.filter(item => !item.data?.hideInMenu);
}, [items]);
if (list.length === 0) {
return null;
}
return (
<nav className='flex-1 overflow-y-auto scrollbar bg-sidebar border border-sidebar-border rounded-lg p-4 shadow-sm'>
<h2 className="text-sm font-semibold text-sidebar-foreground"></h2>
<div className="space-y-1">
{list.map(item => (
<a
key={item.id}
href={`${basename}/docs/${item.id}/`}
className="group block rounded-md hover:bg-sidebar-accent transition-all duration-200 ease-in-out"
>
<div className="px-3 py-2.5">
<h3 className="text-sm font-semibold text-sidebar-foreground group-hover:text-sidebar-accent-foreground transition-colors">
{item.data?.title}
</h3>
{item.data?.tags && item.data.tags.length > 0 && (
<div className="flex flex-wrap gap-1.5 mt-2">
{item.data.tags.map(tag => (
<span
key={tag}
className="text-xs px-2 py-0.5 rounded-full bg-muted/60 text-muted-foreground font-medium hover:bg-muted transition-colors"
>
{tag}
</span>
))}
</div>
)}
</div>
</a>
))}
</div>
</nav>
);
}

View File

@@ -12,6 +12,11 @@ const docs = defineCollection({
// pubDate: z.coerce.date(), // pubDate: z.coerce.date(),
createdAt: z.coerce.date().optional(), createdAt: z.coerce.date().optional(),
updatedAt: z.coerce.date().optional(), updatedAt: z.coerce.date().optional(),
showMenu: z.boolean().optional().default(true),
/**
* 在侧边栏隐藏该文档
*/
hideInMenu: z.boolean().optional().default(false),
}), }),
}); });

8
src/data/docs/menu.md Normal file
View File

@@ -0,0 +1,8 @@
---
title: 'astro 概览'
tags: ['astro', 'simple', 'template']
createdAt: '2025-11-25 20:00:00'
hideInMenu: true
---
## 概览

View File

@@ -1,6 +1,8 @@
--- ---
title: 'astro 例子' title: 'astro 例子'
tags: ['astro', 'simple', 'template'] tags: ['astro', 'simple', 'template']
createdAt: '2025-11-25 20:00:00'
hideInMenu: true
--- ---
## astro-simplate-template ## astro-simplate-template

View File

@@ -5,29 +5,34 @@ export interface Props {
import '../styles/global.css'; import '../styles/global.css';
import '../styles/theme.css'; import '../styles/theme.css';
import 'github-markdown-css/github-markdown-light.css'; import 'github-markdown-css/github-markdown-light.css';
import { Menu, MenuItem } from '../apps/menu';
export interface Props { export interface Props {
title?: string; title?: string;
description?: string; description?: string;
lang?: string; lang?: string;
charset?: string; charset?: string;
showMenu?: boolean;
menu?: MenuItem[];
basename?: string;
} }
const { title = 'Light Code', description = 'A lightweight code editor', lang = 'zh-CN', charset = 'UTF-8' } = Astro.props; const {
title = 'Light Code',
description = 'A lightweight code editor',
lang = 'zh-CN',
charset = 'UTF-8',
showMenu = true,
menu,
basename = '',
} = Astro.props;
--- ---
<html lang='zh-CN'> <html lang={lang}>
<head> <head>
<meta charset='UTF-8' /> <meta charset={charset} />
<meta name='viewport' content='width=device-width, initial-scale=1.0' /> <meta name='viewport' content='width=device-width, initial-scale=1.0' />
<title>Docs</title> <title>{title}</title>
<link <meta name='description' content={description} />
rel='stylesheet'
href='https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.8.1/github-markdown-light.min.css'
integrity='sha512-X175XRJAO6PHAUi8AA7GP8uUF5Wiv+w9bOi64i02CHKDQBsO1yy0jLSKaUKg/NhRCDYBmOLQCfKaTaXiyZlLrw=='
crossorigin='anonymous'
referrerpolicy='no-referrer'
/>
<style> <style>
html, html,
body { body {
@@ -37,25 +42,29 @@ const { title = 'Light Code', description = 'A lightweight code editor', lang =
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
} }
body {
display: flex;
flex-direction: column;
align-items: center;
}
</style> </style>
</head> </head>
<body> <body class='flex flex-col items-center bg-background'>
<div> <div class='w-full'>
<slot name='header' /> <slot name='header' />
</div> </div>
<main class='p-2 flex-1 overflow-hidden'> <main class='flex-1 flex overflow-hidden w-full max-w-7xl px-4 py-4'>
<div class='markdown-body h-full scrollbar border-gray-200 overflow-auto px-6 py-2 w-[800px] border my-4 rounded-md shadow-md'> {
<slot /> showMenu && (
<aside class='w-64 min-w-64 h-full flex flex-col'>
<Menu items={menu!} client:only basename={basename} />
</aside>
)
}
<div class='flex-1 h-full flex items-start justify-center overflow-hidden'>
<article class='markdown-body h-full scrollbar overflow-auto px-8 py-6 w-full max-w-4xl border border-border rounded-lg shadow-sm bg-card'>
<slot />
</article>
</div> </div>
</main> </main>
<footer> <footer class='w-full border-t border-border bg-card/50 backdrop-blur-sm'>
<slot name='footer'> <slot name='footer'>
<p>Copyrignt &copy; 2025</p> <div class='text-center text-sm text-muted-foreground py-4'>Copyright &copy; 2025</div>
</slot> </slot>
</footer> </footer>
</body> </body>

View File

@@ -1,23 +1,31 @@
--- ---
import { getCollection, render } from 'astro:content'; import { getCollection, render } from 'astro:content';
import Main from '@/layouts/mdx.astro'; import Main from '@/layouts/mdx.astro';
import { basename } from '@/modules/basename';
// 1. 为每个集合条目生成一个新路径 // 1. 为每个集合条目生成一个新路径
export async function getStaticPaths() { export async function getStaticPaths() {
const posts = await getCollection('docs'); const posts = await getCollection('docs');
return posts.map((post) => ({ return posts.map((post) => ({
params: { id: post.id }, params: { id: post.id },
props: { post }, props: { post },
data: post,
})); }));
} }
type Post = { type Post = {
data: { title: string }; data: { title: string; tags: string[]; showMenu?: boolean };
}; };
// 2. 对于你的模板,你可以直接从 prop 获取条目 // 2. 对于你的模板,你可以直接从 prop 获取条目
const { post } = Astro.props as { post: Post }; const { post } = Astro.props as { post: Post };
const { Content } = await render(post); const { Content } = await render(post);
console.log('post', post);
const showMenu = post.data?.showMenu;
const staticPaths = await getStaticPaths();
const menu = staticPaths.map((item) => item.data);
--- ---
<Main> <Main showMenu={showMenu} menu={menu} basename={basename}>
<!-- <h1 slot={'header'}>{post.data.title}</h1> -->
<Content /> <Content />
<div slot='menu'>
<div>sdfsdfsdf sfsdfsdf</div>
</div>
</Main> </Main>