diff --git a/frontend/assets/app.js b/frontend/assets/app.js index 665522e..be5fb07 100644 --- a/frontend/assets/app.js +++ b/frontend/assets/app.js @@ -5,9 +5,12 @@ const state = { meetingId: null, meetings: [], templateName: "template1.md", - editMode: false, + templates: [], processing: false, - activeTab: "template", + resultEditMode: false, + rightEditMode: false, + selectedTreeKey: "", + rightResource: null, }; const STORAGE_KEY = "meeting-workspace-preferences"; @@ -28,61 +31,37 @@ function savePreferences(partial) { function applySavedLayout() { const prefs = loadPreferences(); - const sidebar = document.getElementById("sidebar"); - const resultPanel = document.getElementById("result-panel"); - const templatePanel = document.getElementById("template-panel"); + const sidebar = $("#sidebar"); + const resultPanel = $("#result-panel"); + const templatePanel = $("#template-panel"); if (prefs.layout?.sidebarWidth) { sidebar.style.flexBasis = `${prefs.layout.sidebarWidth}px`; sidebar.style.flexGrow = "0"; } - if (prefs.layout?.templateWidth) { templatePanel.style.flexBasis = `${prefs.layout.templateWidth}px`; templatePanel.style.flexGrow = "0"; } - if (prefs.layout?.resultWidth) { resultPanel.style.flexBasis = `${prefs.layout.resultWidth}px`; resultPanel.style.flexGrow = "0"; } - if (prefs.templateName) { state.templateName = prefs.templateName; } - - if (prefs.activeTab === "template" || prefs.activeTab === "original") { - state.activeTab = prefs.activeTab; - } } function persistLayout() { - const sidebar = document.getElementById("sidebar"); - const resultPanel = document.getElementById("result-panel"); - const templatePanel = document.getElementById("template-panel"); - savePreferences({ layout: { - sidebarWidth: Math.round(sidebar.getBoundingClientRect().width), - resultWidth: Math.round(resultPanel.getBoundingClientRect().width), - templateWidth: Math.round(templatePanel.getBoundingClientRect().width), + sidebarWidth: Math.round($("#sidebar").getBoundingClientRect().width), + resultWidth: Math.round($("#result-panel").getBoundingClientRect().width), + templateWidth: Math.round($("#template-panel").getBoundingClientRect().width), }, }); } -function activateTab(tabName) { - state.activeTab = tabName; - $$("#panel-tabs .tab").forEach((item) => { - item.classList.toggle("active", item.dataset.tab === tabName); - }); - - const showTemplate = tabName === "template"; - $("#template-tab").hidden = !showTemplate; - $("#original-tab").hidden = showTemplate; - - savePreferences({ activeTab: tabName }); -} - function toast(message, type = "ok") { const el = $("#toast"); el.textContent = message; @@ -112,6 +91,10 @@ function meetingById(meetingId) { return state.meetings.find((item) => item.id === meetingId) || null; } +function isMarkdownFile(name = "") { + return name.toLowerCase().endsWith(".md"); +} + function renderMeetingStatus(meeting) { const name = $("#sidebar-meeting-name"); const meta = $("#sidebar-meeting-meta"); @@ -131,7 +114,9 @@ function renderMeetingStatus(meeting) { } name.textContent = `当前会议:${meeting.name}`; - meta.textContent = `ID: ${meeting.id} · 导入时间:${meeting.created_at || "未知"} · 源文件:${meeting.original_filename || meeting.transcript_filename || "未知"}`; + meta.textContent = + `ID: ${meeting.id} · 导入时间:${meeting.created_at || "未知"} · 原始文件:` + + `${meeting.original_filename || meeting.transcript_filename || "未知"}`; tip.textContent = `当前处理会议:${meeting.name} (${meeting.id})`; summaryBadge.textContent = meeting.has_summary ? "已生成总结" : "未生成总结"; topicsBadge.textContent = meeting.has_topics ? "已生成主题 JSON" : "未生成主题 JSON"; @@ -145,48 +130,48 @@ function resetProcessingStream() { $("#stream-content").textContent = ""; } +function showResultEmpty() { + state.resultEditMode = false; + $("#btn-toggle-result-edit").disabled = true; + $("#btn-toggle-result-edit").textContent = "编辑结果"; + $("#result-editor").style.display = "none"; + $("#result-md").style.display = "none"; + $("#processing-indicator").hidden = true; + $("#result-empty").hidden = false; +} + +function setResultEditMode(editMode) { + state.resultEditMode = editMode; + $("#result-editor").style.display = editMode ? "block" : "none"; + $("#result-md").style.display = editMode ? "none" : "block"; + $("#btn-toggle-result-edit").textContent = editMode ? "保存结果" : "编辑结果"; +} + function showResult(markdown) { resetProcessingStream(); $("#processing-indicator").hidden = true; $("#result-empty").hidden = true; - const result = $("#result-md"); - result.style.display = "block"; - result.innerHTML = marked.parse(markdown); - result.scrollTop = 0; + $("#result-editor").value = markdown; + $("#result-md").innerHTML = marked.parse(markdown || ""); + $("#result-md").scrollTop = 0; + $("#btn-toggle-result-edit").disabled = !state.meetingId; + setResultEditMode(false); } function showProcessingView() { $("#result-empty").hidden = true; + $("#result-editor").style.display = "none"; $("#result-md").style.display = "none"; $("#processing-indicator").hidden = false; + $("#btn-toggle-result-edit").disabled = true; } -function showEmpty() { - resetProcessingStream(); - $("#processing-indicator").hidden = true; - $("#result-md").style.display = "none"; - $("#result-empty").hidden = false; -} - -function showResultPanel() { - resetProcessingStream(); - $("#result-empty").hidden = true; - $("#processing-indicator").hidden = true; - $("#result-md").style.display = "none"; -} - -function toDisplayContent(filename, content) { - if (filename.endsWith(".json")) { - try { - return `\`\`\`json\n${JSON.stringify(JSON.parse(content), null, 2)}\n\`\`\``; - } catch { - return content; - } - } - if (filename.endsWith(".txt")) { - return `\`\`\`\n${content}\n\`\`\``; - } - return content; +function setSelectedTreeKey(key) { + state.selectedTreeKey = key; + $$(".tree-row").forEach((row) => { + row.classList.toggle("selected", row.dataset.nodeKey === key); + row.classList.toggle("active-meeting", row.dataset.meetingId === state.meetingId); + }); } async function setCurrentMeeting(meetingId) { @@ -198,15 +183,7 @@ async function setCurrentMeeting(meetingId) { state.meetingId = data.active_meeting_id; renderMeetingStatus(data.meeting); $("#btn-process").disabled = !state.meetingId || state.processing; - highlightSelectedMeeting(); -} - -function highlightSelectedMeeting() { - $$(".tree-row").forEach((row) => { - const isCurrent = row.dataset.meetingId === state.meetingId; - row.classList.toggle("selected", isCurrent); - row.classList.toggle("active-meeting", isCurrent); - }); + setSelectedTreeKey(state.selectedTreeKey); } function renderNode(node, parent, depth) { @@ -217,15 +194,19 @@ function renderNode(node, parent, depth) { row.className = "tree-row"; row.style.paddingLeft = `${10 + depth * 18}px`; + if (node.id) { + row.dataset.meetingId = node.id; + } + if (node.type === "folder") { const arrow = document.createElement("span"); arrow.className = `arrow ${node.children?.length ? "" : "none"}`; - arrow.textContent = "▶"; + arrow.textContent = "▸"; row.appendChild(arrow); const icon = document.createElement("span"); icon.className = "icon"; - icon.textContent = node.id ? "🗂" : "📁"; + icon.textContent = node.id ? "📁" : "🗂"; row.appendChild(icon); const label = document.createElement("span"); @@ -241,7 +222,7 @@ function renderNode(node, parent, depth) { } if (node.id) { - row.dataset.meetingId = node.id; + row.dataset.nodeKey = `meeting:${node.id}`; const del = document.createElement("span"); del.className = "del-btn"; del.textContent = "删除"; @@ -250,6 +231,8 @@ function renderNode(node, parent, depth) { await deleteMeetingNode(node.id, node.delete_mode || "meeting"); }); row.appendChild(del); + } else { + row.dataset.nodeKey = `folder:${node.name}`; } row.addEventListener("click", async () => { @@ -261,9 +244,13 @@ function renderNode(node, parent, depth) { } if (node.id) { await selectMeeting(node.id); + } else { + setSelectedTreeKey(row.dataset.nodeKey); } }); } else { + row.dataset.nodeKey = `file:${node.path}`; + const spacer = document.createElement("span"); spacer.className = "arrow none"; row.appendChild(spacer); @@ -273,7 +260,9 @@ function renderNode(node, parent, depth) { if (node.name.endsWith(".md")) { icon.textContent = "📝"; } else if (node.name.endsWith(".json")) { - icon.textContent = "🔎"; + icon.textContent = "🧩"; + } else if (node.name.endsWith(".yaml") || node.name.endsWith(".yml")) { + icon.textContent = "⚙️"; } else { icon.textContent = "📄"; } @@ -285,14 +274,7 @@ function renderNode(node, parent, depth) { row.appendChild(label); row.addEventListener("click", async () => { - if (!node.path) { - return; - } - const parts = node.path.replace(/^(meetings|results_md|results_json)\//, "").split("/"); - const meetingId = parts[0]; - const filename = parts.slice(1).join("/"); - await setCurrentMeeting(meetingId); - await viewMeetingFile(meetingId, filename); + await openTreeResource(node.path); }); } @@ -315,7 +297,7 @@ function buildTree(tree) { const root = $("#file-tree"); root.innerHTML = ""; (tree.children || []).forEach((child) => renderNode(child, root, 0)); - highlightSelectedMeeting(); + setSelectedTreeKey(state.selectedTreeKey); } async function loadTree() { @@ -323,27 +305,176 @@ async function loadTree() { buildTree(tree); } +async function loadMeetingSummary(meetingId) { + const result = await api(`/api/meetings/${meetingId}/file/meeting_summary.md`); + showResult(result.content); +} + async function selectMeeting(meetingId) { if (state.processing) { return; } await setCurrentMeeting(meetingId); - showResultPanel(); + setSelectedTreeKey(`meeting:${meetingId}`); try { - const result = await api(`/api/meetings/${meetingId}/file/meeting_summary.md`); - showResult(result.content); + await loadMeetingSummary(meetingId); } catch { - showEmpty(); + showResultEmpty(); } } -async function viewMeetingFile(meetingId, filename) { +function renderSidePreview(resource) { + $("#side-editor").style.display = "none"; + $("#side-preview").style.display = "none"; + $("#side-plain-preview").style.display = "none"; + + if (!resource) { + $("#side-plain-preview").style.display = "block"; + $("#side-plain-preview").textContent = "请选择一个资源"; + return; + } + + if (isMarkdownFile(resource.name)) { + $("#side-preview").style.display = "block"; + $("#side-preview").innerHTML = marked.parse(resource.content || ""); + return; + } + + $("#side-plain-preview").style.display = "block"; + $("#side-plain-preview").textContent = resource.content || ""; +} + +function syncTemplateSelection(name) { + state.templateName = name; + savePreferences({ templateName: name }); + $("#tpl-select").value = name; +} + +function applyRightResource(resource) { + state.rightResource = resource; + $("#editor-resource-label").textContent = `当前资源:${resource.label}`; + $("#side-editor").value = resource.content || ""; + $("#btn-toggle-side-edit").disabled = !resource.editable; + $("#btn-toggle-side-edit").textContent = resource.editable ? "编辑资源" : "只读资源"; + state.rightEditMode = false; + renderSidePreview(resource); + + if (resource.type === "template") { + syncTemplateSelection(resource.name); + } +} + +function setRightEditMode(editMode) { + state.rightEditMode = editMode; + const resource = state.rightResource; + if (!resource || !resource.editable) { + renderSidePreview(resource); + return; + } + + $("#btn-toggle-side-edit").textContent = editMode ? "保存资源" : "编辑资源"; + if (editMode) { + $("#side-preview").style.display = "none"; + $("#side-plain-preview").style.display = "none"; + $("#side-editor").style.display = "block"; + } else { + resource.content = $("#side-editor").value; + renderSidePreview(resource); + } +} + +async function openRightResource(resource) { + applyRightResource(resource); + if (resource.treeKey) { + setSelectedTreeKey(resource.treeKey); + } +} + +async function openTemplate(name, treeKey = `file:templates/${name}`) { + const data = await api(`/api/templates/${encodeURIComponent(name)}`); + await openRightResource({ + type: "template", + name, + label: `模板 / ${name}`, + content: data.content, + editable: true, + treeKey, + }); +} + +async function openPrompt(name, treeKey = `file:prompts/${name}`) { + const data = await api(`/api/prompts/${encodeURIComponent(name)}`); + await openRightResource({ + type: "prompt", + name, + label: `提示词 / ${name}`, + content: data.content, + editable: true, + treeKey, + }); +} + +async function openMeetingFile(meetingId, filename, treeKey = `file:meetings/${meetingId}/${filename}`) { + const data = await api(`/api/meetings/${meetingId}/file/${encodeURIComponent(filename)}`); + await openRightResource({ + type: "meeting-file", + meetingId, + name: filename, + label: `会议原文 / ${meetingById(meetingId)?.name || meetingId} / ${filename}`, + content: data.content, + editable: false, + treeKey, + }); +} + +async function openResultFile(meetingId, filename, treeKey) { + const data = await api(`/api/meetings/${meetingId}/file/${encodeURIComponent(filename)}`); + await openRightResource({ + type: "result-file", + meetingId, + name: filename, + label: `处理结果 / ${meetingById(meetingId)?.name || meetingId} / ${filename}`, + content: data.content, + editable: false, + treeKey, + }); +} + +async function openTreeResource(path) { if (state.processing) { return; } - const result = await api(`/api/meetings/${meetingId}/file/${encodeURIComponent(filename)}`); - showResult(toDisplayContent(filename, result.content)); + + const parts = path.split("/"); + const group = parts[0]; + const treeKey = `file:${path}`; + + if (group === "templates") { + await openTemplate(parts.slice(1).join("/"), treeKey); + return; + } + if (group === "prompts") { + await openPrompt(parts.slice(1).join("/"), treeKey); + return; + } + + const meetingId = parts[1]; + const filename = parts.slice(2).join("/"); + await setCurrentMeeting(meetingId); + + if (group === "results_md" && filename === "meeting_summary.md") { + setSelectedTreeKey(treeKey); + await loadMeetingSummary(meetingId); + return; + } + if (group === "meetings") { + await openMeetingFile(meetingId, filename, treeKey); + return; + } + if (group === "results_json" || group === "results_md") { + await openResultFile(meetingId, filename, treeKey); + } } async function deleteMeetingNode(meetingId, deleteMode) { @@ -365,74 +496,19 @@ async function deleteMeetingNode(meetingId, deleteMode) { await refresh(); if (isDeleteMeeting && !meetingById(state.meetingId)) { - showEmpty(); + showResultEmpty(); return; } if (!isDeleteMeeting && state.meetingId === meetingId) { try { - const result = await api(`/api/meetings/${meetingId}/file/meeting_summary.md`); - showResult(result.content); + await loadMeetingSummary(meetingId); } catch { - showEmpty(); + showResultEmpty(); } } } -function updateTemplatePreview(content) { - const preview = $("#template-preview"); - preview.style.display = "block"; - preview.innerHTML = marked.parse(content); -} - -async function loadTemplate(name) { - state.templateName = name; - savePreferences({ templateName: name }); - const data = await api(`/api/templates/${name}`); - state.editMode = false; - $("#template-editor").value = data.content; - $("#template-editor").style.display = "none"; - $("#template-preview").style.display = "block"; - updateTemplatePreview(data.content); - $("#btn-toggle-edit").textContent = "编辑模板"; - $("#tpl-select").value = name; -} - -async function loadOriginalContent(meetingId) { - const originalText = $("#original-content"); - const originalMarkdown = $("#original-markdown"); - - if (!meetingId) { - originalMarkdown.hidden = true; - originalMarkdown.style.display = "none"; - originalText.hidden = false; - originalText.textContent = "未选择会议"; - return; - } - try { - const data = await api(`/api/meetings/${meetingId}/transcript`); - const filename = (data.filename || "").toLowerCase(); - if (filename.endsWith(".md")) { - originalText.hidden = true; - originalMarkdown.hidden = false; - originalMarkdown.style.display = "block"; - originalMarkdown.innerHTML = marked.parse(data.content); - originalMarkdown.scrollTop = 0; - } else { - originalMarkdown.hidden = true; - originalMarkdown.style.display = "none"; - originalText.hidden = false; - originalText.textContent = data.content; - originalText.scrollTop = 0; - } - } catch { - originalMarkdown.hidden = true; - originalMarkdown.style.display = "none"; - originalText.hidden = false; - originalText.textContent = "无法加载当前会议原文"; - } -} - function initResize(gutterId, leftId, rightId) { const gutter = document.getElementById(gutterId); const left = document.getElementById(leftId); @@ -460,6 +536,7 @@ function initResize(gutterId, leftId, rightId) { if (!dragging) { return; } + const dx = event.clientX - startX; const minLeft = Number(left.dataset.minWidth || 220); const minRight = Number(right.dataset.minWidth || 320); @@ -497,6 +574,8 @@ function initResize(gutterId, leftId, rightId) { async function refresh() { const templateData = await api("/api/templates"); + state.templates = templateData; + const select = $("#tpl-select"); select.innerHTML = ""; templateData.forEach((item) => { @@ -509,27 +588,39 @@ async function refresh() { if (!templateData.some((item) => item.name === state.templateName) && templateData[0]) { state.templateName = templateData[0].name; } + if (state.templateName) { + syncTemplateSelection(state.templateName); + } const meetingsData = await api("/api/meetings"); state.meetings = meetingsData.meetings || []; state.meetingId = meetingsData.active_meeting_id || null; await loadTree(); - await loadTemplate(state.templateName); - - const current = meetingById(state.meetingId); - renderMeetingStatus(current); + renderMeetingStatus(meetingById(state.meetingId)); $("#btn-process").disabled = !state.meetingId || state.processing; - if (current) { + if (state.meetingId) { try { - const result = await api(`/api/meetings/${current.id}/file/meeting_summary.md`); - showResult(result.content); + await loadMeetingSummary(state.meetingId); } catch { - showEmpty(); + showResultEmpty(); } } else { - showEmpty(); + showResultEmpty(); + } + + if ( + state.rightResource && + state.rightResource.type === "template" && + templateData.some((item) => item.name === state.rightResource.name) + ) { + await openTemplate(state.rightResource.name, state.rightResource.treeKey); + return; + } + + if (!state.rightResource && state.templateName) { + await openTemplate(state.templateName); } } @@ -613,43 +704,68 @@ $("#btn-process").addEventListener("click", () => { }; }); -$("#btn-toggle-edit").addEventListener("click", async () => { - state.editMode = !state.editMode; - if (state.editMode) { - $("#template-editor").style.display = "block"; - $("#template-preview").style.display = "none"; - $("#btn-toggle-edit").textContent = "保存模板"; +$("#btn-toggle-result-edit").addEventListener("click", async () => { + if (!state.meetingId) { return; } - const content = $("#template-editor").value; - $("#template-editor").style.display = "none"; - $("#template-preview").style.display = "block"; - $("#btn-toggle-edit").textContent = "编辑模板"; - updateTemplatePreview(content); + if (!state.resultEditMode) { + setResultEditMode(true); + return; + } - await api(`/api/templates/${state.templateName}`, { + const content = $("#result-editor").value; + await api(`/api/meetings/${state.meetingId}/summary`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content }), }); - toast("模板已保存"); + showResult(content); + await refresh(); + toast("会议结果已保存"); +}); + +$("#btn-toggle-side-edit").addEventListener("click", async () => { + const resource = state.rightResource; + if (!resource || !resource.editable) { + return; + } + + if (!state.rightEditMode) { + setRightEditMode(true); + return; + } + + const content = $("#side-editor").value; + if (resource.type === "template") { + await api(`/api/templates/${encodeURIComponent(resource.name)}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ content }), + }); + } else if (resource.type === "prompt") { + await api(`/api/prompts/${encodeURIComponent(resource.name)}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ content }), + }); + } + + resource.content = content; + setRightEditMode(false); + toast("资源已保存"); }); $("#tpl-select").addEventListener("change", async (event) => { - await loadTemplate(event.target.value); + syncTemplateSelection(event.target.value); + await openTemplate(event.target.value); }); -$("#panel-tabs").addEventListener("click", async (event) => { - const tab = event.target.closest(".tab"); - if (!tab) { +$("#btn-open-template").addEventListener("click", async () => { + if (!state.templateName) { return; } - activateTab(tab.dataset.tab); - - if (tab.dataset.tab === "original") { - await loadOriginalContent(state.meetingId); - } + await openTemplate(state.templateName); }); $("#btn-import").addEventListener("click", () => { @@ -727,9 +843,9 @@ $$("[data-close]").forEach((button) => { }); document.addEventListener("DOMContentLoaded", async () => { - document.getElementById("sidebar").dataset.minWidth = "260"; - document.getElementById("result-panel").dataset.minWidth = "360"; - document.getElementById("template-panel").dataset.minWidth = "360"; + $("#sidebar").dataset.minWidth = "260"; + $("#result-panel").dataset.minWidth = "360"; + $("#template-panel").dataset.minWidth = "360"; applySavedLayout(); initResize("gutter-1", "sidebar", "result-panel"); @@ -737,10 +853,6 @@ document.addEventListener("DOMContentLoaded", async () => { try { await refresh(); - activateTab(state.activeTab); - if (state.activeTab === "original") { - await loadOriginalContent(state.meetingId); - } } catch (error) { toast(error.message, "err"); } diff --git a/frontend/assets/styles.css b/frontend/assets/styles.css index aaba3f3..6077ba5 100644 --- a/frontend/assets/styles.css +++ b/frontend/assets/styles.css @@ -51,6 +51,11 @@ textarea { font: inherit; } +.inline-label { + color: var(--muted); + font-size: 13px; +} + .app-shell { height: var(--app-h); padding: 24px; @@ -176,8 +181,8 @@ textarea { .panel-scroll, .tree, -#template-tab, -#original-tab { +#result-editor, +#side-editor { height: 100%; min-height: 0; } @@ -185,10 +190,11 @@ textarea { .tree, #result-body, #template-body, -#template-editor, -#template-preview, -#original-content, -#result-md { +#result-editor, +#result-md, +#side-editor, +#side-preview, +#side-plain-preview { overflow: auto; scrollbar-width: thin; scrollbar-color: #8bb8f1 rgba(232, 242, 255, 0.7); @@ -197,10 +203,11 @@ textarea { .tree::-webkit-scrollbar, #result-body::-webkit-scrollbar, #template-body::-webkit-scrollbar, -#template-editor::-webkit-scrollbar, -#template-preview::-webkit-scrollbar, -#original-content::-webkit-scrollbar, -#result-md::-webkit-scrollbar { +#result-editor::-webkit-scrollbar, +#result-md::-webkit-scrollbar, +#side-editor::-webkit-scrollbar, +#side-preview::-webkit-scrollbar, +#side-plain-preview::-webkit-scrollbar { width: 10px; height: 10px; } @@ -208,10 +215,11 @@ textarea { .tree::-webkit-scrollbar-track, #result-body::-webkit-scrollbar-track, #template-body::-webkit-scrollbar-track, -#template-editor::-webkit-scrollbar-track, -#template-preview::-webkit-scrollbar-track, -#original-content::-webkit-scrollbar-track, -#result-md::-webkit-scrollbar-track { +#result-editor::-webkit-scrollbar-track, +#result-md::-webkit-scrollbar-track, +#side-editor::-webkit-scrollbar-track, +#side-preview::-webkit-scrollbar-track, +#side-plain-preview::-webkit-scrollbar-track { background: rgba(232, 242, 255, 0.8); border-radius: 999px; } @@ -219,10 +227,11 @@ textarea { .tree::-webkit-scrollbar-thumb, #result-body::-webkit-scrollbar-thumb, #template-body::-webkit-scrollbar-thumb, -#template-editor::-webkit-scrollbar-thumb, -#template-preview::-webkit-scrollbar-thumb, -#original-content::-webkit-scrollbar-thumb, -#result-md::-webkit-scrollbar-thumb { +#result-editor::-webkit-scrollbar-thumb, +#result-md::-webkit-scrollbar-thumb, +#side-editor::-webkit-scrollbar-thumb, +#side-preview::-webkit-scrollbar-thumb, +#side-plain-preview::-webkit-scrollbar-thumb { background: linear-gradient(180deg, #8bb8f1, #4f93eb); border-radius: 999px; border: 2px solid rgba(232, 242, 255, 0.8); @@ -484,8 +493,9 @@ select.btn { } .stream-content, -#original-content, -#template-editor { +#result-editor, +#side-editor, +#side-plain-preview { font-family: var(--mono); } @@ -523,59 +533,39 @@ select.btn { } #result-md, -#template-preview, -#original-markdown, -#original-content { +#side-preview, +#side-plain-preview, +#result-editor, +#side-editor { padding: 18px 20px; } #result-md, -#template-preview, -#original-markdown { +#side-preview, +#side-plain-preview, +#result-editor, +#side-editor { display: none; } -#template-editor { +#result-editor, +#side-editor { width: 100%; height: 100%; border: 0; - padding: 18px 20px; background: transparent; resize: none; outline: none; font-size: 13px; line-height: 1.7; - display: none; } -#original-content { +#side-plain-preview { margin: 0; white-space: pre-wrap; line-height: 1.7; } -.panel-tabs { - display: inline-flex; - border: 1px solid var(--line); - border-radius: 999px; - overflow: hidden; - background: rgba(232, 242, 255, 0.55); -} - -.tab { - min-height: 34px; - padding: 0 14px; - border: 0; - background: transparent; - color: var(--muted); - cursor: pointer; -} - -.tab.active { - background: rgba(47, 128, 237, 0.15); - color: var(--accent-strong); -} - .md-content { line-height: 1.8; color: var(--text); diff --git a/frontend/index.html b/frontend/index.html index f0c6aab..940c1e2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -24,7 +24,7 @@