前端优化

This commit is contained in:
ryan
2026-06-09 11:34:48 +08:00
parent 31f0fb4ceb
commit f428839602
+34 -135
View File
@@ -1,6 +1,5 @@
import * as React from "react"
import {motion} from "motion/react"
import {Badge} from "@/components/ui/badge"
import {cn} from "@/lib/utils"
import {FileTextIcon} from "lucide-react"
@@ -17,97 +16,32 @@ import {FileTextIcon} from "lucide-react"
* @returns {React.ReactNode} 加载页面组件
*/
function LoadingCard() {
export function AppleSpinner({ className = "size-8 text-muted-foreground" }: { className?: string }) {
const spokes = Array.from({ length: 12 })
return (
<div className="relative w-[240px] aspect-[1.586] mx-auto perspective-1200 group">
<div className={cn("absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[120%] h-[120%] blur-[80px] pointer-events-none transition-colors duration-1000 bg-primary/10")} />
<motion.div
initial={{ rotateY: 0, rotateX: 0, y: 0 }}
animate={{
rotateY: [-10, 10, -10],
rotateX: [4, -4, 4],
y: [-6, 6, -6],
}}
transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut",
}}
style={{ transformStyle: "preserve-3d" }}
className="relative w-full h-full"
>
<div
className="absolute -bottom-10 left-1/2 -translate-x-1/2 w-[85%] h-4 bg-black/40 blur-xl rounded-[100%] transition-all duration-500"
style={{ transform: 'translateZ(-20px)' }}
/>
<div className={cn("absolute inset-0 rounded-2xl bg-[#1a1a1a] shadow-2xl border border-white/10 overflow-hidden backdrop-blur-xl")}>
<div className="absolute inset-0 bg-gradient-to-br from-white/5 to-transparent pointer-events-none" />
<div className="absolute inset-0 opacity-[0.05] bg-[url('https://grainy-gradients.vercel.app/noise.svg')] mix-blend-overlay" />
<div className="relative h-full p-6 flex flex-col justify-between z-10">
<div className="flex justify-between items-start">
<div className="relative w-11 h-8 rounded-md bg-[#d4d4d8] shadow-inner overflow-hidden flex items-center justify-center">
<div className="absolute inset-0 bg-[linear-gradient(135deg,transparent_0%,rgba(0,0,0,0.1)_50%,transparent_100%)]" />
<div className="w-full h-[1px] bg-black/10 absolute top-1/2" />
<div className="h-full w-[1px] bg-black/10 absolute left-1/3" />
<div className="h-full w-[1px] bg-black/10 absolute right-1/3" />
</div>
<div className="flex flex-col items-end gap-[2px]">
<div className="w-1.5 h-1.5 rounded-full bg-white/20" />
<div className="w-1.5 h-1.5 rounded-full bg-white/40" />
<div className="w-1.5 h-1.5 rounded-full bg-white/80" />
</div>
</div>
<div className="space-y-3 mt-4">
<div className="flex gap-2">
<div className="h-1 w-12 rounded-full bg-white/10" />
<div className="h-1 w-8 rounded-full bg-white/10" />
</div>
</div>
<div className="flex justify-between items-end">
<div className="space-y-1.5">
<div className="h-1.5 w-20 rounded-full bg-white/20" />
<div className="h-1.5 w-12 rounded-full bg-white/20" />
</div>
<div className="font-serif italic text-xl font-bold tracking-widest text-white drop-shadow-md">
Wavelet
</div>
</div>
</div>
<motion.div
className="absolute -inset-[200%] bg-gradient-to-r from-transparent via-white/5 to-transparent -skew-x-12"
animate={{
x: ['-100%', '200%'],
<div className={cn("relative flex items-center justify-center", className)}>
<style dangerouslySetInnerHTML={{ __html: `
@keyframes apple-spinner-fade {
0% { opacity: 1; }
100% { opacity: 0.15; }
}
.apple-spinner-spoke {
animation: apple-spinner-fade 1.2s linear infinite;
}
`}} />
<div className="relative size-full">
{spokes.map((_, i) => (
<div
key={i}
className="apple-spinner-spoke absolute top-0 left-[46%] w-[8%] h-[28%] bg-current rounded-full"
style={{
transform: `rotate(${i * 30}deg)`,
transformOrigin: "50% 178.5%",
animationDelay: `${(i - 12) * 0.1}s`,
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "easeInOut",
repeatDelay: 2
}}
style={{ mixBlendMode: 'overlay' }}
/>
</div>
<div
className={cn("absolute inset-0 rounded-2xl translate-z-[-2px] border border-white/5 bg-[#0f0f0f]")}
style={{ transform: 'translateZ(-2px)' }}
/>
<div
className={cn("absolute inset-0 rounded-2xl translate-z-[-4px] border border-white/5 bg-[#0f0f0f]")}
style={{ transform: 'translateZ(-4px)' }}
/>
<div
className="absolute inset-0 rounded-2xl bg-black/80 translate-z-[-10px] blur-xl"
style={{ transform: 'translateZ(-15px)' }}
/>
</motion.div>
))}
</div>
</div>
)
}
@@ -117,54 +51,19 @@ function LoadingCard() {
*
* 用于统一显示加载状态
*/
export function LoadingPage({ text = "系统", badgeText = "系统" }: { text?: string, badgeText?: string }) {
export function LoadingPage(props: { text?: string; badgeText?: string }) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ = props
return (
<div className="absolute inset-0 z-50 overflow-hidden font-sans bg-background/80 backdrop-blur-md text-foreground flex items-center justify-center">
<div className="w-full max-w-md mx-auto text-center px-4 flex flex-col items-center gap-8">
<LoadingCard />
<div className="space-y-3 w-full flex flex-col items-center">
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="relative flex items-center justify-center gap-2"
>
<span className="text-3xl font-bold tracking-tight text-foreground">Wavelet</span>
{badgeText && (
<div className="absolute left-full top-1/3 -translate-y-1/2 ml-2">
<Badge variant="outline" className="text-[10px] px-1.5 py-0 h-5 border-foreground/20 text-muted-foreground whitespace-nowrap">
{badgeText}
</Badge>
</div>
)}
</motion.div>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.4 }}
className="flex flex-col items-center justify-center gap-4 text-sm text-muted-foreground w-full max-w-[200px]"
>
<div className="relative h-1 w-full overflow-hidden rounded-full bg-muted">
<motion.div
className="absolute inset-y-0 left-0 h-full w-1/3 rounded-full bg-primary"
animate={{
x: ["-100%", "300%"],
}}
transition={{
duration: 1.2,
repeat: Infinity,
ease: "easeInOut",
}}
/>
</div>
<span className="font-mono text-xs tracking-wider opacity-60">{text.toUpperCase()}</span>
</motion.div>
</div>
</div>
<motion.div
initial={{ opacity: 0, scale: 0.96 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.25, ease: "easeOut" }}
className="flex items-center justify-center"
>
<AppleSpinner className="size-9 text-muted-foreground/80" />
</motion.div>
</div>
)
}