feat(ui3): high-fidelity command center redesign with stage-library layout and unified sidebar
This commit is contained in:
parent
c4622ea0b6
commit
f7bcca7a8e
5 changed files with 208 additions and 158 deletions
1
.beads/bd.sock.startlock
Normal file
1
.beads/bd.sock.startlock
Normal file
|
|
@ -0,0 +1 @@
|
|||
95088
|
||||
|
|
@ -174,35 +174,37 @@ export function ActivityPanel({ issues, collapsed = false }: ActivityPanelProps)
|
|||
|
||||
if (collapsed) {
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4 py-4 h-full bg-black/20">
|
||||
{/* Collapsed Agent Icons */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{agentRoster.slice(0, 5).map(agent => (
|
||||
<div className="flex flex-col items-center gap-6 py-6 h-full bg-black/40 border-l border-white/5 shadow-2xl">
|
||||
{/* Collapsed Agent Icons with ZFC Rings */}
|
||||
<div className="flex flex-col gap-4">
|
||||
{agentRoster.slice(0, 6).map(agent => (
|
||||
<div key={agent.beadId} className="relative group cursor-help" title={`${agent.name} (${agent.status})`}>
|
||||
<Avatar className="h-8 w-8 ring-1 ring-white/10 hover:ring-white/30 transition-all">
|
||||
<AvatarFallback className="text-[10px] bg-white/5">
|
||||
<div className={cn(
|
||||
"absolute -inset-1 rounded-full blur-[2px] transition-opacity duration-500",
|
||||
agent.status === 'active' ? 'bg-emerald-500/20 opacity-100 animate-pulse' :
|
||||
agent.status === 'stale' ? 'bg-amber-500/10 opacity-50' : 'bg-rose-500/20 opacity-100'
|
||||
)} />
|
||||
<Avatar className={cn(
|
||||
"h-9 w-9 ring-2 transition-all duration-300 relative z-10",
|
||||
agent.status === 'active' ? 'ring-emerald-500/40' :
|
||||
agent.status === 'stale' ? 'ring-amber-500/20' : 'ring-rose-500/40'
|
||||
)}>
|
||||
<AvatarFallback className="text-[10px] font-bold bg-[#1a1a1a] text-text-muted">
|
||||
{getInitials(agent.name)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className={cn(
|
||||
"absolute -bottom-0.5 -right-0.5 w-2.5 h-2.5 rounded-full border-2 border-[#1e1e1e]",
|
||||
agent.status === 'active' ? 'bg-emerald-500' :
|
||||
agent.status === 'stale' ? 'bg-amber-500' : 'bg-rose-500'
|
||||
)} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="w-4 h-[1px] bg-white/10" />
|
||||
<div className="w-6 h-[1px] bg-white/10 mx-auto" />
|
||||
|
||||
{/* Mini Activity Dots (Just visual pulse) */}
|
||||
<div className="flex flex-col gap-1">
|
||||
{/* Just show a few recent activity dots as a visual "heartbeat" */}
|
||||
{activities.slice(0, 5).map((act) => (
|
||||
{/* Activity Pulses */}
|
||||
<div className="flex flex-col gap-2 opacity-40">
|
||||
{activities.slice(0, 8).map((act) => (
|
||||
<div key={act.id} className={cn(
|
||||
"w-1.5 h-1.5 rounded-full opacity-50",
|
||||
act.kind === 'created' ? 'bg-emerald-500' : 'bg-cyan-500'
|
||||
"w-1 h-1 rounded-full",
|
||||
act.kind === 'created' ? 'bg-emerald-500 shadow-[0_0_4px_#10b981]' : 'bg-cyan-500 shadow-[0_0_4px_#06b6d4]'
|
||||
)} />
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -211,44 +213,52 @@ export function ActivityPanel({ issues, collapsed = false }: ActivityPanelProps)
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
<div className="flex flex-col h-full bg-[#1a1a1a]/95 backdrop-blur-xl">
|
||||
{/* AGENT ROSTER SECTION */}
|
||||
<div className="flex-shrink-0 p-3 border-b border-border">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-semibold">Agents</h3>
|
||||
<div className="flex gap-2">
|
||||
{activeAgents > 0 && (
|
||||
<Badge variant="default" className="bg-emerald-500/20 text-emerald-400 border-emerald-500/30">
|
||||
{activeAgents} active
|
||||
</Badge>
|
||||
)}
|
||||
{staleAgents > 0 && (
|
||||
<Badge variant="secondary" className="bg-amber-500/20 text-amber-400 border-amber-500/30">
|
||||
{staleAgents} stale
|
||||
</Badge>
|
||||
)}
|
||||
<div className="flex-shrink-0 p-4 border-b border-white/5 bg-white/[0.02]">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse shadow-[0_0_8px_#10b981]" />
|
||||
<h3 className="text-xs font-bold uppercase tracking-[0.2em] text-text-muted">Live Agents</h3>
|
||||
</div>
|
||||
<div className="text-[10px] font-mono text-emerald-500/60 bg-emerald-500/5 px-2 py-0.5 rounded border border-emerald-500/10">
|
||||
{activeAgents} ONLINE
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{agentRoster.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground italic">No active agents</p>
|
||||
<p className="text-xs text-text-muted/40 italic text-center py-4">No agents broadcasting</p>
|
||||
) : (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
{agentRoster.map(agent => (
|
||||
<div
|
||||
key={agent.beadId}
|
||||
className="flex items-center gap-2 px-2 py-1.5 rounded-md bg-muted/50 hover:bg-muted transition-colors"
|
||||
className="group flex items-center gap-3 p-2 rounded-xl bg-white/[0.03] border border-white/5 hover:border-white/10 hover:bg-white/[0.05] transition-all duration-300"
|
||||
>
|
||||
<Avatar className="h-6 w-6">
|
||||
<AvatarFallback className="text-xs">
|
||||
{getInitials(agent.name)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs font-medium">{agent.name}</span>
|
||||
<span className="text-[10px] text-muted-foreground capitalize">
|
||||
{agent.status}
|
||||
</span>
|
||||
<div className="relative">
|
||||
<div className={cn(
|
||||
"absolute -inset-0.5 rounded-full blur-[1px] opacity-0 group-hover:opacity-100 transition-opacity",
|
||||
agent.status === 'active' ? 'bg-emerald-500/30' : 'bg-amber-500/30'
|
||||
)} />
|
||||
<Avatar className="h-8 w-8 relative z-10 ring-1 ring-white/10">
|
||||
<AvatarFallback className="text-[10px] font-bold bg-[#252525]">
|
||||
{getInitials(agent.name)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-col flex-1 min-w-0">
|
||||
<span className="text-xs font-semibold text-text-primary group-hover:text-white transition-colors">{agent.name}</span>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className={cn(
|
||||
"text-[9px] uppercase tracking-wider font-bold",
|
||||
agent.status === 'active' ? 'text-emerald-500' : 'text-amber-500'
|
||||
)}>
|
||||
{agent.status}
|
||||
</span>
|
||||
<span className="text-[9px] text-text-muted/40 font-mono">
|
||||
{agent.lastSeen ? formatRelativeTime(agent.lastSeen) : 'N/A'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -257,62 +267,62 @@ export function ActivityPanel({ issues, collapsed = false }: ActivityPanelProps)
|
|||
</div>
|
||||
|
||||
{/* ACTIVITY FEED SECTION */}
|
||||
<div className="flex-1 min-h-0">
|
||||
<div className="p-3 border-b border-border">
|
||||
<h3 className="text-sm font-semibold">Recent Activity</h3>
|
||||
<div className="flex-1 min-h-0 flex flex-col">
|
||||
<div className="p-4 flex items-center gap-2 border-b border-white/5">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="text-text-muted/60"><path d="M22 12h-4l-3 9L9 3l-3 9H2"></path></svg>
|
||||
<h3 className="text-xs font-bold uppercase tracking-[0.2em] text-text-muted">Telemetry Stream</h3>
|
||||
</div>
|
||||
|
||||
<ScrollArea className="h-[calc(100%-40px)]">
|
||||
<ScrollArea className="flex-1">
|
||||
{isLoading ? (
|
||||
<div className="p-4 text-center text-sm text-muted-foreground">
|
||||
Loading...
|
||||
<div className="p-10 flex flex-col items-center gap-3">
|
||||
<div className="w-4 h-4 border-2 border-teal-500 border-t-transparent rounded-full animate-spin" />
|
||||
<span className="text-[10px] font-mono text-text-muted">SYNCING...</span>
|
||||
</div>
|
||||
) : activities.length === 0 ? (
|
||||
<div className="p-4 text-center text-sm text-muted-foreground">
|
||||
No recent activity
|
||||
<div className="p-10 text-center opacity-30">
|
||||
<p className="text-[10px] font-mono">VOID_STREAM_NULL</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-2">
|
||||
{activities.map((activity, index) => {
|
||||
<div className="p-3 space-y-3">
|
||||
{activities.map((activity) => {
|
||||
const eventInfo = getEventKindInfo(activity.kind);
|
||||
return (
|
||||
<div key={activity.id}>
|
||||
<div className="flex items-start gap-2 py-2 px-1 rounded hover:bg-muted/50 transition-colors">
|
||||
<div className="flex flex-col items-center mt-0.5">
|
||||
<div className={`w-2 h-2 rounded-full ${
|
||||
activity.kind === 'heartbeat' ? 'bg-muted' :
|
||||
activity.kind === 'created' ? 'bg-emerald-500' :
|
||||
activity.kind === 'closed' ? 'bg-amber-500' :
|
||||
'bg-cyan-500'
|
||||
}`} />
|
||||
<div key={activity.id} className="group relative">
|
||||
<div className="absolute -left-3 top-0 bottom-0 w-[1px] bg-white/5 group-hover:bg-white/10 transition-colors" />
|
||||
|
||||
<div className="p-3 rounded-xl bg-white/[0.02] border border-white/5 hover:border-white/10 transition-all duration-300">
|
||||
<div className="flex items-center gap-2 mb-1.5">
|
||||
<div className={cn(
|
||||
"w-1.5 h-1.5 rounded-full shrink-0",
|
||||
activity.kind === 'closed' ? 'bg-amber-500' : 'bg-emerald-500'
|
||||
)} />
|
||||
<span className={cn("text-[10px] font-bold uppercase tracking-wider", eventInfo.color)}>
|
||||
{eventInfo.label}
|
||||
</span>
|
||||
<span className="text-[9px] text-text-muted/30 font-mono ml-auto">
|
||||
{formatRelativeTime(activity.timestamp)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className={`text-xs font-medium ${eventInfo.color}`}>
|
||||
{eventInfo.label}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground font-mono">
|
||||
{activity.beadId}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-foreground line-clamp-1 mt-0.5">
|
||||
{activity.beadTitle}
|
||||
</p>
|
||||
<div className="flex items-center gap-1 mt-0.5">
|
||||
{activity.actor && (
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
{activity.actor}
|
||||
</span>
|
||||
)}
|
||||
<span className="text-[10px] text-muted-foreground">
|
||||
{formatRelativeTime(activity.timestamp)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="text-xs font-medium text-text-secondary leading-snug line-clamp-2 mb-2 group-hover:text-text-primary transition-colors">
|
||||
{activity.beadTitle}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-[10px] font-mono text-teal-500/50">
|
||||
{activity.beadId}
|
||||
</span>
|
||||
{activity.actor && (
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="w-3 h-3 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-[6px] font-bold">
|
||||
{activity.actor[0].toUpperCase()}
|
||||
</div>
|
||||
<span className="text-[9px] text-text-muted/60">{activity.actor}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{index < activities.length - 1 && (
|
||||
<Separator className="my-0.5" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -45,26 +45,24 @@ export function ThreadDrawer({ isOpen, onClose, title, id, items = SAMPLE_ITEMS,
|
|||
|
||||
return (
|
||||
<div
|
||||
className="h-full flex flex-col"
|
||||
className="h-full flex flex-col bg-[#1a1a1a]/95 backdrop-blur-2xl"
|
||||
style={{
|
||||
width: embedded ? '100%' : '24rem', // Full width when embedded
|
||||
backgroundColor: 'var(--color-bg-card)',
|
||||
width: embedded ? '100%' : '26rem',
|
||||
borderLeft: embedded ? 'none' : '1px solid rgba(255, 255, 255, 0.1)',
|
||||
boxShadow: embedded ? 'none' : '-4px 0 20px rgba(0, 0, 0, 0.3)',
|
||||
boxShadow: embedded ? 'none' : '-10px 0 40px rgba(0, 0, 0, 0.5)',
|
||||
}}
|
||||
>
|
||||
{/* Header */}
|
||||
{/* Header: Mission Control Style */}
|
||||
<div
|
||||
className="flex items-center justify-between p-4 border-b flex-shrink-0"
|
||||
style={{ borderColor: 'rgba(255, 255, 255, 0.1)' }}
|
||||
className="flex items-center justify-between p-5 border-b border-white/5 bg-white/[0.02]"
|
||||
>
|
||||
<div className="flex-1 min-w-0 mr-4">
|
||||
<span className="text-teal-400 font-mono text-sm">
|
||||
{id}
|
||||
</span>
|
||||
<div className="flex-1 min-w-0 pr-4">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="w-1 h-1 rounded-full bg-teal-500 animate-ping" />
|
||||
<span className="text-[10px] font-bold font-mono text-teal-500/70 tracking-[0.2em]">MISSION_{id}</span>
|
||||
</div>
|
||||
<h2
|
||||
className="text-sm font-semibold truncate"
|
||||
style={{ color: 'var(--color-text-primary)' }}
|
||||
className="text-base font-bold text-white truncate leading-tight tracking-tight"
|
||||
title={title}
|
||||
>
|
||||
{title}
|
||||
|
|
@ -72,35 +70,31 @@ export function ThreadDrawer({ isOpen, onClose, title, id, items = SAMPLE_ITEMS,
|
|||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-1.5 rounded-md hover:bg-white/10 transition-colors flex-shrink-0"
|
||||
className="p-2 rounded-xl bg-white/5 hover:bg-white/10 border border-white/5 transition-all text-text-muted hover:text-white"
|
||||
aria-label="Close"
|
||||
>
|
||||
<X size={18} style={{ color: 'var(--color-text-muted)' }} />
|
||||
<X size={18} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Thread Content */}
|
||||
<div className="flex-1 overflow-y-auto p-4 custom-scrollbar">
|
||||
<ThreadView items={items} />
|
||||
<div className="flex-1 overflow-y-auto p-5 custom-scrollbar space-y-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<ThreadView items={items} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Compose */}
|
||||
{/* Compose: Technical Input Field */}
|
||||
<div
|
||||
className="p-4 border-t flex-shrink-0"
|
||||
style={{ borderColor: 'rgba(255, 255, 255, 0.1)' }}
|
||||
className="p-5 border-t border-white/5 bg-black/20"
|
||||
>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex items-center gap-3 p-1.5 rounded-2xl bg-[#252525] border border-white/5 shadow-inner group focus-within:border-teal-500/30 transition-all">
|
||||
<input
|
||||
type="text"
|
||||
value={comment}
|
||||
onChange={(e) => setComment(e.target.value)}
|
||||
placeholder="Add a comment..."
|
||||
className="flex-1 px-3 py-2 rounded-md text-sm outline-none focus:ring-1 focus:ring-teal-500/50 transition-all"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-bg-input)',
|
||||
color: 'var(--color-text-primary)',
|
||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
}}
|
||||
placeholder="Transmit message..."
|
||||
className="flex-1 bg-transparent px-3 py-2 text-sm text-white placeholder:text-text-muted/30 outline-none"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && comment.trim()) {
|
||||
setComment('');
|
||||
|
|
@ -108,16 +102,20 @@ export function ThreadDrawer({ isOpen, onClose, title, id, items = SAMPLE_ITEMS,
|
|||
}}
|
||||
/>
|
||||
<button
|
||||
className="p-2 rounded-md hover:opacity-90 transition-opacity"
|
||||
style={{
|
||||
backgroundColor: 'var(--color-accent-green)',
|
||||
color: '#fff',
|
||||
}}
|
||||
className="p-2.5 rounded-xl bg-emerald-500 text-white shadow-[0_0_15px_rgba(16,185,129,0.3)] hover:shadow-[0_0_20px_rgba(16,185,129,0.5)] transition-all active:scale-95 flex-shrink-0"
|
||||
aria-label="Send comment"
|
||||
>
|
||||
<Send size={16} />
|
||||
<Send size={16} fill="currentColor" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-3 flex items-center justify-between px-1">
|
||||
<span className="text-[8px] font-mono text-text-muted/30 uppercase tracking-[0.2em]">Encrypted Channel_Active</span>
|
||||
<div className="flex gap-2">
|
||||
<div className="w-1 h-1 rounded-full bg-white/10" />
|
||||
<div className="w-1 h-1 rounded-full bg-white/10" />
|
||||
<div className="w-1 h-1 rounded-full bg-white/10" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { useMemo } from 'react';
|
|||
import type { BeadIssue } from '../../lib/types';
|
||||
import { buildSocialCards } from '../../lib/social-cards';
|
||||
import { SocialCard } from './social-card';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface SocialPageProps {
|
||||
issues: BeadIssue[];
|
||||
|
|
@ -13,44 +14,84 @@ interface SocialPageProps {
|
|||
|
||||
export function SocialPage({ issues, selectedId, onSelect }: SocialPageProps) {
|
||||
const cards = useMemo(() => buildSocialCards(issues), [issues]);
|
||||
|
||||
const selectedTask = useMemo(() =>
|
||||
cards.find(c => c.id === selectedId) || null,
|
||||
[cards, selectedId]);
|
||||
|
||||
const otherCards = useMemo(() =>
|
||||
cards.filter(c => c.id !== selectedId),
|
||||
[cards, selectedId]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full bg-earthy-gradient overflow-hidden">
|
||||
{/* Top: Card Stream (Restricted Height) */}
|
||||
<div className="flex-none h-[55vh] min-h-[500px] overflow-y-auto custom-scrollbar border-b border-white/5 bg-black/10 shadow-inner">
|
||||
<div className="p-6 md:p-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 max-w-7xl mx-auto">
|
||||
{cards.map((card) => (
|
||||
<SocialCard
|
||||
key={card.id}
|
||||
data={card}
|
||||
selected={selectedId === card.id}
|
||||
onClick={() => onSelect(card.id)}
|
||||
/>
|
||||
))}
|
||||
{cards.length === 0 && (
|
||||
<div className="col-span-full flex flex-col items-center justify-center py-20 text-text-muted opacity-60">
|
||||
<div className="text-4xl mb-4">📭</div>
|
||||
<p>No active tasks found in stream.</p>
|
||||
<div className="h-full flex flex-col bg-[#1a1a1a] overflow-hidden">
|
||||
{/* Background Atmosphere */}
|
||||
<div className="absolute inset-0 bg-earthy-gradient opacity-20 pointer-events-none" />
|
||||
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar relative z-10">
|
||||
<div className="max-w-[1400px] mx-auto p-8 space-y-12">
|
||||
|
||||
{/* STAGE: Featured / Selected Task (Media Player "Now Playing") */}
|
||||
<section className="relative min-h-[400px] flex flex-col justify-center">
|
||||
{selectedTask ? (
|
||||
<div className="animate-in fade-in zoom-in-95 duration-700 ease-out">
|
||||
<div className="mb-8 flex items-center gap-4">
|
||||
<div className="h-[1px] flex-1 bg-gradient-to-r from-transparent via-teal-500/20 to-transparent" />
|
||||
<div className="flex flex-col items-center">
|
||||
<span className="text-[10px] font-bold uppercase tracking-[0.4em] text-teal-500/60 mb-1">Module Active</span>
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-teal-500 shadow-[0_0_12px_#14b8a6]" />
|
||||
</div>
|
||||
<div className="h-[1px] flex-1 bg-gradient-to-r from-transparent via-teal-500/20 to-transparent" />
|
||||
</div>
|
||||
<div className="flex justify-center relative">
|
||||
<div className="absolute inset-0 bg-teal-500/5 blur-[100px] rounded-full scale-150" />
|
||||
<SocialCard
|
||||
data={selectedTask}
|
||||
selected={true}
|
||||
className="w-full max-w-3xl scale-110 shadow-soft-xl border-teal-500/20 ring-1 ring-teal-500/30 relative z-10"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="group relative py-24 rounded-[4rem] bg-gradient-to-b from-white/[0.03] to-transparent border border-white/5 overflow-hidden flex flex-col items-center justify-center transition-all duration-1000">
|
||||
{/* Holographic Ring Effect */}
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[300px] h-[300px] border border-teal-500/10 rounded-full animate-[spin_10s_linear_infinite]" />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[260px] h-[260px] border border-dashed border-white/5 rounded-full animate-[spin_15s_linear_infinite_reverse]" />
|
||||
|
||||
<div className="relative z-10 flex flex-col items-center">
|
||||
<div className="w-16 h-16 rounded-3xl bg-white/5 flex items-center justify-center mb-6 ring-1 ring-white/10 group-hover:ring-teal-500/30 transition-all duration-500">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" className="text-text-muted/40 group-hover:text-teal-500/60 transition-colors">
|
||||
<path d="M12 2v20M2 12h20M12 2a10 10 0 0 1 10 10M12 2a10 10 0 0 0-10 10M12 22a10 10 0 0 0 10-10M12 22a10 10 0 0 1-10-10"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className="text-xl font-bold text-white/20 tracking-widest uppercase mb-2">Initialize Focus</h2>
|
||||
<p className="text-sm text-text-muted/20 font-mono">STANDBY_MODE // AWAITING_INPUT</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Bottom: Conversation Deck (Fills remaining space) */}
|
||||
<div className="flex-1 bg-surface-muted/20 backdrop-blur-xl p-6 flex items-center justify-center relative">
|
||||
{/* Placeholder for Chat Interface */}
|
||||
<div className="text-center space-y-2 max-w-md">
|
||||
<div className="w-12 h-12 rounded-2xl bg-white/5 mx-auto flex items-center justify-center mb-4 ring-1 ring-white/10">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="text-text-muted">
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-text-primary">Conversation Deck</h3>
|
||||
<p className="text-sm text-text-muted/70">Select a task above to open its secure communication channel and activity log.</p>
|
||||
{/* LIBRARY: The Feed (Masonry Grid) */}
|
||||
<section className="space-y-6">
|
||||
<div className="flex items-center justify-between px-4">
|
||||
<h3 className="text-sm font-bold uppercase tracking-[0.2em] text-text-muted/60">Module Library</h3>
|
||||
<div className="text-[10px] text-text-muted/40 font-mono">{otherCards.length} Units Available</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-6 pb-20">
|
||||
{otherCards.map((card) => (
|
||||
<SocialCard
|
||||
key={card.id}
|
||||
data={card}
|
||||
selected={false}
|
||||
onClick={() => onSelect(card.id)}
|
||||
className="hover:scale-[1.02] active:scale-[0.98]"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ export interface UrlState {
|
|||
}
|
||||
|
||||
const DEFAULT_VIEW: ViewType = 'social';
|
||||
const DEFAULT_PANEL: PanelState = 'closed';
|
||||
const DEFAULT_PANEL: PanelState = 'open';
|
||||
const DEFAULT_DRAWER: DrawerState = 'closed';
|
||||
const DEFAULT_GRAPH_TAB: GraphTabType = 'flow';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue