style: overall optimized UI style

This commit is contained in:
Guoqi Sun 2024-12-21 20:13:18 +08:00
parent 18abe2f3d9
commit cd3581de17
26 changed files with 263 additions and 143 deletions

View file

@ -42,7 +42,8 @@
"lint-staged": "^15.2.11", "lint-staged": "^15.2.11",
"prettier": "^3.4.2", "prettier": "^3.4.2",
"prettier-plugin-astro": "^0.14.1", "prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.6.9" "prettier-plugin-tailwindcss": "^0.6.9",
"sass": "^1.83.0"
}, },
"lint-staged": { "lint-staged": {
"*/**/*.{js,jsx,ts,tsx,astro}": [ "*/**/*.{js,jsx,ts,tsx,astro}": [

66
pnpm-lock.yaml generated
View file

@ -13,10 +13,10 @@ importers:
version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.4.2)(typescript@5.7.2) version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.4.2)(typescript@5.7.2)
'@astrojs/mdx': '@astrojs/mdx':
specifier: ^4.0.2 specifier: ^4.0.2
version: 4.0.2(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1)) version: 4.0.2(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1))
'@astrojs/react': '@astrojs/react':
specifier: ^4.1.0 specifier: ^4.1.0
version: 4.1.0(@types/node@22.10.2)(@types/react-dom@18.3.1)(@types/react@18.3.12)(jiti@2.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(yaml@2.6.1) version: 4.1.0(@types/node@22.10.2)(@types/react-dom@18.3.1)(@types/react@18.3.12)(jiti@2.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.0)(yaml@2.6.1)
'@astrojs/rss': '@astrojs/rss':
specifier: ^4.0.10 specifier: ^4.0.10
version: 4.0.10 version: 4.0.10
@ -25,7 +25,7 @@ importers:
version: 3.2.1 version: 3.2.1
'@astrojs/tailwind': '@astrojs/tailwind':
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.1.3(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16) version: 5.1.3(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16)
'@types/react': '@types/react':
specifier: ^18.3.12 specifier: ^18.3.12
version: 18.3.12 version: 18.3.12
@ -34,10 +34,10 @@ importers:
version: 18.3.1 version: 18.3.1
astro: astro:
specifier: ^5.1.0 specifier: ^5.1.0
version: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1) version: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1)
astro-og-canvas: astro-og-canvas:
specifier: ^0.5.5 specifier: ^0.5.5
version: 0.5.5(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1)) version: 0.5.5(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1))
canvaskit-wasm: canvaskit-wasm:
specifier: ^0.39.1 specifier: ^0.39.1
version: 0.39.1 version: 0.39.1
@ -99,6 +99,9 @@ importers:
prettier-plugin-tailwindcss: prettier-plugin-tailwindcss:
specifier: ^0.6.9 specifier: ^0.6.9
version: 0.6.9(prettier-plugin-astro@0.14.1)(prettier@3.4.2) version: 0.6.9(prettier-plugin-astro@0.14.1)(prettier@3.4.2)
sass:
specifier: ^1.83.0
version: 1.83.0
packages: packages:
@ -2019,6 +2022,9 @@ packages:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
immutable@5.0.3:
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
import-fresh@3.3.0: import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -3082,6 +3088,11 @@ packages:
sass-formatter@0.7.9: sass-formatter@0.7.9:
resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==} resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
sass@1.83.0:
resolution: {integrity: sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==}
engines: {node: '>=14.0.0'}
hasBin: true
sax@1.4.1: sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
@ -3821,12 +3832,12 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@astrojs/mdx@4.0.2(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1))': '@astrojs/mdx@4.0.2(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1))':
dependencies: dependencies:
'@astrojs/markdown-remark': 6.0.1 '@astrojs/markdown-remark': 6.0.1
'@mdx-js/mdx': 3.1.0(acorn@8.14.0) '@mdx-js/mdx': 3.1.0(acorn@8.14.0)
acorn: 8.14.0 acorn: 8.14.0
astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1) astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1)
es-module-lexer: 1.5.4 es-module-lexer: 1.5.4
estree-util-visit: 2.0.0 estree-util-visit: 2.0.0
hast-util-to-html: 9.0.3 hast-util-to-html: 9.0.3
@ -3844,15 +3855,15 @@ snapshots:
dependencies: dependencies:
prismjs: 1.29.0 prismjs: 1.29.0
'@astrojs/react@4.1.0(@types/node@22.10.2)(@types/react-dom@18.3.1)(@types/react@18.3.12)(jiti@2.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(yaml@2.6.1)': '@astrojs/react@4.1.0(@types/node@22.10.2)(@types/react-dom@18.3.1)(@types/react@18.3.12)(jiti@2.4.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.0)(yaml@2.6.1)':
dependencies: dependencies:
'@types/react': 18.3.12 '@types/react': 18.3.12
'@types/react-dom': 18.3.1 '@types/react-dom': 18.3.1
'@vitejs/plugin-react': 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1)) '@vitejs/plugin-react': 4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1))
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
ultrahtml: 1.5.3 ultrahtml: 1.5.3
vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1) vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- jiti - jiti
@ -3878,9 +3889,9 @@ snapshots:
stream-replace-string: 2.0.0 stream-replace-string: 2.0.0
zod: 3.23.8 zod: 3.23.8
'@astrojs/tailwind@5.1.3(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16)': '@astrojs/tailwind@5.1.3(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1))(tailwindcss@3.4.16)':
dependencies: dependencies:
astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1) astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1)
autoprefixer: 10.4.20(postcss@8.4.49) autoprefixer: 10.4.20(postcss@8.4.49)
postcss: 8.4.49 postcss: 8.4.49
postcss-load-config: 4.0.2(postcss@8.4.49) postcss-load-config: 4.0.2(postcss@8.4.49)
@ -4700,14 +4711,14 @@ snapshots:
'@ungap/structured-clone@1.2.0': {} '@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1))': '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1))':
dependencies: dependencies:
'@babel/core': 7.26.0 '@babel/core': 7.26.0
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
'@types/babel__core': 7.20.5 '@types/babel__core': 7.20.5
react-refresh: 0.14.2 react-refresh: 0.14.2
vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1) vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -4884,14 +4895,14 @@ snapshots:
- supports-color - supports-color
- typescript - typescript
astro-og-canvas@0.5.5(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1)): astro-og-canvas@0.5.5(astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1)):
dependencies: dependencies:
astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1) astro: 5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1)
canvaskit-wasm: 0.39.1 canvaskit-wasm: 0.39.1
deterministic-object-hash: 2.0.2 deterministic-object-hash: 2.0.2
entities: 4.5.0 entities: 4.5.0
astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(typescript@5.7.2)(yaml@2.6.1): astro@5.1.0(@types/node@22.10.2)(jiti@2.4.2)(rollup@4.27.4)(sass@1.83.0)(typescript@5.7.2)(yaml@2.6.1):
dependencies: dependencies:
'@astrojs/compiler': 2.10.3 '@astrojs/compiler': 2.10.3
'@astrojs/internal-helpers': 0.4.2 '@astrojs/internal-helpers': 0.4.2
@ -4943,8 +4954,8 @@ snapshots:
unist-util-visit: 5.0.0 unist-util-visit: 5.0.0
unstorage: 1.14.1 unstorage: 1.14.1
vfile: 6.0.3 vfile: 6.0.3
vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1) vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1)
vitefu: 1.0.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1)) vitefu: 1.0.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1))
which-pm: 3.0.0 which-pm: 3.0.0
xxhash-wasm: 1.1.0 xxhash-wasm: 1.1.0
yargs-parser: 21.1.1 yargs-parser: 21.1.1
@ -5954,6 +5965,8 @@ snapshots:
ignore@5.3.2: {} ignore@5.3.2: {}
immutable@5.0.3: {}
import-fresh@3.3.0: import-fresh@3.3.0:
dependencies: dependencies:
parent-module: 1.0.1 parent-module: 1.0.1
@ -7311,6 +7324,14 @@ snapshots:
dependencies: dependencies:
suf-log: 2.5.3 suf-log: 2.5.3
sass@1.83.0:
dependencies:
chokidar: 4.0.1
immutable: 5.0.3
source-map-js: 1.2.1
optionalDependencies:
'@parcel/watcher': 2.5.0
sax@1.4.1: {} sax@1.4.1: {}
scheduler@0.23.2: scheduler@0.23.2:
@ -7758,7 +7779,7 @@ snapshots:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
vfile-message: 4.0.2 vfile-message: 4.0.2
vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1): vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1):
dependencies: dependencies:
esbuild: 0.24.0 esbuild: 0.24.0
postcss: 8.4.49 postcss: 8.4.49
@ -7767,11 +7788,12 @@ snapshots:
'@types/node': 22.10.2 '@types/node': 22.10.2
fsevents: 2.3.3 fsevents: 2.3.3
jiti: 2.4.2 jiti: 2.4.2
sass: 1.83.0
yaml: 2.6.1 yaml: 2.6.1
vitefu@1.0.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1)): vitefu@1.0.4(vite@6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1)):
optionalDependencies: optionalDependencies:
vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(yaml@2.6.1) vite: 6.0.3(@types/node@22.10.2)(jiti@2.4.2)(sass@1.83.0)(yaml@2.6.1)
volar-service-css@0.0.62(@volar/language-service@2.4.10): volar-service-css@0.0.62(@volar/language-service@2.4.10):
dependencies: dependencies:

BIN
public/noise.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -1,7 +1,8 @@
--- ---
import { latestPosts } from "~/config" import { latestPosts } from "~/config"
import { getLangFromUrl, useTranslations } from "~/i18n/utils" import { getLangFromUrl, useTranslations } from "~/i18n/utils"
import { formatDate, getPostsByLocale } from "~/utils" import { getPostsByLocale } from "~/utils"
import PostList from "./post-list.astro"
const lang = getLangFromUrl(Astro.url) const lang = getLangFromUrl(Astro.url)
const t = useTranslations(lang) const t = useTranslations(lang)
@ -13,13 +14,11 @@ const posts = allPosts.slice(0, latestPosts)
<div class="my-8 text-xl font-medium md:my-8">{t("blog.latest")}</div> <div class="my-8 text-xl font-medium md:my-8">{t("blog.latest")}</div>
{ {
posts.map((post: any) => ( posts.map((post: any) => (
<a href={`/${lang}/posts/${post.id}/`} class="visited:text-purple-500/90"> <PostList
<div class="my-2 flex text-lg"> post={post}
<p class="flex w-36 flex-shrink-0 truncate text-gray-500 dark:text-gray-400"> lang={lang}
<time>{formatDate(post.data.pubDate)}</time> dateFormat="YYYY-MM-DD"
</p> dateWidth="w-32"
<p class="line-clamp-2">{post.data.title}</p> />
</div>
</a>
)) ))
} }

View file

@ -2,12 +2,16 @@
const currentYear = new Date().getFullYear() const currentYear = new Date().getFullYear()
--- ---
<footer class="my-10 flex flex-wrap items-center gap-1"> <footer class="relative z-10 my-10 flex flex-wrap items-center gap-1">
<p>&copy; {currentYear}</p> <p>&copy; {currentYear}</p>
{ {
[ [
{ text: "Designed By", link: "https://sunguoqi.com", label: "Guoqi Sun" }, {
text: "Designed By",
link: "https://sunguoqi.com",
label: "Guoqi Sun",
},
{ {
text: "Powered By", text: "Powered By",
link: "https://github.com/sun0225SUN/astro-air", link: "https://github.com/sun0225SUN/astro-air",

View file

@ -7,6 +7,6 @@ const lang = getLangFromUrl(Astro.url)
const IntroContent = lang === "zh" ? IntroContentZh : IntroContentEn const IntroContent = lang === "zh" ? IntroContentZh : IntroContentEn
--- ---
<div class="my-10"> <div class="relative z-10 my-10">
<IntroContent /> <IntroContent />
</div> </div>

View file

@ -5,7 +5,7 @@ import { getLangFromUrl, useTranslations } from "~/i18n/utils"
const lang = getLangFromUrl(Astro.url) const lang = getLangFromUrl(Astro.url)
const t = useTranslations(lang) const t = useTranslations(lang)
const { home, archive, tags, custom, about } = const { home, archive, custom, about } =
lang === "zh" ? zh.navigation : en.navigation lang === "zh" ? zh.navigation : en.navigation
--- ---
@ -27,16 +27,6 @@ const { home, archive, tags, custom, about } =
</a> </a>
) )
} }
{
tags && (
<a
href={`/${lang}/tags`}
class="hover:underline hover:underline-offset-4"
>
<p>{t("nav.tags")}</p>
</a>
)
}
{ {
custom?.map((tab) => ( custom?.map((tab) => (
<a <a

View file

@ -0,0 +1,23 @@
---
interface Props {
post: any
lang: string
dateFormat?: string
dateWidth?: string
}
const { post, lang, dateFormat = "default", dateWidth = "w-36" } = Astro.props
import { formatDate } from "~/utils"
---
<a
href={`/${lang}/posts/${post.id}/`}
class="my-3 flex visited:text-purple-500/90 md:my-2"
>
<p
class={`flex ${dateWidth} flex-shrink-0 truncate text-gray-500 dark:text-gray-400`}
>
<time>{formatDate(post.data.pubDate, dateFormat)}</time>
</p>
<p class="line-clamp-2 text-lg hover:underline">{post.data.title}</p>
</a>

View file

@ -1,7 +1,7 @@
--- ---
import { getLangFromUrl, useTranslations } from "~/i18n/utils" import { getLangFromUrl, useTranslations } from "~/i18n/utils"
import MainLayout from "~/layouts/main.astro" import MainLayout from "~/layouts/main.astro"
import { formatDate } from "~/utils" import PostList from "./post-list.astro"
interface Props { interface Props {
posts: any[] posts: any[]
@ -17,30 +17,24 @@ const filteredPosts = posts.filter((post: any) => post.data.tags?.includes(tag))
--- ---
<MainLayout> <MainLayout>
<div class="mb-4 mt-2 text-2xl"> <div class="relative z-10">
{tag} <div class="my-9 mt-2 text-2xl font-semibold">#{tag}</div>
</div>
{ {
filteredPosts.length > 0 ? ( filteredPosts.length > 0 ? (
<ul class="space-y-4"> <ul class="space-y-4">
{filteredPosts.map((post: any) => ( {filteredPosts.map((post: any) => (
<li> <PostList
<a post={post}
href={`/${lang}/posts/${post.id}/`} lang={lang}
class="block rounded-lg p-2 transition-colors hover:bg-gray-100 dark:hover:bg-gray-800" dateFormat="YYYY-MM-DD"
> dateWidth="w-32"
<div class="flex items-center text-lg"> />
<p class="mr-4 w-36 flex-shrink-0 truncate text-gray-500 dark:text-gray-400">
<time>{formatDate(post.data.pubDate)}</time>
</p>
<p class="line-clamp-2 flex-grow">{post.data.title}</p>
</div>
</a>
</li>
))} ))}
</ul> </ul>
) : ( ) : (
<p class="text-gray-500">{t("tag.no_posts")}</p> <p class="text-gray-500">{t("tag.no_posts")}</p>
) )
} }
</div>
</MainLayout> </MainLayout>

View file

@ -0,0 +1,74 @@
import { useEffect, useState } from "react"
export function CodeBackground() {
const charGroups = {
brackets: {
chars: ["{", "}", "(", ")", "[", "]", "<", ">"],
weight: 3,
},
operators: {
chars: ["=", "+", "-", "*", "/", "%", "=>", "&&", "||", "|", "&", "..."],
weight: 2,
},
punctuation: {
chars: [".", ";", ":", ","],
weight: 4,
},
keywords: {
chars: [
"const",
"let",
"var",
"function",
"if",
"else",
"return",
"class",
"import",
"export",
"from",
"async",
"await",
"try",
"catch",
"interface",
"type",
"extends",
"implements",
],
weight: 1,
},
values: {
chars: ["null", "undefined", "true", "false", "void", "any", "never"],
weight: 1,
},
}
const [backgroundChars, setBackgroundChars] = useState<string[]>([])
useEffect(() => {
const getWeightedRandomChar = () => {
const weightedChars = Object.values(charGroups).reduce((acc, group) => {
const chars = Array(group.weight).fill(group.chars).flat()
return [...acc, ...chars]
}, [] as string[])
return weightedChars[Math.floor(Math.random() * weightedChars.length)]
}
const chars = new Array(2000).fill(null).map(() => getWeightedRandomChar())
setBackgroundChars(chars)
}, [])
return (
<div className="fixed inset-0 z-0 flex h-screen w-screen select-none flex-wrap overflow-hidden">
{backgroundChars.map((char, index) => (
<span
key={index}
className="px-1 text-sm text-transparent duration-[0.8s] hover:text-black/50 hover:duration-0 dark:hover:text-white/50"
>
{char}
</span>
))}
</div>
)
}

View file

@ -1,5 +1,5 @@
export function NoiseBackground() { export function NoiseBackground() {
return ( return (
<div className="fixed inset-0 -z-10 h-full w-full bg-[url('https://framerusercontent.com/images/rR6HYXBrMmX4cRpXfXUOvpvpB0.png')] bg-[length:128px_128px] bg-repeat opacity-[0.06]"></div> <div className="fixed inset-0 z-[-1] h-full w-full bg-[url('/noise.png')] bg-[length:128px_128px] bg-repeat opacity-[0.06]"></div>
) )
} }

View file

@ -1,6 +1,6 @@
export const title = "About Me" export const title = "About Me"
## {title} {title}
<img <img
className="block dark:hidden" className="block dark:hidden"

View file

@ -25,14 +25,13 @@ const common = {
navigation: { navigation: {
home: true, home: true,
archive: true, archive: true,
tags: true,
about: true,
custom: [ custom: [
{ {
label: "CamLife", label: "CamLife",
link: "https://camlife.cn", link: "https://camlife.cn",
}, },
], ],
about: true,
}, },
} }

View file

@ -1,6 +1,6 @@
export const title = "关于我" export const title = "关于我"
## {title} {title}
<img <img
className="block dark:hidden" className="block dark:hidden"

View file

@ -1,6 +1,7 @@
--- ---
title: "我的第一篇博客文章" title: "我的第一篇博客文章"
pubDate: 2020-07-01 pubDate: 2020-07-01
updatedDate: 2020-07-01
description: "这是我 Astro 博客的第一篇文章。" description: "这是我 Astro 博客的第一篇文章。"
author: "Astro 学习者" author: "Astro 学习者"
image: image:
@ -22,3 +23,7 @@ tags: ["astro", "博客", "公开学习"]
## 下一步计划 ## 下一步计划
我将完成 Astro 教程,然后继续编写更多内容。关注我以获取更多信息。 我将完成 Astro 教程,然后继续编写更多内容。关注我以获取更多信息。
```python
print("Hello, World!")
```

View file

@ -5,7 +5,7 @@ description: "全面指南,帮助您将 Astro 网站部署到各种平台"
image: image:
url: "https://docs.astro.build/assets/arc.webp" url: "https://docs.astro.build/assets/arc.webp"
alt: "Astro 部署插图" alt: "Astro 部署插图"
pubDate: 2024-08-19 pubDate: 2024-08-26
tags: ["astro", "i18n", "本地化", "网页开发"] tags: ["astro", "i18n", "本地化", "网页开发"]
--- ---

View file

@ -11,10 +11,10 @@ export const ui = {
en: { en: {
"nav.home": "Home", "nav.home": "Home",
"nav.archive": "Archive", "nav.archive": "Archive",
"nav.tags": "Tags",
"nav.about": "About", "nav.about": "About",
"nav.twitter": "Twitter", "nav.twitter": "Twitter",
"blog.latest": "Latest Posts", "blog.latest": "Latest Posts",
"archive.title": "All Posts",
"tag.title": "Tag:", "tag.title": "Tag:",
"tag.no_posts": "No posts found for tag", "tag.no_posts": "No posts found for tag",
}, },
@ -23,8 +23,8 @@ export const ui = {
"nav.about": "关于", "nav.about": "关于",
"nav.blog": "推特", "nav.blog": "推特",
"nav.archive": "归档", "nav.archive": "归档",
"nav.tags": "标签", "blog.latest": "近期文章",
"blog.latest": "最近文章", "archive.title": "所有文章",
"tag.title": "标签:", "tag.title": "标签:",
"tag.no_posts": "没有找到标签为的文章", "tag.no_posts": "没有找到标签为的文章",
}, },

View file

@ -1,6 +1,7 @@
--- ---
import "~/styles/globals.css" import "~/styles/globals.css"
import { NoiseBackground } from "~/components/react/noise-background" import { NoiseBackground } from "~/components/react/noise-background"
import { CodeBackground } from "~/components/react/code-background"
import { ClientRouter } from "astro:transitions" import { ClientRouter } from "astro:transitions"
import { getLangFromUrl } from "~/i18n/utils" import { getLangFromUrl } from "~/i18n/utils"
import { en, zh } from "~/config" import { en, zh } from "~/config"
@ -71,10 +72,11 @@ const config = lang === "zh" ? zh.meta : en.meta
}) })
</script> </script>
</head> </head>
<body class="dark:bg-[#121212] dark:text-white"> <body
<div class="flex min-h-screen w-full justify-center px-6 md:p-0"> class="flex min-h-screen w-full justify-center px-6 dark:bg-[#121212] dark:text-white md:px-0"
>
<slot /> <slot />
<NoiseBackground /> <NoiseBackground />
</div> <CodeBackground client:load />
</body> </body>
</html> </html>

View file

@ -10,8 +10,10 @@ const openGraphImage = !ogImage ? `/og/${filename}.png` : ogImage
<BaseLayout title={title} description={description} ogImage={openGraphImage}> <BaseLayout title={title} description={description} ogImage={openGraphImage}>
<main class="max-auto mb-10 w-full max-w-3xl"> <main class="max-auto mb-10 w-full max-w-3xl">
<div class="relative z-10">
<Header /> <Header />
<Navigation /> <Navigation />
<slot /> <slot />
</div>
</main> </main>
</BaseLayout> </BaseLayout>

View file

@ -16,7 +16,7 @@ const ogImage = "https://sunguoqi.com/me.png"
--- ---
<MainLayout title="about" description="test" ogImage={ogImage}> <MainLayout title="about" description="test" ogImage={ogImage}>
<div class="prose dark:prose-invert"> <div class="prose relative z-10 dark:prose-invert">
<AboutContent /> <AboutContent />
</div> </div>
</MainLayout> </MainLayout>

View file

@ -1,15 +1,16 @@
--- ---
import PostList from "~/components/astro/post-list.astro"
import { getLangFromUrl } from "~/i18n/utils" import { getLangFromUrl } from "~/i18n/utils"
import MainLayout from "~/layouts/main.astro" import MainLayout from "~/layouts/main.astro"
import { formatDate, getPostsByLocale } from "~/utils" import { getPostsByLocale } from "~/utils"
import { getLanguagePaths } from "~/utils/langs" import { getLanguagePaths } from "~/utils/langs"
const lang = getLangFromUrl(Astro.url)
export function getStaticPaths() { export function getStaticPaths() {
return getLanguagePaths() return getLanguagePaths()
} }
const lang = getLangFromUrl(Astro.url)
const posts = await getPostsByLocale(lang) const posts = await getPostsByLocale(lang)
const postsByYear = posts.reduce( const postsByYear = posts.reduce(
@ -28,24 +29,20 @@ const years = Object.keys(postsByYear).sort((a, b) => Number(b) - Number(a))
--- ---
<MainLayout> <MainLayout>
<div class="space-y-8"> <div class="relative z-10">
{ {
years.map((year) => ( years.map((year) => (
<div class="year-group"> <div class="year-group my-8">
<h2 class="mb-4 text-2xl font-bold">{year}</h2> <h2 class="my-4 text-2xl font-bold">{year}</h2>
<div class="space-y-2">
{postsByYear[year].map((post: any) => ( {postsByYear[year].map((post: any) => (
<a href={`/${lang}/posts/${post.id}/`}> <PostList
<div class="my-2 flex text-lg"> post={post}
<p class="flex w-36 flex-shrink-0 truncate text-gray-500 dark:text-gray-400"> lang={lang}
<time>{formatDate(post.data.pubDate)}</time> dateFormat="MM-DD"
</p> dateWidth="w-20"
<p class="line-clamp-2">{post.data.title}</p> />
</div>
</a>
))} ))}
</div> </div>
</div>
)) ))
} }
</div> </div>

View file

@ -1,8 +1,10 @@
--- ---
import { langs } from "~/i18n/ui" import { langs } from "~/i18n/ui"
import { getLangFromUrl } from "~/i18n/utils"
import MainLayout from "~/layouts/main.astro" import MainLayout from "~/layouts/main.astro"
import "~/styles/post.css" import "~/styles/post.css"
import { getPostsByLocale } from "~/utils" import "~/styles/post.scss"
import { formatDate, getPostsByLocale } from "~/utils"
export async function getStaticPaths() { export async function getStaticPaths() {
const allPaths = [] const allPaths = []
@ -19,11 +21,30 @@ export async function getStaticPaths() {
return allPaths return allPaths
} }
const lang = getLangFromUrl(Astro.url)
const { post } = Astro.props const { post } = Astro.props
--- ---
<MainLayout {...post.data}> <MainLayout {...post.data}>
<article class="prose dark:prose-invert"> <article class="prose relative z-10 w-full max-w-full dark:prose-invert">
<div set:html={post.rendered.html} /> <div class="flex flex-col gap-2">
<h2 class="!my-0 text-3xl font-semibold">{post.data.title}</h2>
<div class="my-3 text-gray-500 dark:text-white/80">
{formatDate(post.data.pubDate)}
</div>
</div>
<div class="my-6" set:html={post.rendered.html} />
<div class="space-x-3 pb-10 text-sm text-gray-500">
{
post.data.tags.map((tag: string) => (
<a href={`/${lang}/tags/${tag}`} class="no-underline">
<p class="inline-block hover:scale-105">#{tag}</p>
</a>
))
}
</div>
</article> </article>
</MainLayout> </MainLayout>

View file

@ -1,26 +0,0 @@
---
import { getLangFromUrl } from "~/i18n/utils"
import MainLayout from "~/layouts/main.astro"
import { getPostsByLocale } from "~/utils"
import { getLanguagePaths } from "~/utils/langs"
export function getStaticPaths() {
return getLanguagePaths()
}
const lang = getLangFromUrl(Astro.url)
const posts = await getPostsByLocale(lang)
const tags = [...new Set(posts.map((post: any) => post.data.tags).flat())]
---
<MainLayout>
<div>
{
tags.map((tag) => (
<span class="mx-4">
<a href={`/${lang}/tags/${tag}`}>{tag}</a>
</span>
))
}
</div>
</MainLayout>

View file

@ -1,5 +1,5 @@
article code { article code {
@apply rounded bg-gray-100 px-1 dark:bg-gray-900; @apply rounded bg-orange-500/50 px-1 dark:bg-orange-500/80;
} }
article code::before, article code::before,

5
src/styles/post.scss Normal file
View file

@ -0,0 +1,5 @@
article {
h2 {
margin: 2rem 0 !important;
}
}

View file

@ -1,13 +1,21 @@
import { getCollection } from "astro:content" import { getCollection } from "astro:content"
export const formatDate = (date: Date | string | undefined): string => { export const formatDate = (
date: Date | string | undefined,
format: string = "YYYY-MM-DD",
): string => {
const validDate = date ? new Date(date) : new Date() const validDate = date ? new Date(date) : new Date()
const year = validDate.getFullYear() const tokens: Record<string, string> = {
const month = String(validDate.getMonth() + 1).padStart(2, "0") YYYY: validDate.getFullYear().toString(),
const day = String(validDate.getDate()).padStart(2, "0") MM: String(validDate.getMonth() + 1).padStart(2, "0"),
DD: String(validDate.getDate()).padStart(2, "0"),
HH: String(validDate.getHours()).padStart(2, "0"),
mm: String(validDate.getMinutes()).padStart(2, "0"),
ss: String(validDate.getSeconds()).padStart(2, "0"),
}
return `${year}-${month}-${day}` return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => tokens[match])
} }
export const getPostsByLocale = async (locale: string) => { export const getPostsByLocale = async (locale: string) => {