feat: complete header and footer components and dark/light mode switching function
This commit is contained in:
parent
51e76a3b99
commit
e5b8bd7ab0
16 changed files with 234 additions and 19 deletions
6
.vscode/extensions.json
vendored
6
.vscode/extensions.json
vendored
|
|
@ -1,4 +1,8 @@
|
||||||
{
|
{
|
||||||
"recommendations": ["astro-build.astro-vscode"],
|
"recommendations": [
|
||||||
|
"astro-build.astro-vscode",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"dbaeumer.vscode-eslint"
|
||||||
|
],
|
||||||
"unwantedRecommendations": []
|
"unwantedRecommendations": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
|
@ -1,4 +1,9 @@
|
||||||
{
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[astro]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.organizeImports": "always"
|
"source.organizeImports": "always"
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"@types/react": "^18.3.12",
|
"@types/react": "^18.3.12",
|
||||||
"@types/react-dom": "^18.3.1",
|
"@types/react-dom": "^18.3.1",
|
||||||
"astro": "^5.0.0-beta.10",
|
"astro": "^5.0.0-beta.10",
|
||||||
|
"lucide-react": "^0.461.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"tailwindcss": "^3.4.15",
|
"tailwindcss": "^3.4.15",
|
||||||
|
|
|
||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
|
|
@ -26,6 +26,9 @@ importers:
|
||||||
astro:
|
astro:
|
||||||
specifier: ^5.0.0-beta.10
|
specifier: ^5.0.0-beta.10
|
||||||
version: 5.0.0-beta.10(jiti@1.21.6)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1)
|
version: 5.0.0-beta.10(jiti@1.21.6)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1)
|
||||||
|
lucide-react:
|
||||||
|
specifier: ^0.461.0
|
||||||
|
version: 0.461.0(react@18.3.1)
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
|
|
@ -1991,6 +1994,11 @@ packages:
|
||||||
lru-cache@5.1.1:
|
lru-cache@5.1.1:
|
||||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||||
|
|
||||||
|
lucide-react@0.461.0:
|
||||||
|
resolution: {integrity: sha512-Scpw3D/dV1bgVRC5Kh774RCm99z0iZpPv75M6kg7QL1lLvkQ1rmI1Sjjic1aGp1ULBwd7FokV6ry0g+d6pMB+w==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
||||||
|
|
||||||
magic-string@0.30.14:
|
magic-string@0.30.14:
|
||||||
resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==}
|
resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==}
|
||||||
|
|
||||||
|
|
@ -5297,6 +5305,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
|
|
||||||
|
lucide-react@0.461.0(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
magic-string@0.30.14:
|
magic-string@0.30.14:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
|
|
|
||||||
22
src/components/astro/footer.astro
Normal file
22
src/components/astro/footer.astro
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="my-10 flex flex-col md:flex-row">
|
||||||
|
<p>
|
||||||
|
© {new Date().getFullYear()}
|
||||||
|
</p>
|
||||||
|
<p class="mx-1 hidden md:block">|</p>
|
||||||
|
<p class="mr-1">Designed By</p>
|
||||||
|
<a href="https://sunguoqi.com" class="text-blue-500 hover:underline">
|
||||||
|
Guoqi Sun
|
||||||
|
</a>
|
||||||
|
<p class="mx-1 hidden md:block">|</p>
|
||||||
|
<p class="mr-1">Powered By</p>
|
||||||
|
<a
|
||||||
|
href="https://github.com/sun0225SUN/astro-air"
|
||||||
|
class="text-blue-500 hover:underline"
|
||||||
|
>
|
||||||
|
Astro Air
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
17
src/components/astro/header.astro
Normal file
17
src/components/astro/header.astro
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
import { Rss } from "lucide-react"
|
||||||
|
import ThemeToggle from "~/components/astro/theme-toggle.astro"
|
||||||
|
import { site } from "~/config"
|
||||||
|
---
|
||||||
|
|
||||||
|
<header class="flex h-20 w-full items-center justify-between">
|
||||||
|
<a href="/">
|
||||||
|
<div class="text-xl font-semibold">{site.name}</div>
|
||||||
|
</a>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<a href="/atom.xml" target="_blank">
|
||||||
|
<Rss />
|
||||||
|
</a>
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
57
src/components/astro/theme-toggle.astro
Normal file
57
src/components/astro/theme-toggle.astro
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
import { Moon, Sun } from "lucide-react"
|
||||||
|
---
|
||||||
|
|
||||||
|
<button id="themeToggle">
|
||||||
|
<Sun className="dark:hidden" />
|
||||||
|
<Moon className="hidden dark:block" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// check current theme
|
||||||
|
const theme = (() => {
|
||||||
|
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
|
||||||
|
return localStorage.getItem("theme")
|
||||||
|
}
|
||||||
|
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
return "light"
|
||||||
|
})()
|
||||||
|
|
||||||
|
// set theme
|
||||||
|
if (theme === "light") {
|
||||||
|
document.documentElement.classList.remove("dark")
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add("dark")
|
||||||
|
}
|
||||||
|
|
||||||
|
// save theme
|
||||||
|
window.localStorage.setItem("theme", theme!)
|
||||||
|
|
||||||
|
// update theme
|
||||||
|
const updateTheme = () => {
|
||||||
|
const isDark = document.documentElement.classList.contains("dark")
|
||||||
|
localStorage.setItem("theme", isDark ? "dark" : "light")
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle theme
|
||||||
|
const handleToggleClick = () => {
|
||||||
|
const element = document.documentElement
|
||||||
|
|
||||||
|
if (!document.startViewTransition) {
|
||||||
|
element.classList.toggle("dark")
|
||||||
|
updateTheme()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
document.startViewTransition(() => {
|
||||||
|
element.classList.toggle("dark")
|
||||||
|
updateTheme()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById("themeToggle")!
|
||||||
|
.addEventListener("click", handleToggleClick)
|
||||||
|
</script>
|
||||||
28
src/config.ts
Normal file
28
src/config.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
export const site = {
|
||||||
|
name: "小孙同学",
|
||||||
|
favicon: "/avatar.png",
|
||||||
|
title: "小孙同学",
|
||||||
|
url: "https://blog.sunguoqi.com",
|
||||||
|
slogan: "一个浪漫的理性主义者",
|
||||||
|
description:
|
||||||
|
"🖥️ 前端小学生(React)|📸 摄影爱好者(Nikon Zfc)|🛸 旅行探索家(体验派)|🚴 骑行蹭风选手( Java 鱼雷 6-top )|🍎 科技产品发烧友(苹果&小米)<br/><br/> ✨ 路虽远行则将至,事虽难做则必成。热爱可抵岁月漫长。山高路远,独善其身,看世界,也找自己。希望能成为一个有趣的人~",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tabs = [
|
||||||
|
// {
|
||||||
|
// label: "归档",
|
||||||
|
// link: "./archive",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: "标签",
|
||||||
|
// link: "./tags",
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
label: "影集",
|
||||||
|
link: "https://camlife.cn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "关于",
|
||||||
|
link: "https://sunguoqi.com",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
||||||
<meta name="generator" content={Astro.generator} />
|
|
||||||
<title>Astro Basics</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<slot />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
42
src/layouts/base.astro
Normal file
42
src/layouts/base.astro
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
---
|
||||||
|
import "~/styles/globals.css"
|
||||||
|
import { site } from "~/config"
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href={site.favicon} />
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
<title>{site.title} - {site.slogan}</title>
|
||||||
|
<meta name="description" content={site.description} />
|
||||||
|
<script is:inline>
|
||||||
|
// set theme before page load
|
||||||
|
const theme = (() => {
|
||||||
|
if (
|
||||||
|
typeof localStorage !== "undefined" &&
|
||||||
|
localStorage.getItem("theme")
|
||||||
|
) {
|
||||||
|
return localStorage.getItem("theme")
|
||||||
|
}
|
||||||
|
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
|
return "dark"
|
||||||
|
}
|
||||||
|
return "light"
|
||||||
|
})()
|
||||||
|
|
||||||
|
if (theme === "dark") {
|
||||||
|
document.documentElement.classList.add("dark")
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
class="flex min-h-screen w-full justify-center dark:bg-[#121212] dark:text-white"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
src/layouts/home.astro
Normal file
9
src/layouts/home.astro
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import BaseLayout from "./base.astro"
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout>
|
||||||
|
<main class="max-auto w-full max-w-3xl">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
</BaseLayout>
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
---
|
---
|
||||||
import Layout from "../layouts/layout.astro"
|
import Footer from "~/components/astro/footer.astro"
|
||||||
import { Test } from "../components/test"
|
import Header from "~/components/astro/header.astro"
|
||||||
|
import { Test } from "../components/react/test"
|
||||||
|
import HomeLayout from "../layouts/home.astro"
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<HomeLayout>
|
||||||
|
<Header />
|
||||||
<Test />
|
<Test />
|
||||||
</Layout>
|
<Footer />
|
||||||
|
</HomeLayout>
|
||||||
|
|
|
||||||
27
src/styles/globals.css
Normal file
27
src/styles/globals.css
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Theme toggle effect */
|
||||||
|
/* https://theme-toggle.rdsx.dev/ */
|
||||||
|
/* https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API */
|
||||||
|
::view-transition-group(root) {
|
||||||
|
animation-timing-function: cubic-bezier(0.25, 1, 0.5, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-new(root) {
|
||||||
|
mask: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><filter id="blur"><feGaussianBlur stdDeviation="2"/></filter></defs><circle cx="0" cy="0" r="18" fill="white" filter="url(%23blur)"/></svg>')
|
||||||
|
top left / 0 no-repeat;
|
||||||
|
mask-origin: content-box;
|
||||||
|
animation: scale 1s;
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(root),
|
||||||
|
.dark::view-transition-old(root) {
|
||||||
|
animation: scale 1s;
|
||||||
|
transform-origin: top left;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scale {
|
||||||
|
to {
|
||||||
|
mask-size: 350vmax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
|
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
|
||||||
|
darkMode: ["class"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "react",
|
"jsxImportSource": "react",
|
||||||
|
|
||||||
/* Path Aliases */
|
/* Path Aliases */
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue