feat(ui): add Container component and replace manual container divs

Implement a reusable Container component with size variants (sm, md, lg, xl, full) to standardize content width across the application. Replace all manual container divs with the new component for consistent styling and maintainability.
This commit is contained in:
joyzhao
2025-06-19 18:10:49 +08:00
parent b4a8d13cdd
commit 5fcf7a9d33
12 changed files with 97 additions and 46 deletions

View File

@@ -3,6 +3,7 @@ import { personalInfo } from "@/lib/data";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import Container from "./ui/Container";
import { type FooterProps } from "@/types"; import { type FooterProps } from "@/types";
export default function Footer({ lang: propLang }: FooterProps) { export default function Footer({ lang: propLang }: FooterProps) {
@@ -20,7 +21,7 @@ export default function Footer({ lang: propLang }: FooterProps) {
const t = useTranslations(lang); const t = useTranslations(lang);
return ( return (
<footer className="border-t border-purple-500/10 py-6 bg-gradient-to-b from-background to-muted/20 backdrop-blur-sm"> <footer className="border-t border-purple-500/10 py-6 bg-gradient-to-b from-background to-muted/20 backdrop-blur-sm">
<div className="container max-w-4xl mx-auto px-6 md:px-4"> <Container size="sm">
<motion.div <motion.div
className="flex flex-col md:flex-row justify-between items-center" className="flex flex-col md:flex-row justify-between items-center"
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
@@ -67,7 +68,7 @@ export default function Footer({ lang: propLang }: FooterProps) {
</motion.span> </motion.span>
</motion.p> </motion.p>
</motion.div> </motion.div>
</div> </Container>
</footer> </footer>
); );
} }

View File

@@ -1,6 +1,7 @@
import { personalInfo } from "@/lib/data"; import { personalInfo } from "@/lib/data";
import LanguageSwitcher from "./LanguageSwitcher"; import LanguageSwitcher from "./LanguageSwitcher";
import ThemeToggle from "./ui/theme-toggle"; import ThemeToggle from "./ui/theme-toggle";
import Container from "./ui/Container";
import { useTranslations, getLocalizedPath, type Lang } from "@/i18n/utils"; import { useTranslations, getLocalizedPath, type Lang } from "@/i18n/utils";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
@@ -43,7 +44,7 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
? 'backdrop-blur-md backdrop-filter bg-white/80 dark:bg-black/80 border-b border-border/30 shadow-lg shadow-black/5 dark:shadow-black/20' ? 'backdrop-blur-md backdrop-filter bg-white/80 dark:bg-black/80 border-b border-border/30 shadow-lg shadow-black/5 dark:shadow-black/20'
: 'bg-transparent' : 'bg-transparent'
}`}> }`}>
<div className="container max-w-4xl mx-auto p-4 flex justify-between items-center"> <Container size="sm" className="p-4 flex justify-between items-center">
<a <a
className="flex items-center text-lg font-medium transition-opacity duration-150 hover:opacity-80" className="flex items-center text-lg font-medium transition-opacity duration-150 hover:opacity-80"
href={getLocalizedPath('/', lang)} href={getLocalizedPath('/', lang)}
@@ -85,7 +86,7 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
{isMenuOpen ? <X size={24} /> : <Menu size={24} />} {isMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button> </button>
</div> </div>
</div> </Container>
{/* Mobile Navigation */} {/* Mobile Navigation */}
<div className={`md:hidden overflow-hidden transition-all duration-200 ease-out ${ <div className={`md:hidden overflow-hidden transition-all duration-200 ease-out ${

View File

@@ -0,0 +1,39 @@
import { cn } from "@/lib/utils";
import { type ReactNode } from "react";
interface ContainerProps {
children: ReactNode;
className?: string;
size?: "sm" | "md" | "lg" | "xl" | "full";
}
/**
* Container component for consistent content width across the site
* @param children - The content to be wrapped
* @param className - Additional classes to apply
* @param size - Container size variant (sm: max-w-4xl, md: max-w-6xl, lg: max-w-7xl, xl: max-w-screen-2xl, full: w-full)
*/
export default function Container({
children,
className,
size = "md"
}: ContainerProps) {
// Map size variants to max-width classes
const sizeClasses = {
sm: "max-w-4xl", // Same as header/footer (narrower content)
md: "max-w-6xl", // Default for most content areas
lg: "max-w-7xl", // For wider content like blog posts with sidebars
xl: "max-w-screen-2xl", // For very wide content
full: "w-full" // No max width constraint
};
return (
<div className={cn(
"container mx-auto px-4 sm:px-6 lg:px-8",
sizeClasses[size],
className
)}>
{children}
</div>
);
}

View File

@@ -5,6 +5,7 @@ import { type Lang, type FrontmatterProps } from '@/types';
import { defaultLang } from '@/i18n/ui'; import { defaultLang } from '@/i18n/ui';
import GlassHeader from '@/components/GlassHeader'; import GlassHeader from '@/components/GlassHeader';
import Footer from '@/components/Footer'; import Footer from '@/components/Footer';
import Container from '../components/ui/Container';
// Use Astro's MarkdownLayoutProps for proper type safety // Use Astro's MarkdownLayoutProps for proper type safety
export type Props = MarkdownLayoutProps<FrontmatterProps>; export type Props = MarkdownLayoutProps<FrontmatterProps>;
@@ -21,7 +22,7 @@ const lang = Astro.currentLocale as Lang || defaultLang;
<div class="fixed inset-0 -z-10 h-full w-full bg-background"> <div class="fixed inset-0 -z-10 h-full w-full bg-background">
<!-- Additional subtle gradient for about page --> <!-- Additional subtle gradient for about page -->
<div class="absolute inset-0 bg-gradient-to-br from-purple-50/30 via-transparent to-blue-50/20 dark:from-purple-950/20 dark:via-transparent dark:to-blue-950/10"> <div class="absolute inset-0 bg-gradient-to-br from-purple-50/30 via-transparent to-blue-50/20 dark:from-purple-950/20 dark:via-transparent dark:to-blue-950/10">
</div> </div>
</div> </div>
<!-- Glass Header with navigation --> <!-- Glass Header with navigation -->
@@ -29,7 +30,7 @@ const lang = Astro.currentLocale as Lang || defaultLang;
<!-- Main content with proper spacing for fixed header --> <!-- Main content with proper spacing for fixed header -->
<div class="pt-16 sm:pt-20"> <div class="pt-16 sm:pt-20">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8"> <Container client:load size="md" className="py-8 md:py-12">
<div class="max-w-7xl mx-auto"> <div class="max-w-7xl mx-auto">
<div class="grid grid-cols-1 xl:grid-cols-4 gap-6 lg:gap-8"> <div class="grid grid-cols-1 xl:grid-cols-4 gap-6 lg:gap-8">
<!-- Main Content --> <!-- Main Content -->

View File

@@ -10,6 +10,7 @@ import AuthorCard from '@/components/AuthorCard';
import TableOfContents from '@/components/layout/TableOfContents.astro'; import TableOfContents from '@/components/layout/TableOfContents.astro';
import BlogNavigation from '@/components/layout/BlogNavigation.astro'; import BlogNavigation from '@/components/layout/BlogNavigation.astro';
import PostMeta from '@/components/blog/PostMeta.astro'; import PostMeta from '@/components/blog/PostMeta.astro';
import Container from '../components/ui/Container';
// Use Astro's MarkdownLayoutProps for proper type safety // Use Astro's MarkdownLayoutProps for proper type safety
export type Props = MarkdownLayoutProps<FrontmatterProps>; export type Props = MarkdownLayoutProps<FrontmatterProps>;
@@ -41,7 +42,7 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
<!-- Main content with proper spacing for fixed header --> <!-- Main content with proper spacing for fixed header -->
<div class="pt-16 sm:pt-20"> <div class="pt-16 sm:pt-20">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-6 sm:py-8"> <Container client:load size="md" className="py-6 sm:py-8">
<div class="max-w-7xl mx-auto"> <div class="max-w-7xl mx-auto">
<div class="grid grid-cols-1 xl:grid-cols-4 gap-6 lg:gap-8"> <div class="grid grid-cols-1 xl:grid-cols-4 gap-6 lg:gap-8">
<!-- Main Content --> <!-- Main Content -->
@@ -98,7 +99,7 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
</aside> </aside>
</div> </div>
</div> </div>
</div> </Container>
</div> </div>
<!-- Footer --> <!-- Footer -->

View File

@@ -7,6 +7,7 @@ import BlogLayout from './BlogLayout.astro';
import BlogList from '../components/blog/BlogList.astro'; import BlogList from '../components/blog/BlogList.astro';
import CategoryCard from '../components/blog/CategoryCard.astro'; import CategoryCard from '../components/blog/CategoryCard.astro';
import TagCard from '../components/blog/TagCard.astro'; import TagCard from '../components/blog/TagCard.astro';
import Container from '../components/ui/Container';
import { type Lang } from '@/i18n/utils'; import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui'; import { defaultLang } from '@/i18n/ui';
import { type BlogPost } from '@/types'; import { type BlogPost } from '@/types';
@@ -53,7 +54,7 @@ const localizedText = getLocalizedText();
--- ---
<BlogLayout title={title} description={Astro.props.description}> <BlogLayout title={title} description={Astro.props.description}>
<div class="container max-w-6xl px-4 py-8"> <Container client:load size="md" className="py-8">
<!-- Header Section - Centered at the top --> <!-- Header Section - Centered at the top -->
<div class="text-center mb-10"> <div class="text-center mb-10">
<h1 class="text-4xl font-bold mb-3"> <h1 class="text-4xl font-bold mb-3">
@@ -91,5 +92,5 @@ const localizedText = getLocalizedText();
)} )}
</div> </div>
</div> </div>
</div> </Container>
</BlogLayout> </BlogLayout>

View File

@@ -3,6 +3,7 @@ import BlogLayout from '../../layouts/BlogLayout.astro';
import BlogList from '../../components/blog/BlogList.astro'; import BlogList from '../../components/blog/BlogList.astro';
import CategoryCard from '../../components/blog/CategoryCard.astro'; import CategoryCard from '../../components/blog/CategoryCard.astro';
import TagCard from '../../components/blog/TagCard.astro'; import TagCard from '../../components/blog/TagCard.astro';
import Container from '../../components/ui/Container';
import { type BlogPost } from '@/types'; import { type BlogPost } from '@/types';
import { type Lang } from '@/i18n/utils'; import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui'; import { defaultLang } from '@/i18n/ui';
@@ -43,7 +44,7 @@ const sortedBlogPosts = sortPostsByDate(blogPosts);
<BlogLayout title="Blog - Joy Zhao" description="Dive into my thoughts on coding, tech trends, and developer life. Explore my latest posts below."> <BlogLayout title="Blog - Joy Zhao" description="Dive into my thoughts on coding, tech trends, and developer life. Explore my latest posts below.">
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Header Section --> <!-- Header Section -->
<div class="container mx-auto px-4 pt-24 pb-12"> <Container client:load size="md" className="pt-24 pb-12">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6"> <h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
Our <span class="text-purple-500">Latest</span> Blog Our <span class="text-purple-500">Latest</span> Blog
@@ -52,10 +53,10 @@ const sortedBlogPosts = sortPostsByDate(blogPosts);
Dive into my thoughts on coding, tech trends, and developer life. Explore my latest posts below. Dive into my thoughts on coding, tech trends, and developer life. Explore my latest posts below.
</p> </p>
</div> </div>
</div> </Container>
<!-- Main Content --> <!-- Main Content -->
<div class="container mx-auto px-4 pb-20"> <Container client:load size="md" className="pb-20">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8"> <div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- 侧边栏 --> <!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8"> <div class="lg:col-span-1 space-y-8">

View File

@@ -3,6 +3,7 @@ import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader"; import GlassHeader from "@/components/GlassHeader";
import SkillsMarquee from "@/components/SkillsMarquee"; import SkillsMarquee from "@/components/SkillsMarquee";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
import Container from "@/components/ui/Container";
import { useTranslations, type Lang } from "@/i18n/utils"; import { useTranslations, type Lang } from "@/i18n/utils";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import { personalInfo, services } from "@/lib/data"; import { personalInfo, services } from "@/lib/data";
@@ -14,14 +15,14 @@ const pageTitle = t('site.title');
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" /> <GlassHeader client:only="react" lang={lang} />
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Hero Section - Inlined Content --> <!-- Hero Section - Inlined Content -->
<section class="py-32 relative overflow-hidden min-h-screen flex items-center"> <section class="py-32 relative overflow-hidden min-h-screen flex flex-col justify-center">
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div> <div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Greeting --> <!-- Greeting -->
<div class="flex items-center justify-center mb-6"> <div class="flex items-center justify-center mb-6">
@@ -162,14 +163,14 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
<SkillsMarquee lang={lang} client:only="react" /> <SkillsMarquee lang={lang} client:only="react" />
<!-- Services Section - Inlined Content --> <!-- Services Section - Inlined Content -->
<section id="services" class="py-20 px-4 bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800"> <section id="services" class="py-20 bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800">
<div class="max-w-6xl mx-auto"> <Container client:load size="md">
<h2 class="text-4xl font-bold text-center mb-16 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> <h2 class="text-4xl font-bold text-center mb-16 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
Services I Offer Services I Offer
</h2> </h2>
@@ -196,7 +197,7 @@ const pageTitle = t('site.title');
</div> </div>
))} ))}
</div> </div>
</div> </Container>
</section> </section>
<!-- About Section - Inlined Content --> <!-- About Section - Inlined Content -->
@@ -204,7 +205,7 @@ const pageTitle = t('site.title');
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-blue-900/10 via-purple-800/5 to-indigo-700/10 dark:from-blue-900/20 dark:via-purple-800/10 dark:to-indigo-700/20"></div> <div class="absolute inset-0 bg-gradient-to-br from-blue-900/10 via-purple-800/5 to-indigo-700/10 dark:from-blue-900/20 dark:via-purple-800/10 dark:to-indigo-700/20"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Section Title --> <!-- Section Title -->
<div class="flex items-center justify-center mb-6"> <div class="flex items-center justify-center mb-6">
@@ -331,7 +332,7 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
<!-- Projects Section - Inlined Content --> <!-- Projects Section - Inlined Content -->
@@ -339,7 +340,7 @@ const pageTitle = t('site.title');
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h2 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-purple-600 bg-clip-text text-transparent"> <h2 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-purple-600 bg-clip-text text-transparent">
Latest Projects Latest Projects
@@ -547,7 +548,7 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
</main> </main>
<Footer lang={lang} client:only="react" /> <Footer lang={lang} client:only="react" />

View File

@@ -2,6 +2,7 @@
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader"; import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
import Container from "@/components/ui/Container";
import { useTranslations, type Lang } from "@/i18n/utils"; import { useTranslations, type Lang } from "@/i18n/utils";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import { projects } from "@/lib/data"; import { projects } from "@/lib/data";
@@ -23,7 +24,7 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div> <div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Main title --> <!-- Main title -->
<h1 class="text-5xl md:text-6xl font-bold mb-6 bg-gradient-to-r from-gray-900 via-purple-600 to-purple-800 dark:from-white dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent"> <h1 class="text-5xl md:text-6xl font-bold mb-6 bg-gradient-to-r from-gray-900 via-purple-600 to-purple-800 dark:from-white dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent">
@@ -35,7 +36,7 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
{t('projects.description')} {t('projects.description')}
</p> </p>
</div> </div>
</div> </Container>
</section> </section>
<!-- Projects Grid Section --> <!-- Projects Grid Section -->
@@ -43,7 +44,7 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch"> <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch">
{currentProjects.map((project) => ( {currentProjects.map((project) => (
<div class={`group overflow-hidden border border-${project.color}-500/20 hover:border-${project.color}-500/40 h-full flex flex-col transition-all duration-500 hover:scale-105 bg-white/10 dark:bg-gray-800/50 backdrop-blur-sm rounded-xl relative`}> <div class={`group overflow-hidden border border-${project.color}-500/20 hover:border-${project.color}-500/40 h-full flex flex-col transition-all duration-500 hover:scale-105 bg-white/10 dark:bg-gray-800/50 backdrop-blur-sm rounded-xl relative`}>

View File

@@ -3,6 +3,7 @@ import BlogLayout from '../../../layouts/BlogLayout.astro';
import BlogList from '../../../components/blog/BlogList.astro'; import BlogList from '../../../components/blog/BlogList.astro';
import CategoryCard from '../../../components/blog/CategoryCard.astro'; import CategoryCard from '../../../components/blog/CategoryCard.astro';
import TagCard from '../../../components/blog/TagCard.astro'; import TagCard from '../../../components/blog/TagCard.astro';
import Container from '../../../components/ui/Container';
import { type BlogPost } from '@/types'; import { type BlogPost } from '@/types';
import { type Lang } from '@/i18n/utils'; import { type Lang } from '@/i18n/utils';
import { defaultLang } from '@/i18n/ui'; import { defaultLang } from '@/i18n/ui';
@@ -55,19 +56,19 @@ const tags = extractTags(allPostsArray);
<BlogLayout title="博客 - 赵桂阳" description="深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。"> <BlogLayout title="博客 - 赵桂阳" description="深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。">
<main class="min-h-screen"> <main class="min-h-screen">
<!-- 头部区域 --> <!-- 头部区域 -->
<div class="container mx-auto px-4 pt-24 pb-12"> <Container client:load size="md" className="pt-24 pb-12">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6"> <h1 class="text-5xl md:text-6xl font-bold bg-gradient-to-r from-foreground via-purple-600 to-purple-800 dark:from-foreground dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent mb-6">
我的 <span class="text-purple-500">最新</span> 博客 我的<span class="text-purple-500">博客</span>
</h1> </h1>
<p class="text-xl text-muted-foreground max-w-3xl mx-auto"> <p class="text-xl text-muted-foreground max-w-3xl mx-auto">
深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。 深入我对编程、技术趋势和开发者生活的思考。探索我的最新文章。
</p> </p>
</div> </div>
</div> </Container>
<!-- 主要内容 --> <!-- 主要内容 -->
<div class="container mx-auto px-4 pb-20"> <Container client:load size="md" className="pb-20">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8"> <div class="grid grid-cols-1 lg:grid-cols-4 gap-8">
<!-- 侧边栏 --> <!-- 侧边栏 -->
<div class="lg:col-span-1 space-y-8"> <div class="lg:col-span-1 space-y-8">

View File

@@ -3,6 +3,7 @@ import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader"; import GlassHeader from "@/components/GlassHeader";
import SkillsMarquee from "@/components/SkillsMarquee"; import SkillsMarquee from "@/components/SkillsMarquee";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
import Container from "@/components/ui/Container";
import { useTranslations, type Lang } from "@/i18n/utils"; import { useTranslations, type Lang } from "@/i18n/utils";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import { personalInfo, services } from "@/lib/data"; import { personalInfo, services } from "@/lib/data";
@@ -14,14 +15,14 @@ const pageTitle = t('site.title');
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" /> <GlassHeader client:only="react" lang={lang} />
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Hero Section - Inlined Content --> <!-- Hero Section - Inlined Content -->
<section class="py-32 relative overflow-hidden min-h-screen flex items-center"> <section class="py-32 relative overflow-hidden min-h-screen flex flex-col justify-center">
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div> <div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Greeting --> <!-- Greeting -->
<div class="flex items-center justify-center mb-6"> <div class="flex items-center justify-center mb-6">
@@ -106,6 +107,7 @@ const pageTitle = t('site.title');
</a> </a>
</div> </div>
</div> </div>
</Container>
<!-- Terminal mockup --> <!-- Terminal mockup -->
<div class="max-w-4xl mx-auto"> <div class="max-w-4xl mx-auto">
@@ -162,14 +164,14 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
<SkillsMarquee lang={lang} client:only="react" /> <SkillsMarquee lang={lang} client:only="react" />
<!-- Services Section - Inlined Content --> <!-- Services Section - Inlined Content -->
<section id="services" class="py-20 px-4 bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800"> <section id="services" class="py-20 px-4 bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-slate-800">
<div class="max-w-6xl mx-auto"> <Container client:load size="md">
<h2 class="text-4xl font-bold text-center mb-16 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> <h2 class="text-4xl font-bold text-center mb-16 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
我提供的服务 我提供的服务
</h2> </h2>
@@ -196,7 +198,7 @@ const pageTitle = t('site.title');
</div> </div>
))} ))}
</div> </div>
</div> </Container>
</section> </section>
<!-- About Section - Inlined Content --> <!-- About Section - Inlined Content -->
@@ -204,7 +206,7 @@ const pageTitle = t('site.title');
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-blue-900/10 via-purple-800/5 to-indigo-700/10 dark:from-blue-900/20 dark:via-purple-800/10 dark:to-indigo-700/20"></div> <div class="absolute inset-0 bg-gradient-to-br from-blue-900/10 via-purple-800/5 to-indigo-700/10 dark:from-blue-900/20 dark:via-purple-800/10 dark:to-indigo-700/20"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Section Title --> <!-- Section Title -->
<div class="flex items-center justify-center mb-6"> <div class="flex items-center justify-center mb-6">
@@ -331,7 +333,7 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
<!-- Projects Section - Inlined Content --> <!-- Projects Section - Inlined Content -->
@@ -339,7 +341,7 @@ const pageTitle = t('site.title');
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h2 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-purple-600 bg-clip-text text-transparent"> <h2 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-purple-600 bg-clip-text text-transparent">
我的项目 我的项目
@@ -539,7 +541,7 @@ const pageTitle = t('site.title');
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
</main> </main>
<Footer lang={lang} client:load /> <Footer lang={lang} client:load />

View File

@@ -2,6 +2,7 @@
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import GlassHeader from "@/components/GlassHeader"; import GlassHeader from "@/components/GlassHeader";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
import Container from "@/components/ui/Container";
import { useTranslations, type Lang } from "@/i18n/utils"; import { useTranslations, type Lang } from "@/i18n/utils";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import { projects } from "@/lib/data"; import { projects } from "@/lib/data";
@@ -16,14 +17,14 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" /> <GlassHeader lang={lang} client:only="react" />
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Projects Hero Section --> <!-- Projects Hero Section -->
<section class="py-24 relative overflow-hidden"> <section class="py-24 relative overflow-hidden">
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div> <div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 via-purple-800/10 to-purple-700/20 dark:from-purple-900/30 dark:via-purple-800/20 dark:to-purple-700/30"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="text-center mb-16"> <div class="text-center mb-16">
<!-- Main title --> <!-- Main title -->
<h1 class="text-5xl md:text-6xl font-bold mb-6 bg-gradient-to-r from-gray-900 via-purple-600 to-purple-800 dark:from-white dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent"> <h1 class="text-5xl md:text-6xl font-bold mb-6 bg-gradient-to-r from-gray-900 via-purple-600 to-purple-800 dark:from-white dark:via-purple-200 dark:to-purple-300 bg-clip-text text-transparent">
@@ -35,7 +36,7 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
{t('projects.description')} {t('projects.description')}
</p> </p>
</div> </div>
</div> </Container>
</section> </section>
<!-- Projects Grid Section --> <!-- Projects Grid Section -->
@@ -43,7 +44,7 @@ const currentProjects = projects[lang as keyof typeof projects] || projects.en;
<!-- Background gradient --> <!-- Background gradient -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-b from-transparent via-purple-900/5 to-transparent"></div>
<div class="container max-w-6xl mx-auto px-6 md:px-4 relative z-10"> <Container client:load size="md" className="relative z-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch"> <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch">
{currentProjects.map((project) => ( {currentProjects.map((project) => (
<div class={`group overflow-hidden border border-${project.color}-500/20 hover:border-${project.color}-500/40 h-full flex flex-col transition-all duration-500 hover:scale-105 bg-white/10 dark:bg-gray-800/50 backdrop-blur-sm rounded-xl relative`}> <div class={`group overflow-hidden border border-${project.color}-500/20 hover:border-${project.color}-500/40 h-full flex flex-col transition-all duration-500 hover:scale-105 bg-white/10 dark:bg-gray-800/50 backdrop-blur-sm rounded-xl relative`}>