add journal

This commit is contained in:
2026-03-31 01:03:09 -07:00
parent 15e14c0dcc
commit c1ee0b9acd
4 changed files with 52 additions and 9 deletions

View File

@@ -873,6 +873,7 @@ function Flow() {
const canvasRightZoomRef = useRef(null);
const suppressPaneContextMenuUntilRef = useRef(0);
const loadNodeOutputRequestVersionsRef = useRef(new Map());
const journalContentRef = useRef('');
const reactFlow = useReactFlow();
// ── WebSocket ───────────────────────────────────────────────────────
@@ -1959,12 +1960,13 @@ function Flow() {
const openJournalTab = useCallback(() => {
setHelpTabs((prev) => {
if (prev.find((t) => t.label === 'Journal')) return prev;
return [...prev, { label: 'Journal', type: 'journal', content: '' }];
return [...prev, { label: 'Journal', type: 'journal', content: journalContentRef.current }];
});
setActiveHelpTab('Journal');
}, []);
const updateTabContent = useCallback((label, content) => {
if (label === 'Journal') journalContentRef.current = content;
setHelpTabs((prev) => prev.map((t) => t.label === label ? { ...t, content } : t));
}, []);
@@ -1993,6 +1995,10 @@ function Flow() {
setNodes(sortNodesForParentOrder(hydrated.nodes));
setEdges(hydrated.edges);
nextIdRef.current = hydrated.nextNodeId;
journalContentRef.current = data.journalContent || '';
setHelpTabs((prev) => prev.map((t) =>
t.label === 'Journal' ? { ...t, content: journalContentRef.current } : t,
));
initializeDynamicNodes(hydrated.nodes);
}, [initializeDynamicNodes, setNodes, setEdges]);
@@ -2095,6 +2101,7 @@ function Flow() {
const stampedBlob = await stampLogoOnBlob(blob);
const workflow = serializeWorkflowState(allNodes, reactFlow.getEdges());
if (journalContentRef.current) workflow.journalContent = journalContentRef.current;
return embedWorkflow(stampedBlob, workflow);
}, [reactFlow]);
@@ -3003,6 +3010,7 @@ function Flow() {
onTabSelect={setActiveHelpTab}
onTabClose={closeHelpTab}
onTabContentChange={updateTabContent}
onOpenJournal={openJournalTab}
/>
</NodeContext.Provider>
);

View File

@@ -4,7 +4,11 @@ import { marked } from 'marked';
function JournalTab({ content, onChange }) {
const [isEditing, setIsEditing] = useState(false);
const renderedHtml = content?.trim() ? marked.parse(content) : '';
let renderedHtml = '';
if (!isEditing && content?.trim()) {
try { renderedHtml = marked.parse(content); } catch { /* fallback to raw */ renderedHtml = content; }
}
return (
<div className="node-help-journal">
@@ -34,23 +38,26 @@ function JournalTab({ content, onChange }) {
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
/>
) : (
) : renderedHtml ? (
<div
className="node-help-panel-body node-help-journal-preview nowheel"
onDoubleClick={() => setIsEditing(true)}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={renderedHtml ? { __html: renderedHtml } : undefined}
dangerouslySetInnerHTML={{ __html: renderedHtml }}
/>
) : (
<div
className="node-help-panel-body node-help-journal-preview nowheel"
onDoubleClick={() => setIsEditing(true)}
>
{!renderedHtml && (
<span className="node-help-journal-placeholder">Double-click to write</span>
)}
<span className="node-help-journal-placeholder">Double-click to write</span>
</div>
)}
</div>
);
}
function HelpPanelManager({ tabs, activeTab, onTabSelect, onTabClose, onTabContentChange }) {
function HelpPanelManager({ tabs, activeTab, onTabSelect, onTabClose, onTabContentChange, onOpenJournal }) {
const [collapsed, setCollapsed] = useState(false);
useEffect(() => {
@@ -92,6 +99,15 @@ function HelpPanelManager({ tabs, activeTab, onTabSelect, onTabClose, onTabConte
</button>
</div>
))}
{!tabs.some((t) => t.type === 'journal') && (
<button
className="node-help-tab-add"
title="Open Journal"
onClick={onOpenJournal}
>
+
</button>
)}
</div>
{/* Content */}

View File

@@ -543,6 +543,25 @@ html, body, #root {
}
.node-help-tab-close:hover { opacity: 1; }
.node-help-tab-add {
background: none;
border: 1px dashed #334155;
color: #475569;
font-size: 13px;
line-height: 1;
width: 22px;
height: 22px;
border-radius: 4px;
cursor: pointer;
align-self: center;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: color 0.12s, border-color 0.12s;
}
.node-help-tab-add:hover { color: #f1f5f9; border-color: #64748b; }
.node-help-panel {
position: fixed;
top: 60px;