ELNOR REPO READER TEXT MIRROR Original path: Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/DOC20 Workspace Redo/Q_WORKSPACE_V5_1.jsx Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- import { useState, useRef, useCallback, useEffect } from "react"; const font={sans:"'Söhne','Helvetica Neue',-apple-system,BlinkMacSystemFont,sans-serif"}; const R={sm:"6px",md:"10px",full:"9999px"}; const c={bgApp:"#F8F8F6",bgPanel:"#FFFFFF",bgPanelAlt:"#F9FAFB",bgCard:"#FFFFFF",bgInput:"#EFF1F3",bgSidebar:"#131820",textPri:"#1A1D21",textSec:"#5E6570",textTer:"#8B919A",accentBtn:"#31588c",warn:"#D97706",error:"#B04040",border:"#E0E2E5",borderLight:"#ECEEF0",green:"#2E8B57",agentAv:"#a1a7aa",borderDark:"#263040"}; const Ic=({d,size=18,color,sw=1.75})=>; const I={Plus:p=>,X:p=>,Check:p=>,Spark:p=>,MsgCircle:p=>,ChevD:p=>,ChevR:p=>,Search:p=>,Maximize:p=>,Save:p=>,Copy:p=>,Link:p=>,Eye:p=>,Edit:p=>,Undo:p=>,Redo:p=>,Folder:p=>,FileText:p=>,Settings:p=>,List:p=>,Bell:p=>,Calendar:p=>,Mail:p=>,Zap:p=>,Sun:p=>,Grip:p=>,Grid:p=>,}; const Dot=({color,size=8})=>; const Btn=({children,primary,ghost,small,onClick,disabled,style:s})=>; const Av=({letter,color,size=20})=>
{letter}
; const TBtn=({icon,title,active,onClick,label,dropdown})=>; const Sep=()=>
; const Toast=({msg,onDone})=>{useEffect(()=>{const t=setTimeout(onDone,2200);return()=>clearTimeout(t)},[onDone]);return
{msg}
}; const DItem=({children,onClick,active})=>; const agents=[{name:"Elnor",color:c.agentAv,letter:"E"}]; // Feed presets library const feedPresets=[ {id:"fp1",name:"System Activity",icon:"spark",desc:"Agent completions, chain results, memory updates",category:"system",cost:false}, {id:"fp2",name:"System Notices",icon:"bell",desc:"Errors, warnings, sync issues, re-auth needed",category:"system",cost:false}, {id:"fp3",name:"Gate Approvals",icon:"check",desc:"Pending chain gates and approval requests",category:"system",cost:false}, {id:"fp4",name:"Active Operations",icon:"zap",desc:"Running agents, chains, and tasks",category:"system",cost:false}, {id:"fp5",name:"Morning Summary",icon:"sun",desc:"Daily briefing from Elnor — overnight activity, priorities",category:"agent",cost:true}, {id:"fp6",name:"Email Watch",icon:"mail",desc:"Flag important emails per your criteria",category:"agent",cost:true}, {id:"fp7",name:"Deadline Tracker",icon:"calendar",desc:"Calendar deadlines from Outlook integration",category:"agent",cost:true}, ]; // Block data const initBlocks=[ {id:"b00",type:"text",content:""}, {id:"b0",type:"bar",title:"Email from Sparacino received — Narayanan agreement redline",time:"2:15 PM",accent:c.accentBtn}, {id:"b1",type:"text",content:"Quick note: need to confirm with Danny that he's available for the May trial week before filing the expert disclosure."}, {id:"b2",type:"tasks",title:"To Do",collapsed:false,tasks:[ {id:"t1",text:"Draft expert disclosure for Christensen",done:false,due:"Apr 4",link:"Expert Depo Prep",sub:[{id:"s1",text:"Pull Christensen CV",done:true},{id:"s2",text:"List opinions to be offered",done:false},{id:"s3",text:"Identify documents reviewed",done:false}]}, {id:"t2",text:"Review Henderson MSJ brief — Elnor tracked changes",done:false,due:"Mar 20",link:"Henderson Discovery Priorities"}, {id:"t3",text:"Respond to Sparacino re: Narayanan agreement",done:false,due:"Mar 19"}, {id:"t4",text:"Follow up: opposing counsel on discovery extension",done:false,due:"Mar 19"}, {id:"t5",text:"Review Quark patent analysis — new filings",done:false,link:"Quark Patent Analysis"}, {id:"t6",text:"File Folb trial exhibit list",done:true,due:"Mar 17"}, ]}, {id:"b3",type:"thread",collapsed:false,contextQuote:"opposing counsel on discovery extension",messages:[ {id:"m1",author:"You",color:c.accentBtn,body:"@Elnor draft a response declining the extension, cite the scheduling order deadline and the prejudice from further delay",time:"45m"}, {id:"m2",author:"Elnor",color:c.agentAv,body:"Draft ready. Key points: scheduling order set discovery cutoff March 28, extension would prejudice plaintiff's expert disclosure timeline, defendant has had 4 months to complete discovery. Want me to open it in a new note or paste below?",time:"40m"}, ]}, {id:"b4",type:"text",content:"Call with Sparacino re: Narayanan — need to confirm NY vs CA choice of law for the restrictive covenant."}, {id:"b5",type:"feed",title:"Activity Brief",collapsed:false,preset:"fp1",sections:[ {key:"elnor",icon:"spark",label:"Elnor",items:[ {text:"Reviewed 3 Henderson depo transcripts — flagged 2 citation issues",time:"5h"},{text:"Updated Quark patent landscape — 4 new filings",time:"4h"},{text:"Scanned SEC filings — no Henderson-relevant amendments",time:"3h"}, ]}, {key:"system",icon:"bell",label:"System",items:[ {text:"OneDrive sync paused — re-auth needed",time:"6h",accent:c.warn},{text:"DOC15 red-team review completed — 3 findings",time:"2h",accent:c.green}, ]}, ]}, {id:"b6",type:"text",content:""}, ]; const feedIcons={spark:,bell:,check:,zap:,sun:,mail:,calendar:}; export default function WorkspaceV5(){ const idC=useRef(500);const nid=()=>"x"+(++idC.current); const [browserOpen,setBrowserOpen]=useState(false); const [commentsOpen,setCommentsOpen]=useState(false); const [rightTab,setRightTab]=useState("comments"); const [showMarkup,setShowMarkup]=useState(true); const [findBar,setFindBar]=useState(false); const [fullScreen,setFullScreen]=useState(false); const [openDrop,setOpenDrop]=useState(null); const [toast,setToast]=useState(null); const [blocks,setBlocks]=useState(initBlocks); const [expandedTask,setExpandedTask]=useState(null); const [threadReplyId,setThreadReplyId]=useState(null); const [threadReplyText,setThreadReplyText]=useState(""); const [newTaskText,setNewTaskText]=useState(""); const [newSubText,setNewSubText]=useState({}); const [collapsedFeeds,setCollapsedFeeds]=useState(new Set()); const [editingTitle,setEditingTitle]=useState(null); // Module picker state const [pickerOpen,setPickerOpen]=useState(false); const [pickerStep,setPickerStep]=useState("choose"); // "choose" | "feed_presets" | "feed_custom" const [pickerTab,setPickerTab]=useState("system"); const [customName,setCustomName]=useState(""); const [customInstruction,setCustomInstruction]=useState(""); const editorRef=useRef(null);const agent=agents[0];const flash=msg=>setToast(msg); const toggleBlock=(id)=>setBlocks(p=>p.map(b=>b.id===id?{...b,collapsed:!b.collapsed}:b)); const toggleTask=(bid,tid)=>setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,done:!t.done}:t)}:b)); const toggleSub=(bid,tid,sid)=>setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,sub:t.sub.map(s=>s.id===sid?{...s,done:!s.done}:s)}:t)}:b)); const deleteBlock=id=>setBlocks(p=>p.filter(b=>b.id!==id)); const toggleFeedSection=key=>{const s=new Set(collapsedFeeds);s.has(key)?s.delete(key):s.add(key);setCollapsedFeeds(s)}; const addTask=(bid,text)=>{if(!text.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:[...b.tasks,{id:nid(),text:text.trim(),done:false,sub:[]}]}:b));setNewTaskText("")}; const addSubtask=(bid,tid,text)=>{if(!text.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,tasks:b.tasks.map(t=>t.id===tid?{...t,sub:[...t.sub,{id:nid(),text:text.trim(),done:false}]}:t)}:b));setNewSubText(p=>({...p,[tid]:""}))}; const addThreadReply=(bid)=>{if(!threadReplyText.trim())return;setBlocks(p=>p.map(b=>b.id===bid?{...b,messages:[...b.messages,{id:nid(),author:"You",color:c.accentBtn,body:threadReplyText.trim(),time:"now"}]}:b));setThreadReplyId(null);setThreadReplyText("")}; // Insert block at end (toolbar button inserts at cursor position in real impl) const insertBlock=(type,preset)=>{ const newId=nid();let block; if(type==="tasks")block={id:newId,type:"tasks",title:"New Task List",collapsed:false,tasks:[]}; else if(type==="feed"){ const p=preset||{name:"Custom Feed",sections:[]}; block={id:newId,type:"feed",title:p.name,collapsed:false,preset:p.id,sections: p.id==="fp1"?[{key:"activity",icon:"spark",label:"Activity",items:[{text:"Waiting for events…",time:"now"}]}]: p.id==="fp2"?[{key:"notices",icon:"bell",label:"Notices",items:[{text:"No active notices",time:"now"}]}]: p.id==="fp5"?[{key:"morning",icon:"sun",label:"Summary",items:[{text:"Generating morning brief…",time:"now"}]}]: [{key:"custom",icon:"spark",label:p.name,items:[{text:"Configure this feed via the gear icon or @Elnor",time:"now"}]}] }; } else if(type==="thread")block={id:newId,type:"thread",collapsed:false,contextQuote:"",messages:[{id:nid(),author:"You",color:c.accentBtn,body:"@Elnor ",time:"now"}]}; else if(type==="bar")block={id:newId,type:"bar",title:"New notice — click Elnor to configure",accent:c.warn}; else return; setBlocks(p=>{ // Simulate inserting at cursor — in real Tiptap, inserts at cursor position // In mockup, insert before the last text block (simulates typing position) const lastTextIdx=p.map((b,i)=>b.type==="text"?i:-1).filter(i=>i>=0).pop(); const pos=lastTextIdx!==undefined?lastTextIdx:p.length; return [...p.slice(0,pos),block,...p.slice(pos)]; }); setPickerOpen(false);setPickerStep("choose"); flash(`${type==="feed"?(preset?.name||"Feed"):type} block added`); }; const DragHandle=()=>
e.currentTarget.style.opacity=0.55} onMouseLeave={e=>e.currentTarget.style.opacity=0.18}>
; const renderBlock=(block)=>{ // BAR if(block.type==="bar") return
{block.title} {block.time&&{block.time}}
; // TEXT if(block.type==="text") return
{const d=e.currentTarget.querySelector("[data-del]");if(d)d.style.opacity=0.4}} onMouseLeave={e=>{const d=e.currentTarget.querySelector("[data-del]");if(d)d.style.opacity=0}}>

{block.content||"Type here… @Elnor to ask, /todo /feed /ask for modules"}

; // TASKS if(block.type==="tasks"){ const active=block.tasks.filter(t=>!t.done);const done=block.tasks.filter(t=>t.done); if(block.collapsed) return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}>{block.title}{active.length} open
; return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",backgroundColor:c.bgPanelAlt,cursor:"pointer",borderBottom:`1px solid ${c.borderLight}`}}> {editingTitle===block.id?{setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}} onKeyDown={e=>{if(e.key==="Enter"){setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}if(e.key==="Escape")setEditingTitle(null)}} onClick={e=>e.stopPropagation()} style={{flex:1,fontSize:12.5,fontWeight:700,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"1px 6px",outline:"none",fontFamily:font.sans,backgroundColor:c.bgCard}}/> :{e.stopPropagation();setEditingTitle(block.id)}}>{block.title}} {active.length} open
{active.map(task=>
setExpandedTask(expandedTask===task.id?null:task.id)}> toggleTask(block.id,task.id)} onClick={e=>e.stopPropagation()} style={{width:15,height:15,accentColor:c.accentBtn,flexShrink:0}}/> {task.text}
{task.due&&{task.due}} {task.link&&{e.stopPropagation();flash(`Open "${task.link}"`)}}>Note} {task.sub?.length>0&&{task.sub.filter(s=>s.done).length}/{task.sub.length}}
{expandedTask===task.id&&
{task.sub?.map(s=>
toggleSub(block.id,task.id,s.id)} style={{width:13,height:13,accentColor:c.accentBtn}}/> {s.text}
)}
setNewSubText(p=>({...p,[task.id]:e.target.value}))} placeholder="Add subtask…" onKeyDown={e=>{if(e.key==="Enter")addSubtask(block.id,task.id,newSubText[task.id]||"")}} style={{flex:1,border:"none",borderBottom:`1px solid ${c.borderLight}`,outline:"none",fontSize:12,fontFamily:font.sans,color:c.textPri,backgroundColor:"transparent",padding:"2px 0"}}/>
flash("@Elnor…")}>@Elnor flash(task.link?`Open "${task.link}"`:"Link note…")}>{task.link?"Open Note":"Link Note"}
}
)}
setNewTaskText(e.target.value)} placeholder="Add task…" onKeyDown={e=>{if(e.key==="Enter")addTask(block.id,newTaskText)}} style={{flex:1,border:"none",borderBottom:`1px solid ${c.borderLight}`,outline:"none",fontSize:13.5,fontFamily:font.sans,color:c.textPri,backgroundColor:"transparent",padding:"2px 0"}}/>
{done.length>0&&
Done ({done.length}) {done.map(t=>
toggleTask(block.id,t.id)} style={{width:14,height:14,accentColor:c.accentBtn}}/>{t.text}
)}
}
; } // FEED if(block.type==="feed"){ const totalItems=block.sections.reduce((a,s)=>a+s.items.length,0); if(block.collapsed) return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}>{block.title}● live{totalItems}
; return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",backgroundColor:c.bgPanelAlt,cursor:"pointer",borderBottom:`1px solid ${c.borderLight}`}}> {editingTitle===block.id?{setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}} onKeyDown={e=>{if(e.key==="Enter"){setBlocks(p=>p.map(b=>b.id===block.id?{...b,title:e.target.value||block.title}:b));setEditingTitle(null)}if(e.key==="Escape")setEditingTitle(null)}} onClick={e=>e.stopPropagation()} style={{flex:1,fontSize:12.5,fontWeight:700,border:`1px solid ${c.accentBtn}40`,borderRadius:3,padding:"1px 6px",outline:"none",fontFamily:font.sans,backgroundColor:c.bgCard}}/> :{e.stopPropagation();setEditingTitle(block.id)}}>{block.title}} ● auto-updating {totalItems}
{block.sections.map(sec=>
toggleFeedSection(sec.key)} style={{display:"flex",alignItems:"center",gap:5,padding:"3px 4px",cursor:"pointer"}}>
{feedIcons[sec.icon]||}{sec.label}({sec.items.length})
{!collapsedFeeds.has(sec.key)&&sec.items.map((item,i)=>
{item.accent&&} {item.text} {item.time}
)}
)}
; } // THREAD if(block.type==="thread"){ if(block.collapsed) return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"6px 10px",borderRadius:R.sm,border:`1px solid ${c.borderLight}`,backgroundColor:c.bgPanelAlt,cursor:"pointer"}}>Elnor · {block.messages.length} messages{block.messages[block.messages.length-1]?.time}
; return
toggleBlock(block.id)} style={{padding:"5px 12px",display:"flex",alignItems:"center",gap:6,cursor:"pointer",backgroundColor:c.accentBtn+"06",borderBottom:`1px solid ${c.accentBtn}15`}}> Thread · {block.messages.length} {block.contextQuote&&re: "{block.contextQuote}"}
{block.messages.map((msg,i)=>
{msg.author}{msg.time}{msg.author==="You"&&<>editdelete}
{msg.body}
)} {threadReplyId===block.id?