mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
前端优化
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user