refactor(styles): enhance glass effects, card designs, and transitions across components

- Replaced `client:only="react"` with `client:load transition:persist="header"` for `GlassHeader` to improve page transitions and header consistency.
- Updated card and surface designs with refined colors, borders, and shadows for a cleaner, modern look.
- Adjusted CSS variables for better contrast and distinct layers.
- Applied consistent blur and backdrop styles across components for visual cohesion.
This commit is contained in:
zguiyang
2026-03-14 12:43:11 +08:00
parent 56aac2f9f2
commit 043cdc6734
20 changed files with 49 additions and 47 deletions

View File

@@ -126,10 +126,10 @@ export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
<div className={`md:hidden overflow-hidden transition-all duration-300 ease-out ${ <div className={`md:hidden overflow-hidden transition-all duration-300 ease-out ${
isMenuOpen ? 'max-h-80 opacity-100' : 'max-h-0 opacity-0' isMenuOpen ? 'max-h-80 opacity-100' : 'max-h-0 opacity-0'
}`}> }`}>
<div className={`py-4 px-4 border-t border-border/10 glass-effect ${ <div className={`py-4 px-4 border-t border-border/10 glass-effect shadow-xl ${
isScrolled isScrolled
? 'bg-white/80 dark:bg-black/80 shadow-sm' ? 'bg-white/90 dark:bg-black/80'
: 'bg-white/85 dark:bg-black/85' : 'bg-white/95 dark:bg-black/85'
}`}> }`}>
<nav className="flex flex-col space-y-3 text-sm font-medium"> <nav className="flex flex-col space-y-3 text-sm font-medium">
{navItems.map((item) => { {navItems.map((item) => {

View File

@@ -47,7 +47,7 @@ const statusColor = statusClassMap[project.status as keyof typeof statusClassMap
<article <article
data-project-card data-project-card
data-type={project.type} data-type={project.type}
class="group flex flex-col overflow-hidden rounded-3xl border border-border/50 bg-card/50 backdrop-blur-sm transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/5" class="group flex flex-col overflow-hidden rounded-3xl border border-border/40 bg-card/60 backdrop-blur-md transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl hover:shadow-primary/5"
> >
{/* 顶部封面图区域 */} {/* 顶部封面图区域 */}
<div class="relative aspect-[16/10] overflow-hidden"> <div class="relative aspect-[16/10] overflow-hidden">

View File

@@ -76,7 +76,7 @@ const readMoreText = lang === 'zh' ? '阅读更多' : 'Read More';
{posts.length > 0 ? ( {posts.length > 0 ? (
posts.map((post, index) => ( posts.map((post, index) => (
<article class="group"> <article class="group">
<div class="bg-card/50 backdrop-blur-sm rounded-2xl overflow-hidden border border-border hover:border-primary/50 transition-all duration-300 hover:transform hover:scale-[1.02]"> <div class="bg-card/60 backdrop-blur-md rounded-2xl overflow-hidden border border-border/40 hover:border-primary/50 transition-all duration-300 hover:transform hover:scale-[1.02] hover:shadow-xl hover:shadow-primary/5">
<div class="flex flex-col md:flex-row"> <div class="flex flex-col md:flex-row">
{/* Featured Image */} {/* Featured Image */}
<div class="relative overflow-hidden md:w-80 md:flex-shrink-0"> <div class="relative overflow-hidden md:w-80 md:flex-shrink-0">

View File

@@ -41,7 +41,7 @@ const titles = {
const title = titles[lang] || titles[defaultLang]; const title = titles[lang] || titles[defaultLang];
--- ---
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-6 border border-border"> <div class="bg-card/60 backdrop-blur-md rounded-2xl p-6 border border-border/40">
<h3 class="text-xl font-semibold text-card-foreground mb-4 flex items-center"> <h3 class="text-xl font-semibold text-card-foreground mb-4 flex items-center">
<Tag className="w-5 h-5 mr-2 text-primary" /> <Tag className="w-5 h-5 mr-2 text-primary" />
{title} {title}
@@ -61,6 +61,6 @@ const title = titles[lang] || titles[defaultLang];
<div class="flex flex-col items-center justify-center py-6"> <div class="flex flex-col items-center justify-center py-6">
<p class="text-muted-foreground text-center">{lang === 'zh' ? '暂无分类' : 'No categories yet'}</p> <p class="text-muted-foreground text-center">{lang === 'zh' ? '暂无分类' : 'No categories yet'}</p>
</div> </div>
) )}
</div> </div>
</div> </div>

View File

@@ -127,7 +127,7 @@ const getReadingTimeText = (minutes: number) => {
: tag.toLowerCase(); : tag.toLowerCase();
return ( return (
<a href={`/${lang === 'en' ? '' : 'zh/'}blog/tags/${encodeURIComponent(tagRoute)}`} class="inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-gray-100 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 transition-colors border border-gray-200 dark:border-gray-600"> <a href={`/${lang === 'en' ? '' : 'zh/'}blog/tags/${encodeURIComponent(tagRoute)}`} class="inline-flex items-center px-2.5 py-1 rounded-md text-xs font-medium bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors border border-border">
# {tag} # {tag}
</a> </a>
); );

View File

@@ -41,7 +41,7 @@ const titles = {
const title = titles[lang] || titles[defaultLang]; const title = titles[lang] || titles[defaultLang];
--- ---
<div class="bg-card/50 backdrop-blur-sm rounded-2xl p-6 border border-border"> <div class="bg-card/60 backdrop-blur-md rounded-2xl p-6 border border-border/40">
<h3 class="text-xl font-semibold text-card-foreground mb-4 flex items-center"> <h3 class="text-xl font-semibold text-card-foreground mb-4 flex items-center">
<Hash className='w-5 h-5 mr-2 text-primary' /> <Hash className='w-5 h-5 mr-2 text-primary' />
{title} {title}

View File

@@ -22,7 +22,7 @@ const lang = Astro.currentLocale as Lang || defaultLang;
</div> </div>
<!-- Glass Header with navigation --> <!-- Glass Header with navigation -->
<GlassHeader lang={lang} client:load /> <GlassHeader lang={lang} client:load transition:persist="header" />
<!-- Main content with proper spacing for fixed header --> <!-- Main content with proper spacing for fixed header -->
<div class="pt-16"> <div class="pt-16">

View File

@@ -43,7 +43,7 @@ const finalReadingTime = readTime ? parseInt(readTime.replace(/\D/g, '')) : unde
<Layout title={title} description={description}> <Layout title={title} description={description}>
<!-- Glass Header with navigation --> <!-- Glass Header with navigation -->
<GlassHeader lang={lang} client:load /> <GlassHeader lang={lang} client:load transition:persist="header" />
<!-- 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">

View File

@@ -1,4 +1,5 @@
--- ---
import { ClientRouter } from "astro:transitions";
import BackToTop from "@/components/ui/back-to-top"; import BackToTop from "@/components/ui/back-to-top";
import { useTranslations } from "@/i18n/utils"; import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n"; import type { Lang } from "@/types/i18n";
@@ -26,6 +27,7 @@ const t = useTranslations(lang);
<meta name="description" content={description} /> <meta name="description" content={description} />
<title>{title} | {t("site.title")}</title> <title>{title} | {t("site.title")}</title>
<!-- View Transitions for smooth page transitions --> <!-- View Transitions for smooth page transitions -->
<ClientRouter />
<meta name="view-transition" content="same-origin" /> <meta name="view-transition" content="same-origin" />
{ {
import.meta.env.MODE === 'production' && ( import.meta.env.MODE === 'production' && (

View File

@@ -37,7 +37,7 @@ const pageTitle = t("about.title");
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" lang={lang} /> <GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20"> <main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20">
<!-- Background Decor --> <!-- Background Decor -->

View File

@@ -14,7 +14,7 @@ const pageTitle = lang === 'zh' ? '合作' : 'Hire Me';
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Hire Page Hero --> <!-- Hire Page Hero -->
<section class="py-24 relative overflow-hidden"> <section class="py-24 relative overflow-hidden">

View File

@@ -43,7 +43,7 @@ const keyFacts = [
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" lang={lang} /> <GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen"> <main class="min-h-screen">
<div class="relative overflow-hidden"> <div class="relative overflow-hidden">

View File

@@ -14,7 +14,7 @@ const pageTitle = lang === 'zh' ? '现在' : 'Now';
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden"> <main class="min-h-screen relative overflow-hidden">
<!-- 背景装饰 --> <!-- 背景装饰 -->
<div class="absolute inset-0 -z-10"> <div class="absolute inset-0 -z-10">

View File

@@ -26,7 +26,7 @@ const filterOptions = [
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden"> <main class="min-h-screen relative overflow-hidden">
<div <div
aria-hidden="true" aria-hidden="true"

View File

@@ -37,7 +37,7 @@ const pageTitle = t("about.title");
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" lang={lang} /> <GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20"> <main class="min-h-screen relative overflow-hidden pt-16 sm:pt-20">
<!-- Background Decor --> <!-- Background Decor -->

View File

@@ -14,7 +14,7 @@ const pageTitle = lang === 'zh' ? '合作' : 'Hire Me';
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen"> <main class="min-h-screen">
<!-- Hire Page Hero --> <!-- Hire Page Hero -->
<section class="py-24 relative overflow-hidden"> <section class="py-24 relative overflow-hidden">

View File

@@ -42,7 +42,7 @@ const keyFacts = [
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader client:only="react" lang={lang} /> <GlassHeader client:load transition:persist="header" lang={lang} />
<main class="min-h-screen"> <main class="min-h-screen">
<div class="relative overflow-hidden"> <div class="relative overflow-hidden">

View File

@@ -14,7 +14,7 @@ const pageTitle = lang === 'zh' ? '现在' : 'Now';
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden"> <main class="min-h-screen relative overflow-hidden">
<!-- 背景装饰 --> <!-- 背景装饰 -->
<div class="absolute inset-0 -z-10"> <div class="absolute inset-0 -z-10">

View File

@@ -26,7 +26,7 @@ const filterOptions = [
--- ---
<Layout title={pageTitle}> <Layout title={pageTitle}>
<GlassHeader lang={lang} client:only="react" /> <GlassHeader lang={lang} client:load transition:persist="header" />
<main class="min-h-screen relative overflow-hidden"> <main class="min-h-screen relative overflow-hidden">
<div <div
aria-hidden="true" aria-hidden="true"

View File

@@ -44,23 +44,23 @@
:root { :root {
--radius: 0.75rem; --radius: 0.75rem;
--background: #F1F5F9; /* 更柔和的蓝灰色,不再是纯白或过于扎眼的浅色 */ --background: #F8FAFC; /* 稍微浅一点,增加与卡片的区分度 */
--foreground: #1E293B; --foreground: #0F172A; /* 更深的颜色,提高对比度 */
--card: #FFFFFF; --card: #FFFFFF;
--card-foreground: #1E293B; --card-foreground: #0F172A;
--popover: #FFFFFF; --popover: #FFFFFF;
--popover-foreground: #1E293B; --popover-foreground: #0F172A;
--primary: #2563EB; --primary: #2563EB;
--primary-foreground: #FFFFFF; --primary-foreground: #FFFFFF;
--secondary: #E4E4E7; --secondary: #F1F5F9;
--secondary-foreground: #1E293B; --secondary-foreground: #0F172A;
--muted: #F4F4F5; --muted: #F1F5F9;
--muted-foreground: #71717A; --muted-foreground: #64748B;
--accent: #F97316; --accent: #F97316;
--accent-foreground: #FFFFFF; --accent-foreground: #FFFFFF;
--destructive: #EF4444; --destructive: #EF4444;
--border: #E4E4E7; --border: #E2E8F0;
--input: #E4E4E7; --input: #E2E8F0;
--ring: #2563EB; --ring: #2563EB;
--chart-1: oklch(0.646 0.222 41.116); --chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704); --chart-2: oklch(0.6 0.118 184.704);
@@ -82,22 +82,22 @@
--gradient-primary: linear-gradient(135deg, #2563EB, #F97316); --gradient-primary: linear-gradient(135deg, #2563EB, #F97316);
--gradient-secondary: linear-gradient(135deg, #3B82F6, #10B981); --gradient-secondary: linear-gradient(135deg, #3B82F6, #10B981);
--gradient-accent: linear-gradient(135deg, #F97316, #FB923C); --gradient-accent: linear-gradient(135deg, #F97316, #FB923C);
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.05); --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl: 0 12px 40px rgba(37, 99, 235, 0.15); --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--animation-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); --animation-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
--animation-smooth: cubic-bezier(0.65, 0, 0.35, 1); --animation-smooth: cubic-bezier(0.65, 0, 0.35, 1);
--animation-spring: cubic-bezier(0.22, 1, 0.36, 1); --animation-spring: cubic-bezier(0.22, 1, 0.36, 1);
/* Global UI Design Tokens */ /* Global UI Design Tokens */
--ui-hero-overlay: linear-gradient(135deg, rgb(30 58 138 / 0.2), rgb(37 99 235 / 0.1), rgb(154 52 18 / 0.2)); --ui-hero-overlay: linear-gradient(135deg, rgb(30 58 138 / 0.05), rgb(37 99 235 / 0.03), rgb(154 52 18 / 0.05));
--ui-title-gradient: linear-gradient(90deg, #111827 0%, var(--primary) 50%, #ea580c 100%); --ui-title-gradient: linear-gradient(90deg, #0F172A 0%, #2563EB 50%, #ea580c 100%);
--ui-surface-bg: rgb(248 250 252 / 0.75); --ui-surface-bg: rgb(255 255 255 / 0.8);
--ui-surface-border: rgb(228 228 231 / 0.7); --ui-surface-border: rgb(226 232 240 / 0.8);
--ui-surface-shadow: var(--shadow-sm); --ui-surface-shadow: 0 4px 12px -2px rgb(0 0 0 / 0.05);
--ui-surface-blur: 10px; --ui-surface-blur: 12px;
--ui-section-soft-bg: rgb(37 99 235 / 0.05); --ui-section-soft-bg: rgb(37 99 235 / 0.03);
} }
.dark { .dark {