This commit is contained in:
2025-11-10 16:54:07 +08:00
commit b2a99d2a66
25 changed files with 9960 additions and 0 deletions

439
src/routes/+layout.svelte Normal file
View File

@@ -0,0 +1,439 @@
<script lang="ts">
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { goto } from '$app/navigation';
let isDarkMode = false;
let currentPath = '/';
let currentCategory: string | null = null;
const primaryNav = [
{ label: 'Today', href: '/', icon: 'today' },
{ label: 'Projects', href: '/projects', icon: 'projects' },
{ label: 'About', href: '/about', icon: 'about' },
{ label: 'Contact', href: '/contact', icon: 'contact' }
];
const categoryNav = [
{ label: 'Brand Design', href: '/projects?category=Brand Design' },
{ label: 'UI/UX Design', href: '/projects?category=UI/UX Design' },
{ label: 'Web Design', href: '/projects?category=Web Design' },
{ label: 'Graphic Design', href: '/projects?category=Graphic Design' },
{ label: 'Photography', href: '/projects?category=Photography' },
{ label: 'Print Design', href: '/projects?category=Print Design' }
];
function toggleTheme() {
isDarkMode = !isDarkMode;
document.documentElement.classList.toggle('dark', isDarkMode);
}
function navigateTo(href: string) {
goto(href);
}
$: currentPath = $page.url.pathname;
$: currentCategory = $page.url.searchParams.get('category');
onMount(() => {
// 检测系统主题偏好
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
isDarkMode = prefersDark;
document.documentElement.classList.toggle('dark', isDarkMode);
});
</script>
<svelte:head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="LiuBai Design - A modern creative studio experience built with SvelteKit" />
</svelte:head>
<div class="app-shell">
<aside class="sidebar">
<header class="sidebar__header">
<div class="sidebar__store-icon" aria-hidden="true">🎨</div>
<div class="sidebar__heading">
<span class="sidebar__title">LiuBai Design</span>
<span class="sidebar__subtitle">Creative Studio</span>
</div>
</header>
<div class="sidebar__search">
<span class="sidebar__search-icon" aria-hidden="true">🔍</span>
<input type="search" placeholder="Search" aria-label="Search LiuBai Design" />
</div>
<nav class="sidebar__nav">
<div class="sidebar__section" aria-label="Primary navigation">
{#each primaryNav as item}
<button
class:active={item.href === '/' ? currentPath === '/' : currentPath.startsWith(item.href)}
on:click={() => navigateTo(item.href)}
>
<span class="sidebar__bullet" aria-hidden="true"></span>
{item.label}
</button>
{/each}
</div>
<div class="sidebar__section" aria-label="Design categories">
<span class="sidebar__section-label">Design Categories</span>
{#each categoryNav as item}
<button
class:active={currentCategory === item.label}
on:click={() => navigateTo(item.href)}
>
{item.label}
</button>
{/each}
</div>
</nav>
<footer class="sidebar__footer">
<button on:click={toggleTheme} aria-label="Toggle theme">
<span class="sidebar__avatar" aria-hidden="true">{isDarkMode ? '☀️' : '🌙'}</span>
{isDarkMode ? 'Light' : 'Dark'}
</button>
<button aria-label="Account">
<span class="sidebar__avatar" aria-hidden="true">🧑‍💻</span>
Account
</button>
</footer>
</aside>
<main class="content">
<slot />
</main>
</div>
<style>
:global(html) {
height: 100%;
scroll-behavior: smooth;
}
:global(body) {
margin: 0;
padding: 0;
font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
transition: background-color 0.3s ease, color 0.3s ease;
}
/* 亮色模式 */
:global(body) {
background: #f5f5f7;
color: #1d1d1f;
}
/* 暗色模式 */
:global(.dark body) {
background: radial-gradient(circle at top left, rgba(46, 46, 82, 0.6), transparent 40%),
radial-gradient(circle at bottom right, rgba(36, 36, 60, 0.5), transparent 45%),
#050506;
color: #ffffff;
}
.app-shell {
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
min-height: 100vh;
}
.sidebar {
display: grid;
grid-template-rows: auto auto 1fr auto;
gap: 32px;
padding: 32px 24px;
background: rgba(255, 255, 255, 0.8);
border-right: 1px solid rgba(0, 0, 0, 0.08);
backdrop-filter: blur(30px);
box-shadow: 12px 0 40px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:global(.dark) .sidebar {
background: rgba(10, 10, 18, 0.9);
border-right: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 12px 0 40px rgba(0, 0, 0, 0.35);
}
.sidebar__header {
display: flex;
gap: 12px;
align-items: center;
}
.sidebar__store-icon {
width: 36px;
height: 36px;
border-radius: 12px;
background: linear-gradient(135deg, #4f46e5 0%, #9333ea 100%);
display: grid;
place-items: center;
font-size: 20px;
color: white;
}
.sidebar__heading {
display: flex;
flex-direction: column;
color: rgba(0, 0, 0, 0.9);
transition: color 0.3s ease;
}
:global(.dark) .sidebar__heading {
color: rgba(255, 255, 255, 0.9);
}
.sidebar__title {
font-size: 15px;
font-weight: 600;
letter-spacing: 0.02em;
}
.sidebar__subtitle {
font-size: 13px;
color: rgba(255, 255, 255, 0.55);
}
.sidebar__search {
position: relative;
display: flex;
align-items: center;
}
.sidebar__search-icon {
position: absolute;
left: 14px;
font-size: 14px;
color: rgba(0, 0, 0, 0.4);
transition: color 0.3s ease;
}
:global(.dark) .sidebar__search-icon {
color: rgba(255, 255, 255, 0.4);
}
.sidebar__search input {
width: 100%;
padding: 10px 14px 10px 34px;
border-radius: 12px;
border: none;
background: rgba(0, 0, 0, 0.08);
color: rgba(0, 0, 0, 0.88);
font-size: 13px;
transition: all 0.3s ease;
}
:global(.dark) .sidebar__search input {
background: rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.88);
}
.sidebar__search input:focus {
outline: none;
background: rgba(0, 0, 0, 0.12);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.35);
}
:global(.dark) .sidebar__search input:focus {
background: rgba(255, 255, 255, 0.12);
box-shadow: 0 0 0 2px rgba(147, 197, 253, 0.35);
}
.sidebar__nav {
display: flex;
flex-direction: column;
gap: 36px;
}
.sidebar__section {
display: grid;
gap: 4px;
}
.sidebar__section-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: rgba(0, 0, 0, 0.35);
margin-bottom: 8px;
transition: color 0.3s ease;
}
:global(.dark) .sidebar__section-label {
color: rgba(255, 255, 255, 0.35);
}
.sidebar__section button {
position: relative;
display: flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
border-radius: 12px;
border: none;
background: transparent;
color: rgba(0, 0, 0, 0.66);
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
:global(.dark) .sidebar__section button {
color: rgba(255, 255, 255, 0.66);
}
.sidebar__section button:hover {
color: rgba(0, 0, 0, 0.9);
background: rgba(0, 0, 0, 0.06);
}
:global(.dark) .sidebar__section button:hover {
color: rgba(255, 255, 255, 0.9);
background: rgba(255, 255, 255, 0.06);
}
.sidebar__section button.active {
color: #ffffff;
background: linear-gradient(135deg, rgba(88, 88, 255, 0.45), rgba(138, 92, 255, 0.45));
}
.sidebar__bullet {
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.4);
transition: background 0.3s ease;
}
:global(.dark) .sidebar__bullet {
background: rgba(255, 255, 255, 0.4);
}
.sidebar__section button.active .sidebar__bullet {
background: #ffffff;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
}
.sidebar__footer button {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 14px;
border-radius: 12px;
border: 1px solid rgba(0, 0, 0, 0.08);
background: rgba(0, 0, 0, 0.03);
color: rgba(0, 0, 0, 0.72);
font-size: 13px;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 8px;
}
:global(.dark) .sidebar__footer button {
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.03);
color: rgba(255, 255, 255, 0.72);
}
.sidebar__footer button:hover {
border-color: rgba(0, 0, 0, 0.2);
background: rgba(0, 0, 0, 0.08);
color: #000000;
}
:global(.dark) .sidebar__footer button:hover {
border-color: rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.08);
color: #ffffff;
}
.sidebar__avatar {
width: 28px;
height: 28px;
border-radius: 9px;
background: rgba(0, 0, 0, 0.1);
display: grid;
place-items: center;
transition: background 0.3s ease;
}
:global(.dark) .sidebar__avatar {
background: rgba(255, 255, 255, 0.1);
}
.content {
position: relative;
overflow-y: auto;
padding: 48px 56px 64px;
background: linear-gradient(180deg, rgba(245, 245, 247, 0.9) 0%, rgba(240, 240, 242, 0.92) 55%, rgba(235, 235, 237, 0.96) 100%);
box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
:global(.dark) .content {
background: linear-gradient(180deg, rgba(16, 16, 28, 0.9) 0%, rgba(8, 8, 18, 0.92) 55%, rgba(6, 6, 12, 0.96) 100%);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.content::-webkit-scrollbar {
width: 10px;
}
.content::-webkit-scrollbar-track {
background: rgba(200, 200, 200, 0.7);
}
:global(.dark) .content::-webkit-scrollbar-track {
background: rgba(12, 12, 18, 0.7);
}
.content::-webkit-scrollbar-thumb {
background: rgba(150, 150, 150, 0.45);
border-radius: 6px;
}
:global(.dark) .content::-webkit-scrollbar-thumb {
background: rgba(110, 110, 145, 0.45);
}
@media (max-width: 1024px) {
.app-shell {
grid-template-columns: 240px 1fr;
}
.content {
padding: 36px 32px 48px;
}
}
@media (max-width: 860px) {
.app-shell {
grid-template-columns: 1fr;
}
.sidebar {
position: sticky;
top: 0;
z-index: 10;
grid-template-rows: auto;
grid-auto-flow: column;
overflow-x: auto;
padding: 20px 24px;
gap: 24px;
}
.sidebar__nav,
.sidebar__footer {
display: none;
}
.content {
padding: 24px;
}
}
</style>

700
src/routes/+page.svelte Normal file
View File

@@ -0,0 +1,700 @@
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
// 特色项目数据
const featuredProjects = [
{
id: 1,
title: 'Creative Brand Identity',
subtitle: 'Complete visual system for modern brands',
badge: 'FEATURED PROJECT',
category: 'Brand Design',
description: 'A comprehensive brand identity system featuring logo design, color palettes, typography, and brand guidelines.',
bgColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%), radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.15) 0%, transparent 50%)',
textColor: 'white',
image: '🎨',
buttonText: 'View Project'
},
{
id: 2,
title: 'Mobile App Interface',
subtitle: 'Modern UI/UX for digital experiences',
badge: 'UI/UX DESIGN',
category: 'Digital Design',
description: 'Intuitive mobile interface design with focus on user experience and modern aesthetics.',
bgColor: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%), radial-gradient(circle at 20% 80%, rgba(240, 147, 251, 0.3) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.15) 0%, transparent 50%)',
textColor: 'white',
image: '📱',
buttonText: 'Explore'
}
];
const smallProjects = [
{
id: 3,
name: 'Web Portfolio',
category: 'Web Design',
icon: '💻',
bgColor: '#4f46e5'
},
{
id: 4,
name: 'Print Design',
category: 'Graphic Design',
icon: '📄',
bgColor: '#059669'
},
{
id: 5,
name: 'Photography',
category: 'Visual Arts',
icon: '📸',
bgColor: '#dc2626'
},
{
id: 6,
name: 'Illustration',
category: 'Digital Art',
icon: '🖼️',
bgColor: '#7c3aed'
}
];
function navigateToProject(projectId: number) {
goto(`/projects/${projectId}`);
}
function navigateToProjects() {
goto('/projects');
}
function navigateToContact() {
goto('/contact');
}
onMount(() => {
console.log('Home page mounted');
});
</script>
<svelte:head>
<title>LiuBai Design - Creative Studio</title>
<meta name="description" content="LiuBai Design - Discover amazing creative works and design solutions" />
</svelte:head>
<div class="today-page">
<!-- 页面标题 -->
<header class="page-header">
<h1 class="page-title">Today</h1>
<p class="page-subtitle">Discover our latest creative works and design solutions</p>
</header>
<!-- 主要特色项目 -->
<section class="hero-section">
<div class="hero-card" style="background: {featuredProjects[0].bgColor}" on:click={() => navigateToProject(featuredProjects[0].id)} role="button" tabindex="0">
<div class="hero-content">
<div class="hero-badge">{featuredProjects[0].badge}</div>
<h2 class="hero-title">{featuredProjects[0].title}</h2>
<p class="hero-description">{featuredProjects[0].description}</p>
<div class="hero-project-info">
<div class="project-icon">{featuredProjects[0].image}</div>
<div class="project-details">
<h3 class="project-name">{featuredProjects[0].subtitle}</h3>
<p class="project-category">{featuredProjects[0].category}</p>
</div>
<button class="project-button" on:click|stopPropagation={() => navigateToProject(featuredProjects[0].id)}>{featuredProjects[0].buttonText}</button>
</div>
</div>
</div>
</section>
<!-- 项目展示区域 -->
<section class="projects-section">
<div class="section-header">
<h2 class="section-title">Featured Works</h2>
<p class="section-subtitle">Explore our creative portfolio</p>
</div>
<div class="projects-grid">
<!-- 大型项目卡片 -->
<div class="large-project-card" style="background: {featuredProjects[1].bgColor}" on:click={() => navigateToProject(featuredProjects[1].id)} role="button" tabindex="0">
<div class="card-content">
<div class="card-badge">{featuredProjects[1].badge}</div>
<h3 class="card-title">{featuredProjects[1].title}</h3>
<p class="card-description">{featuredProjects[1].description}</p>
<div class="card-project-info">
<div class="project-icon small">{featuredProjects[1].image}</div>
<div class="project-details">
<h4 class="project-name">{featuredProjects[1].subtitle}</h4>
<p class="project-category">{featuredProjects[1].category}</p>
</div>
<button class="project-button small" on:click|stopPropagation={() => navigateToProject(featuredProjects[1].id)}>{featuredProjects[1].buttonText}</button>
</div>
</div>
</div>
<!-- 小型项目卡片网格 -->
<div class="small-projects-grid">
{#each smallProjects as project}
<div class="small-project-card" on:click={navigateToProjects} role="button" tabindex="0">
<div class="small-card-icon" style="background-color: {project.bgColor}">
{project.icon}
</div>
<h4 class="small-card-title">{project.name}</h4>
<p class="small-card-category">{project.category}</p>
<button class="small-card-button" on:click|stopPropagation={navigateToProjects}>View</button>
</div>
{/each}
</div>
</div>
</section>
<!-- 服务展示 -->
<section class="services-section">
<div class="section-header">
<h2 class="section-title">Our Services</h2>
<p class="section-subtitle">What we can create for you</p>
</div>
<div class="services-grid">
<div class="service-card" on:click={navigateToContact} role="button" tabindex="0">
<div class="service-icon">🎨</div>
<h3 class="service-title">Brand Identity</h3>
<p class="service-description">Complete visual identity systems that tell your brand's story</p>
</div>
<div class="service-card" on:click={navigateToContact} role="button" tabindex="0">
<div class="service-icon">💻</div>
<h3 class="service-title">Web Design</h3>
<p class="service-description">Modern, responsive websites that engage and convert</p>
</div>
<div class="service-card" on:click={navigateToContact} role="button" tabindex="0">
<div class="service-icon">📱</div>
<h3 class="service-title">UI/UX Design</h3>
<p class="service-description">Intuitive interfaces that users love to interact with</p>
</div>
<div class="service-card" on:click={navigateToContact} role="button" tabindex="0">
<div class="service-icon">📸</div>
<h3 class="service-title">Photography</h3>
<p class="service-description">Professional photography for brands and products</p>
</div>
</div>
</section>
</div>
<style>
.today-page {
max-width: 1200px;
margin: 0 auto;
padding: 0;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.page-header {
margin-bottom: 32px;
}
.page-title {
font-size: 48px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .page-title {
color: #f5f5f7;
}
.page-subtitle {
font-size: 18px;
color: #6B7280;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .page-subtitle {
color: #9CA3AF;
}
/* Hero Section */
.hero-section {
margin-bottom: 48px;
}
.hero-card {
border-radius: 24px;
padding: 48px;
color: white;
position: relative;
overflow: hidden;
min-height: 400px;
display: flex;
align-items: flex-end;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.hero-card:hover {
transform: translateY(-8px) scale(1.02);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
}
.hero-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 50%);
pointer-events: none;
}
.hero-content {
width: 100%;
z-index: 2;
}
.hero-badge {
display: inline-block;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
padding: 8px 16px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 16px;
border: 1px solid rgba(255, 255, 255, 0.3);
animation: slideInUp 0.8s ease-out 0.2s both;
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.hero-title {
font-size: 36px;
font-weight: 700;
margin-bottom: 16px;
line-height: 1.2;
animation: slideInUp 0.8s ease-out 0.4s both;
}
.hero-description {
font-size: 18px;
margin-bottom: 32px;
opacity: 0.9;
line-height: 1.5;
animation: slideInUp 0.8s ease-out 0.6s both;
}
.hero-project-info {
display: flex;
align-items: center;
gap: 16px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
padding: 16px 24px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.2);
animation: slideInUp 0.8s ease-out 0.8s both;
transition: all 0.3s ease;
}
.hero-project-info:hover {
background: rgba(255, 255, 255, 0.15);
border-color: rgba(255, 255, 255, 0.4);
transform: translateY(-2px);
}
.project-icon {
width: 64px;
height: 64px;
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
}
.project-icon.small {
width: 48px;
height: 48px;
font-size: 24px;
border-radius: 12px;
}
.project-details {
flex: 1;
}
.project-name {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
}
.project-category {
font-size: 14px;
opacity: 0.8;
margin: 0;
}
.project-button {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 12px 24px;
border-radius: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
overflow: hidden;
}
.project-button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.project-button:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.project-button:hover::before {
width: 300px;
height: 300px;
}
.project-button:active {
transform: translateY(0);
}
.project-button.small {
padding: 8px 16px;
font-size: 14px;
}
/* Projects Section */
.projects-section {
margin-bottom: 48px;
}
.section-header {
margin-bottom: 32px;
}
.section-title {
font-size: 32px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .section-title {
color: #f5f5f7;
}
.section-subtitle {
font-size: 16px;
color: #6B7280;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .section-subtitle {
color: #9CA3AF;
}
.projects-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.large-project-card {
border-radius: 20px;
padding: 32px;
color: white;
min-height: 300px;
display: flex;
align-items: flex-end;
cursor: pointer;
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.large-project-card:hover {
transform: translateY(-6px) scale(1.02);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
.large-project-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 50%);
pointer-events: none;
}
.card-content {
width: 100%;
}
.card-badge {
display: inline-block;
background: rgba(255, 255, 255, 0.2);
padding: 6px 12px;
border-radius: 16px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 12px;
}
.card-title {
font-size: 24px;
font-weight: 700;
margin-bottom: 12px;
line-height: 1.2;
}
.card-description {
font-size: 14px;
margin-bottom: 24px;
opacity: 0.9;
line-height: 1.4;
}
.card-project-info {
display: flex;
align-items: center;
gap: 12px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
padding: 12px 16px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.small-projects-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.small-project-card {
background: white;
padding: 24px;
border-radius: 16px;
text-align: center;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
animation: slideInUp 0.6s ease-out both;
}
.small-project-card:nth-child(1) { animation-delay: 0.1s; }
.small-project-card:nth-child(2) { animation-delay: 0.2s; }
.small-project-card:nth-child(3) { animation-delay: 0.3s; }
.small-project-card:nth-child(4) { animation-delay: 0.4s; }
:global(.dark) .small-project-card {
background: rgba(28, 28, 30, 0.8);
color: #f5f5f7;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
}
.small-project-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
:global(.dark) .small-project-card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
}
.small-card-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
margin: 0 auto 16px;
color: white;
}
.small-card-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 4px;
}
.small-card-category {
font-size: 14px;
color: #6B7280;
margin-bottom: 16px;
transition: color 0.3s ease;
}
:global(.dark) .small-card-category {
color: #9CA3AF;
}
.small-card-button {
background: #007AFF;
color: white;
border: none;
padding: 8px 16px;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
}
.small-card-button:hover {
background: #0056CC;
transform: translateY(-1px);
}
/* Services Section */
.services-section {
margin-bottom: 48px;
}
.services-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 24px;
}
.service-card {
background: white;
padding: 32px 24px;
border-radius: 16px;
text-align: center;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
animation: slideInUp 0.6s ease-out both;
}
.service-card:nth-child(1) { animation-delay: 0.2s; }
.service-card:nth-child(2) { animation-delay: 0.3s; }
.service-card:nth-child(3) { animation-delay: 0.4s; }
.service-card:nth-child(4) { animation-delay: 0.5s; }
:global(.dark) .service-card {
background: rgba(28, 28, 30, 0.8);
color: #f5f5f7;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
}
.service-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
:global(.dark) .service-card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3);
}
.service-icon {
font-size: 48px;
margin-bottom: 16px;
}
.service-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 12px;
}
.service-description {
font-size: 14px;
color: #6B7280;
line-height: 1.5;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .service-description {
color: #9CA3AF;
}
/* 响应式设计 */
@media (max-width: 768px) {
.hero-card {
padding: 32px 24px;
min-height: 300px;
}
.hero-title {
font-size: 28px;
}
.hero-description {
font-size: 16px;
}
.hero-project-info {
flex-direction: column;
text-align: center;
gap: 12px;
}
.projects-grid {
grid-template-columns: 1fr;
}
.small-projects-grid {
grid-template-columns: 1fr;
}
.services-grid {
grid-template-columns: 1fr;
}
}
</style>

View File

@@ -0,0 +1,587 @@
<script lang="ts">
import { onMount } from 'svelte';
const skills = [
{ name: 'Brand Identity', level: 95, icon: '🎨' },
{ name: 'UI/UX Design', level: 90, icon: '📱' },
{ name: 'Web Development', level: 85, icon: '💻' },
{ name: 'Print Design', level: 88, icon: '📄' },
{ name: 'Photography', level: 80, icon: '📸' },
{ name: 'Illustration', level: 75, icon: '🖼️' }
];
const timeline = [
{
year: '2024',
title: 'Founded LiuBai Design',
description: 'Established creative studio focusing on modern brand identity and digital experiences.'
},
{
year: '2023',
title: 'Senior Designer at Tech Corp',
description: 'Led design team for major product launches and brand redesign initiatives.'
},
{
year: '2022',
title: 'Freelance Designer',
description: 'Worked with various startups and established companies on branding and web design projects.'
},
{
year: '2021',
title: 'Design Degree Completed',
description: 'Graduated with honors in Visual Communication Design from Design University.'
}
];
onMount(() => {
console.log('About page mounted');
});
</script>
<svelte:head>
<title>About - LiuBai Design</title>
<meta name="description" content="Learn about LiuBai Design studio and our creative approach" />
</svelte:head>
<div class="about-page">
<!-- Hero Section -->
<section class="hero-section">
<div class="hero-content">
<div class="hero-avatar">
<div class="avatar-icon">🎨</div>
</div>
<h1 class="hero-title">About LiuBai Design</h1>
<p class="hero-description">
We are a creative studio passionate about crafting meaningful brand experiences
and digital solutions that connect with people and drive results.
</p>
</div>
</section>
<!-- Story Section -->
<section class="story-section">
<div class="section-header">
<h2 class="section-title">Our Story</h2>
</div>
<div class="story-content">
<p class="story-text">
Founded in 2024, LiuBai Design emerged from a passion for creating visual experiences
that not only look beautiful but also serve a purpose. We believe that great design
is the perfect balance between aesthetics and functionality.
</p>
<p class="story-text">
Our approach combines strategic thinking with creative execution, ensuring that every
project we undertake delivers both visual impact and measurable results for our clients.
</p>
</div>
</section>
<!-- Skills Section -->
<section class="skills-section">
<div class="section-header">
<h2 class="section-title">What We Do</h2>
<p class="section-subtitle">Our areas of expertise</p>
</div>
<div class="skills-grid">
{#each skills as skill, index}
<div class="skill-card" style="animation-delay: {index * 0.1}s">
<div class="skill-icon">{skill.icon}</div>
<h3 class="skill-name">{skill.name}</h3>
<div class="skill-bar">
<div class="skill-progress" style="width: {skill.level}%"></div>
</div>
<span class="skill-level">{skill.level}%</span>
</div>
{/each}
</div>
</section>
<!-- Timeline Section -->
<section class="timeline-section">
<div class="section-header">
<h2 class="section-title">Our Journey</h2>
<p class="section-subtitle">Key milestones in our creative journey</p>
</div>
<div class="timeline">
{#each timeline as item, index}
<div class="timeline-item" style="animation-delay: {index * 0.2}s">
<div class="timeline-marker"></div>
<div class="timeline-content">
<div class="timeline-year">{item.year}</div>
<h3 class="timeline-title">{item.title}</h3>
<p class="timeline-description">{item.description}</p>
</div>
</div>
{/each}
</div>
</section>
<!-- Values Section -->
<section class="values-section">
<div class="section-header">
<h2 class="section-title">Our Values</h2>
</div>
<div class="values-grid">
<div class="value-card">
<div class="value-icon">💡</div>
<h3 class="value-title">Innovation</h3>
<p class="value-description">
We constantly explore new design trends and technologies to deliver cutting-edge solutions.
</p>
</div>
<div class="value-card">
<div class="value-icon">🤝</div>
<h3 class="value-title">Collaboration</h3>
<p class="value-description">
We work closely with our clients as partners to understand their vision and goals.
</p>
</div>
<div class="value-card">
<div class="value-icon"></div>
<h3 class="value-title">Excellence</h3>
<p class="value-description">
We strive for perfection in every detail and never compromise on quality.
</p>
</div>
</div>
</section>
<!-- Contact CTA -->
<section class="cta-section">
<div class="cta-content">
<h2 class="cta-title">Ready to Work Together?</h2>
<p class="cta-description">
Let's create something amazing together. Get in touch to discuss your project.
</p>
<button class="cta-button" on:click={() => window.location.href = '/contact'}>
Get In Touch
</button>
</div>
</section>
</div>
<style>
.about-page {
max-width: 1200px;
margin: 0 auto;
padding: 0;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Hero Section */
.hero-section {
text-align: center;
margin-bottom: 64px;
}
.hero-avatar {
width: 120px;
height: 120px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 32px;
position: relative;
overflow: hidden;
}
.hero-avatar::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0) 50%);
}
.avatar-icon {
font-size: 48px;
z-index: 2;
}
.hero-title {
font-size: 48px;
font-weight: 700;
margin-bottom: 16px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .hero-title {
color: #f5f5f7;
}
.hero-description {
font-size: 20px;
color: #6B7280;
line-height: 1.6;
max-width: 600px;
margin: 0 auto;
transition: color 0.3s ease;
}
:global(.dark) .hero-description {
color: #9CA3AF;
}
/* Section Headers */
.section-header {
text-align: center;
margin-bottom: 48px;
}
.section-title {
font-size: 36px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .section-title {
color: #f5f5f7;
}
.section-subtitle {
font-size: 16px;
color: #6B7280;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .section-subtitle {
color: #9CA3AF;
}
/* Story Section */
.story-section {
margin-bottom: 80px;
}
.story-content {
max-width: 800px;
margin: 0 auto;
}
.story-text {
font-size: 18px;
color: #374151;
line-height: 1.7;
margin-bottom: 24px;
transition: color 0.3s ease;
}
:global(.dark) .story-text {
color: #D1D5DB;
}
/* Skills Section */
.skills-section {
margin-bottom: 80px;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
}
.skill-card {
background: white;
padding: 32px 24px;
border-radius: 20px;
text-align: center;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
animation: slideInUp 0.6s ease-out both;
}
:global(.dark) .skill-card {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.skill-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.skill-icon {
font-size: 48px;
margin-bottom: 16px;
}
.skill-name {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .skill-name {
color: #f5f5f7;
}
.skill-bar {
width: 100%;
height: 8px;
background: #f3f4f6;
border-radius: 4px;
overflow: hidden;
margin-bottom: 8px;
}
:global(.dark) .skill-bar {
background: #374151;
}
.skill-progress {
height: 100%;
background: linear-gradient(90deg, #007AFF 0%, #00C7FF 100%);
border-radius: 4px;
transition: width 1s ease-out 0.5s;
}
.skill-level {
font-size: 14px;
font-weight: 600;
color: #007AFF;
}
/* Timeline Section */
.timeline-section {
margin-bottom: 80px;
}
.timeline {
max-width: 600px;
margin: 0 auto;
position: relative;
}
.timeline::before {
content: '';
position: absolute;
left: 20px;
top: 0;
bottom: 0;
width: 2px;
background: #e5e7eb;
}
:global(.dark) .timeline::before {
background: #374151;
}
.timeline-item {
position: relative;
padding-left: 60px;
margin-bottom: 48px;
animation: slideInLeft 0.6s ease-out both;
}
.timeline-marker {
position: absolute;
left: 12px;
top: 8px;
width: 16px;
height: 16px;
background: #007AFF;
border-radius: 50%;
border: 3px solid white;
box-shadow: 0 0 0 3px #e5e7eb;
}
:global(.dark) .timeline-marker {
border-color: rgba(28, 28, 30, 0.8);
box-shadow: 0 0 0 3px #374151;
}
.timeline-year {
font-size: 14px;
font-weight: 600;
color: #007AFF;
margin-bottom: 8px;
}
.timeline-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .timeline-title {
color: #f5f5f7;
}
.timeline-description {
font-size: 16px;
color: #6B7280;
line-height: 1.5;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .timeline-description {
color: #9CA3AF;
}
/* Values Section */
.values-section {
margin-bottom: 80px;
}
.values-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 32px;
}
.value-card {
text-align: center;
padding: 32px 24px;
}
.value-icon {
font-size: 64px;
margin-bottom: 24px;
}
.value-title {
font-size: 24px;
font-weight: 600;
margin-bottom: 16px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .value-title {
color: #f5f5f7;
}
.value-description {
font-size: 16px;
color: #6B7280;
line-height: 1.6;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .value-description {
color: #9CA3AF;
}
/* CTA Section */
.cta-section {
text-align: center;
padding: 64px 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 24px;
color: white;
margin-bottom: 48px;
}
.cta-title {
font-size: 36px;
font-weight: 700;
margin-bottom: 16px;
}
.cta-description {
font-size: 18px;
margin-bottom: 32px;
opacity: 0.9;
}
.cta-button {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 16px 32px;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.cta-button:hover {
background: rgba(255, 255, 255, 0.3);
border-color: rgba(255, 255, 255, 0.5);
transform: translateY(-2px);
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.hero-title {
font-size: 32px;
}
.section-title {
font-size: 28px;
}
.skills-grid {
grid-template-columns: 1fr;
}
.values-grid {
grid-template-columns: 1fr;
}
.timeline {
margin-left: 20px;
}
.timeline-item {
padding-left: 40px;
}
.cta-section {
padding: 48px 24px;
}
.cta-title {
font-size: 28px;
}
}
</style>

View File

@@ -0,0 +1,667 @@
<script lang="ts">
import { onMount } from 'svelte';
let formData = {
name: '',
email: '',
company: '',
project: '',
budget: '',
message: ''
};
let isSubmitting = false;
let submitMessage = '';
const budgetOptions = [
'Under $5,000',
'$5,000 - $10,000',
'$10,000 - $25,000',
'$25,000 - $50,000',
'Over $50,000'
];
const projectTypes = [
'Brand Identity',
'Web Design',
'Mobile App',
'Print Design',
'Photography',
'Other'
];
async function handleSubmit() {
isSubmitting = true;
// 模拟表单提交
try {
await new Promise(resolve => setTimeout(resolve, 2000));
// 这里应该是实际的表单提交逻辑
console.log('Form submitted:', formData);
submitMessage = 'Thank you for your message! We\'ll get back to you within 24 hours.';
// 重置表单
formData = {
name: '',
email: '',
company: '',
project: '',
budget: '',
message: ''
};
} catch (error) {
submitMessage = 'Sorry, there was an error sending your message. Please try again.';
} finally {
isSubmitting = false;
}
}
onMount(() => {
console.log('Contact page mounted');
});
</script>
<svelte:head>
<title>Contact - LiuBai Design</title>
<meta name="description" content="Get in touch with LiuBai Design for your next creative project" />
</svelte:head>
<div class="contact-page">
<!-- Hero Section -->
<section class="hero-section">
<div class="hero-content">
<h1 class="hero-title">Let's Create Something Amazing</h1>
<p class="hero-description">
Ready to bring your vision to life? We'd love to hear about your project
and discuss how we can help you achieve your goals.
</p>
</div>
</section>
<div class="contact-content">
<!-- Contact Form -->
<div class="form-section">
<div class="form-header">
<h2 class="form-title">Tell Us About Your Project</h2>
<p class="form-description">
Fill out the form below and we'll get back to you within 24 hours.
</p>
</div>
{#if submitMessage}
<div class="submit-message" class:success={submitMessage.includes('Thank you')} class:error={submitMessage.includes('error')}>
{submitMessage}
</div>
{/if}
<form class="contact-form" on:submit|preventDefault={handleSubmit}>
<div class="form-row">
<div class="form-group">
<label for="name" class="form-label">Name *</label>
<input
type="text"
id="name"
bind:value={formData.name}
class="form-input"
required
placeholder="Your full name"
/>
</div>
<div class="form-group">
<label for="email" class="form-label">Email *</label>
<input
type="email"
id="email"
bind:value={formData.email}
class="form-input"
required
placeholder="your@email.com"
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="company" class="form-label">Company</label>
<input
type="text"
id="company"
bind:value={formData.company}
class="form-input"
placeholder="Your company name"
/>
</div>
<div class="form-group">
<label for="project" class="form-label">Project Type</label>
<select id="project" bind:value={formData.project} class="form-select">
<option value="">Select project type</option>
{#each projectTypes as type}
<option value={type}>{type}</option>
{/each}
</select>
</div>
</div>
<div class="form-group">
<label for="budget" class="form-label">Budget Range</label>
<select id="budget" bind:value={formData.budget} class="form-select">
<option value="">Select budget range</option>
{#each budgetOptions as budget}
<option value={budget}>{budget}</option>
{/each}
</select>
</div>
<div class="form-group">
<label for="message" class="form-label">Project Details *</label>
<textarea
id="message"
bind:value={formData.message}
class="form-textarea"
required
placeholder="Tell us about your project, goals, timeline, and any specific requirements..."
rows="6"
></textarea>
</div>
<button
type="submit"
class="submit-button"
disabled={isSubmitting}
>
{#if isSubmitting}
<span class="loading-spinner"></span>
Sending...
{:else}
Send Message
{/if}
</button>
</form>
</div>
<!-- Contact Info -->
<div class="info-section">
<div class="info-card">
<h3 class="info-title">Get In Touch</h3>
<div class="contact-methods">
<div class="contact-method">
<div class="method-icon">📧</div>
<div class="method-content">
<div class="method-label">Email</div>
<div class="method-value">hello@liubaidesign.com</div>
</div>
</div>
<div class="contact-method">
<div class="method-icon">📱</div>
<div class="method-content">
<div class="method-label">Phone</div>
<div class="method-value">+1 (555) 123-4567</div>
</div>
</div>
<div class="contact-method">
<div class="method-icon">📍</div>
<div class="method-content">
<div class="method-label">Location</div>
<div class="method-value">San Francisco, CA</div>
</div>
</div>
</div>
</div>
<div class="info-card">
<h3 class="info-title">What Happens Next?</h3>
<div class="process-steps">
<div class="process-step">
<div class="step-number">1</div>
<div class="step-content">
<div class="step-title">We Review</div>
<div class="step-description">We'll review your project details and requirements</div>
</div>
</div>
<div class="process-step">
<div class="step-number">2</div>
<div class="step-content">
<div class="step-title">We Connect</div>
<div class="step-description">Schedule a call to discuss your vision and goals</div>
</div>
</div>
<div class="process-step">
<div class="step-number">3</div>
<div class="step-content">
<div class="step-title">We Propose</div>
<div class="step-description">Receive a detailed proposal and timeline</div>
</div>
</div>
</div>
</div>
<div class="info-card">
<h3 class="info-title">Follow Us</h3>
<div class="social-links">
<a href="#" class="social-link">
<div class="social-icon">📘</div>
<span>Facebook</span>
</a>
<a href="#" class="social-link">
<div class="social-icon">📷</div>
<span>Instagram</span>
</a>
<a href="#" class="social-link">
<div class="social-icon">🐦</div>
<span>Twitter</span>
</a>
<a href="#" class="social-link">
<div class="social-icon">💼</div>
<span>LinkedIn</span>
</a>
</div>
</div>
</div>
</div>
</div>
<style>
.contact-page {
max-width: 1200px;
margin: 0 auto;
padding: 0;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Hero Section */
.hero-section {
text-align: center;
margin-bottom: 64px;
}
.hero-title {
font-size: 48px;
font-weight: 700;
margin-bottom: 16px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .hero-title {
color: #f5f5f7;
}
.hero-description {
font-size: 20px;
color: #6B7280;
line-height: 1.6;
max-width: 600px;
margin: 0 auto;
transition: color 0.3s ease;
}
:global(.dark) .hero-description {
color: #9CA3AF;
}
/* Contact Content */
.contact-content {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 48px;
}
/* Form Section */
.form-section {
background: white;
padding: 48px;
border-radius: 24px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:global(.dark) .form-section {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.form-header {
margin-bottom: 32px;
}
.form-title {
font-size: 32px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .form-title {
color: #f5f5f7;
}
.form-description {
font-size: 16px;
color: #6B7280;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .form-description {
color: #9CA3AF;
}
.submit-message {
padding: 16px;
border-radius: 12px;
margin-bottom: 24px;
font-weight: 500;
}
.submit-message.success {
background: #dcfce7;
color: #166534;
border: 1px solid #bbf7d0;
}
.submit-message.error {
background: #fef2f2;
color: #dc2626;
border: 1px solid #fecaca;
}
:global(.dark) .submit-message.success {
background: rgba(34, 197, 94, 0.1);
color: #22c55e;
border-color: rgba(34, 197, 94, 0.3);
}
:global(.dark) .submit-message.error {
background: rgba(239, 68, 68, 0.1);
color: #ef4444;
border-color: rgba(239, 68, 68, 0.3);
}
/* Form Styles */
.contact-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-label {
font-size: 14px;
font-weight: 600;
color: #374151;
transition: color 0.3s ease;
}
:global(.dark) .form-label {
color: #D1D5DB;
}
.form-input,
.form-select,
.form-textarea {
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 12px;
font-size: 16px;
transition: all 0.3s ease;
background: white;
color: #1d1d1f;
}
:global(.dark) .form-input,
:global(.dark) .form-select,
:global(.dark) .form-textarea {
background: rgba(55, 65, 81, 0.5);
border-color: #4B5563;
color: #f5f5f7;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
outline: none;
border-color: #007AFF;
box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1);
}
.form-textarea {
resize: vertical;
min-height: 120px;
}
.submit-button {
background: #007AFF;
color: white;
border: none;
padding: 18px 32px;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.submit-button:hover:not(:disabled) {
background: #0056CC;
transform: translateY(-2px);
}
.submit-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.loading-spinner {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Info Section */
.info-section {
display: flex;
flex-direction: column;
gap: 24px;
}
.info-card {
background: white;
padding: 32px 24px;
border-radius: 20px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
:global(.dark) .info-card {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.info-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 20px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .info-title {
color: #f5f5f7;
}
/* Contact Methods */
.contact-methods {
display: flex;
flex-direction: column;
gap: 16px;
}
.contact-method {
display: flex;
align-items: center;
gap: 12px;
}
.method-icon {
font-size: 24px;
width: 40px;
text-align: center;
}
.method-label {
font-size: 12px;
font-weight: 600;
color: #9CA3AF;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.method-value {
font-size: 14px;
font-weight: 500;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .method-value {
color: #f5f5f7;
}
/* Process Steps */
.process-steps {
display: flex;
flex-direction: column;
gap: 16px;
}
.process-step {
display: flex;
align-items: flex-start;
gap: 12px;
}
.step-number {
width: 32px;
height: 32px;
background: #007AFF;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 600;
flex-shrink: 0;
}
.step-title {
font-size: 14px;
font-weight: 600;
color: #1d1d1f;
margin-bottom: 4px;
transition: color 0.3s ease;
}
:global(.dark) .step-title {
color: #f5f5f7;
}
.step-description {
font-size: 12px;
color: #6B7280;
line-height: 1.4;
transition: color 0.3s ease;
}
:global(.dark) .step-description {
color: #9CA3AF;
}
/* Social Links */
.social-links {
display: flex;
flex-direction: column;
gap: 12px;
}
.social-link {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 0;
color: #1d1d1f;
text-decoration: none;
transition: all 0.3s ease;
}
:global(.dark) .social-link {
color: #f5f5f7;
}
.social-link:hover {
color: #007AFF;
transform: translateX(4px);
}
.social-icon {
font-size: 20px;
width: 32px;
text-align: center;
}
/* 响应式设计 */
@media (max-width: 768px) {
.contact-content {
grid-template-columns: 1fr;
gap: 32px;
}
.form-section {
padding: 32px 24px;
}
.form-row {
grid-template-columns: 1fr;
}
.hero-title {
font-size: 32px;
}
.form-title {
font-size: 24px;
}
}
</style>

View File

@@ -0,0 +1,410 @@
<script lang="ts">
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { goto } from '$app/navigation';
// 项目数据
const projects = [
{
id: 1,
title: 'Creative Brand Identity',
category: 'Brand Design',
description: 'Complete visual identity system for modern brands',
image: '🎨',
tags: ['Logo Design', 'Brand Guidelines', 'Typography'],
status: 'Completed',
client: 'Tech Startup',
year: '2024'
},
{
id: 2,
title: 'Mobile App Interface',
category: 'UI/UX Design',
description: 'Modern mobile interface with focus on user experience',
image: '📱',
tags: ['Mobile Design', 'User Experience', 'Prototyping'],
status: 'In Progress',
client: 'E-commerce Platform',
year: '2024'
},
{
id: 3,
title: 'Web Portfolio',
category: 'Web Design',
description: 'Responsive portfolio website with modern aesthetics',
image: '💻',
tags: ['Web Development', 'Responsive Design', 'Animation'],
status: 'Completed',
client: 'Creative Agency',
year: '2023'
},
{
id: 4,
title: 'Print Design Collection',
category: 'Graphic Design',
description: 'Various print materials including brochures and posters',
image: '📄',
tags: ['Print Design', 'Layout', 'Typography'],
status: 'Completed',
client: 'Local Business',
year: '2023'
}
];
let selectedCategory = 'All';
const categories = ['All', 'Brand Design', 'UI/UX Design', 'Web Design', 'Graphic Design'];
$: filteredProjects = selectedCategory === 'All'
? projects
: projects.filter(project => project.category === selectedCategory);
function navigateToProject(projectId: number) {
goto(`/projects/${projectId}`);
}
function selectCategory(category: string) {
selectedCategory = category;
// 更新URL参数
const url = new URL(window.location.href);
if (category === 'All') {
url.searchParams.delete('category');
} else {
url.searchParams.set('category', category);
}
goto(url.pathname + url.search, { replaceState: true });
}
onMount(() => {
// 从URL参数读取分类
const urlCategory = $page.url.searchParams.get('category');
if (urlCategory && categories.includes(urlCategory)) {
selectedCategory = urlCategory;
}
console.log('Projects page mounted');
});
</script>
<svelte:head>
<title>Projects - LiuBai Design</title>
<meta name="description" content="Explore our creative projects and design portfolio" />
</svelte:head>
<div class="projects-page">
<header class="page-header">
<h1 class="page-title">Projects</h1>
<p class="page-subtitle">Explore our creative works and design solutions</p>
</header>
<!-- 分类筛选 -->
<div class="filter-section">
<div class="filter-tabs">
{#each categories as category}
<button
class="filter-tab"
class:active={selectedCategory === category}
on:click={() => selectCategory(category)}
>
{category}
</button>
{/each}
</div>
</div>
<!-- 项目网格 -->
<div class="projects-grid">
{#each filteredProjects as project (project.id)}
<div class="project-card" on:click={() => navigateToProject(project.id)} role="button" tabindex="0">
<div class="project-image">
<div class="project-icon">{project.image}</div>
<div class="project-status" class:completed={project.status === 'Completed'}>
{project.status}
</div>
</div>
<div class="project-content">
<div class="project-category">{project.category}</div>
<h3 class="project-title">{project.title}</h3>
<p class="project-description">{project.description}</p>
<div class="project-meta">
<span class="project-client">{project.client}</span>
<span class="project-year">{project.year}</span>
</div>
<div class="project-tags">
{#each project.tags as tag}
<span class="tag">{tag}</span>
{/each}
</div>
</div>
</div>
{/each}
</div>
{#if filteredProjects.length === 0}
<div class="empty-state">
<div class="empty-icon">🔍</div>
<h3>No projects found</h3>
<p>Try selecting a different category</p>
</div>
{/if}
</div>
<style>
.projects-page {
max-width: 1200px;
margin: 0 auto;
padding: 0;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.page-header {
margin-bottom: 32px;
}
.page-title {
font-size: 48px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .page-title {
color: #f5f5f7;
}
.page-subtitle {
font-size: 18px;
color: #6B7280;
margin: 0;
transition: color 0.3s ease;
}
:global(.dark) .page-subtitle {
color: #9CA3AF;
}
.filter-section {
margin-bottom: 32px;
}
.filter-tabs {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.filter-tab {
padding: 12px 24px;
border: 2px solid #e5e7eb;
background: white;
border-radius: 25px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
color: #374151;
}
:global(.dark) .filter-tab {
background: rgba(28, 28, 30, 0.8);
border-color: #374151;
color: #9CA3AF;
}
.filter-tab:hover {
border-color: #007AFF;
color: #007AFF;
}
.filter-tab.active {
background: #007AFF;
border-color: #007AFF;
color: white;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 24px;
margin-bottom: 48px;
}
.project-card {
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
cursor: pointer;
animation: slideInUp 0.6s ease-out both;
}
:global(.dark) .project-card {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
}
.project-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
:global(.dark) .project-card:hover {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.2);
}
.project-image {
height: 200px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.project-icon {
font-size: 64px;
}
.project-status {
position: absolute;
top: 16px;
right: 16px;
padding: 6px 12px;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
border-radius: 12px;
font-size: 12px;
font-weight: 600;
color: white;
text-transform: uppercase;
}
.project-status.completed {
background: rgba(34, 197, 94, 0.2);
color: #22c55e;
}
.project-content {
padding: 24px;
}
.project-category {
font-size: 12px;
font-weight: 600;
color: #007AFF;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.project-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .project-title {
color: #f5f5f7;
}
.project-description {
font-size: 14px;
color: #6B7280;
line-height: 1.5;
margin-bottom: 16px;
transition: color 0.3s ease;
}
:global(.dark) .project-description {
color: #9CA3AF;
}
.project-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
font-size: 12px;
color: #9CA3AF;
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag {
padding: 4px 8px;
background: #f3f4f6;
border-radius: 8px;
font-size: 11px;
font-weight: 500;
color: #374151;
transition: all 0.3s ease;
}
:global(.dark) .tag {
background: #374151;
color: #9CA3AF;
}
.empty-state {
text-align: center;
padding: 64px 24px;
}
.empty-icon {
font-size: 64px;
margin-bottom: 16px;
}
.empty-state h3 {
font-size: 24px;
font-weight: 600;
margin-bottom: 8px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .empty-state h3 {
color: #f5f5f7;
}
.empty-state p {
color: #6B7280;
transition: color 0.3s ease;
}
:global(.dark) .empty-state p {
color: #9CA3AF;
}
/* 响应式设计 */
@media (max-width: 768px) {
.projects-grid {
grid-template-columns: 1fr;
}
.filter-tabs {
justify-content: center;
}
.filter-tab {
padding: 10px 20px;
font-size: 14px;
}
}
</style>

View File

@@ -0,0 +1,569 @@
<script lang="ts">
import { page } from '$app/stores';
import { onMount } from 'svelte';
// 项目数据实际应用中应该从API获取
const projectsData = {
'1': {
id: 1,
title: 'Creative Brand Identity',
category: 'Brand Design',
description: 'A comprehensive brand identity system featuring logo design, color palettes, typography, and brand guidelines for a modern tech startup.',
image: '🎨',
client: 'Tech Startup',
year: '2024',
duration: '3 months',
status: 'Completed',
tags: ['Logo Design', 'Brand Guidelines', 'Typography', 'Color Theory'],
challenge: 'Create a modern, memorable brand identity that reflects innovation and trustworthiness while appealing to both B2B and B2C audiences.',
solution: 'Developed a clean, geometric logo with a vibrant color palette and comprehensive brand guidelines that ensure consistency across all touchpoints.',
results: 'Increased brand recognition by 150% and improved customer engagement across digital platforms.',
gallery: ['🎨', '🖼️', '📊', '📱', '💻', '📄']
},
'2': {
id: 2,
title: 'Mobile App Interface',
category: 'UI/UX Design',
description: 'Modern mobile interface design with focus on user experience and accessibility for an e-commerce platform.',
image: '📱',
client: 'E-commerce Platform',
year: '2024',
duration: '4 months',
status: 'In Progress',
tags: ['Mobile Design', 'User Experience', 'Prototyping', 'Accessibility'],
challenge: 'Design an intuitive shopping experience that reduces cart abandonment and improves conversion rates.',
solution: 'Created a streamlined user flow with clear navigation, optimized product discovery, and simplified checkout process.',
results: 'Currently in development phase with promising user testing results showing 40% improvement in task completion.',
gallery: ['📱', '🛒', '💳', '🔍', '⭐', '📊']
},
'3': {
id: 3,
title: 'Web Portfolio',
category: 'Web Design',
description: 'Responsive portfolio website with modern aesthetics and smooth animations for a creative agency.',
image: '💻',
client: 'Creative Agency',
year: '2023',
duration: '2 months',
status: 'Completed',
tags: ['Web Development', 'Responsive Design', 'Animation', 'Performance'],
challenge: 'Create a visually stunning portfolio that showcases work effectively while maintaining fast loading times.',
solution: 'Implemented a clean, grid-based layout with optimized images and smooth CSS animations.',
results: 'Achieved 95+ PageSpeed score and increased client inquiries by 200%.',
gallery: ['💻', '🎨', '📸', '🎬', '📱', '⚡']
},
'4': {
id: 4,
title: 'Print Design Collection',
category: 'Graphic Design',
description: 'Various print materials including brochures, posters, and business cards for local businesses.',
image: '📄',
client: 'Local Business',
year: '2023',
duration: '1 month',
status: 'Completed',
tags: ['Print Design', 'Layout', 'Typography', 'Brand Consistency'],
challenge: 'Create cohesive print materials that work across different formats and maintain brand consistency.',
solution: 'Developed a flexible design system that adapts to various print formats while maintaining visual hierarchy.',
results: 'Improved brand perception and increased foot traffic by 30%.',
gallery: ['📄', '📰', '🏷️', '📋', '📊', '🎨']
}
};
$: projectId = $page.params.id;
$: project = projectsData[projectId];
function goBack() {
window.history.back();
}
onMount(() => {
if (!project) {
// 如果项目不存在,重定向到项目列表页
window.location.href = '/projects';
}
});
</script>
<svelte:head>
<title>{project?.title || 'Project'} - LiuBai Design</title>
<meta name="description" content={project?.description || 'Project details'} />
</svelte:head>
{#if project}
<div class="project-detail">
<!-- 返回按钮 -->
<button class="back-button" on:click={goBack}>
← Back to Projects
</button>
<!-- 项目头部 -->
<header class="project-header">
<div class="project-hero">
<div class="project-hero-image">
<div class="hero-icon">{project.image}</div>
</div>
<div class="project-hero-content">
<div class="project-category">{project.category}</div>
<h1 class="project-title">{project.title}</h1>
<p class="project-description">{project.description}</p>
<div class="project-meta-grid">
<div class="meta-item">
<span class="meta-label">Client</span>
<span class="meta-value">{project.client}</span>
</div>
<div class="meta-item">
<span class="meta-label">Year</span>
<span class="meta-value">{project.year}</span>
</div>
<div class="meta-item">
<span class="meta-label">Duration</span>
<span class="meta-value">{project.duration}</span>
</div>
<div class="meta-item">
<span class="meta-label">Status</span>
<span class="meta-value status" class:completed={project.status === 'Completed'}>
{project.status}
</span>
</div>
</div>
<div class="project-tags">
{#each project.tags as tag}
<span class="tag">{tag}</span>
{/each}
</div>
</div>
</div>
</header>
<!-- 项目内容 -->
<div class="project-content">
<div class="content-section">
<h2>Challenge</h2>
<p>{project.challenge}</p>
</div>
<div class="content-section">
<h2>Solution</h2>
<p>{project.solution}</p>
</div>
<div class="content-section">
<h2>Results</h2>
<p>{project.results}</p>
</div>
<div class="content-section">
<h2>Gallery</h2>
<div class="gallery-grid">
{#each project.gallery as item, index}
<div class="gallery-item" style="animation-delay: {index * 0.1}s">
<div class="gallery-icon">{item}</div>
</div>
{/each}
</div>
</div>
</div>
<!-- 相关项目 -->
<div class="related-projects">
<h2>More Projects</h2>
<div class="related-grid">
{#each Object.values(projectsData).filter(p => p.id !== project.id).slice(0, 3) as relatedProject}
<div class="related-card" on:click={() => window.location.href = `/projects/${relatedProject.id}`}>
<div class="related-image">
<div class="related-icon">{relatedProject.image}</div>
</div>
<div class="related-content">
<div class="related-category">{relatedProject.category}</div>
<h3 class="related-title">{relatedProject.title}</h3>
</div>
</div>
{/each}
</div>
</div>
</div>
{:else}
<div class="loading">
<div class="loading-spinner">🔄</div>
<p>Loading project...</p>
</div>
{/if}
<style>
.project-detail {
max-width: 1200px;
margin: 0 auto;
padding: 0;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.back-button {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 0;
background: none;
border: none;
color: #007AFF;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
margin-bottom: 32px;
}
.back-button:hover {
color: #0056CC;
transform: translateX(-4px);
}
.project-header {
margin-bottom: 48px;
}
.project-hero {
display: grid;
grid-template-columns: 300px 1fr;
gap: 48px;
align-items: start;
}
.project-hero-image {
aspect-ratio: 1;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.project-hero-image::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 50%);
}
.hero-icon {
font-size: 120px;
z-index: 2;
}
.project-category {
font-size: 14px;
font-weight: 600;
color: #007AFF;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 12px;
}
.project-title {
font-size: 48px;
font-weight: 700;
margin-bottom: 16px;
color: #1d1d1f;
line-height: 1.2;
transition: color 0.3s ease;
}
:global(.dark) .project-title {
color: #f5f5f7;
}
.project-description {
font-size: 18px;
color: #6B7280;
line-height: 1.6;
margin-bottom: 32px;
transition: color 0.3s ease;
}
:global(.dark) .project-description {
color: #9CA3AF;
}
.project-meta-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
margin-bottom: 32px;
}
.meta-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.meta-label {
font-size: 12px;
font-weight: 600;
color: #9CA3AF;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.meta-value {
font-size: 16px;
font-weight: 600;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .meta-value {
color: #f5f5f7;
}
.meta-value.status {
color: #f59e0b;
}
.meta-value.status.completed {
color: #22c55e;
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.tag {
padding: 8px 16px;
background: #f3f4f6;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
color: #374151;
transition: all 0.3s ease;
}
:global(.dark) .tag {
background: #374151;
color: #9CA3AF;
}
.project-content {
margin-bottom: 64px;
}
.content-section {
margin-bottom: 48px;
}
.content-section h2 {
font-size: 32px;
font-weight: 700;
margin-bottom: 16px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .content-section h2 {
color: #f5f5f7;
}
.content-section p {
font-size: 16px;
color: #6B7280;
line-height: 1.7;
transition: color 0.3s ease;
}
:global(.dark) .content-section p {
color: #9CA3AF;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
}
.gallery-item {
aspect-ratio: 1;
background: white;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
animation: slideInUp 0.6s ease-out both;
}
:global(.dark) .gallery-item {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.gallery-item:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.gallery-icon {
font-size: 48px;
}
.related-projects {
margin-bottom: 48px;
}
.related-projects h2 {
font-size: 32px;
font-weight: 700;
margin-bottom: 24px;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .related-projects h2 {
color: #f5f5f7;
}
.related-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
}
.related-card {
background: white;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
:global(.dark) .related-card {
background: rgba(28, 28, 30, 0.8);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.related-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.related-image {
height: 150px;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
display: flex;
align-items: center;
justify-content: center;
}
.related-icon {
font-size: 48px;
}
.related-content {
padding: 20px;
}
.related-category {
font-size: 12px;
font-weight: 600;
color: #007AFF;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
.related-title {
font-size: 18px;
font-weight: 600;
color: #1d1d1f;
transition: color 0.3s ease;
}
:global(.dark) .related-title {
color: #f5f5f7;
}
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400px;
text-align: center;
}
.loading-spinner {
font-size: 48px;
animation: spin 1s linear infinite;
margin-bottom: 16px;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.project-hero {
grid-template-columns: 1fr;
gap: 24px;
text-align: center;
}
.project-hero-image {
max-width: 200px;
margin: 0 auto;
}
.hero-icon {
font-size: 80px;
}
.project-title {
font-size: 32px;
}
.project-meta-grid {
grid-template-columns: 1fr;
}
.gallery-grid {
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.related-grid {
grid-template-columns: 1fr;
}
}
</style>