Merge pull request #6 from handsomezhuzhu/v0/kdaugh14-4907-7424b84c

Redesign navigation with centered layout and cyberpunk animations
This commit is contained in:
vercel[bot]
2026-03-07 15:05:52 +00:00
committed by GitHub
5 changed files with 836 additions and 781 deletions

View File

@@ -1,5 +1,4 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@@ -124,3 +123,79 @@
@apply bg-background text-foreground;
}
}
/* Cyber glow animation - 文字白色,光晕颜色流动 */
@keyframes glow-flow {
0% { text-shadow: 0 0 12px oklch(0.75 0.18 180 / 0.9), 0 0 30px oklch(0.75 0.18 180 / 0.5), 0 0 60px oklch(0.75 0.18 180 / 0.2); }
25% { text-shadow: 0 0 12px oklch(0.70 0.20 220 / 0.9), 0 0 30px oklch(0.70 0.20 220 / 0.5), 0 0 60px oklch(0.70 0.20 220 / 0.2); }
50% { text-shadow: 0 0 12px oklch(0.65 0.22 280 / 0.9), 0 0 30px oklch(0.65 0.22 280 / 0.5), 0 0 60px oklch(0.65 0.22 280 / 0.2); }
75% { text-shadow: 0 0 12px oklch(0.72 0.20 240 / 0.9), 0 0 30px oklch(0.72 0.20 240 / 0.5), 0 0 60px oklch(0.72 0.20 240 / 0.2); }
100% { text-shadow: 0 0 12px oklch(0.75 0.18 180 / 0.9), 0 0 30px oklch(0.75 0.18 180 / 0.5), 0 0 60px oklch(0.75 0.18 180 / 0.2); }
}
.cyber-title {
color: oklch(0.98 0 0);
animation: glow-flow 6s ease infinite;
}
/* Animation utilities */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes zoom-in-95 {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes zoom-out-95 {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.95); }
}
@keyframes slide-in-from-top-2 {
from { transform: translateY(-0.5rem); }
to { transform: translateY(0); }
}
@keyframes slide-in-from-bottom-2 {
from { transform: translateY(0.5rem); }
to { transform: translateY(0); }
}
@keyframes slide-in-from-left-2 {
from { transform: translateX(-0.5rem); }
to { transform: translateX(0); }
}
@keyframes slide-in-from-right-2 {
from { transform: translateX(0.5rem); }
to { transform: translateX(0); }
}
.animate-in {
animation-duration: 150ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animation-fill-mode: both;
}
.animate-out {
animation-duration: 150ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animation-fill-mode: both;
}
.fade-in-0 { animation-name: fade-in; }
.fade-out-0 { animation-name: fade-out; }
.zoom-in-95 { animation-name: zoom-in-95; }
.zoom-out-95 { animation-name: zoom-out-95; }
.slide-in-from-top-2 { animation-name: slide-in-from-top-2; }
.slide-in-from-bottom-2 { animation-name: slide-in-from-bottom-2; }
.slide-in-from-left-2 { animation-name: slide-in-from-left-2; }
.slide-in-from-right-2 { animation-name: slide-in-from-right-2; }

View File

@@ -2,8 +2,8 @@
import type React from "react"
import { useState } from "react"
import { ExternalLink, Globe, Server, Mail, Zap, Shield, Code, FileText, Search } from "lucide-react"
import { useState, useEffect } from "react"
import { ExternalLink, Server, Mail, Zap, Shield, Code, FileText, Search } from "lucide-react"
interface Site {
domain: string
@@ -373,6 +373,37 @@ function getServerBadgeStyle(server: string) {
export function SiteNavigation() {
const [searchQuery, setSearchQuery] = useState("")
const [displayText, setDisplayText] = useState("")
const [isAnimationDone, setIsAnimationDone] = useState(false)
const fullText = "SIMON站点导航"
useEffect(() => {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*_-+=<>?/\\|~"
let frame = 0
const totalFrames = fullText.length * 5
const interval = setInterval(() => {
let output = ""
for (let i = 0; i < fullText.length; i++) {
if (i < Math.floor(frame / 5)) {
output += fullText[i]
} else {
output += chars[Math.floor(Math.random() * chars.length)]
}
}
setDisplayText(output)
frame++
if (frame > totalFrames) {
clearInterval(interval)
setDisplayText(fullText)
setIsAnimationDone(true)
}
}, 40)
return () => {
clearInterval(interval)
}
}, [])
const filteredCategories = categories
.map((category) => ({
@@ -393,19 +424,22 @@ export function SiteNavigation() {
<div className="mx-auto max-w-6xl">
{/* Header - 居中设计 */}
<header className="mb-16 text-center">
<div className="inline-flex items-center justify-center gap-3 mb-6">
<div className="p-3 bg-primary/10 rounded-2xl">
<Globe className="size-8 text-primary" />
</div>
</div>
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4">
<h1
className={`text-4xl md:text-6xl font-bold tracking-widest mb-4 font-mono transition-all duration-500 ${
isAnimationDone ? "cyber-title" : "text-foreground"
}`}
>
{displayText || "SIMON站点导航"}
</h1>
<p className="text-muted-foreground text-lg md:text-xl">
<span className="font-mono text-primary/80">zhuzihan.com</span>
<div className="flex items-center justify-center gap-2 mb-2">
<span className="block h-px w-16 bg-primary/30" />
<p className="text-muted-foreground text-sm md:text-base tracking-widest uppercase font-mono">
<span className="text-primary/80">zhuzihan.com</span>
<span className="mx-2 text-border">|</span>
</p>
<span className="block h-px w-16 bg-primary/30" />
</div>
</header>
{/* Search - 居中设计 */}

View File

@@ -56,7 +56,7 @@
"recharts": "2.15.4",
"sonner": "^1.7.4",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"tailwindcss-animate": "1.0.7",
"vaul": "^1.1.2",
"zod": "3.25.76"
},
@@ -67,7 +67,6 @@
"@types/react-dom": "^19",
"postcss": "^8.5",
"tailwindcss": "^4.1.9",
"tw-animate-css": "1.3.3",
"typescript": "^5"
}
}

1474
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
@import 'tailwindcss';
@import 'tw-animate-css';
@custom-variant dark (&:is(.dark *));