V0.1
This commit is contained in:
parent
2daa593025
commit
9df3e44fd0
@ -1,77 +1,95 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { TerminalSquare, Filter, RefreshCw } from 'lucide-react';
|
||||
import { TerminalSquare, Filter, RefreshCw, Cpu, Brain, Zap } from 'lucide-react';
|
||||
|
||||
const mockLogs = [
|
||||
{ id: 1, time: '10:41:30', agent: 'Analyst', type: 'REJECT', cost: '$0.0012', prompt: 'Evaluate lot: "RTX 4090 Box Only" against criteria...', response: '{"verdict": "REJECT", "reason": "Listing explicitly states \'Box Only\', violating target criteria."}' },
|
||||
{ id: 2, time: '10:40:12', agent: 'Analyst', type: 'APPROVE', cost: '$0.0025', prompt: 'Evaluate lot: "ThinkPad T14 Gen 3" against criteria...', response: '{"verdict": "APPROVE", "reason": "Matches specs, good condition, price $450 is significantly below $800 avg."}' },
|
||||
{ id: 3, time: '10:39:45', agent: 'Strategist', type: 'OPTIMIZE', cost: '$0.0050', prompt: 'Analyze last 24h win rates on ShopGoodwill...', response: '{"action": "UPDATE_SCHEDULE", "target": "ShopGoodwill", "new_cron": "0 * * * *"}' },
|
||||
{ id: 4, time: '10:35:10', agent: 'Scout', type: 'INFO', cost: '$0.0005', prompt: 'Parse unstructured layout changes on eBay UK...', response: '{"action": "SELECTORS_UPDATED", "confidence": 0.98 }' },
|
||||
];
|
||||
|
||||
export default function AILogPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8 h-[calc(100vh-64px)] flex flex-col">
|
||||
<div className="flex justify-between items-end mb-6 shrink-0">
|
||||
<div className="container mx-auto px-6 py-12 h-[calc(100vh-80px)] flex flex-col">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 shrink-0 gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">NEURAL_<span className="text-primary">TELEMETRY</span></h1>
|
||||
<p className="text-muted-foreground">Raw input/output logs from all connected LLMs.</p>
|
||||
<h1 className="text-4xl font-extrabold tracking-tight mb-2 flex items-center gap-3">
|
||||
Neural Telemetry <span className="text-primary"><Brain className="w-8 h-8" /></span>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-lg">Raw input/output logs from all connected LLM agents.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="flex items-center gap-2 px-3 py-1.5 bg-card border border-border rounded font-mono text-xs hover:border-primary transition-colors">
|
||||
<Filter className="w-3 h-3" /> FILTER
|
||||
<div className="flex gap-3">
|
||||
<button className="flex items-center gap-2 px-5 py-2.5 bg-secondary hover:bg-secondary/80 border-2 border-border/50 rounded-full font-bold transition-all hover:scale-105 shadow-sm">
|
||||
<Filter className="w-4 h-4" /> Filter
|
||||
</button>
|
||||
<button className="flex items-center gap-2 px-3 py-1.5 bg-card border border-border rounded font-mono text-xs hover:text-primary transition-colors">
|
||||
<RefreshCw className="w-3 h-3" /> REFRESH
|
||||
<button className="flex items-center gap-2 px-5 py-2.5 bg-primary hover:bg-primary/90 text-primary-foreground rounded-full font-bold transition-all hover:scale-105 shadow-lg hover:shadow-primary/30">
|
||||
<RefreshCw className="w-4 h-4" /> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 bg-card border border-border rounded-lg overflow-hidden flex flex-col">
|
||||
<div className="grid grid-cols-12 gap-4 p-3 border-b border-border bg-background/50 font-mono text-xs text-muted-foreground shrink-0">
|
||||
<div className="col-span-2">TIMESTAMP / AGENT</div>
|
||||
<div className="col-span-1">TYPE</div>
|
||||
<div className="col-span-4">PROMPT_PREVIEW</div>
|
||||
<div className="col-span-4">RESPONSE_PREVIEW</div>
|
||||
<div className="col-span-1 text-right">COST</div>
|
||||
<div className="flex-1 bg-card border-2 border-border/50 rounded-3xl overflow-hidden flex flex-col shadow-sm">
|
||||
<div className="grid grid-cols-12 gap-4 p-5 border-b-2 border-border/50 bg-secondary/30 text-sm font-bold text-muted-foreground uppercase tracking-wider shrink-0">
|
||||
<div className="col-span-2 md:col-span-2">Time / Agent</div>
|
||||
<div className="col-span-2 md:col-span-1">Action</div>
|
||||
<div className="col-span-4 md:col-span-4">Prompt Context</div>
|
||||
<div className="col-span-4 md:col-span-4">JSON Response</div>
|
||||
<div className="hidden md:flex col-span-1 justify-end">Est. Cost</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto p-2 space-y-2">
|
||||
<div className="flex-1 overflow-auto p-4 space-y-3 custom-scrollbar">
|
||||
{mockLogs.map((log, i) => (
|
||||
<motion.div
|
||||
key={log.id}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="grid grid-cols-12 gap-4 p-3 bg-background border border-border/50 rounded font-mono text-sm hover:border-primary/50 transition-colors cursor-pointer"
|
||||
transition={{ delay: i * 0.1, type: "spring" }}
|
||||
className="grid grid-cols-12 gap-4 p-4 bg-secondary/20 hover:bg-secondary/50 border border-border/30 rounded-2xl transition-colors cursor-pointer group"
|
||||
>
|
||||
<div className="col-span-2 flex flex-col justify-center">
|
||||
<span className="text-primary">{log.time}</span>
|
||||
<span className="text-xs text-muted-foreground">{log.agent}</span>
|
||||
<div className="col-span-2 md:col-span-2 flex flex-col justify-center">
|
||||
<span className="font-bold text-foreground">{log.time}</span>
|
||||
<span className="text-xs font-semibold text-muted-foreground flex items-center gap-1 mt-1">
|
||||
{log.agent === 'Analyst' ? <Brain className="w-3 h-3 text-purple-500" /> : log.agent === 'Strategist' ? <Zap className="w-3 h-3 text-amber-500" /> : <Cpu className="w-3 h-3 text-blue-500" />}
|
||||
{log.agent}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex items-center">
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${log.type === 'APPROVE' ? 'bg-primary/20 text-primary' : log.type === 'REJECT' ? 'bg-destructive/20 text-destructive' : 'bg-accent/20 text-accent'}`}>
|
||||
<div className="col-span-2 md:col-span-1 flex items-center">
|
||||
<span className={`px-3 py-1 rounded-full text-xs font-bold ${
|
||||
log.type === 'APPROVE' ? 'bg-green-500/10 text-green-600 dark:text-green-400' :
|
||||
log.type === 'REJECT' ? 'bg-red-500/10 text-red-600 dark:text-red-400' :
|
||||
log.type === 'OPTIMIZE' ? 'bg-amber-500/10 text-amber-600 dark:text-amber-400' :
|
||||
'bg-blue-500/10 text-blue-600 dark:text-blue-400'
|
||||
}`}>
|
||||
{log.type}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-4 text-muted-foreground truncate flex items-center">
|
||||
<div className="col-span-4 md:col-span-4 text-muted-foreground text-sm flex items-center truncate font-medium pr-4">
|
||||
{log.prompt}
|
||||
</div>
|
||||
<div className="col-span-4 truncate flex items-center">
|
||||
<div className="col-span-4 md:col-span-4 text-sm flex items-center truncate font-mono text-foreground/80 bg-background/50 px-3 py-1.5 rounded-lg border border-border/30">
|
||||
{log.response}
|
||||
</div>
|
||||
<div className="col-span-1 text-right flex items-center justify-end text-xs text-muted-foreground">
|
||||
<div className="hidden md:flex col-span-1 items-center justify-end text-sm font-bold text-muted-foreground group-hover:text-primary transition-colors">
|
||||
{log.cost}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
<div className="text-center p-8 text-muted-foreground font-mono text-sm">
|
||||
<TerminalSquare className="w-8 h-8 mx-auto mb-2 opacity-50" />
|
||||
End of stream. Waiting for new inferences...
|
||||
</div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.5 }}
|
||||
className="text-center p-12 text-muted-foreground flex flex-col items-center justify-center gap-4"
|
||||
>
|
||||
<div className="p-4 bg-secondary/30 rounded-full animate-pulse">
|
||||
<TerminalSquare className="w-8 h-8 text-muted-foreground/50" />
|
||||
</div>
|
||||
<span className="font-medium text-lg">End of stream. Awaiting new neural inferences...</span>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,83 +1,169 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { Activity, Zap, ShieldAlert, Cpu } from 'lucide-react';
|
||||
import { Activity, Zap, ShieldAlert, Cpu, TrendingUp, CheckCircle2, Clock } from 'lucide-react';
|
||||
|
||||
const stats = [
|
||||
{ title: 'Lots Scanned', value: '142,893', icon: Activity, color: 'text-blue-500', bg: 'bg-blue-500/10', border: 'border-blue-500/20' },
|
||||
{ title: 'Active Targets', value: '84', icon: Zap, color: 'text-amber-500', bg: 'bg-amber-500/10', border: 'border-amber-500/20' },
|
||||
{ title: 'Alerts Fired', value: '1,204', icon: TrendingUp, color: 'text-purple-500', bg: 'bg-purple-500/10', border: 'border-purple-500/20' },
|
||||
{ title: 'AI Decisions', value: '89,430', icon: Cpu, color: 'text-green-500', bg: 'bg-green-500/10', border: 'border-green-500/20' },
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 20, scale: 0.9 },
|
||||
show: { opacity: 1, y: 0, scale: 1, transition: { type: "spring" as const, stiffness: 300, damping: 24 } }
|
||||
};
|
||||
|
||||
export default function DashboardPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">SYSTEM_<span className="text-primary">OVERVIEW</span></h1>
|
||||
<p className="text-muted-foreground">Real-time status of all autonomous agents.</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 bg-card border border-border rounded font-mono text-sm">
|
||||
Status: <span className="text-primary animate-pulse">RUNNING</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container mx-auto px-6 py-12 relative">
|
||||
<div className="absolute top-0 right-0 w-[50%] h-[50%] bg-primary/5 rounded-full blur-[150px] pointer-events-none -z-10" />
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||
{[
|
||||
{ title: 'Lots Scanned', value: '142,893', icon: Activity, color: 'text-primary' },
|
||||
{ title: 'Active Targets', value: '84', icon: Zap, color: 'text-accent' },
|
||||
{ title: 'Alerts Fired', value: '1,204', icon: ShieldAlert, color: 'text-destructive' },
|
||||
{ title: 'AI Decisions', value: '89,430', icon: Cpu, color: 'text-primary' },
|
||||
].map((stat, i) => (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="flex flex-col md:flex-row justify-between items-start md:items-end mb-12 gap-4"
|
||||
>
|
||||
<div>
|
||||
<h1 className="text-5xl font-black tracking-tight mb-3 flex items-center gap-4 drop-shadow-sm">
|
||||
System Overview <motion.span animate={{ y: [0, -10, 0] }} transition={{ duration: 2, repeat: Infinity }} className="text-4xl">🚀</motion.span>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-xl font-medium">Real-time status of all your autonomous AI agents.</p>
|
||||
</div>
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="flex items-center gap-3 px-6 py-3 bg-green-500/10 text-green-500 border border-green-500/20 rounded-full font-black shadow-inner shadow-green-500/10 backdrop-blur-md"
|
||||
>
|
||||
<span className="relative flex h-3.5 w-3.5">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-3.5 w-3.5 bg-green-500 shadow-[0_0_10px_rgba(34,197,94,1)]"></span>
|
||||
</span>
|
||||
All Systems Go
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12"
|
||||
>
|
||||
{stats.map((stat, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="p-6 bg-card border border-border rounded-lg"
|
||||
variants={itemVariants}
|
||||
whileHover={{ y: -5, scale: 1.02 }}
|
||||
className={`p-6 bg-card/80 backdrop-blur-xl border border-white/5 hover:${stat.border} rounded-[2rem] shadow-lg hover:shadow-xl transition-all relative overflow-hidden group`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div className="text-muted-foreground font-mono text-sm">{stat.title}</div>
|
||||
<stat.icon className={`w-5 h-5 ${stat.color}`} />
|
||||
<div className={`absolute -right-10 -top-10 w-32 h-32 ${stat.bg} rounded-full blur-[40px] group-hover:scale-150 transition-transform duration-700`} />
|
||||
<div className="flex justify-between items-start mb-6 relative z-10">
|
||||
<div className="text-muted-foreground font-bold text-lg">{stat.title}</div>
|
||||
<div className={`p-3 rounded-2xl ${stat.bg} shadow-inner`}>
|
||||
<stat.icon className={`w-6 h-6 ${stat.color}`} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={`text-3xl font-bold font-mono ${stat.color}`}>{stat.value}</div>
|
||||
<div className="text-5xl font-black text-foreground drop-shadow-md relative z-10">{stat.value}</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
<div className="col-span-2">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.4 }}
|
||||
className="p-6 bg-card border border-border rounded-lg h-96 flex flex-col"
|
||||
initial={{ opacity: 0, x: -30 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.3, type: "spring" as const }}
|
||||
className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] h-[500px] flex flex-col shadow-xl relative overflow-hidden"
|
||||
>
|
||||
<h2 className="text-xl font-bold font-mono mb-4 border-b border-border pb-2">LIVE_ACTIVITY_LOG</h2>
|
||||
<div className="flex-1 overflow-auto font-mono text-sm space-y-3">
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:42:01]</span> <span>Scout Agent detected new items on eBay_UK...</span></div>
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:41:55]</span> <span>Analyst Agent processing 14 lots for "RTX 4090"...</span></div>
|
||||
<div className="flex gap-4 text-accent"><span className="text-primary">[10:41:30]</span> <span>MATCH FOUND: "RTX 4090 Box Only" - Rejected by AI (Reason: Scam)</span></div>
|
||||
<div className="flex gap-4 text-primary"><span className="text-primary">[10:40:12]</span> <span>HIGH VALUE MATCH: "ThinkPad T14 Gen 3" - $450 (Est: $800). Alert Sent.</span></div>
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:39:45]</span> <span>Strategist Agent optimizing scrape timings for ShopGoodwill...</span></div>
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 to-transparent pointer-events-none" />
|
||||
<div className="flex items-center gap-4 mb-8 pb-6 border-b border-border/50 relative z-10">
|
||||
<Clock className="w-8 h-8 text-primary" />
|
||||
<h2 className="text-3xl font-black tracking-tight">Live Activity Log</h2>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto space-y-4 pr-4 custom-scrollbar relative z-10">
|
||||
{[
|
||||
{ time: '10:42:01 AM', msg: 'Scout Agent detected new items on eBay_UK...', type: 'normal' },
|
||||
{ time: '10:41:55 AM', msg: 'Analyst Agent processing 14 lots for "RTX 4090"...', type: 'normal' },
|
||||
{ time: '10:41:30 AM', msg: 'MATCH FOUND: "RTX 4090 Box Only" - Rejected by AI (Reason: Scam)', type: 'warning' },
|
||||
{ time: '10:40:12 AM', msg: 'HIGH VALUE MATCH: "ThinkPad T14 Gen 3" - $450 (Est: $800). Alert Sent.', type: 'success' },
|
||||
{ time: '10:39:45 AM', msg: 'Strategist Agent optimizing scrape timings for ShopGoodwill...', type: 'normal' },
|
||||
].map((log, j) => (
|
||||
<motion.div
|
||||
key={j}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.5 + (j * 0.1) }}
|
||||
className={`flex gap-4 p-5 rounded-2xl ${
|
||||
log.type === 'warning' ? 'bg-amber-500/10 border border-amber-500/20' :
|
||||
log.type === 'success' ? 'bg-green-500/10 border border-green-500/20 shadow-[0_0_15px_rgba(34,197,94,0.15)]' :
|
||||
'bg-secondary/40 border border-white/5'
|
||||
} backdrop-blur-sm transition-all hover:scale-[1.01]`}
|
||||
>
|
||||
<span className={`whitespace-nowrap font-bold ${
|
||||
log.type === 'warning' ? 'text-amber-500' :
|
||||
log.type === 'success' ? 'text-green-500' :
|
||||
'text-muted-foreground'
|
||||
}`}>{log.time}</span>
|
||||
<span className={`font-bold ${
|
||||
log.type === 'warning' ? 'text-amber-600 dark:text-amber-400' :
|
||||
log.type === 'success' ? 'text-green-600 dark:text-green-400 flex items-center gap-2' :
|
||||
'text-foreground'
|
||||
}`}>
|
||||
{log.type === 'success' && <CheckCircle2 className="w-5 h-5" />}
|
||||
{log.msg}
|
||||
</span>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.5 }}
|
||||
className="p-6 bg-card border border-border rounded-lg h-96"
|
||||
initial={{ opacity: 0, x: 30 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: 0.4, type: "spring" as const }}
|
||||
className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] h-[500px] shadow-xl relative overflow-hidden"
|
||||
>
|
||||
<h2 className="text-xl font-bold font-mono mb-4 border-b border-border pb-2">NODE_HEALTH</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>eBay US</span> <span className="text-primary">100%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '100%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>eBay UK</span> <span className="text-primary">98%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '98%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>HiBid</span> <span className="text-accent">85%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-accent h-1.5 rounded-full" style={{width: '85%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>ShopGoodwill</span> <span className="text-primary">99%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '99%'}}></div></div>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-gradient-to-bl from-accent/5 to-transparent pointer-events-none" />
|
||||
<div className="flex items-center gap-4 mb-8 pb-6 border-b border-border/50 relative z-10">
|
||||
<Activity className="w-8 h-8 text-primary" />
|
||||
<h2 className="text-3xl font-black tracking-tight">Node Health</h2>
|
||||
</div>
|
||||
<div className="space-y-8 relative z-10">
|
||||
{[
|
||||
{ name: 'eBay US', health: 100, color: 'bg-green-500', shadow: 'shadow-[0_0_15px_rgba(34,197,94,0.5)]' },
|
||||
{ name: 'eBay UK', health: 98, color: 'bg-blue-500', shadow: 'shadow-[0_0_15px_rgba(59,130,246,0.5)]' },
|
||||
{ name: 'HiBid', health: 85, color: 'bg-amber-500', shadow: 'shadow-[0_0_15px_rgba(245,158,11,0.5)]' },
|
||||
{ name: 'ShopGoodwill', health: 99, color: 'bg-purple-500', shadow: 'shadow-[0_0_15px_rgba(168,85,247,0.5)]' }
|
||||
].map((node, i) => (
|
||||
<div key={i} className="group">
|
||||
<div className="flex justify-between text-lg font-black mb-3">
|
||||
<span>{node.name}</span>
|
||||
<span className={node.health < 90 ? "text-amber-500" : "text-green-500"}>{node.health}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-secondary/50 rounded-full h-4 overflow-hidden border border-white/5">
|
||||
<motion.div
|
||||
initial={{ width: 0 }}
|
||||
animate={{ width: `${node.health}%` }}
|
||||
transition={{ duration: 1.5, delay: 0.6 + (i * 0.15), type: "spring" as const, bounce: 0.2 }}
|
||||
className={`${node.color} h-full rounded-full ${node.shadow} relative`}
|
||||
>
|
||||
<div className="absolute top-0 right-0 bottom-0 w-20 bg-gradient-to-r from-transparent to-white/30" />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
@ -1,133 +1,113 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--color-background: oklch(0.145 0 0);
|
||||
--color-foreground: oklch(0.985 0 0);
|
||||
--color-card: oklch(0.145 0 0);
|
||||
--color-card-foreground: oklch(0.985 0 0);
|
||||
--color-popover: oklch(0.145 0 0);
|
||||
--color-popover-foreground: oklch(0.985 0 0);
|
||||
--color-primary: oklch(0.835 0.28 152); /* Neon green #00ff88 equivalent */
|
||||
--color-primary-foreground: oklch(0.145 0 0);
|
||||
--color-secondary: oklch(0.269 0 0);
|
||||
--color-secondary-foreground: oklch(0.985 0 0);
|
||||
--color-muted: oklch(0.269 0 0);
|
||||
--color-muted-foreground: oklch(0.708 0 0);
|
||||
--color-accent: oklch(0.85 0.17 95); /* Neon gold #fbbf24 */
|
||||
--color-accent-foreground: oklch(0.145 0 0);
|
||||
--color-destructive: oklch(0.637 0.237 25.331); /* Neon red #ef4444 */
|
||||
--color-destructive-foreground: oklch(0.985 0 0);
|
||||
--color-border: oklch(0.269 0 0);
|
||||
--color-input: oklch(0.269 0 0);
|
||||
--color-ring: oklch(0.835 0.28 152);
|
||||
--radius: 0.5rem;
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--radius: 0.75rem;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 222 47% 6%;
|
||||
--foreground: 210 40% 98%;
|
||||
--border: 217 32% 17%;
|
||||
--background: oklch(0.985 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(0.985 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(0.985 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
|
||||
/* Vibrant tech blue/purple for fun tech style */
|
||||
--primary: oklch(0.55 0.25 260);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
|
||||
--secondary: oklch(0.95 0.05 250);
|
||||
--secondary-foreground: oklch(0.2 0.1 260);
|
||||
|
||||
--muted: oklch(0.96 0 0);
|
||||
--muted-foreground: oklch(0.5 0 0);
|
||||
|
||||
/* Fun energetic orange accent */
|
||||
--accent: oklch(0.7 0.2 40);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
|
||||
--destructive: oklch(0.6 0.2 20);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
|
||||
--border: oklch(0.9 0 0);
|
||||
--input: oklch(0.9 0 0);
|
||||
--ring: oklch(0.55 0.25 260);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.15 0.02 260);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.18 0.03 260);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.15 0.02 260);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
|
||||
--primary: oklch(0.65 0.25 260); /* Brighter in dark mode */
|
||||
--primary-foreground: oklch(0.1 0.1 260);
|
||||
|
||||
--secondary: oklch(0.25 0.05 260);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
|
||||
--muted: oklch(0.25 0.05 260);
|
||||
--muted-foreground: oklch(0.7 0 0);
|
||||
|
||||
--accent: oklch(0.75 0.2 40);
|
||||
--accent-foreground: oklch(0.1 0.1 40);
|
||||
|
||||
--destructive: oklch(0.5 0.2 20);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
|
||||
--border: oklch(0.25 0.05 260);
|
||||
--input: oklch(0.25 0.05 260);
|
||||
--ring: oklch(0.65 0.25 260);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #0a0e17;
|
||||
color: #f8fafc;
|
||||
border-color: #1e293b;
|
||||
background-image:
|
||||
radial-gradient(circle at 15% 50%, rgba(0, 255, 136, 0.04) 0%, transparent 25%),
|
||||
radial-gradient(circle at 85% 30%, rgba(251, 191, 36, 0.04) 0%, transparent 25%);
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
border-color: var(--border);
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Cyberpunk Styles */
|
||||
.neon-text-primary {
|
||||
text-shadow: 0 0 10px rgba(0, 255, 136, 0.5), 0 0 20px rgba(0, 255, 136, 0.3);
|
||||
/* Base Fun Tech Styles */
|
||||
.bg-gradient-tech {
|
||||
background-image: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%);
|
||||
}
|
||||
|
||||
.neon-text-accent {
|
||||
text-shadow: 0 0 10px rgba(251, 191, 36, 0.5), 0 0 20px rgba(251, 191, 36, 0.3);
|
||||
.text-gradient-tech {
|
||||
background-image: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.neon-box-primary {
|
||||
box-shadow: 0 0 15px rgba(0, 255, 136, 0.2), inset 0 0 10px rgba(0, 255, 136, 0.1);
|
||||
border: 1px solid rgba(0, 255, 136, 0.4);
|
||||
}
|
||||
|
||||
.neon-box-accent {
|
||||
box-shadow: 0 0 15px rgba(251, 191, 36, 0.2), inset 0 0 10px rgba(251, 191, 36, 0.1);
|
||||
border: 1px solid rgba(251, 191, 36, 0.4);
|
||||
}
|
||||
|
||||
.cyber-grid {
|
||||
/* Animated Grid Background */
|
||||
.tech-grid {
|
||||
background-size: 40px 40px;
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
|
||||
mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
|
||||
-webkit-mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
|
||||
linear-gradient(to right, oklch(0.5 0 0 / 0.05) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, oklch(0.5 0 0 / 0.05) 1px, transparent 1px);
|
||||
mask-image: radial-gradient(circle at center, black 40%, transparent 100%);
|
||||
-webkit-mask-image: radial-gradient(circle at center, black 40%, transparent 100%);
|
||||
}
|
||||
|
||||
.glitch-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.glitch-text::before,
|
||||
.glitch-text::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.glitch-text::before {
|
||||
color: #0ff;
|
||||
z-index: -1;
|
||||
animation: glitch-anim-1 2s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch-text::after {
|
||||
color: #f0f;
|
||||
z-index: -2;
|
||||
animation: glitch-anim-2 3s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
@keyframes glitch-anim-1 {
|
||||
0% { clip-path: inset(20% 0 80% 0); transform: translate(-2px, 1px); }
|
||||
20% { clip-path: inset(60% 0 10% 0); transform: translate(2px, -1px); }
|
||||
40% { clip-path: inset(40% 0 50% 0); transform: translate(-2px, 2px); }
|
||||
60% { clip-path: inset(80% 0 5% 0); transform: translate(2px, -2px); }
|
||||
80% { clip-path: inset(10% 0 70% 0); transform: translate(-1px, 1px); }
|
||||
100% { clip-path: inset(30% 0 50% 0); transform: translate(1px, -1px); }
|
||||
}
|
||||
|
||||
@keyframes glitch-anim-2 {
|
||||
0% { clip-path: inset(10% 0 60% 0); transform: translate(2px, -1px); }
|
||||
20% { clip-path: inset(30% 0 20% 0); transform: translate(-2px, 1px); }
|
||||
40% { clip-path: inset(70% 0 10% 0); transform: translate(2px, -2px); }
|
||||
60% { clip-path: inset(20% 0 50% 0); transform: translate(-2px, 2px); }
|
||||
80% { clip-path: inset(50% 0 30% 0); transform: translate(1px, -1px); }
|
||||
100% { clip-path: inset(5% 0 80% 0); transform: translate(-1px, 1px); }
|
||||
}
|
||||
|
||||
/* CRT Scanline effect */
|
||||
.scanlines::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(18, 16, 16, 0) 50%,
|
||||
rgba(0, 0, 0, 0.25) 50%
|
||||
);
|
||||
background-size: 100% 4px;
|
||||
z-index: 50;
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { Plus, Search, GripVertical, Settings2, Trash2 } from 'lucide-react';
|
||||
import { Plus, Search, GripVertical, Settings2, Trash2, Target } from 'lucide-react';
|
||||
|
||||
const mockTargets = [
|
||||
{ id: 1, term: 'ThinkPad T14 Gen 3', maxPrice: 600, weight: 1.5, status: 'active' },
|
||||
@ -11,59 +11,63 @@ const mockTargets = [
|
||||
|
||||
export default function KeywordsPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div className="container mx-auto px-6 py-12">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center mb-10 gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">TARGET_<span className="text-accent">VECTORS</span></h1>
|
||||
<p className="text-muted-foreground">Define what the AI agents should hunt for.</p>
|
||||
<h1 className="text-4xl font-extrabold tracking-tight mb-2 flex items-center gap-3">
|
||||
Target Vectors <span className="text-primary"><Target className="w-8 h-8" /></span>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-lg">Define the precise assets your AI agents should hunt for.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-4 py-2 bg-accent hover:bg-accent/90 text-accent-foreground rounded font-mono text-sm font-bold shadow-[0_0_15px_rgba(251,191,36,0.3)]">
|
||||
<Plus className="w-4 h-4" /> ADD_TARGET
|
||||
<button className="flex items-center gap-3 px-6 py-3 bg-primary hover:bg-primary/90 text-primary-foreground rounded-full font-bold shadow-lg hover:shadow-primary/30 transition-all hover:scale-105 active:scale-95">
|
||||
<Plus className="w-5 h-5" /> New Target
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="bg-card border border-border rounded-lg overflow-hidden">
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-border bg-background/50 font-mono text-xs text-muted-foreground">
|
||||
<div className="col-span-1">ORDER</div>
|
||||
<div className="col-span-5">SEARCH_TERM</div>
|
||||
<div className="col-span-2">MAX_PRICE</div>
|
||||
<div className="col-span-2">PRIORITY</div>
|
||||
<div className="col-span-2 text-right">ACTIONS</div>
|
||||
<div className="bg-card border-2 border-border/50 rounded-3xl overflow-hidden shadow-sm">
|
||||
<div className="grid grid-cols-12 gap-4 p-6 border-b-2 border-border/50 bg-secondary/30 text-sm font-bold text-muted-foreground uppercase tracking-wider">
|
||||
<div className="col-span-1">Sort</div>
|
||||
<div className="col-span-5">Search Query</div>
|
||||
<div className="col-span-2">Max Price</div>
|
||||
<div className="col-span-2">Priority</div>
|
||||
<div className="col-span-2 text-right">Actions</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="divide-y divide-border/30">
|
||||
{mockTargets.map((target, i) => (
|
||||
<motion.div
|
||||
key={target.id}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="grid grid-cols-12 gap-4 p-4 border-b border-border/50 items-center hover:bg-background/30 transition-colors group"
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.1, type: "spring" }}
|
||||
className={`grid grid-cols-12 gap-4 p-6 items-center hover:bg-secondary/10 transition-colors group ${target.status === 'paused' ? 'opacity-50' : ''}`}
|
||||
>
|
||||
<div className="col-span-1 text-muted-foreground">
|
||||
<GripVertical className="w-4 h-4 cursor-grab" />
|
||||
<div className="col-span-1 text-muted-foreground/50 group-hover:text-primary transition-colors">
|
||||
<GripVertical className="w-6 h-6 cursor-grab" />
|
||||
</div>
|
||||
<div className="col-span-5 font-bold flex items-center gap-2">
|
||||
<Search className="w-4 h-4 text-primary" />
|
||||
<div className="col-span-5 text-lg font-bold flex items-center gap-3">
|
||||
<div className={`p-2 rounded-xl ${target.status === 'active' ? 'bg-primary/10 text-primary' : 'bg-muted text-muted-foreground'}`}>
|
||||
<Search className="w-5 h-5" />
|
||||
</div>
|
||||
{target.term}
|
||||
</div>
|
||||
<div className="col-span-2 font-mono">
|
||||
<div className="col-span-2 text-xl font-black text-foreground">
|
||||
${target.maxPrice}
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 h-1.5 bg-background rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent" style={{width: `${(target.weight / 2) * 100}%`}}></div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-24 h-2.5 bg-secondary rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent rounded-full transition-all" style={{width: `${(target.weight / 2) * 100}%`}}></div>
|
||||
</div>
|
||||
<span className="font-mono text-xs">{target.weight}x</span>
|
||||
<span className="font-bold text-sm bg-accent/10 text-accent px-2 py-1 rounded-md">{target.weight}x</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-end gap-2">
|
||||
<button className="p-2 hover:bg-background rounded text-muted-foreground hover:text-primary transition-colors">
|
||||
<Settings2 className="w-4 h-4" />
|
||||
<div className="col-span-2 flex justify-end gap-3 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<button className="p-2.5 bg-secondary hover:bg-primary/10 text-muted-foreground hover:text-primary rounded-xl transition-all shadow-sm hover:shadow-primary/20">
|
||||
<Settings2 className="w-5 h-5" />
|
||||
</button>
|
||||
<button className="p-2 hover:bg-background rounded text-muted-foreground hover:text-destructive transition-colors">
|
||||
<Trash2 className="w-4 h-4" />
|
||||
<button className="p-2.5 bg-secondary hover:bg-destructive/10 text-muted-foreground hover:text-destructive rounded-xl transition-all shadow-sm hover:shadow-destructive/20">
|
||||
<Trash2 className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
@ -71,13 +75,24 @@ export default function KeywordsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 p-6 border border-border border-dashed rounded-lg bg-card/30">
|
||||
<h3 className="font-mono text-primary mb-2 flex items-center gap-2"><Settings2 className="w-4 h-4" /> AI_FILTERING_TEMPLATE</h3>
|
||||
<p className="text-sm text-muted-foreground mb-4">You can define a natural language description for the LLM to verify against. e.g. "Item must not be broken. Must include power cable. Ignore 'box only' listings."</p>
|
||||
<div className="w-full h-24 bg-background border border-border rounded p-3 font-mono text-sm text-muted-foreground cursor-text">
|
||||
// Enter custom instructions for the Analyst Agent here...
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="mt-10 p-8 border-2 border-primary/20 bg-primary/5 rounded-3xl"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-3 bg-primary/20 rounded-2xl">
|
||||
<Settings2 className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold">Global AI Filtering Template</h3>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-lg text-muted-foreground mb-6 font-medium">Define a natural language description for the LLM to verify against globally. For example: <span className="text-foreground bg-secondary px-2 py-0.5 rounded-md">"Item must not be broken. Must include power cable. Ignore 'box only' listings."</span></p>
|
||||
<textarea
|
||||
className="w-full h-32 bg-background/50 border-2 border-border/50 focus:border-primary rounded-2xl p-5 text-lg text-foreground font-medium outline-none resize-none transition-all shadow-inner placeholder:text-muted-foreground/50"
|
||||
placeholder="Enter custom instructions for the Analyst Agent here..."
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2,13 +2,15 @@ import type { Metadata } from "next";
|
||||
import { Inter, JetBrains_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import Navbar from "@/components/Navbar";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import PageTransition from "@/components/PageTransition";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
|
||||
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-mono" });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "BidWraith | The AI Auction Sniper That Never Sleeps",
|
||||
description: "BidWraith continuously watches global auction sites, finds under-priced deals, and sends real-time alerts. Catch every deal before anyone else.",
|
||||
title: "BidWraith | AI Auction Intelligence",
|
||||
description: "BidWraith is the smartest way to track global auction sites. Get real-time alerts and beat the competition.",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@ -17,14 +19,23 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" className={`${inter.variable} ${jetbrainsMono.variable} dark`}>
|
||||
<body className={`${inter.className} bg-background text-foreground antialiased min-h-screen flex flex-col scanlines`}>
|
||||
{/* Ambient background particles/grid layer could go here */}
|
||||
<div className="fixed inset-0 cyber-grid -z-10 opacity-30 pointer-events-none" />
|
||||
<Navbar />
|
||||
<main className="flex-1">
|
||||
{children}
|
||||
</main>
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body className={`${inter.className} ${jetbrainsMono.variable} bg-background text-foreground antialiased min-h-screen flex flex-col transition-colors duration-300`}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{/* Fun tech subtle background grid */}
|
||||
<div className="fixed inset-0 tech-grid -z-10 pointer-events-none" />
|
||||
<Navbar />
|
||||
<main className="flex-1 w-full flex flex-col relative overflow-hidden">
|
||||
<PageTransition>
|
||||
{children}
|
||||
</PageTransition>
|
||||
</main>
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@ -1,69 +1,121 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { ExternalLink, Clock, Brain } from 'lucide-react';
|
||||
import { ExternalLink, Clock, Brain, Download, RefreshCw, ShoppingCart, Info } from 'lucide-react';
|
||||
|
||||
const mockListings = [
|
||||
{ id: 1, title: 'Lenovo ThinkPad T14 Gen 3 AMD Ryzen 7', price: '$450.00', estValue: '$800.00', site: 'eBay US', time: '14m 30s', verdict: 'HIGH_OPPORTUNITY' },
|
||||
{ id: 2, title: 'NVIDIA RTX 3080 Founders Edition', price: '$320.00', estValue: '$450.00', site: 'HiBid', time: '1h 12m', verdict: 'GOOD_DEAL' },
|
||||
{ id: 3, title: 'Lot of 10x iPhone 12 Pro 128GB Unlocked', price: '$1200.00', estValue: '$2500.00', site: 'ShopGoodwill', time: '4h 05m', verdict: 'RESELLER_DREAM' },
|
||||
{ id: 4, title: 'Sony A7IV Mirrorless Camera Body', price: '$1500.00', estValue: '$1900.00', site: 'eBay UK', time: '5m 10s', verdict: 'URGENT' },
|
||||
{ id: 1, title: 'Lenovo ThinkPad T14 Gen 3 AMD Ryzen 7', price: '$450.00', estValue: '$800.00', site: 'eBay US', time: '14m 30s', verdict: 'HIGH_OPPORTUNITY', image: '💻' },
|
||||
{ id: 2, title: 'NVIDIA RTX 3080 Founders Edition', price: '$320.00', estValue: '$450.00', site: 'HiBid', time: '1h 12m', verdict: 'GOOD_DEAL', image: '🎮' },
|
||||
{ id: 3, title: 'Lot of 10x iPhone 12 Pro 128GB Unlocked', price: '$1200.00', estValue: '$2500.00', site: 'ShopGoodwill', time: '4h 05m', verdict: 'RESELLER_DREAM', image: '📱' },
|
||||
{ id: 4, title: 'Sony A7IV Mirrorless Camera Body', price: '$1500.00', estValue: '$1900.00', site: 'eBay UK', time: '5m 10s', verdict: 'URGENT', image: '📸' },
|
||||
];
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
delayChildren: 0.2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 30, scale: 0.95 },
|
||||
show: { opacity: 1, y: 0, scale: 1, transition: { type: "spring" as const, stiffness: 300, damping: 24 } }
|
||||
};
|
||||
|
||||
export default function ListingsPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div className="container mx-auto px-6 py-12 relative">
|
||||
<div className="absolute top-[-20%] right-[-10%] w-[40%] h-[40%] bg-primary/10 rounded-full blur-[120px] pointer-events-none -z-10" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, ease: "easeOut" }}
|
||||
className="flex flex-col md:flex-row justify-between items-start md:items-center mb-10 gap-4"
|
||||
>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">ACTIVE_<span className="text-primary">LISTINGS</span></h1>
|
||||
<p className="text-muted-foreground">Filtered lots currently matching your target criteria.</p>
|
||||
<h1 className="text-5xl font-black tracking-tight mb-2 flex items-center gap-4 drop-shadow-sm">
|
||||
Active Deals <motion.div whileHover={{ rotate: 15 }}><ShoppingCart className="w-10 h-10 text-primary drop-shadow-md" /></motion.div>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-xl font-medium">Live opportunities filtered by your AI agents.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="px-4 py-2 bg-card border border-border rounded font-mono text-sm hover:border-primary transition-colors">Export CSV</button>
|
||||
<button className="px-4 py-2 bg-primary text-primary-foreground rounded font-mono text-sm font-bold shadow-[0_0_10px_rgba(0,255,136,0.3)]">Force Refresh</button>
|
||||
<div className="flex gap-3">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}
|
||||
className="flex items-center gap-2 px-6 py-3 bg-secondary/80 backdrop-blur-md hover:bg-secondary border border-border/50 rounded-full font-bold transition-all shadow-sm"
|
||||
>
|
||||
<Download className="w-4 h-4" /> Export
|
||||
</motion.button>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05, boxShadow: "0 0 20px rgba(139, 92, 246, 0.4)" }} whileTap={{ scale: 0.95 }}
|
||||
className="flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-full font-bold shadow-lg transition-all relative overflow-hidden group"
|
||||
>
|
||||
<span className="absolute inset-0 bg-white/20 translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-500" />
|
||||
<RefreshCw className="w-4 h-4 group-hover:rotate-180 transition-transform duration-500" /> Refresh
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid gap-4">
|
||||
{mockListings.map((lot, i) => (
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
className="grid gap-6"
|
||||
>
|
||||
{mockListings.map((lot) => (
|
||||
<motion.div
|
||||
key={lot.id}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="flex flex-col md:flex-row gap-4 p-4 bg-card border border-border hover:border-primary/50 transition-colors rounded-lg group"
|
||||
variants={itemVariants}
|
||||
whileHover={{ y: -5, scale: 1.01 }}
|
||||
className="flex flex-col md:flex-row gap-6 p-6 bg-card/80 backdrop-blur-xl border border-white/5 hover:border-primary/40 transition-colors rounded-3xl group shadow-lg hover:shadow-2xl relative overflow-hidden"
|
||||
>
|
||||
<div className="w-full md:w-48 h-32 bg-background rounded border border-border flex items-center justify-center text-muted-foreground font-mono text-xs overflow-hidden relative">
|
||||
<div className="absolute inset-0 bg-gradient-to-tr from-primary/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
||||
[IMAGE_DATA]
|
||||
<div className="absolute top-0 left-0 w-2 h-full bg-gradient-to-b from-primary to-accent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="w-full md:w-64 h-48 bg-secondary/40 rounded-2xl flex flex-col items-center justify-center overflow-hidden relative border border-white/5 shadow-inner">
|
||||
<motion.span
|
||||
animate={{ y: [0, -10, 0] }}
|
||||
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
|
||||
className="text-7xl group-hover:scale-110 transition-transform duration-500 drop-shadow-xl"
|
||||
>
|
||||
{lot.image}
|
||||
</motion.span>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-primary/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500"></div>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col justify-between">
|
||||
<div className="flex-1 flex flex-col justify-between py-2">
|
||||
<div>
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h3 className="font-bold text-lg leading-tight group-hover:text-primary transition-colors">{lot.title}</h3>
|
||||
<div className={`px-2 py-1 text-xs font-mono rounded ${lot.verdict === 'URGENT' ? 'bg-destructive/20 text-destructive border border-destructive/30' : 'bg-primary/10 text-primary border border-primary/30'}`}>
|
||||
{lot.verdict}
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center mb-4 gap-2">
|
||||
<h3 className="font-black text-3xl leading-tight group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-primary group-hover:to-accent transition-all">{lot.title}</h3>
|
||||
<div className={`px-5 py-2 text-sm font-black rounded-full whitespace-nowrap shadow-inner border ${lot.verdict === 'URGENT' ? 'bg-red-500/10 border-red-500/20 text-red-500' : lot.verdict === 'RESELLER_DREAM' ? 'bg-purple-500/10 border-purple-500/20 text-purple-500' : 'bg-green-500/10 border-green-500/20 text-green-500'}`}>
|
||||
{lot.verdict.replace('_', ' ')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-sm font-mono text-muted-foreground mb-4">
|
||||
<span className="flex items-center gap-1"><ExternalLink className="w-3 h-3" /> {lot.site}</span>
|
||||
<span className="flex items-center gap-1 text-accent"><Clock className="w-3 h-3" /> {lot.time}</span>
|
||||
<span className="flex items-center gap-1"><Brain className="w-3 h-3 text-primary" /> Verified</span>
|
||||
<div className="flex flex-wrap items-center gap-4 text-sm font-bold text-muted-foreground mb-4">
|
||||
<span className="flex items-center gap-2 bg-secondary/60 px-4 py-1.5 rounded-xl border border-white/5"><ExternalLink className="w-4 h-4" /> {lot.site}</span>
|
||||
<span className="flex items-center gap-2 bg-amber-500/10 text-amber-500 px-4 py-1.5 rounded-xl border border-amber-500/20"><Clock className="w-4 h-4" /> Ends in {lot.time}</span>
|
||||
<span className="flex items-center gap-2 bg-blue-500/10 text-blue-500 px-4 py-1.5 rounded-xl border border-blue-500/20"><Brain className="w-4 h-4" /> AI Verified</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-end">
|
||||
<div>
|
||||
<div className="text-2xl font-bold font-mono">{lot.price}</div>
|
||||
<div className="text-xs font-mono text-muted-foreground">Est. Value: <span className="line-through">{lot.estValue}</span></div>
|
||||
<div className="flex flex-col sm:flex-row justify-between items-end gap-4 mt-4">
|
||||
<div className="flex items-baseline gap-4">
|
||||
<div className="text-5xl font-black text-foreground drop-shadow-md">{lot.price}</div>
|
||||
<div className="text-sm font-black text-muted-foreground mb-1">
|
||||
Est: <span className="line-through decoration-red-500 decoration-2">{lot.estValue}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button className="px-6 py-2 bg-background border border-border hover:border-primary hover:text-primary rounded font-mono text-sm transition-all group-hover:shadow-[0_0_15px_rgba(0,255,136,0.1)]">
|
||||
ANALYZE LOT
|
||||
</button>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}
|
||||
className="w-full sm:w-auto px-8 py-4 bg-secondary/80 hover:bg-primary hover:text-primary-foreground rounded-2xl font-black text-lg transition-all shadow-md group-hover:shadow-xl flex items-center justify-center gap-3 border border-white/5 group-hover:border-primary/50"
|
||||
>
|
||||
<Info className="w-5 h-5" /> Analyze Lot
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,113 +1,194 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowRight, Crosshair, Brain, BellRing, Ghost } from 'lucide-react';
|
||||
import { motion, useScroll, useTransform } from 'framer-motion';
|
||||
import { Rocket, Target, Zap, ShieldCheck, Cpu, ChevronRight } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import GlitchText from '@/components/GlitchText';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const Hero3D = dynamic(() => import('@/components/Hero3D'), { ssr: false });
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: Crosshair,
|
||||
icon: Target,
|
||||
title: "Always-On Radar",
|
||||
description: "Monitors dozens of auction sites simultaneously. The engine never sleeps, so you never miss an ending lot.",
|
||||
color: "text-blue-500",
|
||||
bg: "bg-blue-500/10"
|
||||
},
|
||||
{
|
||||
icon: Brain,
|
||||
icon: Cpu,
|
||||
title: "AI-Grade Filtering",
|
||||
description: "External LLMs score and filter every lot against your precise custom targets. We drop the noise and show only true deals.",
|
||||
color: "text-purple-500",
|
||||
bg: "bg-purple-500/10"
|
||||
},
|
||||
{
|
||||
icon: BellRing,
|
||||
icon: Zap,
|
||||
title: "Real-Time Comms",
|
||||
description: "Instant alerts delivered via Telegram, Discord, or Email the minute a high-value lot appears or is about to close.",
|
||||
color: "text-yellow-500",
|
||||
bg: "bg-yellow-500/10"
|
||||
},
|
||||
{
|
||||
icon: Ghost,
|
||||
icon: ShieldCheck,
|
||||
title: "Stealth Engine",
|
||||
description: "Human-like browsing algorithms bypass standard detection, ensuring reliable intelligence gathering from any platform.",
|
||||
color: "text-green-500",
|
||||
bg: "bg-green-500/10"
|
||||
}
|
||||
];
|
||||
|
||||
export default function LandingPage() {
|
||||
const { scrollYProgress } = useScroll();
|
||||
const yHero = useTransform(scrollYProgress, [0, 1], ["0%", "50%"]);
|
||||
const opacityHero = useTransform(scrollYProgress, [0, 0.2], [1, 0]);
|
||||
|
||||
return (
|
||||
<div className="relative overflow-hidden w-full">
|
||||
<div className="relative w-full min-h-screen bg-background text-foreground overflow-hidden font-sans">
|
||||
|
||||
{/* Dynamic 3D Background */}
|
||||
<div className="fixed inset-0 w-full h-[100vh] pointer-events-none -z-20">
|
||||
<Hero3D />
|
||||
</div>
|
||||
|
||||
{/* Dynamic Background Blob Elements */}
|
||||
<div className="fixed top-0 left-0 w-full h-full overflow-hidden -z-10 opacity-40 pointer-events-none mix-blend-screen">
|
||||
<motion.div
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 90, 0],
|
||||
}}
|
||||
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
|
||||
className="absolute top-[-20%] left-[-10%] w-[50%] h-[50%] bg-primary/20 rounded-full blur-[140px]"
|
||||
/>
|
||||
<motion.div
|
||||
animate={{
|
||||
scale: [1, 1.5, 1],
|
||||
rotate: [0, -90, 0],
|
||||
}}
|
||||
transition={{ duration: 25, repeat: Infinity, ease: "linear" }}
|
||||
className="absolute bottom-[-10%] right-[-10%] w-[50%] h-[50%] bg-accent/20 rounded-full blur-[140px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="container mx-auto px-4 pt-32 pb-24 text-center relative z-10">
|
||||
<section className="container mx-auto px-6 pt-32 pb-32 text-center relative z-10 min-h-[90vh] flex flex-col justify-center">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto"
|
||||
style={{ y: yHero, opacity: opacityHero }}
|
||||
initial={{ opacity: 0, y: 50, scale: 0.9 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
transition={{ duration: 1, type: "spring" as const, bounce: 0.4 }}
|
||||
className="max-w-5xl mx-auto flex flex-col items-center backdrop-blur-sm bg-background/30 p-12 rounded-[3rem] border border-white/10 shadow-2xl"
|
||||
>
|
||||
<div className="mb-6 inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/30 text-primary text-sm font-mono uppercase">
|
||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse"></span>
|
||||
System v4 Deployed
|
||||
</div>
|
||||
<h1 className="text-5xl md:text-7xl font-bold mb-6 tracking-tight">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: 0.2, type: "spring" as const }}
|
||||
className="mb-8 inline-flex items-center gap-3 px-6 py-2 rounded-full bg-secondary/80 backdrop-blur-md text-primary font-bold text-sm shadow-[0_0_30px_rgba(139,92,246,0.3)] border border-primary/20"
|
||||
>
|
||||
<span className="flex h-3 w-3 relative">
|
||||
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
|
||||
<span className="relative inline-flex rounded-full h-3 w-3 bg-primary"></span>
|
||||
</span>
|
||||
System v5 Neural Engine Online
|
||||
</motion.div>
|
||||
<h1 className="text-6xl md:text-8xl font-black mb-8 tracking-tighter leading-[1.1]">
|
||||
The AI Sniper That <br />
|
||||
<span className="text-primary neon-text-primary"><GlitchText text="NEVER SLEEPS" /></span>
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-br from-primary via-accent to-blue-500 drop-shadow-sm">Never Sleeps</span>
|
||||
</h1>
|
||||
<p className="text-xl md:text-2xl text-muted-foreground mb-10 max-w-2xl mx-auto">
|
||||
BidWraith watches every global auction site, scores every lot with AI, and alerts you the moment a real deal drops.
|
||||
<p className="text-xl md:text-2xl text-muted-foreground mb-12 max-w-3xl mx-auto leading-relaxed font-medium">
|
||||
BidWraith watches every global auction site, scores every lot with deep AI, and alerts you the moment a real deal drops. Get the ultimate edge.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link href="/dashboard" className="inline-flex items-center justify-center gap-2 bg-primary hover:bg-primary/90 text-primary-foreground px-8 py-4 rounded-md font-bold text-lg transition-all shadow-[0_0_20px_rgba(0,255,136,0.3)] hover:shadow-[0_0_30px_rgba(0,255,136,0.5)]">
|
||||
Initialize Console <ArrowRight className="w-5 h-5" />
|
||||
<div className="flex flex-col sm:flex-row gap-6 justify-center w-full sm:w-auto">
|
||||
<Link href="/dashboard" className="group relative inline-flex items-center justify-center gap-3 bg-primary text-primary-foreground px-10 py-5 rounded-2xl font-bold text-xl transition-all hover:scale-105 shadow-[0_0_40px_rgba(139,92,246,0.5)] w-full sm:w-auto overflow-hidden">
|
||||
<motion.span
|
||||
className="absolute inset-0 bg-white/20"
|
||||
initial={{ x: "-100%" }}
|
||||
whileHover={{ x: "100%" }}
|
||||
transition={{ duration: 0.6, ease: "easeInOut" }}
|
||||
/>
|
||||
<Rocket className="w-6 h-6 group-hover:-translate-y-1 group-hover:translate-x-1 transition-transform" />
|
||||
Initialize Console
|
||||
</Link>
|
||||
<Link href="#features" className="inline-flex items-center justify-center gap-2 bg-card hover:bg-card/80 border border-border px-8 py-4 rounded-md font-bold text-lg transition-colors">
|
||||
Read Briefing
|
||||
<Link href="#features" className="group inline-flex items-center justify-center gap-3 bg-secondary/80 backdrop-blur-md hover:bg-secondary text-foreground border border-border px-10 py-5 rounded-2xl font-bold text-xl transition-all w-full sm:w-auto">
|
||||
Explore Tech
|
||||
<ChevronRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* Stats Strip */}
|
||||
<section className="border-y border-border bg-card/50 backdrop-blur-sm py-8 relative z-10">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center font-mono">
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-primary mb-1">24/7</div>
|
||||
<div className="text-sm text-muted-foreground">Uptime</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-accent mb-1">< 1s</div>
|
||||
<div className="text-sm text-muted-foreground">Alert Latency</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-primary mb-1">42</div>
|
||||
<div className="text-sm text-muted-foreground">API Endpoints</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-accent mb-1">100%</div>
|
||||
<div className="text-sm text-muted-foreground">Stealth Rate</div>
|
||||
{/* Stats Strip with Scroll Reveal */}
|
||||
<section className="py-12 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="container mx-auto px-6"
|
||||
>
|
||||
<div className="bg-secondary/60 backdrop-blur-2xl border border-white/10 rounded-3xl p-8 shadow-2xl relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-primary/10 via-transparent to-accent/10 pointer-events-none" />
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center relative z-10">
|
||||
{[
|
||||
{ label: 'Uptime', value: '24/7', color: 'text-primary' },
|
||||
{ label: 'Alert Latency', value: '< 1s', color: 'text-accent' },
|
||||
{ label: 'API Endpoints', value: '42', color: 'text-blue-500' },
|
||||
{ label: 'Stealth Rate', value: '100%', color: 'text-green-500' }
|
||||
].map((stat, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
className="flex flex-col items-center justify-center p-4 cursor-default"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ scale: 0 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ type: "spring" as const, delay: i * 0.1 }}
|
||||
className={`text-5xl md:text-6xl font-black mb-2 drop-shadow-md ${stat.color}`}
|
||||
>
|
||||
{stat.value}
|
||||
</motion.div>
|
||||
<div className="text-sm md:text-base font-bold text-muted-foreground uppercase tracking-widest">{stat.label}</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* Features Section */}
|
||||
<section id="features" className="py-24 relative z-10">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl md:text-5xl font-bold mb-4">Core <span className="text-primary">Directives</span></h2>
|
||||
<p className="text-muted-foreground text-lg max-w-2xl mx-auto">Advanced architecture designed to give you an unfair advantage in the global market.</p>
|
||||
</div>
|
||||
<section id="features" className="py-32 relative z-10">
|
||||
<div className="container mx-auto px-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-center mb-24"
|
||||
>
|
||||
<h2 className="text-5xl md:text-7xl font-extrabold mb-6 tracking-tight">Core <span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-accent">Capabilities</span></h2>
|
||||
<p className="text-muted-foreground text-2xl max-w-3xl mx-auto font-medium">Advanced architecture designed to give you an unfair advantage in the global market.</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
<div className="grid md:grid-cols-2 gap-10 max-w-6xl mx-auto">
|
||||
{features.map((feature, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: idx * 0.1 }}
|
||||
className="p-8 rounded-xl bg-card border border-border hover:border-primary/50 transition-colors group relative overflow-hidden"
|
||||
initial={{ opacity: 0, y: 50, rotateX: -10 }}
|
||||
whileInView={{ opacity: 1, y: 0, rotateX: 0 }}
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
transition={{ duration: 0.6, delay: idx * 0.1, type: "spring" as const, bounce: 0.3 }}
|
||||
whileHover={{ y: -10, scale: 1.02 }}
|
||||
className="p-12 rounded-[2.5rem] bg-card/80 backdrop-blur-xl border border-white/5 hover:border-primary/30 transition-all shadow-xl hover:shadow-2xl group relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-primary/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<feature.icon className="w-12 h-12 text-primary mb-6" />
|
||||
<h3 className="text-2xl font-bold mb-3">{feature.title}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed">
|
||||
<div className={`absolute top-0 right-0 w-64 h-64 ${feature.bg} rounded-full blur-[80px] -z-10 group-hover:scale-150 transition-transform duration-700`} />
|
||||
<div className={`w-24 h-24 rounded-3xl ${feature.bg} flex items-center justify-center mb-8 group-hover:scale-110 group-hover:rotate-6 transition-transform duration-300 shadow-inner`}>
|
||||
<feature.icon className={`w-12 h-12 ${feature.color}`} />
|
||||
</div>
|
||||
<h3 className="text-3xl font-black mb-4 tracking-tight">{feature.title}</h3>
|
||||
<p className="text-muted-foreground text-xl leading-relaxed font-medium">
|
||||
{feature.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
@ -116,28 +197,30 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Diagram Section */}
|
||||
<section className="py-24 bg-card/30 border-t border-border relative z-10">
|
||||
<div className="container mx-auto px-4 text-center">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-12">The <span className="text-accent">Execution</span> Pipeline</h2>
|
||||
<div className="flex flex-col md:flex-row items-center justify-center gap-4 md:gap-8 text-lg font-mono">
|
||||
<div className="p-4 border border-border rounded bg-card w-48 shadow-[0_0_15px_rgba(251,191,36,0.1)]">Targets & Rules</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-primary/50 rounded bg-primary/5 w-48 shadow-[0_0_15px_rgba(0,255,136,0.2)] text-primary">Ghost Scraper</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-border rounded bg-card w-48 shadow-[0_0_15px_rgba(251,191,36,0.1)]">AI Analysis</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-accent/50 rounded bg-accent/5 w-48 shadow-[0_0_15px_rgba(251,191,36,0.2)] text-accent">Real-time Alerts</div>
|
||||
{/* Footer CTA with 3D feel */}
|
||||
<section className="py-32 text-center relative z-10 overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 50 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
className="container mx-auto px-6"
|
||||
>
|
||||
<div className="relative bg-gradient-to-br from-primary/30 via-background to-accent/30 border border-white/10 pt-32 pb-24 rounded-[4rem] shadow-2xl overflow-hidden backdrop-blur-md">
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ duration: 50, repeat: Infinity, ease: "linear" }}
|
||||
className="absolute top-[-50%] left-[-20%] w-[100%] h-[150%] bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 mix-blend-overlay pointer-events-none"
|
||||
/>
|
||||
|
||||
<div className="relative z-10">
|
||||
<h2 className="text-6xl md:text-8xl font-black mb-12 tracking-tight drop-shadow-xl">Ready to dominate?</h2>
|
||||
<Link href="/dashboard" className="group inline-flex items-center gap-4 bg-foreground text-background font-bold text-2xl px-14 py-7 rounded-full transition-all shadow-[0_20px_50px_rgba(0,0,0,0.3)] hover:shadow-[0_20px_50px_rgba(139,92,246,0.5)] hover:-translate-y-2">
|
||||
Start Sniping Now
|
||||
<Rocket className="w-8 h-8 group-hover:translate-x-2 group-hover:-translate-y-2 transition-transform" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer CTA */}
|
||||
<section className="py-32 text-center relative z-10">
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-8">Ready to dominate the market?</h2>
|
||||
<Link href="/dashboard" className="inline-flex items-center gap-2 text-primary hover:text-accent font-mono text-xl transition-colors">
|
||||
> ACCESS_SYSTEM_NOW <span className="animate-pulse">_</span>
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,98 +1,177 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { Save, Bell, Shield, Database, Cpu } from 'lucide-react';
|
||||
import { Save, Bell, Shield, Database, Cpu, Settings, MessageSquare, Sliders, HardDrive, Trash2 } from 'lucide-react';
|
||||
|
||||
const containerVariants = {
|
||||
hidden: { opacity: 0 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
transition: {
|
||||
staggerChildren: 0.1,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, y: 20, scale: 0.95 },
|
||||
show: { opacity: 1, y: 0, scale: 1, transition: { type: "spring" as const, stiffness: 300, damping: 24 } }
|
||||
};
|
||||
|
||||
export default function SettingsPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div className="container mx-auto px-6 py-12 relative">
|
||||
<div className="absolute top-[20%] left-[-10%] w-[30%] h-[30%] bg-blue-500/10 rounded-full blur-[120px] pointer-events-none -z-10" />
|
||||
<div className="absolute bottom-[10%] right-[10%] w-[30%] h-[30%] bg-purple-500/10 rounded-full blur-[120px] pointer-events-none -z-10" />
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="flex flex-col md:flex-row justify-between items-start md:items-center mb-12 gap-4"
|
||||
>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">SYSTEM_<span className="text-primary">CONFIG</span></h1>
|
||||
<p className="text-muted-foreground">Adjust core parameters, AI models, and notification routing.</p>
|
||||
<h1 className="text-5xl font-black tracking-tight mb-3 flex items-center gap-4 drop-shadow-sm">
|
||||
System Config <motion.div animate={{ rotate: 360 }} transition={{ duration: 10, repeat: Infinity, ease: "linear" }}><Settings className="w-10 h-10 text-primary drop-shadow-md" /></motion.div>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-xl font-medium">Adjust core parameters, AI models, and notification routing.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-6 py-2 bg-primary hover:bg-primary/90 text-primary-foreground rounded font-mono text-sm font-bold shadow-[0_0_15px_rgba(0,255,136,0.3)] transition-all">
|
||||
<Save className="w-4 h-4" /> COMMIT_CHANGES
|
||||
</button>
|
||||
</div>
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.05, boxShadow: "0 0 25px rgba(139, 92, 246, 0.4)" }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="flex items-center gap-3 px-8 py-4 bg-primary text-primary-foreground rounded-2xl font-black shadow-lg transition-all relative overflow-hidden group"
|
||||
>
|
||||
<span className="absolute inset-0 bg-white/20 translate-y-[100%] group-hover:translate-y-[0%] transition-transform duration-300" />
|
||||
<Save className="w-5 h-5 relative z-10" />
|
||||
<span className="relative z-10">Save Changes</span>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<div className="md:col-span-2 space-y-6">
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Cpu className="w-5 h-5 text-primary" /> AI_ENGINE_SETTINGS</h2>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<motion.div
|
||||
variants={containerVariants}
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
className="grid md:grid-cols-3 gap-8"
|
||||
>
|
||||
<div className="md:col-span-2 space-y-8">
|
||||
{/* AI Settings */}
|
||||
<motion.div variants={itemVariants} className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] shadow-xl relative overflow-hidden group hover:border-blue-500/30 transition-colors">
|
||||
<div className="absolute -right-20 -top-20 w-48 h-48 bg-blue-500/10 rounded-full blur-[60px] group-hover:scale-150 transition-transform duration-700 pointer-events-none" />
|
||||
<h2 className="text-3xl font-black mb-8 flex items-center gap-4 border-b border-border/50 pb-6 relative z-10">
|
||||
<div className="p-3 bg-blue-500/10 rounded-2xl border border-blue-500/20 shadow-inner"><Cpu className="w-8 h-8 text-blue-500" /></div>
|
||||
AI Engine Preferences
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 relative z-10">
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Primary Provider</label>
|
||||
<select className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary">
|
||||
<option>Anthropic (Claude 3.5 Sonnet)</option>
|
||||
<option>OpenAI (GPT-4o)</option>
|
||||
<option>Groq (Llama 3 70B)</option>
|
||||
<option>Ollama (Local)</option>
|
||||
</select>
|
||||
<label className="block text-sm font-black text-muted-foreground mb-3 uppercase tracking-wider">Primary Provider</label>
|
||||
<div className="relative">
|
||||
<select className="w-full bg-secondary/50 border border-white/10 rounded-2xl px-5 py-4 text-lg font-bold focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500/50 transition-all appearance-none shadow-inner cursor-pointer hover:bg-secondary/80">
|
||||
<option>Anthropic (Claude 3.5 Sonnet)</option>
|
||||
<option>OpenAI (GPT-4o)</option>
|
||||
<option>Groq (Llama 3 70B)</option>
|
||||
<option>Ollama (Local)</option>
|
||||
</select>
|
||||
<div className="absolute right-5 top-1/2 -translate-y-1/2 pointer-events-none text-muted-foreground">▼</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Strictness Level</label>
|
||||
<select className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary">
|
||||
<option>High (Miss deals, zero noise)</option>
|
||||
<option selected>Balanced</option>
|
||||
<option>Low (Catch everything, more noise)</option>
|
||||
</select>
|
||||
<label className="block text-sm font-black text-muted-foreground mb-3 uppercase tracking-wider">Strictness Level</label>
|
||||
<div className="relative">
|
||||
<select className="w-full bg-secondary/50 border border-white/10 rounded-2xl px-5 py-4 text-lg font-bold focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500/50 transition-all appearance-none shadow-inner cursor-pointer hover:bg-secondary/80">
|
||||
<option>High (Miss deals, zero noise)</option>
|
||||
<option selected>Balanced</option>
|
||||
<option>Low (Catch everything, more noise)</option>
|
||||
</select>
|
||||
<div className="absolute right-5 top-1/2 -translate-y-1/2 pointer-events-none text-muted-foreground">▼</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">API Key</label>
|
||||
<input type="password" value="*************************" className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary" readOnly/>
|
||||
<div className="col-span-1 md:col-span-2">
|
||||
<label className="block text-sm font-black text-muted-foreground mb-3 uppercase tracking-wider">API Key</label>
|
||||
<input type="password" value="sk-ant-api03-*************************" className="w-full bg-secondary/50 border border-white/10 rounded-2xl px-5 py-4 text-lg font-bold focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500/50 transition-all shadow-inner" readOnly/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.1}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Bell className="w-5 h-5 text-accent" /> ALERT_ROUTING</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between p-3 bg-background border border-border rounded">
|
||||
<div>
|
||||
<div className="font-bold">Telegram Bot</div>
|
||||
<div className="text-xs text-muted-foreground">Status: Connected (@BidWraithBot)</div>
|
||||
{/* Alert Routing */}
|
||||
<motion.div variants={itemVariants} className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] shadow-xl relative overflow-hidden group hover:border-amber-500/30 transition-colors">
|
||||
<div className="absolute -left-20 -bottom-20 w-48 h-48 bg-amber-500/10 rounded-full blur-[60px] group-hover:scale-150 transition-transform duration-700 pointer-events-none" />
|
||||
<h2 className="text-3xl font-black mb-8 flex items-center gap-4 border-b border-border/50 pb-6 relative z-10">
|
||||
<div className="p-3 bg-amber-500/10 rounded-2xl border border-amber-500/20 shadow-inner"><Bell className="w-8 h-8 text-amber-500" /></div>
|
||||
Alert Routing
|
||||
</h2>
|
||||
<div className="space-y-4 relative z-10">
|
||||
<motion.div whileHover={{ scale: 1.01 }} className="flex items-center justify-between p-6 bg-secondary/40 border border-white/5 rounded-3xl hover:border-amber-500/50 transition-all cursor-pointer shadow-sm">
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="p-4 bg-[#0088cc]/10 rounded-2xl border border-[#0088cc]/20"><MessageSquare className="w-8 h-8 text-[#0088cc]" /></div>
|
||||
<div>
|
||||
<div className="font-black text-xl">Telegram Bot</div>
|
||||
<div className="text-base font-bold text-green-500 mt-1 flex items-center gap-2">
|
||||
<span className="w-2 h-2 rounded-full bg-green-500 animate-pulse" /> Connected (@BidWraithBot)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-10 h-5 bg-primary rounded-full relative cursor-pointer"><div className="absolute right-1 top-1 w-3 h-3 bg-primary-foreground rounded-full"></div></div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-3 bg-background border border-border rounded">
|
||||
<div>
|
||||
<div className="font-bold">Discord Webhook</div>
|
||||
<div className="text-xs text-muted-foreground">Status: Not Configured</div>
|
||||
<div className="w-16 h-8 bg-amber-500 rounded-full relative shadow-[0_0_15px_rgba(245,158,11,0.4)]">
|
||||
<motion.div layout className="absolute right-1 top-1 w-6 h-6 bg-white rounded-full shadow-md"></motion.div>
|
||||
</div>
|
||||
<div className="w-10 h-5 bg-border rounded-full relative cursor-pointer"><div className="absolute left-1 top-1 w-3 h-3 bg-muted-foreground rounded-full"></div></div>
|
||||
</div>
|
||||
</motion.div>
|
||||
<motion.div whileHover={{ scale: 1.01 }} className="flex items-center justify-between p-6 bg-secondary/40 border border-white/5 rounded-3xl hover:border-border/80 transition-all cursor-pointer shadow-sm opacity-70">
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="p-4 bg-[#5865F2]/10 rounded-2xl border border-[#5865F2]/20"><MessageSquare className="w-8 h-8 text-[#5865F2]" /></div>
|
||||
<div>
|
||||
<div className="font-black text-xl">Discord Webhook</div>
|
||||
<div className="text-base font-bold text-muted-foreground mt-1">Not Configured</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-16 h-8 bg-secondary-foreground/20 rounded-full relative shadow-inner">
|
||||
<motion.div layout className="absolute left-1 top-1 w-6 h-6 bg-card rounded-full shadow-sm"></motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.2}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Shield className="w-5 h-5 text-muted-foreground" /> STEALTH_MODE</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-8">
|
||||
{/* Stealth Mode */}
|
||||
<motion.div variants={itemVariants} className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] shadow-xl relative overflow-hidden group hover:border-purple-500/30 transition-colors">
|
||||
<div className="absolute -right-10 -bottom-10 w-40 h-40 bg-purple-500/10 rounded-full blur-[50px] group-hover:scale-150 transition-transform duration-700 pointer-events-none" />
|
||||
<h2 className="text-3xl font-black mb-8 flex items-center gap-4 border-b border-border/50 pb-6 relative z-10">
|
||||
<div className="p-3 bg-purple-500/10 rounded-2xl border border-purple-500/20 shadow-inner"><Shield className="w-8 h-8 text-purple-500" /></div>
|
||||
Stealth Mode
|
||||
</h2>
|
||||
<div className="space-y-8 relative z-10">
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Humanization Level</label>
|
||||
<input type="range" min="1" max="100" defaultValue="75" className="w-full accent-primary" />
|
||||
<div className="flex justify-between text-xs text-muted-foreground mt-1"><span>Fast/Bot</span><span>Slow/Human</span></div>
|
||||
<label className="block text-sm font-black text-muted-foreground mb-4 uppercase tracking-wider">Humanization Level</label>
|
||||
<input type="range" min="1" max="100" defaultValue="75" className="w-full accent-purple-500 h-3 bg-secondary/80 rounded-full appearance-none cursor-pointer shadow-inner" />
|
||||
<div className="flex justify-between text-sm font-bold text-muted-foreground mt-4">
|
||||
<span className="bg-secondary px-3 py-1 rounded-lg">Fast / Bot</span>
|
||||
<span className="bg-secondary px-3 py-1 rounded-lg text-purple-500">Slow / Human</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pt-2">
|
||||
<label className="flex items-center gap-2 text-sm cursor-pointer">
|
||||
<input type="checkbox" defaultChecked className="accent-primary w-4 h-4" /> Use Proxy Rotation
|
||||
<label className="flex items-center justify-between p-5 bg-secondary/40 border border-white/5 rounded-2xl hover:bg-secondary/60 transition-colors cursor-pointer group">
|
||||
<span className="text-lg font-black group-hover:text-purple-500 transition-colors">Use Proxy Rotation</span>
|
||||
<input type="checkbox" defaultChecked className="w-6 h-6 accent-purple-500 rounded text-purple-500 focus:ring-purple-500 bg-card border-white/10" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.3}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Database className="w-5 h-5 text-muted-foreground" /> DATA_MANAGEMENT</h2>
|
||||
<div className="space-y-2">
|
||||
<button className="w-full py-2 bg-background border border-border hover:border-primary text-sm font-mono rounded transition-colors text-left px-3">Export Database Backup</button>
|
||||
<button className="w-full py-2 bg-background border border-border hover:border-primary text-sm font-mono rounded transition-colors text-left px-3">Clear Old Logs (>30d)</button>
|
||||
<button className="w-full py-2 bg-destructive/10 border border-destructive/30 text-destructive hover:bg-destructive hover:text-destructive-foreground text-sm font-mono rounded transition-colors text-left px-3 mt-4">FACTORY RESET</button>
|
||||
{/* Data Management */}
|
||||
<motion.div variants={itemVariants} className="p-8 bg-card/80 backdrop-blur-xl border border-white/5 rounded-[2.5rem] shadow-xl relative overflow-hidden group hover:border-red-500/30 transition-colors">
|
||||
<h2 className="text-3xl font-black mb-8 flex items-center gap-4 border-b border-border/50 pb-6 relative z-10">
|
||||
<div className="p-3 bg-red-500/10 rounded-2xl border border-red-500/20 shadow-inner"><HardDrive className="w-8 h-8 text-red-500" /></div>
|
||||
Data Management
|
||||
</h2>
|
||||
<div className="space-y-4 relative z-10">
|
||||
<motion.button whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} className="w-full py-4 bg-secondary/60 hover:bg-secondary border border-white/5 hover:border-red-500/50 text-lg font-black rounded-2xl transition-all flex items-center justify-center gap-3 text-foreground">
|
||||
<Database className="w-5 h-5 text-red-500" /> Export Database
|
||||
</motion.button>
|
||||
<motion.button whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} className="w-full py-4 bg-red-500/10 hover:bg-red-500/20 border border-red-500/20 text-lg font-black rounded-2xl transition-all flex items-center justify-center gap-3 text-red-500">
|
||||
<Trash2 className="w-5 h-5" /> Purge Old Logs
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { ShieldCheck, ShieldAlert, Cpu, Terminal } from 'lucide-react';
|
||||
import { ShieldCheck, ShieldAlert, Cpu, Network, PauseCircle, PlayCircle, Plus } from 'lucide-react';
|
||||
|
||||
const mockSites = [
|
||||
{ id: 1, name: 'eBay US', url: 'ebay.com', status: 'healthy', lag: '240ms', lastScrape: '2s ago' },
|
||||
@ -12,14 +12,16 @@ const mockSites = [
|
||||
|
||||
export default function SitesPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div className="container mx-auto px-6 py-12">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center mb-10 gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">NETWORK_<span className="text-primary">NODES</span></h1>
|
||||
<p className="text-muted-foreground">Manage auction platforms targeted by the scraping engine.</p>
|
||||
<h1 className="text-4xl font-extrabold tracking-tight mb-2 flex items-center gap-3">
|
||||
Network Nodes <span className="text-primary"><Network className="w-8 h-8" /></span>
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-lg">Manage and monitor the auction platforms your agents are scraping.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-4 py-2 bg-card border border-primary text-primary hover:bg-primary hover:text-primary-foreground transition-all rounded font-mono text-sm shadow-[0_0_15px_rgba(0,255,136,0.1)]">
|
||||
<Terminal className="w-4 h-4" /> ADAPT_NEW_SITE
|
||||
<button className="flex items-center gap-2 px-6 py-3 bg-secondary hover:bg-secondary/80 border-2 border-border/50 text-foreground transition-all rounded-full font-bold shadow-sm hover:shadow-md hover:-translate-y-0.5">
|
||||
<Plus className="w-5 h-5" /> Add New Site
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -27,64 +29,79 @@ export default function SitesPage() {
|
||||
{mockSites.map((site, i) => (
|
||||
<motion.div
|
||||
key={site.id}
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className={`p-6 rounded-lg border ${site.status === 'healthy' ? 'bg-card border-border' : 'bg-card border-accent/50'}`}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: i * 0.1, type: "spring" }}
|
||||
className={`p-6 rounded-3xl border-2 shadow-sm hover:shadow-xl transition-all hover:-translate-y-1 ${site.status === 'healthy' ? 'bg-card border-border/50' : 'bg-amber-500/5 border-amber-500/30'}`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
<div>
|
||||
<h3 className="font-bold text-lg">{site.name}</h3>
|
||||
<div className="text-xs font-mono text-muted-foreground">{site.url}</div>
|
||||
<h3 className="font-bold text-xl mb-1">{site.name}</h3>
|
||||
<div className="text-sm font-medium text-muted-foreground bg-secondary/50 px-2 py-0.5 rounded-md inline-block">{site.url}</div>
|
||||
</div>
|
||||
<div className={`p-2 rounded-xl ${site.status === 'healthy' ? 'bg-green-500/10' : 'bg-amber-500/10'}`}>
|
||||
{site.status === 'healthy' ? (
|
||||
<ShieldCheck className="w-6 h-6 text-green-500" />
|
||||
) : (
|
||||
<ShieldAlert className="w-6 h-6 text-amber-500 animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
{site.status === 'healthy' ? (
|
||||
<ShieldCheck className="w-6 h-6 text-primary" />
|
||||
) : (
|
||||
<ShieldAlert className="w-6 h-6 text-accent animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 font-mono text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Latency:</span>
|
||||
<span className={site.status === 'healthy' ? 'text-foreground' : 'text-accent'}>{site.lag}</span>
|
||||
<div className="space-y-4 font-medium text-sm">
|
||||
<div className="flex justify-between items-center p-3 bg-secondary/30 rounded-xl">
|
||||
<span className="text-muted-foreground">Latency</span>
|
||||
<span className={`font-bold ${site.status === 'healthy' ? 'text-foreground' : 'text-amber-500'}`}>{site.lag}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Last Ping:</span>
|
||||
<span>{site.lastScrape}</span>
|
||||
<div className="flex justify-between items-center p-3 bg-secondary/30 rounded-xl">
|
||||
<span className="text-muted-foreground">Last Ping</span>
|
||||
<span className="font-bold">{site.lastScrape}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Selectors:</span>
|
||||
<span className="text-primary">Verified</span>
|
||||
<div className="flex justify-between items-center p-3 bg-secondary/30 rounded-xl">
|
||||
<span className="text-muted-foreground">Selectors</span>
|
||||
<span className="font-bold text-green-500">Verified</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 pt-4 border-t border-border flex gap-2">
|
||||
<button className="flex-1 py-1.5 bg-background border border-border hover:border-primary/50 rounded text-xs transition-colors flex items-center justify-center gap-1">
|
||||
<Cpu className="w-3 h-3" /> Inspect
|
||||
<div className="mt-6 flex gap-3">
|
||||
<button className="flex-1 py-2.5 bg-secondary hover:bg-primary hover:text-primary-foreground rounded-xl text-sm font-bold transition-colors flex items-center justify-center gap-2">
|
||||
<Cpu className="w-4 h-4" /> Inspect
|
||||
</button>
|
||||
<button className="flex-1 py-1.5 bg-background border border-border hover:border-destructive/50 rounded text-xs transition-colors text-muted-foreground hover:text-destructive">
|
||||
Pause
|
||||
<button className="p-2.5 bg-secondary hover:bg-amber-500/10 text-muted-foreground hover:text-amber-500 rounded-xl transition-colors flex items-center justify-center">
|
||||
<PauseCircle className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 p-6 bg-primary/5 border border-primary/20 rounded-lg">
|
||||
<h3 className="font-mono text-primary mb-4 flex items-center gap-2">
|
||||
<Cpu className="w-5 h-5" /> AUTO_ADAPTATION_ENGINE
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-3xl mb-4">
|
||||
Ghost Node can autonomously learn new site structures. Provide a target URL, and the Scout Agent will attempt to generate valid CSS selectors for listings, prices, and countdown timers.
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="mt-12 p-8 bg-gradient-to-br from-primary/10 to-accent/5 border-2 border-primary/20 rounded-3xl"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-3 bg-primary/20 rounded-2xl">
|
||||
<Cpu className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold">Auto-Adaptation Engine</h3>
|
||||
</div>
|
||||
<p className="text-lg text-muted-foreground max-w-3xl mb-6 font-medium">
|
||||
The engine can autonomously learn new site structures. Provide a target URL, and the Scout Agent will attempt to generate valid selectors for listings, prices, and countdown timers.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<input type="text" placeholder="https://example-auction.com" className="flex-1 bg-background border border-border rounded px-4 py-2 font-mono text-sm focus:outline-none focus:border-primary transition-colors" />
|
||||
<button className="px-6 py-2 bg-primary text-primary-foreground font-bold font-mono rounded hover:bg-primary/90 transition-colors">
|
||||
INITIATE_SCAN
|
||||
<div className="flex flex-col sm:flex-row gap-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="https://example-auction.com"
|
||||
className="flex-1 bg-background/80 backdrop-blur-sm border-2 border-border/50 rounded-2xl px-6 py-4 text-lg focus:outline-none focus:border-primary transition-colors shadow-inner"
|
||||
/>
|
||||
<button className="px-8 py-4 bg-primary text-primary-foreground font-bold text-lg rounded-2xl hover:bg-primary/90 transition-all shadow-lg hover:shadow-primary/30 flex items-center justify-center gap-2 hover:-translate-y-0.5 active:translate-y-0">
|
||||
<PlayCircle className="w-6 h-6" />
|
||||
Initiate Scan
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function GlitchText({ text, className = "" }: { text: string; className?: string }) {
|
||||
return (
|
||||
<span
|
||||
className={`glitch-wrapper inline-block ${className}`}
|
||||
data-text={text}
|
||||
>
|
||||
<span className="glitch-text font-bold" data-text={text}>
|
||||
{text}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
106
frontend/components/Hero3D.tsx
Normal file
106
frontend/components/Hero3D.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useState } from "react";
|
||||
import { Canvas, useFrame } from "@react-three/fiber";
|
||||
import {
|
||||
Float,
|
||||
MeshDistortMaterial,
|
||||
Environment,
|
||||
ContactShadows,
|
||||
Lightformer,
|
||||
PerspectiveCamera
|
||||
} from "@react-three/drei";
|
||||
import * as THREE from "three";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
function FloatingShape() {
|
||||
const mesh = useRef<THREE.Mesh>(null);
|
||||
const { theme, resolvedTheme } = useTheme();
|
||||
const [hovered, setHovered] = useState(false);
|
||||
|
||||
const currentTheme = theme === "system" ? resolvedTheme : theme;
|
||||
const isDark = currentTheme === "dark";
|
||||
|
||||
const color = isDark ? "#6366f1" : "#8b5cf6"; // primary or accent colors
|
||||
const emissive = isDark ? "#3730a3" : "#4c1d95";
|
||||
|
||||
// Animate on interaction
|
||||
useFrame((state) => {
|
||||
if (mesh.current) {
|
||||
mesh.current.rotation.x = THREE.MathUtils.lerp(mesh.current.rotation.x, hovered ? state.mouse.y * 0.5 : state.clock.getElapsedTime() * 0.2, 0.1);
|
||||
mesh.current.rotation.y = THREE.MathUtils.lerp(mesh.current.rotation.y, hovered ? state.mouse.x * 0.5 : state.clock.getElapsedTime() * 0.3, 0.1);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Float
|
||||
speed={4}
|
||||
rotationIntensity={1}
|
||||
floatIntensity={2}
|
||||
>
|
||||
<mesh
|
||||
ref={mesh}
|
||||
onPointerOver={() => setHovered(true)}
|
||||
onPointerOut={() => setHovered(false)}
|
||||
scale={hovered ? 1.1 : 1}
|
||||
>
|
||||
<torusKnotGeometry args={[1.2, 0.4, 256, 64]} />
|
||||
<MeshDistortMaterial
|
||||
color={color}
|
||||
envMapIntensity={isDark ? 0.8 : 0.4}
|
||||
clearcoat={0.9}
|
||||
clearcoatRoughness={0.1}
|
||||
metalness={0.9}
|
||||
roughness={0.1}
|
||||
distort={0.4}
|
||||
speed={3}
|
||||
emissive={emissive}
|
||||
emissiveIntensity={0.2}
|
||||
/>
|
||||
</mesh>
|
||||
</Float>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Hero3D() {
|
||||
const { theme, resolvedTheme } = useTheme();
|
||||
const currentTheme = theme === "system" ? resolvedTheme : theme;
|
||||
const isDark = currentTheme === "dark";
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 w-full h-full -z-10 opacity-70">
|
||||
<Canvas shadows camera={{ position: [0, 0, 5], fov: 45 }}>
|
||||
<PerspectiveCamera makeDefault position={[0, 0, 5]} />
|
||||
|
||||
<ambientLight intensity={isDark ? 0.5 : 0.8} />
|
||||
<spotLight
|
||||
position={[10, 10, 10]}
|
||||
angle={0.15}
|
||||
penumbra={1}
|
||||
intensity={isDark ? 1 : 1.5}
|
||||
castShadow
|
||||
/>
|
||||
<pointLight position={[-10, -10, -10]} intensity={0.5} color="#8b5cf6" />
|
||||
|
||||
<FloatingShape />
|
||||
|
||||
<Environment resolution={256}>
|
||||
<group rotation={[-Math.PI / 3, 0, 1]}>
|
||||
<Lightformer form="circle" intensity={4} rotation-x={Math.PI / 2} position={[0, 5, -9]} scale={2} />
|
||||
<Lightformer form="circle" intensity={2} rotation-y={Math.PI / 2} position={[-5, 1, -1]} scale={2} />
|
||||
<Lightformer form="circle" intensity={2} rotation-y={Math.PI / 2} position={[5, 1, -1]} scale={2} />
|
||||
<Lightformer form="circle" intensity={2} rotation-y={-Math.PI / 2} position={[10, 1, 0]} scale={8} />
|
||||
</group>
|
||||
</Environment>
|
||||
|
||||
<ContactShadows
|
||||
position={[0, -2, 0]}
|
||||
opacity={isDark ? 0.4 : 0.2}
|
||||
scale={20}
|
||||
blur={2}
|
||||
far={4.5}
|
||||
/>
|
||||
</Canvas>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { Activity, LayoutDashboard, List, Search, Globe, Settings, TerminalSquare } from 'lucide-react';
|
||||
import GlitchText from './GlitchText';
|
||||
import { LayoutDashboard, List, Search, Globe, Settings, TerminalSquare, Rocket } from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ThemeToggle } from './theme-toggle';
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard },
|
||||
@ -19,41 +19,62 @@ export default function Navbar() {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-40 w-full border-b border-border bg-background/80 backdrop-blur-md">
|
||||
<motion.header
|
||||
initial={{ y: -100, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.8, type: "spring" as const, bounce: 0.4 }}
|
||||
className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/70 backdrop-blur-2xl transition-all shadow-sm"
|
||||
>
|
||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||
<Link href="/" className="flex items-center gap-2 group">
|
||||
<Activity className="h-6 w-6 text-primary group-hover:text-accent transition-colors" />
|
||||
<GlitchText text="BIDWRAITH" className="text-xl tracking-wider text-foreground" />
|
||||
<motion.div
|
||||
whileHover={{ scale: 1.1, rotate: 10 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
className="bg-primary/10 p-2 rounded-xl transition-colors duration-300"
|
||||
>
|
||||
<Rocket className="h-6 w-6 text-primary group-hover:fill-primary/20 transition-all" />
|
||||
</motion.div>
|
||||
<span className="font-bold text-xl tracking-tight text-foreground group-hover:text-primary transition-colors">
|
||||
BidWraith
|
||||
</span>
|
||||
</Link>
|
||||
<nav className="hidden md:flex gap-6">
|
||||
{navItems.map((item) => {
|
||||
<nav className="hidden md:flex gap-1 bg-secondary/30 p-1.5 rounded-full border border-white/5">
|
||||
{navItems.map((item, idx) => {
|
||||
const isActive = pathname.startsWith(item.href);
|
||||
return (
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className={`flex items-center gap-2 text-sm font-medium transition-colors relative ${isActive ? 'text-primary' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
className={`relative flex items-center gap-2 px-4 py-2 rounded-full text-sm font-bold transition-all duration-300 ${
|
||||
isActive ? 'text-primary-foreground shadow-md' : 'text-muted-foreground hover:text-foreground hover:bg-secondary/80'
|
||||
}`}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
{isActive && (
|
||||
<motion.div
|
||||
layoutId="navbar-indicator"
|
||||
className="absolute -bottom-[21px] left-0 right-0 h-0.5 bg-primary shadow-[0_0_8px_rgba(0,255,136,0.8)]"
|
||||
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
|
||||
layoutId="nav-pill"
|
||||
className="absolute inset-0 bg-primary rounded-full -z-10 shadow-[0_0_15px_rgba(139,92,246,0.4)]"
|
||||
transition={{ type: 'spring', stiffness: 400, damping: 30 }}
|
||||
/>
|
||||
)}
|
||||
<item.icon className={`h-4 w-4 ${isActive ? 'text-primary-foreground' : ''}`} />
|
||||
{item.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="hidden lg:flex items-center gap-2 text-xs font-mono text-primary/70">
|
||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse shadow-[0_0_8px_rgba(0,255,136,0.8)]"></span>
|
||||
SYSTEM_ONLINE
|
||||
</div>
|
||||
<ThemeToggle />
|
||||
<motion.div
|
||||
initial={{ scale: 0 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ delay: 0.5, type: "spring" as const }}
|
||||
className="hidden lg:flex items-center gap-2 px-4 py-1.5 rounded-full bg-secondary text-xs font-bold text-primary shadow-inner border border-primary/20"
|
||||
>
|
||||
<span className="w-2.5 h-2.5 rounded-full bg-green-500 animate-pulse shadow-[0_0_10px_rgba(34,197,94,0.8)]"></span>
|
||||
SYSTEM_ACTIVE
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</motion.header>
|
||||
);
|
||||
}
|
||||
|
||||
22
frontend/components/PageTransition.tsx
Normal file
22
frontend/components/PageTransition.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
export default function PageTransition({ children }: { children: ReactNode }) {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={pathname}
|
||||
initial={{ opacity: 0, y: 20, filter: 'blur(10px)' }}
|
||||
animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}
|
||||
exit={{ opacity: 0, y: -20, filter: 'blur(10px)' }}
|
||||
transition={{ duration: 0.4, type: "spring" as const, bounce: 0.2 }}
|
||||
className="flex-1 w-full flex flex-col"
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
11
frontend/components/theme-provider.tsx
Normal file
11
frontend/components/theme-provider.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
||||
20
frontend/components/theme-toggle.tsx
Normal file
20
frontend/components/theme-toggle.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Moon, Sun } from "lucide-react"
|
||||
import { useTheme } from "next-themes"
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
||||
className="relative inline-flex h-9 w-9 items-center justify-center rounded-md bg-secondary/20 hover:bg-secondary/40 text-secondary-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0 text-amber-500" />
|
||||
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100 text-blue-400" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
587
frontend/package-lock.json
generated
587
frontend/package-lock.json
generated
@ -14,14 +14,20 @@
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-toast": "^1.2.15",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.5.0",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@types/three": "^0.183.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"motion": "^12.36.0",
|
||||
"next": "16.1.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"shadcn": "^4.0.6",
|
||||
"three": "^0.183.2",
|
||||
"three-stdlib": "^2.36.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
@ -550,7 +556,6 @@
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
|
||||
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -746,6 +751,12 @@
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dimforge/rapier3d-compat": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
|
||||
"integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
@ -2329,6 +2340,12 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@mediapipe/tasks-vision": {
|
||||
"version": "0.10.17",
|
||||
"resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz",
|
||||
"integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz",
|
||||
@ -2391,6 +2408,18 @@
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@monogrid/gainmap-js": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.4.0.tgz",
|
||||
"integrity": "sha512-2Z0FATFHaoYJ8b+Y4y4Hgfn3FRFwuU5zRrk+9dFWp4uGAdHGqVEdP7HP+gLA3X469KXHmfupJaUbKo1b/aDKIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"promise-worker-transferable": "^1.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">= 0.159.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mswjs/interceptors": {
|
||||
"version": "0.41.3",
|
||||
"resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz",
|
||||
@ -4313,6 +4342,94 @@
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-three/drei": {
|
||||
"version": "10.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.7.7.tgz",
|
||||
"integrity": "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@mediapipe/tasks-vision": "0.10.17",
|
||||
"@monogrid/gainmap-js": "^3.0.6",
|
||||
"@use-gesture/react": "^10.3.1",
|
||||
"camera-controls": "^3.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"detect-gpu": "^5.0.56",
|
||||
"glsl-noise": "^0.0.0",
|
||||
"hls.js": "^1.5.17",
|
||||
"maath": "^0.10.8",
|
||||
"meshline": "^3.3.1",
|
||||
"stats-gl": "^2.2.8",
|
||||
"stats.js": "^0.17.0",
|
||||
"suspend-react": "^0.1.3",
|
||||
"three-mesh-bvh": "^0.8.3",
|
||||
"three-stdlib": "^2.35.6",
|
||||
"troika-three-text": "^0.52.4",
|
||||
"tunnel-rat": "^0.1.2",
|
||||
"use-sync-external-store": "^1.4.0",
|
||||
"utility-types": "^3.11.0",
|
||||
"zustand": "^5.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-three/fiber": "^9.0.0",
|
||||
"react": "^19",
|
||||
"react-dom": "^19",
|
||||
"three": ">=0.159"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-three/fiber": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.5.0.tgz",
|
||||
"integrity": "sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.17.8",
|
||||
"@types/webxr": "*",
|
||||
"base64-js": "^1.5.1",
|
||||
"buffer": "^6.0.3",
|
||||
"its-fine": "^2.0.0",
|
||||
"react-use-measure": "^2.1.7",
|
||||
"scheduler": "^0.27.0",
|
||||
"suspend-react": "^0.1.3",
|
||||
"use-sync-external-store": "^1.4.0",
|
||||
"zustand": "^5.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": ">=43.0",
|
||||
"expo-asset": ">=8.4",
|
||||
"expo-file-system": ">=11.0",
|
||||
"expo-gl": ">=11.0",
|
||||
"react": ">=19 <19.3",
|
||||
"react-dom": ">=19 <19.3",
|
||||
"react-native": ">=0.78",
|
||||
"three": ">=0.156"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"expo": {
|
||||
"optional": true
|
||||
},
|
||||
"expo-asset": {
|
||||
"optional": true
|
||||
},
|
||||
"expo-file-system": {
|
||||
"optional": true
|
||||
},
|
||||
"expo-gl": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
|
||||
@ -5198,6 +5315,12 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@tweenjs/tween.js": {
|
||||
"version": "23.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
|
||||
"integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
@ -5280,6 +5403,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/draco3d": {
|
||||
"version": "1.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz",
|
||||
"integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
@ -5311,11 +5440,16 @@
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
"integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
|
||||
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
@ -5331,18 +5465,54 @@
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-reconciler": {
|
||||
"version": "0.28.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
|
||||
"integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/stats.js": {
|
||||
"version": "0.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
|
||||
"integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/statuses": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz",
|
||||
"integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.183.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz",
|
||||
"integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dimforge/rapier3d-compat": "~0.12.0",
|
||||
"@tweenjs/tween.js": "~23.1.3",
|
||||
"@types/stats.js": "*",
|
||||
"@types/webxr": ">=0.5.17",
|
||||
"@webgpu/types": "*",
|
||||
"fflate": "~0.8.2",
|
||||
"meshoptimizer": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/validate-npm-package-name": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz",
|
||||
"integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/webxr": {
|
||||
"version": "0.5.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
|
||||
"integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz",
|
||||
@ -5907,6 +6077,24 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@use-gesture/core": {
|
||||
"version": "10.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz",
|
||||
"integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@use-gesture/react": {
|
||||
"version": "10.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz",
|
||||
"integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@use-gesture/core": "10.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz",
|
||||
@ -6039,6 +6227,12 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@webgpu/types": {
|
||||
"version": "0.1.69",
|
||||
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz",
|
||||
"integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
@ -6480,6 +6674,26 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz",
|
||||
@ -6496,7 +6710,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
|
||||
"integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"require-from-string": "^2.0.2"
|
||||
@ -6582,6 +6795,30 @@
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bundle-name": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
|
||||
@ -6663,6 +6900,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/camera-controls": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-3.1.2.tgz",
|
||||
"integrity": "sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.0.0",
|
||||
"npm": ">=10.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.126.1"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001777",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz",
|
||||
@ -6965,6 +7215,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"cross-env": "src/bin/cross-env.js",
|
||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.14",
|
||||
"npm": ">=6",
|
||||
"yarn": ">=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@ -7042,7 +7310,6 @@
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/damerau-levenshtein": {
|
||||
@ -7279,6 +7546,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-gpu": {
|
||||
"version": "5.0.70",
|
||||
"resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz",
|
||||
"integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"webgl-constants": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
@ -7337,6 +7613,12 @@
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/draco3d": {
|
||||
"version": "1.5.7",
|
||||
"resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz",
|
||||
"integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@ -8371,6 +8653,12 @@
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
|
||||
@ -8826,6 +9114,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/glsl-noise": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz",
|
||||
"integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
@ -8968,6 +9262,12 @@
|
||||
"hermes-estree": "0.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hls.js": {
|
||||
"version": "1.6.15",
|
||||
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.15.tgz",
|
||||
"integrity": "sha512-E3a5VwgXimGHwpRGV+WxRTKeSp2DW5DI5MWv34ulL3t5UNmyJWCQ1KmLEHbYzcfThfXG8amBL+fCYPneGHC4VA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/hono": {
|
||||
"version": "4.12.7",
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.7.tgz",
|
||||
@ -9062,6 +9362,26 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@ -9071,6 +9391,12 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
@ -9755,6 +10081,18 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/its-fine": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz",
|
||||
"integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react-reconciler": "^0.28.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
@ -9971,6 +10309,15 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
@ -10344,6 +10691,16 @@
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/maath": {
|
||||
"version": "0.10.8",
|
||||
"resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz",
|
||||
"integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/three": ">=0.134.0",
|
||||
"three": ">=0.134.0"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
@ -10406,6 +10763,21 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/meshline": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz",
|
||||
"integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"three": ">=0.137"
|
||||
}
|
||||
},
|
||||
"node_modules/meshoptimizer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz",
|
||||
"integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
@ -10713,6 +11085,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-themes": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
|
||||
"integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/postcss": {
|
||||
"version": "8.4.31",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||
@ -11338,6 +11720,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/potpack": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz",
|
||||
"integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/powershell-utils": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
|
||||
@ -11413,6 +11801,22 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-worker-transferable": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz",
|
||||
"integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"is-promise": "^2.1.0",
|
||||
"lie": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-worker-transferable/node_modules/is-promise": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
|
||||
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prompts": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||
@ -11731,6 +12135,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-use-measure": {
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz",
|
||||
"integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13",
|
||||
"react-dom": ">=16.13"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/recast": {
|
||||
"version": "0.23.11",
|
||||
"resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
|
||||
@ -12495,6 +12914,32 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stats-gl": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz",
|
||||
"integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/three": "*",
|
||||
"three": "^0.170.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/three": "*",
|
||||
"three": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/stats-gl/node_modules/three": {
|
||||
"version": "0.170.0",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz",
|
||||
"integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stats.js": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz",
|
||||
"integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
@ -12819,6 +13264,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/suspend-react": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz",
|
||||
"integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">=17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-tree": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
||||
@ -12869,6 +13323,44 @@
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.183.2",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz",
|
||||
"integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/three-mesh-bvh": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz",
|
||||
"integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"three": ">= 0.159.0"
|
||||
}
|
||||
},
|
||||
"node_modules/three-stdlib": {
|
||||
"version": "2.36.1",
|
||||
"resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.1.tgz",
|
||||
"integrity": "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/draco3d": "^1.4.0",
|
||||
"@types/offscreencanvas": "^2019.6.4",
|
||||
"@types/webxr": "^0.5.2",
|
||||
"draco3d": "^1.4.1",
|
||||
"fflate": "^0.6.9",
|
||||
"potpack": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.128.0"
|
||||
}
|
||||
},
|
||||
"node_modules/three-stdlib/node_modules/fflate": {
|
||||
"version": "0.6.10",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
||||
"integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tiny-invariant": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||
@ -13013,6 +13505,36 @@
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/troika-three-text": {
|
||||
"version": "0.52.4",
|
||||
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz",
|
||||
"integrity": "sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bidi-js": "^1.0.2",
|
||||
"troika-three-utils": "^0.52.4",
|
||||
"troika-worker-utils": "^0.52.0",
|
||||
"webgl-sdf-generator": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": ">=0.125.0"
|
||||
}
|
||||
},
|
||||
"node_modules/troika-three-utils": {
|
||||
"version": "0.52.4",
|
||||
"resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz",
|
||||
"integrity": "sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"three": ">=0.125.0"
|
||||
}
|
||||
},
|
||||
"node_modules/troika-worker-utils": {
|
||||
"version": "0.52.0",
|
||||
"resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz",
|
||||
"integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
||||
@ -13068,6 +13590,43 @@
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel-rat": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz",
|
||||
"integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"zustand": "^4.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-rat/node_modules/zustand": {
|
||||
"version": "4.5.7",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz",
|
||||
"integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"use-sync-external-store": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=16.8",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=16.8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tw-animate-css": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
|
||||
@ -13443,6 +14002,15 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/utility-types": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz",
|
||||
"integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/validate-npm-package-name": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz",
|
||||
@ -13680,6 +14248,17 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webgl-constants": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz",
|
||||
"integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg=="
|
||||
},
|
||||
"node_modules/webgl-sdf-generator": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz",
|
||||
"integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz",
|
||||
|
||||
@ -24,14 +24,20 @@
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-toast": "^1.2.15",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.5.0",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@types/three": "^0.183.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"motion": "^12.36.0",
|
||||
"next": "16.1.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"shadcn": "^4.0.6",
|
||||
"three": "^0.183.2",
|
||||
"three-stdlib": "^2.36.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user