feat(v2): add SSH management, ctx integration, themes, detached mode, auto-updater
SSH session management: - SshSession struct + ssh_sessions SQLite table in session.rs - CRUD Tauri commands (ssh_session_list/save/delete) in lib.rs - SshDialog.svelte (create/edit modal), SshSessionList.svelte (sidebar) - SSH pane routes to TerminalPane with shell=/usr/bin/ssh + args ctx context database integration: - ctx.rs: read-only CtxDb (SQLITE_OPEN_READ_ONLY for ~/.claude-context/context.db) - 5 Tauri commands (ctx_list_projects/get_context/get_shared/get_summaries/search) - ContextPane.svelte with project selector, tabs, search - ctx-bridge.ts adapter Catppuccin theme flavors (Latte/Frappe/Macchiato/Mocha): - themes.ts: all 4 palette definitions + buildXtermTheme/applyCssVariables - theme.svelte.ts: reactive store with SQLite persistence - SettingsDialog flavor dropdown, TerminalPane theme-aware Detached pane mode (pop-out windows): - detach.ts: isDetachedMode/getDetachedConfig from URL params - App.svelte: conditional rendering of single pane without chrome Other additions: - Shiki syntax highlighting (highlight.ts, lazy singleton, 13 languages) - Tauri auto-updater plugin (tauri-plugin-updater + updater.ts) - AgentPane markdown rendering with Shiki code highlighting - New deps: shiki, @tauri-apps/plugin-updater, tauri-plugin-updater
This commit is contained in:
parent
4f2614186d
commit
4db7ccff60
28 changed files with 2992 additions and 51 deletions
|
|
@ -1,7 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { marked } from 'marked';
|
||||
import { marked, Renderer } from 'marked';
|
||||
import { watchFile, unwatchFile, onFileChanged, type FileChangedPayload } from '../../adapters/file-bridge';
|
||||
import { getHighlighter, highlightCode, escapeHtml } from '../../utils/highlight';
|
||||
|
||||
interface Props {
|
||||
filePath: string;
|
||||
|
|
@ -15,9 +16,18 @@
|
|||
let error = $state('');
|
||||
let unlisten: (() => void) | undefined;
|
||||
|
||||
const renderer = new Renderer();
|
||||
renderer.code = function({ text, lang }: { text: string; lang?: string }) {
|
||||
if (lang) {
|
||||
const highlighted = highlightCode(text, lang);
|
||||
if (highlighted !== escapeHtml(text)) return highlighted;
|
||||
}
|
||||
return `<pre><code>${escapeHtml(text)}</code></pre>`;
|
||||
};
|
||||
|
||||
function renderMarkdown(source: string): void {
|
||||
try {
|
||||
renderedHtml = marked.parse(source, { async: false }) as string;
|
||||
renderedHtml = marked.parse(source, { renderer, async: false }) as string;
|
||||
error = '';
|
||||
} catch (e) {
|
||||
error = `Render error: ${e}`;
|
||||
|
|
@ -26,6 +36,7 @@
|
|||
|
||||
onMount(async () => {
|
||||
try {
|
||||
await getHighlighter();
|
||||
const content = await watchFile(paneId, filePath);
|
||||
renderMarkdown(content);
|
||||
|
||||
|
|
@ -125,6 +136,21 @@
|
|||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.markdown-body :global(.shiki) {
|
||||
background: var(--bg-surface) !important;
|
||||
padding: 12px 14px;
|
||||
border-radius: var(--border-radius);
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.markdown-body :global(.shiki code) {
|
||||
background: none !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body :global(blockquote) {
|
||||
border-left: 3px solid var(--ctp-mauve);
|
||||
margin: 0.5em 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue