Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"electron-log": "^5.3.0",
"electron-updater": "^6.3.0",
"express": "^4.21.0",
"marked": "^17.0.4",
"morphdom": "^2.7.8",
"node-pty": "^1.0.0",
"ws": "^8.18.0"
Expand Down
60 changes: 60 additions & 0 deletions public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ const planViewerEditorEl = document.getElementById('plan-viewer-editor');
const planCopyPathBtn = document.getElementById('plan-copy-path-btn');
const planCopyContentBtn = document.getElementById('plan-copy-content-btn');
const planSaveBtn = document.getElementById('plan-save-btn');
const planPreviewBtn = document.getElementById('plan-preview-btn');
const planViewerPreviewEl = document.getElementById('plan-viewer-preview');

let currentPlanContent = '';
let currentPlanFilePath = '';
let currentPlanFilename = '';
let planEditorView = null;
let planPreviewMode = false;
const loadingStatus = document.getElementById('loading-status');
const sessionFilters = document.getElementById('session-filters');
const searchBar = document.getElementById('search-bar');
Expand All @@ -41,6 +44,8 @@ const memoryViewerEditorEl = document.getElementById('memory-viewer-editor');
const memoryCopyPathBtn = document.getElementById('memory-copy-path-btn');
const memoryCopyContentBtn = document.getElementById('memory-copy-content-btn');
const memorySaveBtn = document.getElementById('memory-save-btn');
const memoryPreviewBtn = document.getElementById('memory-preview-btn');
const memoryViewerPreviewEl = document.getElementById('memory-viewer-preview');
const terminalArea = document.getElementById('terminal-area');
const settingsViewer = document.getElementById('settings-viewer');
const settingsViewerTitle = document.getElementById('settings-viewer-title');
Expand Down Expand Up @@ -1861,6 +1866,14 @@ async function openPlan(plan) {
planViewerTitle.textContent = plan.title;
planViewerFilepath.textContent = currentPlanFilePath;

// Reset preview mode when switching files
if (planPreviewMode) {
planPreviewMode = toggleMarkdownPreview({
editorEl: planViewerEditorEl, previewEl: planViewerPreviewEl,
toggleBtn: planPreviewBtn, editorView: planEditorView, isPreview: true,
});
}

// Create or update CodeMirror editor
if (!planEditorView) {
planEditorView = window.createPlanEditor(planViewerEditorEl);
Expand Down Expand Up @@ -1896,6 +1909,34 @@ planSaveBtn.addEventListener('click', async () => {
flashButtonText(planSaveBtn, 'Saved!');
});

function toggleMarkdownPreview({ editorEl, previewEl, toggleBtn, editorView, isPreview }) {
if (!isPreview) {
const content = editorView ? editorView.state.doc.toString() : '';
previewEl.innerHTML = window.marked.parse(content);
editorEl.style.display = 'none';
previewEl.style.display = 'block';
toggleBtn.textContent = 'Edit';
toggleBtn.classList.add('active');
return true;
} else {
previewEl.style.display = 'none';
editorEl.style.display = '';
toggleBtn.textContent = 'Preview';
toggleBtn.classList.remove('active');
return false;
}
}

planPreviewBtn.addEventListener('click', () => {
planPreviewMode = toggleMarkdownPreview({
editorEl: planViewerEditorEl,
previewEl: planViewerPreviewEl,
toggleBtn: planPreviewBtn,
editorView: planEditorView,
isPreview: planPreviewMode,
});
});

function hideAllViewers() {
planViewer.style.display = 'none';
statsViewer.style.display = 'none';
Expand Down Expand Up @@ -2503,6 +2544,7 @@ let cachedMemoryData = { global: { files: [] }, projects: [] };
let memoryEditorView = null;
let currentMemoryFilePath = null;
let currentMemoryContent = '';
let memoryPreviewMode = false;
const memoryCollapsedState = new Map(); // key → boolean (true = collapsed)

async function loadMemories() {
Expand Down Expand Up @@ -2642,6 +2684,14 @@ async function openMemory(file) {
memoryViewerTitle.textContent = file.filename;
memoryViewerFilename.textContent = file.filePath;

// Reset preview mode when switching files
if (memoryPreviewMode) {
memoryPreviewMode = toggleMarkdownPreview({
editorEl: memoryViewerEditorEl, previewEl: memoryViewerPreviewEl,
toggleBtn: memoryPreviewBtn, editorView: memoryEditorView, isPreview: true,
});
}

// Create or update CodeMirror editor
if (!memoryEditorView) {
memoryEditorView = window.createPlanEditor(memoryViewerEditorEl);
Expand Down Expand Up @@ -2671,6 +2721,16 @@ memorySaveBtn.addEventListener('click', async () => {
}
});

memoryPreviewBtn.addEventListener('click', () => {
memoryPreviewMode = toggleMarkdownPreview({
editorEl: memoryViewerEditorEl,
previewEl: memoryViewerPreviewEl,
toggleBtn: memoryPreviewBtn,
editorView: memoryEditorView,
isPreview: memoryPreviewMode,
});
});

// --- New session dialog ---
async function resolveDefaultSessionOptions(project) {
const effective = await window.api.getEffectiveSettings(project.projectPath);
Expand Down
4 changes: 4 additions & 0 deletions public/codemirror-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { python } from '@codemirror/lang-python';
import { json } from '@codemirror/lang-json';
import { html } from '@codemirror/lang-html';
import { css } from '@codemirror/lang-css';
import { marked } from 'marked';
import { rust } from '@codemirror/lang-rust';
import { go } from '@codemirror/lang-go';
import { java } from '@codemirror/lang-java';
Expand Down Expand Up @@ -202,3 +203,6 @@ window.createUnifiedMergeViewer = createUnifiedMergeViewer;
window.CMEditorView = EditorView;
window.CMEditorState = EditorState;
window.CMMergeView = MergeView;

marked.setOptions({ breaks: true, gfm: true });
window.marked = marked;
4 changes: 4 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@
<button id="memory-copy-path-btn" title="Copy file path"><svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M5.5 10.5h-1a1.5 1.5 0 0 1-1.5-1.5v-5a1.5 1.5 0 0 1 1.5-1.5h5a1.5 1.5 0 0 1 1.5 1.5v1"/></svg></button>
</div>
<div id="memory-viewer-header-controls">
<button id="memory-preview-btn" title="Toggle markdown preview">Preview</button>
<button id="memory-copy-content-btn" title="Copy raw content">Copy</button>
<button id="memory-save-btn" title="Save changes">Save</button>
</div>
</div>
<div id="memory-viewer-editor"></div>
<div id="memory-viewer-preview" class="markdown-preview" style="display:none;"></div>
</div>
<div id="plan-viewer" style="display:none;">
<div id="plan-viewer-header">
Expand All @@ -72,11 +74,13 @@
<button id="plan-copy-path-btn" title="Copy file path"><svg width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/><path d="M5.5 10.5h-1a1.5 1.5 0 0 1-1.5-1.5v-5a1.5 1.5 0 0 1 1.5-1.5h5a1.5 1.5 0 0 1 1.5 1.5v1"/></svg></button>
</div>
<div id="plan-viewer-header-controls">
<button id="plan-preview-btn" title="Toggle markdown preview">Preview</button>
<button id="plan-copy-content-btn" title="Copy raw content">Copy</button>
<button id="plan-save-btn" title="Save changes">Save</button>
</div>
</div>
<div id="plan-viewer-editor"></div>
<div id="plan-viewer-preview" class="markdown-preview" style="display:none;"></div>
</div>
<div id="settings-viewer" style="display:none;">
<div id="settings-viewer-header">
Expand Down
83 changes: 83 additions & 0 deletions public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,8 @@ body { display: flex; flex-direction: column; }
background: rgba(120,130,255,0.1);
}

#plan-preview-btn,
#memory-preview-btn,
#plan-copy-content-btn,
#plan-save-btn {
background: transparent;
Expand All @@ -1125,6 +1127,8 @@ body { display: flex; flex-direction: column; }
font-weight: 500;
}

#plan-preview-btn:hover,
#memory-preview-btn:hover,
#plan-copy-content-btn:hover {
border-color: rgba(120,130,255,0.3);
color: #8088ff;
Expand All @@ -1137,6 +1141,13 @@ body { display: flex; flex-direction: column; }
background: rgba(62,207,90,0.06);
}

#plan-preview-btn.active,
#memory-preview-btn.active {
border-color: rgba(120,130,255,0.4);
color: #8088ff;
background: rgba(120,130,255,0.12);
}

/* Plan CodeMirror editor */
#plan-viewer-editor {
flex: 1;
Expand Down Expand Up @@ -1604,6 +1615,78 @@ body { display: flex; flex-direction: column; }
height: 100%;
}

/* ========== MARKDOWN PREVIEW ========== */
.markdown-preview {
flex: 1;
overflow-y: auto;
padding: 24px 32px;
color: #f8f8f2;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 14px;
line-height: 1.7;
scrollbar-width: thin;
scrollbar-color: rgba(255,255,255,0.08) transparent;
}

.markdown-preview h1, .markdown-preview h2, .markdown-preview h3,
.markdown-preview h4, .markdown-preview h5, .markdown-preview h6 {
color: #bd93f9;
margin: 1.2em 0 0.5em;
font-weight: 600;
}
.markdown-preview h1 { font-size: 1.6em; border-bottom: 1px solid rgba(255,255,255,0.06); padding-bottom: 0.3em; }
.markdown-preview h2 { font-size: 1.35em; border-bottom: 1px solid rgba(255,255,255,0.04); padding-bottom: 0.25em; }
.markdown-preview h3 { font-size: 1.15em; }

.markdown-preview p { margin: 0.6em 0; }

.markdown-preview a { color: #8be9fd; text-decoration: none; }
.markdown-preview a:hover { text-decoration: underline; }

.markdown-preview code {
background: #44475a;
padding: 2px 6px;
border-radius: 4px;
font-family: 'SF Mono', 'Fira Code', Menlo, monospace;
font-size: 0.9em;
}

.markdown-preview pre {
background: #282a36;
border: 1px solid rgba(255,255,255,0.06);
border-radius: 6px;
padding: 14px 18px;
overflow-x: auto;
}
.markdown-preview pre code {
background: none;
padding: 0;
}

.markdown-preview blockquote {
border-left: 3px solid #6272a4;
margin: 0.8em 0;
padding: 0.4em 1em;
color: #b0b0c4;
}

.markdown-preview ul, .markdown-preview ol { padding-left: 1.5em; margin: 0.5em 0; }
.markdown-preview li { margin: 0.25em 0; }

.markdown-preview table { border-collapse: collapse; width: 100%; margin: 1em 0; }
.markdown-preview th, .markdown-preview td {
border: 1px solid rgba(255,255,255,0.08);
padding: 6px 12px;
text-align: left;
}
.markdown-preview th { background: rgba(255,255,255,0.04); color: #bd93f9; }

.markdown-preview hr { border: none; border-top: 1px solid rgba(255,255,255,0.08); margin: 1.5em 0; }

.markdown-preview img { max-width: 100%; border-radius: 6px; }

.markdown-preview input[type="checkbox"] { margin-right: 6px; }

/* ========== JSONL VIEWER ========== */
#jsonl-viewer {
position: absolute;
Expand Down
Loading