mirror of
https://github.com/KazooTTT/kazoottt-blog.git
synced 2025-06-16 15:31:21 +08:00
feat: add sitemap
This commit is contained in:
12138
pnpm-lock.yaml
generated
12138
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,19 @@
|
|||||||
/** @type {import("prettier").Config} */
|
/** @type {import("prettier").Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// i am just using the standard config, change if you need something else
|
// i am just using the standard config, change if you need something else
|
||||||
...require('prettier-config-standard'),
|
...require('prettier-config-standard'),
|
||||||
pluginSearchDirs: [__dirname],
|
pluginSearchDirs: [__dirname],
|
||||||
plugins: [
|
plugins: ['prettier-plugin-astro', 'prettier-plugin-tailwindcss'],
|
||||||
'prettier-plugin-astro',
|
overrides: [
|
||||||
'prettier-plugin-tailwindcss'
|
{
|
||||||
],
|
files: '*.astro',
|
||||||
overrides: [
|
options: {
|
||||||
{
|
parser: 'astro'
|
||||||
files: '*.astro',
|
}
|
||||||
options: {
|
}
|
||||||
parser: 'astro'
|
],
|
||||||
}
|
useTabs: true,
|
||||||
},
|
singleQuote: true,
|
||||||
],
|
trailingComma: 'none',
|
||||||
useTabs: true,
|
printWidth: 100
|
||||||
singleQuote: true,
|
|
||||||
trailingComma: 'none',
|
|
||||||
printWidth: 100
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ import kazootttAvatar from '../../assets/kazoottt-avatar.jpeg'
|
|||||||
import { Image } from 'astro:assets'
|
import { Image } from 'astro:assets'
|
||||||
---
|
---
|
||||||
|
|
||||||
<header class='mb-8 flex w-full flex-wrap pb-3 text-sm sm:flex-nowrap sm:justify-start'>
|
<header class='fixed top-0 left-0 right-0 z-50 bg-white dark:bg-gray-800 shadow-sm'>
|
||||||
<nav
|
<nav
|
||||||
class='relative mx-auto flex w-full items-center justify-between sm:flex sm:items-center'
|
class='mx-auto flex w-full items-center justify-between px-4 py-3 sm:flex sm:items-center'
|
||||||
aria-label='global'
|
aria-label='global'
|
||||||
>
|
>
|
||||||
<a class='flex items-center' href='/'>
|
<a class='flex items-center' href='/'>
|
||||||
@ -18,7 +18,25 @@ import { Image } from 'astro:assets'
|
|||||||
<div class='hidden flex-none text-xl font-semibold sm:block' aria-label='Brand'>KazooTTT</div>
|
<div class='hidden flex-none text-xl font-semibold sm:block' aria-label='Brand'>KazooTTT</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class='flex flex-row items-center justify-center gap-x-5 sm:gap-x-7'>
|
<!-- Mobile menu button -->
|
||||||
|
<button
|
||||||
|
id='mobileMenuButton'
|
||||||
|
class='rounded-md p-2 hover:bg-border sm:hidden'
|
||||||
|
aria-label='Toggle mobile menu'
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
width='24'
|
||||||
|
height='24'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
class='h-6 w-6'
|
||||||
|
>
|
||||||
|
<path fill='currentColor' d='M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Desktop Navigation -->
|
||||||
|
<div class='hidden flex-row items-center justify-center gap-x-7 sm:flex'>
|
||||||
<a
|
<a
|
||||||
href='/blog'
|
href='/blog'
|
||||||
class={`
|
class={`
|
||||||
@ -55,6 +73,34 @@ import { Image } from 'astro:assets'
|
|||||||
aria-label='Nav Menu Item'
|
aria-label='Nav Menu Item'
|
||||||
>Tools
|
>Tools
|
||||||
</a>
|
</a>
|
||||||
|
<div class='relative'>
|
||||||
|
<button
|
||||||
|
class='peer flex items-center text-[1.05rem] font-medium hover:text-foreground/75'
|
||||||
|
aria-label='More Menu'
|
||||||
|
>
|
||||||
|
More
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
width='20'
|
||||||
|
height='20'
|
||||||
|
viewBox='0 0 24 24'
|
||||||
|
class='ml-1 transform transition-transform duration-200 peer-hover:rotate-180'
|
||||||
|
>
|
||||||
|
<path fill='currentColor' d='m12 15l-5-5h10z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class='invisible absolute right-0 mt-2 w-48 rounded-md bg-white py-2 opacity-0 shadow-lg transition-all duration-200 hover:visible hover:opacity-100 peer-hover:visible peer-hover:opacity-100 dark:bg-gray-800'
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href='/friends'
|
||||||
|
class='block px-6 py-3 text-[1.05rem] font-medium transition-colors hover:bg-gray-100 hover:text-foreground/75 dark:hover:bg-gray-700'
|
||||||
|
aria-label='Friends Page'
|
||||||
|
>
|
||||||
|
Friends
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
id='toggleDarkMode'
|
id='toggleDarkMode'
|
||||||
@ -85,6 +131,60 @@ import { Image } from 'astro:assets'
|
|||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile Navigation -->
|
||||||
|
<div
|
||||||
|
id='mobileMenu'
|
||||||
|
class='fixed inset-x-0 top-[72px] hidden rounded-b-lg bg-white shadow-lg dark:bg-gray-800 sm:hidden z-50 max-h-[calc(100vh-72px)] overflow-y-auto'
|
||||||
|
>
|
||||||
|
<div class='space-y-2 px-4 py-2'>
|
||||||
|
<a
|
||||||
|
href='/blog'
|
||||||
|
class={`
|
||||||
|
block py-2 text-[1.05rem] font-medium hover:text-foreground/75
|
||||||
|
${Astro.url.pathname.startsWith('/blog') ? 'text-green-400' : ''}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Blog
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/categories'
|
||||||
|
class={`
|
||||||
|
block py-2 text-[1.05rem] font-medium hover:text-foreground/75
|
||||||
|
${Astro.url.pathname.startsWith('/categories') ? 'text-green-400' : ''}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Cats.
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/tags'
|
||||||
|
class={`
|
||||||
|
block py-2 text-[1.05rem] font-medium hover:text-foreground/75
|
||||||
|
${Astro.url.pathname.startsWith('/tags') ? 'text-green-400' : ''}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Tags
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/tools'
|
||||||
|
class={`
|
||||||
|
block py-2 text-[1.05rem] font-medium hover:text-foreground/75
|
||||||
|
${Astro.url.pathname.startsWith('/tools') ? 'text-green-400' : ''}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Tools
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/friends'
|
||||||
|
class={`
|
||||||
|
block py-2 text-[1.05rem] font-medium hover:text-foreground/75
|
||||||
|
${Astro.url.pathname.startsWith('/friends') ? 'text-green-400' : ''}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Friends
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@ -93,6 +193,8 @@ import { Image } from 'astro:assets'
|
|||||||
return localStorage.getItem('theme')
|
return localStorage.getItem('theme')
|
||||||
}
|
}
|
||||||
const toggleDarkModeButton = document.getElementById('toggleDarkMode')
|
const toggleDarkModeButton = document.getElementById('toggleDarkMode')
|
||||||
|
const mobileMenuButton = document.getElementById('mobileMenuButton')
|
||||||
|
const mobileMenu = document.getElementById('mobileMenu')
|
||||||
|
|
||||||
toggleDarkModeButton?.addEventListener('click', () => {
|
toggleDarkModeButton?.addEventListener('click', () => {
|
||||||
const toggleDarkModeEvent = new CustomEvent('theme-change', {
|
const toggleDarkModeEvent = new CustomEvent('theme-change', {
|
||||||
@ -100,4 +202,18 @@ import { Image } from 'astro:assets'
|
|||||||
})
|
})
|
||||||
document.dispatchEvent(toggleDarkModeEvent)
|
document.dispatchEvent(toggleDarkModeEvent)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mobileMenuButton?.addEventListener('click', () => {
|
||||||
|
mobileMenu?.classList.toggle('hidden')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close mobile menu when clicking outside
|
||||||
|
document.addEventListener('click', (event) => {
|
||||||
|
if (
|
||||||
|
!mobileMenuButton?.contains(event.target as Node) &&
|
||||||
|
!mobileMenu?.contains(event.target as Node)
|
||||||
|
) {
|
||||||
|
mobileMenu?.classList.add('hidden')
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -25,7 +25,7 @@ const {
|
|||||||
<body class='flex justify-center bg-background'>
|
<body class='flex justify-center bg-background'>
|
||||||
<ThemeProvider />
|
<ThemeProvider />
|
||||||
<main
|
<main
|
||||||
class='flex min-h-screen w-screen max-w-[60rem] flex-col items-center px-6 pb-10 pt-7 font-satoshi text-[0.92rem] leading-relaxed sm:px-10 lg:px-10'
|
class='flex min-h-screen w-screen max-w-[60rem] flex-col items-center px-6 pb-10 pt-24 font-satoshi text-[0.92rem] leading-relaxed sm:px-10 lg:px-10'
|
||||||
>
|
>
|
||||||
<Header />
|
<Header />
|
||||||
<slot />
|
<slot />
|
||||||
|
66
src/pages/friends.astro
Normal file
66
src/pages/friends.astro
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
import BaseLayout from '../layouts/BaseLayout.astro'
|
||||||
|
|
||||||
|
const friends = [
|
||||||
|
{
|
||||||
|
name: '大咩整装待发',
|
||||||
|
url: 'https://www.mihuashi.com/profiles/283847?role=painter'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Yuang's Blog",
|
||||||
|
url: 'https://yuuuuang.com/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'huaiying',
|
||||||
|
url: 'https://blog.csdn.net/huaiyingdetective'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Sorry404 Wang',
|
||||||
|
url: 'http://40404.site/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lijinghua',
|
||||||
|
url: 'www.lijinghua.club'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '思无道',
|
||||||
|
url: 'https://siwudao.github.io/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Kai',
|
||||||
|
url: 'https://kaiyi.cool/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout
|
||||||
|
meta={{
|
||||||
|
title: `Friends`,
|
||||||
|
description: 'my friends '
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class='container mx-auto px-4 py-8'>
|
||||||
|
<h1 class='mb-8 text-3xl font-bold'>Friends</h1>
|
||||||
|
<div class='grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3'>
|
||||||
|
{
|
||||||
|
friends.map((friend) => (
|
||||||
|
<a
|
||||||
|
href={friend.url.startsWith('http') ? friend.url : `https://${friend.url}`}
|
||||||
|
target='_blank'
|
||||||
|
rel='noopener noreferrer'
|
||||||
|
class='block rounded-lg bg-white p-6 shadow-md transition-shadow duration-300 hover:shadow-lg dark:bg-gray-800'
|
||||||
|
>
|
||||||
|
<h2 class='mb-2 text-xl font-semibold'>{friend.name}</h2>
|
||||||
|
<p class='truncate text-sm text-gray-600 dark:text-gray-400'>{friend.url}</p>
|
||||||
|
</a>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -94,15 +94,18 @@ const projects = [...directProjects, ...mdProjects].slice(0, MAX_PROJECTS)
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<Section title='About'>
|
<Section title='About'>
|
||||||
<div class='text-muted-foreground space-y-2'>
|
<div class='space-y-2 text-muted-foreground'>
|
||||||
<p>你是一位专注于前端开发的工程师,深度使用 React 技术栈。通过持续学习和实践,你在现代前端工程化方面积累了丰富经验。</p>
|
<p>
|
||||||
|
你是一位专注于前端开发的工程师,深度使用 React
|
||||||
|
技术栈。通过持续学习和实践,你在现代前端工程化方面积累了丰富经验。
|
||||||
|
</p>
|
||||||
<p>你的技术栈:</p>
|
<p>你的技术栈:</p>
|
||||||
<ul class="list-disc list-inside ml-2 mt-1">
|
<ul class='ml-2 mt-1 list-inside list-disc'>
|
||||||
<li>基于 React 生态系统进行 Web 应用开发</li>
|
<li>基于 React 生态系统进行 Web 应用开发</li>
|
||||||
<li>使用 VTK.js 探索数据可视化领域</li>
|
<li>使用 VTK.js 探索数据可视化领域</li>
|
||||||
<li>具备 Python 和 Node.js 全栈开发经验</li>
|
<li>具备 Python 和 Node.js 全栈开发经验</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="mt-2">保持技术热情,持续学习成长中 🌱</p>
|
<p class='mt-2'>保持技术热情,持续学习成长中 🌱</p>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
{
|
{
|
||||||
|
70
src/pages/sitemap.xml.js
Normal file
70
src/pages/sitemap.xml.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import rss from '@astrojs/rss'
|
||||||
|
import { siteConfig } from '@/site-config'
|
||||||
|
import { getAllSortedPosts } from '@/utils'
|
||||||
|
|
||||||
|
export const GET = async () => {
|
||||||
|
const posts = await getAllSortedPosts()
|
||||||
|
|
||||||
|
const items = await Promise.all(
|
||||||
|
posts.map(async (post) => {
|
||||||
|
const entry = post
|
||||||
|
const body = entry.body
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: post.data.title ?? '',
|
||||||
|
description: JSON.stringify(body),
|
||||||
|
pubDate: post.data.date,
|
||||||
|
link: `/blog/${post.slug}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const link = import.meta.env.SITE
|
||||||
|
const locale = ''
|
||||||
|
|
||||||
|
const defaultFields = [
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily',
|
||||||
|
priority: '1.0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}/blog`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily',
|
||||||
|
priority: '0.8'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}/categories`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily',
|
||||||
|
priority: '0.7'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}/tags`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily',
|
||||||
|
priority: '0.7'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}/tools`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'weekly',
|
||||||
|
priority: '0.6'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loc: `${link}${locale}/rss.xml`,
|
||||||
|
lastmod: new Date().toISOString().split('T')[0],
|
||||||
|
changefreq: 'daily',
|
||||||
|
priority: '0.4'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return rss({
|
||||||
|
title: siteConfig.title,
|
||||||
|
description: siteConfig.description + '\nfeedId:76245438397618182+userId:62156866798228480',
|
||||||
|
site: import.meta.env.SITE,
|
||||||
|
items: [...defaultFields, ...items]
|
||||||
|
})
|
||||||
|
}
|
Reference in New Issue
Block a user