feat(admin): 复刻登录页 — boot 过渡动画 + 角色表单
- 搬入 framer-motion,复刻参考项目登录体验 - AICoreEffect:点芯片启动神经链接进度,S-core 数据流点亮,100% 解锁 - AIBanner:青色数据流 + 紫色神经网络背景 - LoginCharacters:四只卡通角色,眼睛跟随鼠标,输密码时遮眼/偷看 - 表单去掉验证码,接现有 login api;账号密码 + 密码显示切换 - 品牌名换 sundynix admin,登录按钮用青蓝渐变 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { motion } from 'framer-motion'
|
||||
|
||||
/** 登录背景:左青色数据流 + 右紫色神经网络 + 中央连线(呼应 logo)。搬自参考项目。 */
|
||||
export default function AIBanner() {
|
||||
const dataParticles = Array.from({ length: 100 }).map((_, i) => ({
|
||||
id: `dp-${i}`,
|
||||
y: 10 + Math.random() * 80,
|
||||
size: Math.random() > 0.8 ? 6 : Math.random() * 3 + 1.5,
|
||||
isSquare: Math.random() > 0.6,
|
||||
duration: Math.random() * 2 + 1.5,
|
||||
delay: Math.random() * 3,
|
||||
opacity: Math.random() * 0.7 + 0.3,
|
||||
}))
|
||||
|
||||
const neuralNodes = [
|
||||
{ x: 10, y: 50 }, { x: 30, y: 25 }, { x: 35, y: 75 },
|
||||
{ x: 55, y: 45 }, { x: 75, y: 15 }, { x: 70, y: 85 },
|
||||
{ x: 90, y: 55 }, { x: 80, y: 40 }, { x: 50, y: 90 },
|
||||
{ x: 20, y: 95 }, { x: 95, y: 20 }, { x: 45, y: 10 },
|
||||
{ x: 85, y: 75 }, { x: 15, y: 20 },
|
||||
]
|
||||
const neuralLines = [
|
||||
[0, 1], [0, 2], [1, 3], [2, 3], [1, 4], [3, 4],
|
||||
[3, 6], [2, 5], [3, 5], [5, 6], [4, 7], [6, 7],
|
||||
[2, 8], [5, 8], [0, 9], [2, 9], [4, 10], [7, 10],
|
||||
[1, 11], [4, 11], [6, 12], [5, 12], [0, 13], [1, 13],
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 h-full w-full overflow-hidden bg-[#080d17]">
|
||||
<div className="pointer-events-none absolute left-[15%] top-1/2 h-[800px] w-[800px] -translate-y-1/2 rounded-full bg-cyan-600/15 blur-[150px] mix-blend-screen" />
|
||||
<div className="pointer-events-none absolute right-[15%] top-1/2 h-[800px] w-[800px] -translate-y-1/2 rounded-full bg-fuchsia-600/15 blur-[150px] mix-blend-screen" />
|
||||
|
||||
<div
|
||||
className="pointer-events-none absolute inset-y-0 left-0 w-[65%]"
|
||||
style={{
|
||||
maskImage:
|
||||
'linear-gradient(to right, black 0%, black 60%, transparent 100%)',
|
||||
WebkitMaskImage:
|
||||
'linear-gradient(to right, black 0%, black 60%, transparent 100%)',
|
||||
}}
|
||||
>
|
||||
{dataParticles.map((p) => (
|
||||
<motion.div
|
||||
key={p.id}
|
||||
className={`absolute bg-cyan-400 ${p.isSquare ? 'rounded-sm' : 'rounded-full'}`}
|
||||
style={{
|
||||
width: p.size,
|
||||
height: p.size,
|
||||
top: `${p.y}%`,
|
||||
boxShadow: p.isSquare
|
||||
? '0 0 12px 3px rgba(6,182,212,0.9)'
|
||||
: '0 0 8px 2px rgba(6,182,212,0.6)',
|
||||
}}
|
||||
initial={{ x: '-10vw', opacity: 0 }}
|
||||
animate={{ x: '75vw', opacity: [0, p.opacity, p.opacity, 0] }}
|
||||
transition={{
|
||||
duration: p.duration * 3.5,
|
||||
repeat: Infinity,
|
||||
delay: p.delay,
|
||||
ease: 'linear',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
<div className="absolute left-0 top-1/2 flex h-[80%] w-full -translate-y-1/2 flex-col justify-between opacity-70">
|
||||
{Array.from({ length: 20 }).map((_, i) => (
|
||||
<motion.div
|
||||
key={`streak-${i}`}
|
||||
className="h-[2px] bg-gradient-to-r from-transparent via-cyan-400 to-transparent"
|
||||
style={{
|
||||
width: `${Math.random() * 40 + 20}%`,
|
||||
filter: 'drop-shadow(0 0 5px rgba(6,182,212,0.8))',
|
||||
}}
|
||||
initial={{ x: '-50%', opacity: 0 }}
|
||||
animate={{ x: '150%', opacity: [0, 1, 1, 0] }}
|
||||
transition={{
|
||||
duration: 7 + Math.random() * 6,
|
||||
repeat: Infinity,
|
||||
delay: Math.random() * 4,
|
||||
ease: 'linear',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 flex w-[45%] items-center justify-end pr-[5%]">
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
className="h-[80%] w-full max-w-[500px] overflow-visible"
|
||||
style={{ filter: 'drop-shadow(0 0 10px rgba(217,70,239,0.6))' }}
|
||||
>
|
||||
{neuralLines.map((line, i) => {
|
||||
const n1 = neuralNodes[line[0]]
|
||||
const n2 = neuralNodes[line[1]]
|
||||
return (
|
||||
<motion.line
|
||||
key={`line-${i}`}
|
||||
x1={n1.x}
|
||||
y1={n1.y}
|
||||
x2={n2.x}
|
||||
y2={n2.y}
|
||||
stroke="rgba(217,70,239,0.5)"
|
||||
strokeWidth="0.5"
|
||||
initial={{ pathLength: 0, opacity: 0 }}
|
||||
animate={{ pathLength: [0, 1, 1, 0], opacity: [0, 1, 1, 0] }}
|
||||
transition={{
|
||||
duration: 10,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
delay: i * 0.3,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{neuralNodes.map((node, i) => (
|
||||
<motion.circle
|
||||
key={`node-${i}`}
|
||||
cx={node.x}
|
||||
cy={node.y}
|
||||
r="1.5"
|
||||
fill="#d946ef"
|
||||
animate={{ r: [1.5, 2.5, 1.5], opacity: [0.4, 0.9, 0.4] }}
|
||||
transition={{ duration: 4.5, repeat: Infinity, delay: i * 0.4 }}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="pointer-events-none absolute left-0 top-1/2 flex h-[600px] w-full -translate-y-1/2 items-center justify-center opacity-60 mix-blend-screen">
|
||||
<svg
|
||||
viewBox="0 0 200 100"
|
||||
preserveAspectRatio="none"
|
||||
className="h-full w-full overflow-visible"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="elegant-grad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stopColor="#06b6d4" stopOpacity="0" />
|
||||
<stop offset="25%" stopColor="#06b6d4" stopOpacity="0.8" />
|
||||
<stop offset="50%" stopColor="#8b5cf6" stopOpacity="0.5" />
|
||||
<stop offset="75%" stopColor="#d946ef" stopOpacity="0.8" />
|
||||
<stop offset="100%" stopColor="#d946ef" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
{Array.from({ length: 4 }).map((_, i) => (
|
||||
<motion.path
|
||||
key={`line-${i}`}
|
||||
d={`M -20 ${30 + i * 10} C 60 ${10 + i * 5}, 140 ${90 - i * 5}, 220 ${70 - i * 10}`}
|
||||
fill="none"
|
||||
stroke="url(#elegant-grad)"
|
||||
strokeWidth={0.2 + i * 0.05}
|
||||
animate={{
|
||||
strokeDasharray: ['0, 400', '400, 0'],
|
||||
opacity: [0.3, 0.7, 0.3],
|
||||
}}
|
||||
transition={{
|
||||
duration: 16 + i * 4,
|
||||
repeat: Infinity,
|
||||
ease: 'easeInOut',
|
||||
delay: i * 2,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user