diff --git a/.playwright-mcp/page-2026-03-17T05-13-50-415Z.png b/.playwright-mcp/page-2026-03-17T05-13-50-415Z.png new file mode 100644 index 0000000..916cb10 Binary files /dev/null and b/.playwright-mcp/page-2026-03-17T05-13-50-415Z.png differ diff --git a/astro.config.mjs b/astro.config.mjs index d37dbd5..d080fb6 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -17,7 +17,7 @@ export default defineConfig({ }, }, integrations: [ - react(), + react(), sitemap({ i18n: { defaultLocale: 'en', @@ -31,6 +31,16 @@ export default defineConfig({ ], vite: { plugins: [tailwindcss()], + build: { + cssCodeSplit: true, + rollupOptions: { + output: { + manualChunks: { + 'vendor-react': ['react', 'react-dom'], + } + } + } + } }, i18n: { // The default locale to fall back to if a page isn't available in the active locale diff --git a/public/fonts/archivo-400.ttf b/public/fonts/archivo-400.ttf new file mode 100644 index 0000000..757e07f Binary files /dev/null and b/public/fonts/archivo-400.ttf differ diff --git a/public/fonts/archivo-400.woff2 b/public/fonts/archivo-400.woff2 new file mode 100644 index 0000000..57d60ba Binary files /dev/null and b/public/fonts/archivo-400.woff2 differ diff --git a/public/fonts/archivo-700.ttf b/public/fonts/archivo-700.ttf new file mode 100644 index 0000000..8893a0d Binary files /dev/null and b/public/fonts/archivo-700.ttf differ diff --git a/public/fonts/archivo-700.woff2 b/public/fonts/archivo-700.woff2 new file mode 100644 index 0000000..b560e57 Binary files /dev/null and b/public/fonts/archivo-700.woff2 differ diff --git a/public/fonts/space-grotesk-400.ttf b/public/fonts/space-grotesk-400.ttf new file mode 100644 index 0000000..576f9b5 Binary files /dev/null and b/public/fonts/space-grotesk-400.ttf differ diff --git a/public/fonts/space-grotesk-400.woff2 b/public/fonts/space-grotesk-400.woff2 new file mode 100644 index 0000000..d587601 Binary files /dev/null and b/public/fonts/space-grotesk-400.woff2 differ diff --git a/public/fonts/space-grotesk-700.ttf b/public/fonts/space-grotesk-700.ttf new file mode 100644 index 0000000..f4f8002 Binary files /dev/null and b/public/fonts/space-grotesk-700.ttf differ diff --git a/public/fonts/space-grotesk-700.woff2 b/public/fonts/space-grotesk-700.woff2 new file mode 100644 index 0000000..9c436fd Binary files /dev/null and b/public/fonts/space-grotesk-700.woff2 differ diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 02d943d..19364b6 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,7 +1,6 @@ import { useTranslations } from "@/i18n/utils"; import type { Lang } from "@/types/i18n"; import { personalInfo } from "@/lib/data/index"; -import { motion } from "framer-motion"; import { useState, useEffect } from "react"; import { defaultLang } from "@/i18n/ui"; import Container from "./ui/Container.tsx"; @@ -9,7 +8,7 @@ import { type FooterProps } from "@/types"; export default function Footer({ lang: propLang }: FooterProps) { const [lang, setLang] = useState(propLang || defaultLang); - + useEffect(() => { const htmlLang = document.documentElement.lang as Lang; if (htmlLang && (!propLang || htmlLang !== lang)) { @@ -21,60 +20,38 @@ export default function Footer({ lang: propLang }: FooterProps) { return ( ); diff --git a/src/components/GlassHeader.tsx b/src/components/GlassHeader.tsx index f99dfc1..ac2759a 100644 --- a/src/components/GlassHeader.tsx +++ b/src/components/GlassHeader.tsx @@ -8,7 +8,6 @@ import { useState, useEffect } from "react"; import { Menu, X, Home, Rocket, PenTool, User, Briefcase, Clock3 } from "lucide-react"; import { defaultLang } from "@/i18n/ui"; import { type GlassHeaderProps } from "@/types"; -import { motion } from "framer-motion"; import { cn } from "@/lib/utils"; export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { @@ -98,7 +97,7 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { }; return ( - -
@@ -119,50 +116,48 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
{personalInfo.name} -
+ {/* Desktop Navigation */}
{/* Language Switcher added here */} - +
- - - - - +
- {/* Mobile Menu Button */} - + +
+ + {/* Mobile Menu Button */} +
@@ -171,15 +166,15 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { isMenuOpen ? 'max-h-80 opacity-100' : 'max-h-0 opacity-0' }`}>
-
+ ); } diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx index 513dfde..b54d0f0 100644 --- a/src/components/LanguageSwitcher.tsx +++ b/src/components/LanguageSwitcher.tsx @@ -3,19 +3,18 @@ import { getLocalizedPath } from "@/i18n/utils"; import type { Lang } from "@/types/i18n"; import { languages as i18nLanguages, defaultLang } from "@/i18n/ui"; import { Check, ChevronDown } from "lucide-react"; -import { motion, AnimatePresence } from "framer-motion"; import { type LanguageSwitcherProps } from "@/types"; const availableLanguages = Object.entries(i18nLanguages).map(([code, name]) => ({ code: code as Lang, name, - icon: code === 'en' ? '🇬🇧' : code === 'zh' ? '🇨🇳' : '🌐' + icon: code === 'en' ? '🇬🇧' : code === 'zh' ? '🇨🇳' : '🌐' })); export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherProps) { const [isOpen, setIsOpen] = useState(false); const [currentLang, setCurrentLang] = useState(propLang || defaultLang); - + useEffect(() => { if (typeof window !== "undefined") { const pathLang = window.location.pathname.startsWith("/zh") ? "zh" : "en"; @@ -32,10 +31,10 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro } } }, [propLang, currentLang]); - + const [selectedLanguage, setSelectedLanguage] = useState(() => { - return availableLanguages.find(l => l.code === currentLang) || - availableLanguages.find(l => l.code === defaultLang) || + return availableLanguages.find(l => l.code === currentLang) || + availableLanguages.find(l => l.code === defaultLang) || availableLanguages[0]; }); @@ -65,45 +64,38 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro return (
- {selectedLanguage.icon} {selectedLanguage.name} {selectedLanguage.code.toUpperCase()} - - - {isOpen && ( - -
- {availableLanguages.map((lang) => ( - - ))} -
-
- )} -
+ + {isOpen && ( +
+
+ {availableLanguages.map((lang) => ( + + ))} +
+
+ )}
); } diff --git a/src/components/layout/TableOfContents.astro b/src/components/layout/TableOfContents.astro index e1c0010..1fb4b82 100644 --- a/src/components/layout/TableOfContents.astro +++ b/src/components/layout/TableOfContents.astro @@ -19,7 +19,7 @@ const title = lang === 'zh' ? '目录' : 'Table of Contents'; {title} - +
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index ff63e6c..c262de6 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -23,6 +23,9 @@ const t = useTranslations(lang); + + + {title} | {t("site.title")} @@ -46,7 +49,7 @@ const t = useTranslations(lang);
- + diff --git a/src/pages/index.astro b/src/pages/index.astro index 4d94962..d5353d7 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -33,7 +33,7 @@ const latestPosts = sortPostsByDate( --- - +
@@ -180,5 +180,5 @@ const latestPosts = sortPostsByDate(
-