ELNOR REPO READER TEXT MIRROR Original path: Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/DOC20 Workspace Redo/Q_WORKSPACE_V4_1 (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=>,Pin: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=>,Trash:p=>,Settings:p=>,List:p=>,Bell:p=>,Calendar:p=>,Mail:p=>,Zap:p=>,Sun:p=>,Grip: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"}]; // ═══ BLOCK DATA ═══ const initBlocks=[ {id:"b0",type:"bar",icon:"mail",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. Call him today."}, {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's 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. NY probably governs but CA may void it entirely under Bus & Prof Code § 16600."}, {id:"b5",type:"feed",title:"Activity Brief",collapsed:false,sections:[ {key:"elnor",icon:"spark",label:"Elnor",items:[ {text:"Reviewed 3 Henderson depo transcripts — flagged 2 citation issues in Chen depo",time:"5h"}, {text:"Updated Quark patent landscape — 4 new filings",time:"4h"}, {text:"Scanned SEC filings — no new Henderson-relevant 10-K amendments",time:"3h"}, ]}, {key:"calendar",icon:"calendar",label:"Deadlines",items:[ {text:"Expert disclosure deadline — Folb v. City of LA",time:"47d",accent:c.error}, {text:"Henderson MSJ response due",time:"12d",accent:c.warn}, {text:"Danny Christensen engagement call",time:"Tomorrow 2pm"}, ]}, {key:"email",icon:"mail",label:"Email",items:[ {text:"Sparacino — Narayanan agreement redline",time:"Yesterday"}, {text:"Opposing counsel — discovery extension request",time:"2d",accent:c.warn}, ]}, {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 flagged",time:"2h",accent:c.green}, ]}, ]}, {id:"b6",type:"text",content:""}, ]; const feedIcons={spark:,calendar:,mail:,bell:,zap:}; // ═══ MAIN ═══ export default function WorkspaceV4_1(){ const idC=useRef(500);const nid=()=>"x"+(++idC.current); const [browserOpen,setBrowserOpen]=useState(true); const [noteListOpen,setNoteListOpen]=useState(true); const [commentsOpen,setCommentsOpen]=useState(false); const [rightTab,setRightTab]=useState("comments"); 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({});// keyed by taskId const [inserterAt,setInserterAt]=useState(null); // index where + was clicked const [bubbleMenu,setBubbleMenu]=useState(null); const [collapsedFeeds,setCollapsedFeeds]=useState(new Set()); const editorRef=useRef(null); const agent=agents[0];const flash=msg=>setToast(msg); const toggleBlock=(id,field="collapsed")=>setBlocks(p=>p.map(b=>b.id===id?{...b,[field]:!b[field]}:b)); const toggleTask=(blockId,taskId)=>setBlocks(p=>p.map(b=>b.id===blockId?{...b,tasks:b.tasks.map(t=>t.id===taskId?{...t,done:!t.done}:t)}:b)); const toggleSub=(blockId,taskId,subId)=>setBlocks(p=>p.map(b=>b.id===blockId?{...b,tasks:b.tasks.map(t=>t.id===taskId?{...t,sub:t.sub.map(s=>s.id===subId?{...s,done:!s.done}:s)}:t)}:b)); const dismissAlert=id=>setBlocks(p=>p.filter(b=>b.id!==id)); const addThreadReply=(blockId)=>{if(!threadReplyText.trim())return;setBlocks(p=>p.map(b=>b.id===blockId?{...b,messages:[...b.messages,{id:nid(),author:"You",color:c.accentBtn,body:threadReplyText.trim(),time:"now"}]}:b));setThreadReplyId(null);setThreadReplyText("")}; const toggleFeedSection=key=>{const s=new Set(collapsedFeeds);s.has(key)?s.delete(key):s.add(key);setCollapsedFeeds(s)}; const insertBlock=(idx,type)=>{const newId=nid();let block; if(type==="tasks")block={id:newId,type:"tasks",title:"New Task List",collapsed:false,tasks:[]}; else if(type==="feed")block={id:newId,type:"feed",title:"New Feed",collapsed:false,sections:[{key:"custom",icon:"spark",label:"Custom",items:[]}]}; 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",icon:"bell",title:"New notice — click Elnor to configure",accent:c.warn}; else block={id:newId,type:"text",content:""}; setBlocks(p=>{const n=[...p];n.splice(idx,0,block);return n});setInserterAt(null);flash(`${type} block added`)}; const handleMouseUp=useCallback(e=>{if(e.target.closest("[data-bubble]"))return;const sel=window.getSelection();if(!sel||sel.isCollapsed||!sel.toString().trim()){setBubbleMenu(null);return}const text=sel.toString().trim();if(text.length<3)return;const rect=sel.getRangeAt(0).getBoundingClientRect();const er=editorRef.current?.getBoundingClientRect();if(!er)return;setBubbleMenu({x:rect.left-er.left+rect.width/2,y:rect.top-er.top-8,text})},[]); const dismissBubble=()=>{setBubbleMenu(null);window.getSelection()?.removeAllRanges()}; // ─── Block Inserter ─── const BlockInserter=({idx})=>{ const [hover,setHover]=useState(false); return
setHover(true)} onMouseLeave={()=>{if(inserterAt!==idx)setHover(false)}}> {(hover||inserterAt===idx)&&<>
} {inserterAt===idx&&
insertBlock(idx,"text")}>Text insertBlock(idx,"tasks")}>Task List insertBlock(idx,"feed")}>Activity Feed insertBlock(idx,"thread")}>@Elnor Thread insertBlock(idx,"bar")}>Notice / Alert Bar
}
; }; // ─── Drag Handle ─── const DragHandle=()=>
e.currentTarget.style.opacity=0.6} onMouseLeave={e=>e.currentTarget.style.opacity=0.25}>
; // ─── Module Header Bar (for collapsed state) ─── const ModuleBar=({block,icon,count,extra})=>
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",position:"relative"}} onMouseEnter={e=>e.currentTarget.style.borderColor=c.accentBtn+"30"} onMouseLeave={e=>e.currentTarget.style.borderColor=c.borderLight}>
{icon} {block.title} {count!==undefined&&{count}} {extra}
; // ─── Render blocks ─── const renderBlock=(block,idx)=>{ // CONFIGURABLE BAR — generic block with Ask Elnor to configure/update if(block.type==="bar") return
{block.icon==="mail"&&} {block.icon==="bell"&&} {block.icon==="zap"&&} {block.icon==="calendar"&&} {!block.icon&&} {block.title} {block.time&&{block.time}}
; // TEXT if(block.type==="text") return

setBlocks(p=>p.map(b=>b.id===block.id?{...b,content:e.target.textContent}:b))}>{block.content||"Type here… @Elnor to ask, /slash for commands"}

; // 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
} count={`${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}`}}> {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?.length>0&&
{task.sub.map(s=>
toggleSub(block.id,task.id,s.id)} style={{width:13,height:13,accentColor:c.accentBtn}}/> {s.text}
)}
flash("@Elnor…")}>@Elnor Subtask flash(task.link?`Open "${task.link}"`:"Link note…")}>{task.link?"Open":"Link"}
}
)} {/* Add task */}
{if(e.target.textContent==="Add task…")e.target.textContent=""}} onBlur={e=>{if(!e.target.textContent.trim())e.target.textContent="Add task…"}}>Add task…
{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
} count={`${totalItems} items`} extra={● live}/>
; return
toggleBlock(block.id)} style={{display:"flex",alignItems:"center",gap:6,padding:"7px 10px",backgroundColor:c.bgPanelAlt,cursor:"pointer",borderBottom:`1px solid ${c.borderLight}`}}> {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",position:"relative"}} onMouseEnter={e=>e.currentTarget.style.borderColor=c.accentBtn+"30"} onMouseLeave={e=>e.currentTarget.style.borderColor=c.borderLight}> 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?