ELNOR REPO READER TEXT MIRROR Original path: Design Mockups/Archived Mockups/DOC20 Mockups and Design/DOC20 Archived Mockups/Q_UNIFIED_WORKSPACE_V3.jsx Source repo: /Users/OpenClaw1/Elnor/Elnor Specs Git branch: main Git commit: dbaa25962edc11ab30e8d4ca1715f9ae5bf77331 Generated: 2026-06-09T01:23:58.539Z --- import { useState, useRef, useEffect, useMemo, useCallback } 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",neutral:"#6B7280",agentAv:"#a1a7aa",borderDark:"#263040",purple:"#7C3AED",incBg:"#2A1F3D",incBorder:"#3d2e5c",incText:"#a78bfa"}; const Ic=({d,size=18,color,sw=1.75})=>; const I={Search:p=>,Plus:p=>,ChevR:p=>,ChevD:p=>,Pin:p=>,Folder:p=>,File:p=>,X:p=>,Check:p=>,Save:p=>,Copy:p=>,Link:p=>,Maximize:p=>,Spark:p=>,MsgCircle:p=>,Undo:p=>,Redo:p=>,Eye:p=>,Edit:p=>,FileText:p=>,ExtLink:p=>,Printer:p=>,Clock:p=>,ArrowL:p=>,ArrowR:p=>,Refresh:p=>,Star:p=>,Lock:p=>,Book:p=>,Scissors:p=>,Globe:p=>,Home:p=>,Settings:p=>,Inbox:p=>,Grid:p=>,Download:p=>,List:p=>,Bell:p=>,Zap:p=>,Sun:p=>,Mail:p=>,Calendar:p=>,Mask:p=>,Trash:p=>}; const Dot=({color,size=8})=>; const Toast=({msg,onDone})=>{useEffect(()=>{const t=setTimeout(onDone,2200);return()=>clearTimeout(t)},[onDone]);return
{msg}
}; const TBtn=({icon,title,active,onClick,label,dropdown})=>; const Sep=()=>
; const Btn=({children,primary,ghost,small,onClick,disabled,style:s})=>; const Av=({letter,color,size=20})=>
{letter}
; const DItem=({children,onClick,active,disabled})=>; const Radio=({selected,label,desc,onClick,disabled})=>; // ═══ DATA ═══ const agentName="Elnor"; const agents=[{name:"Elnor",color:c.agentAv,letter:"E"},{name:"Scout",color:"#5B5F97",letter:"S"}]; const chats=[{name:"Paramount damages strategy",color:c.accentBtn,origin:true},{name:"Brooge loss causation",color:c.green},{name:"New chat",color:c.textTer}]; const typeColors={Note:c.accentBtn,Chat:c.green,Doc:c.textTer,Task:c.warn,Artifact:"#8B5CF6",Prompt:"#D97706",Preset:c.neutral,Skill:c.neutral,Agent:"#5B5F97",Overlay:"#9333EA",Template:"#0891B2",Chain:"#DC2626",Memory:c.green,Room:"#6366F1",Bookmark:c.warn}; const projects=[{id:1,name:"Paramount v. City of LA",color:"#31588c"},{id:2,name:"White v. Brooge Energy",color:"#2E8B57"},{id:3,name:"Internal Ops",color:"#8B7355"}]; const collections=[{name:"Priority",color:"#B04040"},{name:"Research",color:"#2E8B57"},{name:"Draft",color:"#D97706"},{name:"Archive",color:"#6B7280"},{name:"Urgent",color:"#9E5E5E"},{name:"Reference",color:"#5B5F97"}]; const scopeFams=["Collection","Project","Bucket","Places","Folders","Saved Views"]; const typeChips=["Document","Chat","Preset","Skill","Task","Agent","Overlay","Note","Artifact","Prompt","Template","Chain","Memory","Room","Bookmark"]; const sortOptions=["Modified","Alphabetical","Type","Created","Running"]; const initFolders=[{id:"f1",title:"Paramount Case",parent:null},{id:"f2",title:"Expert Reports",parent:"f1"},{id:"f3",title:"Motion Practice",parent:"f1"},{id:"f4",title:"Brooge Research",parent:null},{id:"f5",title:"Reference Materials",parent:null}]; const noteFolders=[{id:"nf1",title:"Case Notes",parent:null},{id:"nf2",title:"Paramount",parent:"nf1"},{id:"nf3",title:"Brooge",parent:"nf1"},{id:"nf4",title:"Session Notes",parent:null}]; const bookmarkFolders=[{id:"bm1",title:"Legal Research",items:["PACER — CACD","Westlaw","CM/ECF Login"]},{id:"bm2",title:"Clients",items:["Paramount SharePoint"]},{id:"bm3",title:"Reference",items:["Cal. Rules of Court","LAMC Full Text"]}]; const noteItems=[{id:"n1",title:"Today — April 4, 2026",mod:"2h",pinned:true,folder:"nf2"},{id:"n2",title:"Trial Prep Checklist",mod:"4h",pinned:true,folder:"nf2"},{id:"n3",title:"Danny Christensen Engagement",mod:"3d",folder:"nf2"},{id:"n4",title:"Brooge Loss Causation Analysis",mod:"1d",folder:"nf3"},{id:"n5",title:"Expert Depo Prep — Sanli",mod:"1w",folder:"nf2"},{id:"n6",title:"Clips: 4.3-1",mod:"1d",folder:"nf4"},{id:"n7",title:"Clips: 4.4-1",mod:"2h",folder:"nf4"}]; const allItems=[{type:"Note",title:"Today — April 4, 2026",time:"2h",pin:true,proj:1,cols:["Priority"]},{type:"Note",title:"Trial Prep Checklist",time:"4h",pin:true,proj:1,cols:[]},{type:"Doc",title:"Sanli Expert Report.pdf",time:"10m",proj:1,cols:["Priority"]},{type:"Artifact",title:"Motion in Limine No. 3",time:"1d",proj:1,cols:[]},{type:"Doc",title:"Christensen_CV.pdf",time:"1d",proj:1,cols:["Reference"]},{type:"Note",title:"Brooge Loss Causation Analysis",time:"1d",proj:2,cols:["Research"]},{type:"Task",title:"Review Sanli depo transcript",time:"2h",proj:1,st:"running",cols:[]},{type:"Chat",title:"Paramount damages strategy",time:"1h",proj:1,cols:["Priority"]},{type:"Artifact",title:"Fair Fund Analysis — Brooge",time:"2h",proj:2,cols:[]},{type:"Doc",title:"BC587659_MIL_3.pdf",time:"2d",proj:1,cols:[]},{type:"Task",title:"Draft Paramount trial brief §III",time:"4h",proj:1,st:"waiting",cols:["Priority"]},{type:"Prompt",title:"Expert Analysis Template",time:"1w",proj:null,cols:[]},{type:"Preset",title:"Legal Brief Review",time:"1w",proj:null,cols:[]},{type:"Doc",title:"Standing_Orders.md",time:"3d",proj:null,cols:["Reference"]}]; const timeVal=t=>{if(t.includes("m"))return parseInt(t);if(t.includes("h"))return parseInt(t)*60;if(t.includes("d"))return parseInt(t)*1440;if(t.includes("w"))return parseInt(t)*10080;return 99999}; const tabColors={note:"#31588c",doc:"#2E8B57",web:"#D97706",clips:"#7C3AED"}; const groupColors=["#EF4444","#F97316","#22C55E","#3B82F6","#8B5CF6","#6B7280"]; const feedPresets=[{id:"fp1",name:"System Activity",icon:"spark",desc:"Agent completions, chain results, memory updates"},{id:"fp2",name:"System Notices",icon:"bell",desc:"Errors, warnings, sync issues"},{id:"fp5",name:"Morning Summary",icon:"sun",desc:"Daily briefing — overnight activity, priorities"}]; const feedIcons={spark:,bell:,sun:}; const initTabs=[ {id:"t1",type:"note",icon:"📝",title:"Today — April 4, 2026",color:tabColors.note,group:"g1"}, {id:"t2",type:"doc",icon:"📄",title:"Sanli Expert Report.pdf",color:tabColors.doc}, {id:"t3",type:"web",icon:"🌐",title:"Paramount MIL — PACER",color:tabColors.web,group:"g1"}, {id:"t4",type:"clips",icon:"✂️",title:"Clips: 4.4-1",color:tabColors.clips}, ]; const initGroups=[{id:"g1",label:"Paramount Research",color:"#22C55E",collapsed:false}]; const initComments=[ {id:"c1",author:"You",color:c.accentBtn,body:"Verify Sanli's discount rate — 18% seems unsupported.",time:"10m ago",status:"open",anchor:"discount rate of 18%",replies:[{id:"r1",author:agentName,color:c.agentAv,body:"Found 3 comparable transactions: average 8-12%. Sanli's 18% is an outlier.",time:"5m ago"}]}, {id:"c2",author:"You",color:c.accentBtn,body:"Cross-ref with Christensen's methodology.",time:"8m ago",status:"open",anchor:"willing buyer-willing seller",replies:[]}, {id:"c3",author:agentName,color:c.agentAv,body:"Sargon gatekeeper standard fully briefed in §II.",time:"6m ago",status:"resolved",anchor:"Legal Standard",replies:[]}, ]; // ═══ MAIN COMPONENT ═══ export default function UnifiedWorkspaceV3(){ const [tabs,setTabs]=useState(initTabs); const [tabGroups,setTabGroups]=useState(initGroups); const [activeTabId,setActiveTabId]=useState("t1"); const [tabContextMenu,setTabContextMenu]=useState(null); const [newTabDrop,setNewTabDrop]=useState(false); const [dragTabId,setDragTabId]=useState(null); const [groupColorPicker,setGroupColorPicker]=useState(null); // Browser column const [browserOpen,setBrowserOpen]=useState(true); const [browserWidth,setBrowserWidth]=useState(280); const [browserMode,setBrowserMode]=useState("browser"); // browser|notes|docs|bookmarks const [activeScope,setActiveScope]=useState(null); const [activeProjIdx,setActiveProjIdx]=useState(0);const [noProject,setNoProject]=useState(false); const [activeTypes,setActiveTypes]=useState(new Set()); const [selectedCollections,setSelectedCollections]=useState(new Set()); const [splitterPos,setSplitterPos]=useState(110); const [selectedIdx,setSelectedIdx]=useState(null); const [folders]=useState(initFolders); const [expandedFolders,setExpandedFolders]=useState(new Set(["f1"])); const [activeFolder,setActiveFolder]=useState(null); const [searchMode,setSearchMode]=useState("this_view"); const [sortKey,setSortKey]=useState("Modified");const [sortDrop,setSortDrop]=useState(false); const [folderOverlay,setFolderOverlay]=useState(false); const [dropTarget,setDropTarget]=useState(null);const [dragItem,setDragItem]=useState(null); const [noteExpandedFolders,setNoteExpandedFolders]=useState(new Set(["nf1"])); const [bmExpanded,setBmExpanded]=useState(new Set(["bm1"])); const [selectedNote,setSelectedNote]=useState("n1"); // Right panel const [rightOpen,setRightOpen]=useState(false);const [rightTab,setRightTab]=useState("comments"); const [rightWidth,setRightWidth]=useState(290); const [comments,setComments]=useState(initComments); const [activeComment,setActiveComment]=useState(null); const [replyingTo,setReplyingTo]=useState(null);const [replyText,setReplyText]=useState(""); const [newCm,setNewCm]=useState(null);const [newCmText,setNewCmText]=useState(""); // Send to Agent state (full from notes mockup) const [agentIdx,setAgentIdx]=useState(0);const [agentDrop,setAgentDrop]=useState(false); const [chatIdx,setChatIdx]=useState(0);const [chatDrop,setChatDrop]=useState(false); const [sendScope,setSendScope]=useState("full"); const [selectedCmIds,setSelectedCmIds]=useState(new Set()); const [outputMode,setOutputMode]=useState("respond_in_chat"); const [subMode,setSubMode]=useState("tracked_changes"); const [instruction,setInstruction]=useState(""); // Content state const [showMarkup,setShowMarkup]=useState(true);const [findBar,setFindBar]=useState(false); const [pinned,setPinned]=useState(false);const [bookmarked,setBookmarked]=useState(false); const [readerMode,setReaderMode]=useState(false);const [openDrop,setOpenDrop]=useState(null); const [bubbleMenu,setBubbleMenu]=useState(null); const [pickerOpen,setPickerOpen]=useState(false);const [pickerStep,setPickerStep]=useState("choose"); const [pickerTab,setPickerTab]=useState("system"); const [showDownloads,setShowDownloads]=useState(false); // Session const [sessionMinutes,setSessionMinutes]=useState(47);const [clipsCount,setClipsCount]=useState(2); const [toast,setToast]=useState(null); const editorRef=useRef(null);const cmRef=useRef(null); const flash=msg=>setToast(msg); const agent=agents[agentIdx]; const activeTab=tabs.find(t=>t.id===activeTabId)||tabs[0]; const openC=comments.filter(x=>x.status==="open"); const resolvedC=comments.filter(x=>x.status==="resolved"); const isNoteType=activeTab.type==="note"||activeTab.type==="clips"; useEffect(()=>{const iv=setInterval(()=>setSessionMinutes(m=>m+1),60000);return()=>clearInterval(iv)},[]); // Auto-switch browser mode based on active tab useEffect(()=>{ if(activeTab.type==="note"||activeTab.type==="clips")setBrowserMode("notes"); else if(activeTab.type==="doc")setBrowserMode("docs"); else if(activeTab.type==="web")setBrowserMode("bookmarks"); },[activeTabId]); // Filtering const toggleType=t=>{const s=new Set(activeTypes);s.has(t)?s.delete(t):s.add(t);setActiveTypes(s)}; const toggleCollection=name=>{const s=new Set(selectedCollections);s.has(name)?s.delete(name):s.add(name);setSelectedCollections(s)}; const toggleFolder=id=>{const s=new Set(expandedFolders);s.has(id)?s.delete(id):s.add(id);setExpandedFolders(s)}; const selectScope=s=>{if(activeScope===s){setActiveScope(null);setActiveFolder(null)}else{setActiveScope(s);setActiveFolder(null)}}; const toggleCmSelect=id=>{const s=new Set(selectedCmIds);s.has(id)?s.delete(id):s.add(id);setSelectedCmIds(s)}; const filtered=useMemo(()=>{ let items=[...allItems]; if(browserMode==="docs")items=items.filter(it=>it.type==="Doc"||it.type==="Artifact"); if(activeScope==="Project"&&!noProject)items=items.filter(it=>it.proj===projects[activeProjIdx].id); if(activeScope==="Project"&&noProject)items=items.filter(it=>it.proj===null); if(selectedCollections.size>0)items=items.filter(it=>[...selectedCollections].every(col=>it.cols?.includes(col))); if(activeTypes.size>0)items=items.filter(it=>activeTypes.has(it.type)); if(sortKey==="Alphabetical")items.sort((a,b)=>a.title.localeCompare(b.title)); else if(sortKey==="Type")items.sort((a,b)=>a.type.localeCompare(b.type)); else items.sort((a,b)=>timeVal(a.time)-timeVal(b.time)); const pp=items.filter(x=>x.pin);const up=items.filter(x=>!x.pin); return [...pp,...up]; },[activeScope,activeProjIdx,noProject,selectedCollections,activeTypes,sortKey,browserMode]); // Folder tree const renderFolderTree=(parentId,depth,isOverlay=false)=>folders.filter(f=>f.parent===parentId).map(f=>{ const hasChildren=folders.some(ch=>ch.parent===f.id);const isExp=expandedFolders.has(f.id); const isActive=!isOverlay&&activeFolder===f.id;const isDrop=dropTarget===f.id; return
{if(!isOverlay)setActiveFolder(isActive?null:f.id)}} onDragOver={e=>{e.preventDefault();setDropTarget(f.id)}} onDragLeave={()=>setDropTarget(null)} onDrop={e=>{e.preventDefault();setDropTarget(null);if(dragItem)flash(`Added to ${f.title}`)}} style={{display:"flex",alignItems:"center",gap:3,padding:isOverlay?"2px 6px":"3px 8px",paddingLeft:(isOverlay?6:8)+depth*(isOverlay?12:14),borderRadius:R.sm,cursor:isOverlay?"default":"pointer",backgroundColor:isDrop?c.accentBtn+"20":isActive?c.accentBtn+"10":"transparent",fontSize:isOverlay?10.5:11.5,fontWeight:isActive?600:400,color:isActive?c.accentBtn:c.textSec,border:isDrop?`1px dashed ${c.accentBtn}`:"1px solid transparent"}}> {hasChildren?{e.stopPropagation();toggleFolder(f.id)}} style={{display:"flex",width:10}}>{isExp?:}:} {f.title}
{isExp&&hasChildren&&renderFolderTree(f.id,depth+1,isOverlay)}
; }); // Note folder tree const renderNoteFolders=(parentId,depth)=>noteFolders.filter(f=>f.parent===parentId).map(f=>{ const hasChildren=noteFolders.some(ch=>ch.parent===f.id);const isExp=noteExpandedFolders.has(f.id); const folderNotes=noteItems.filter(n=>n.folder===f.id); return
{const s=new Set(noteExpandedFolders);s.has(f.id)?s.delete(f.id):s.add(f.id);setNoteExpandedFolders(s)}} style={{display:"flex",alignItems:"center",gap:3,padding:"3px 8px",paddingLeft:8+depth*14,borderRadius:R.sm,cursor:"pointer",fontSize:11.5,color:c.textSec,backgroundColor:c.bgPanelAlt,borderBottom:`1px solid ${c.borderLight}`}}> {isExp?:} {f.title} {folderNotes.length}
{isExp&&<> {folderNotes.map(n=>
{setSelectedNote(n.id);flash(`Open "${n.title}"`)}} style={{display:"flex",alignItems:"center",gap:4,padding:`5px 10px 5px ${22+depth*14}px`,borderBottom:`1px solid ${c.borderLight}`,cursor:"pointer",backgroundColor:selectedNote===n.id?c.accentBtn+"06":"transparent",borderLeft:selectedNote===n.id?`2px solid ${c.accentBtn}`:"2px solid transparent"}}> {n.pinned&&} {n.title} {n.mod}
)} {renderNoteFolders(f.id,depth+1)} }
; }); 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()}; const addReply=cmId=>{if(!replyText.trim())return;setComments(p=>p.map(cm=>cm.id===cmId?{...cm,replies:[...cm.replies,{id:"r"+Date.now(),author:"You",color:c.accentBtn,body:replyText.trim(),time:"just now"}]}:cm));setReplyingTo(null);setReplyText("")}; const resolveComment=id=>setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"resolved"}:cm)); const reopenComment=id=>setComments(p=>p.map(cm=>cm.id===id?{...cm,status:"open"}:cm)); const addComment=()=>{if(!newCmText.trim())return;setComments(p=>[...p,{id:"c"+Date.now(),author:"You",color:c.accentBtn,body:newCmText.trim(),time:"just now",status:"open",anchor:newCm?.text||null,replies:[]}]);setNewCm(null);setNewCmText("")}; const closeTab=id=>{if(tabs.length<=1)return;const idx=tabs.findIndex(t=>t.id===id);setTabs(p=>p.filter(t=>t.id!==id));if(activeTabId===id){const next=tabs[idx===0?1:idx-1];if(next)setActiveTabId(next.id)}}; const addTab=(type,incognito=false)=>{const id="t"+Date.now();const newTab=type==="note"?{id,type:"note",icon:"📝",title:"Untitled Note",color:tabColors.note}:type==="doc"?{id,type:"doc",icon:"📄",title:"Open Document…",color:tabColors.doc}:type==="web"?{id,type:"web",icon:"🌐",title:"New Tab",color:tabColors.web,incognito}:null;if(!newTab)return;setTabs(p=>[...p,newTab]);setActiveTabId(id);setNewTabDrop(false);flash(incognito?"New incognito tab":type==="note"?"New note":type==="doc"?"Opening file picker…":"New tab")}; const handleSend=()=>{if(outputMode==="respond_in_chat")flash(`Opening "${chats[chatIdx].name}" with ref…`);else{if(!instruction.trim())return;flash(`${agent.name}: ${subMode}…`)}}; // Tab drag reorder const handleTabDrop=(targetId)=>{if(!dragTabId||dragTabId===targetId)return;setTabs(prev=>{const dragged=prev.find(t=>t.id===dragTabId);const rest=prev.filter(t=>t.id!==dragTabId);const targetIdx=rest.findIndex(t=>t.id===targetId);return [...rest.slice(0,targetIdx),dragged,...rest.slice(targetIdx)]});setDragTabId(null)}; // CmCard const CmCard=({cm,resolved})=>{const isAct=activeComment===cm.id;return
setActiveComment(isAct?null:cm.id)}>
{cm.anchor&&
"{cm.anchor.slice(0,55)}"
}
{cm.author}{cm.time}
{cm.body}
e.stopPropagation()}> {!resolved&&{setReplyingTo(replyingTo===cm.id?null:cm.id);setReplyText("")}}>Reply} {!resolved&&resolveComment(cm.id)}>Resolve} {resolved&&reopenComment(cm.id)}>Reopen} {cm.author==="You"&&Edit} {cm.author==="You"&&Delete} flash(`Sent to ${agent.name}`)} style={{cursor:"pointer",display:"flex",alignItems:"center",gap:2,color:c.textSec,fontWeight:600,fontSize:10}} onMouseEnter={e=>e.currentTarget.style.color=c.accentBtn} onMouseLeave={e=>e.currentTarget.style.color=c.textSec}>Send
{cm.replies.map(r=>
{r.author}{r.time}
{r.body}
)} {replyingTo===cm.id&&
e.stopPropagation()}>