From d0db9e408e2f8552e648d1f26962c7edd5b5ce47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 04:58:48 +0000 Subject: [PATCH 1/4] Initial plan From b37377a1c4b919a835fe909bfe5701b040ad6060 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 04:59:59 +0000 Subject: [PATCH 2/4] Plan: investigate and fix inline LaTeX rendering Agent-Logs-Url: https://github.com/ThisIs-Developer/Markdown-Viewer/sessions/25e889c7-d501-4e74-9e49-01839bcf0feb Co-authored-by: ThisIs-Developer <109382325+ThisIs-Developer@users.noreply.github.com> --- desktop-app/resources/index.html | 8 +- desktop-app/resources/js/script.js | 353 ++++++++++++++++++++++++++++- desktop-app/resources/styles.css | 247 +++++++++++++++++++- 3 files changed, 591 insertions(+), 17 deletions(-) diff --git a/desktop-app/resources/index.html b/desktop-app/resources/index.html index 87ae86c..e95266a 100644 --- a/desktop-app/resources/index.html +++ b/desktop-app/resources/index.html @@ -51,9 +51,10 @@ - + +
@@ -276,6 +277,11 @@
Menu

Import Markdown from GitHub

+ +
diff --git a/desktop-app/resources/js/script.js b/desktop-app/resources/js/script.js index 7ee9126..cd33aa4 100644 --- a/desktop-app/resources/js/script.js +++ b/desktop-app/resources/js/script.js @@ -65,6 +65,10 @@ document.addEventListener("DOMContentLoaded", function () { const githubImportTitle = document.getElementById("github-import-title"); const githubImportUrlInput = document.getElementById("github-import-url"); const githubImportFileSelect = document.getElementById("github-import-file-select"); + const githubImportSelectionToolbar = document.getElementById("github-import-selection-toolbar"); + const githubImportSelectedCount = document.getElementById("github-import-selected-count"); + const githubImportSelectAllBtn = document.getElementById("github-import-select-all"); + const githubImportTree = document.getElementById("github-import-tree"); const githubImportError = document.getElementById("github-import-error"); const githubImportCancelBtn = document.getElementById("github-import-cancel"); const githubImportSubmitBtn = document.getElementById("github-import-submit"); @@ -132,7 +136,148 @@ document.addEventListener("DOMContentLoaded", function () { renderer: renderer, }); - const sampleMarkdown = `# Welcome to Markdown Viewer + const GITHUB_ALERT_META = { + note: { + label: "Note", + viewBox: "0 0 512 512", + path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z", + }, + tip: { + label: "Tip", + viewBox: "0 0 384 512", + path: "M297.2 248.9C311.6 228.3 320 203.2 320 176c0-70.7-57.3-128-128-128S64 105.3 64 176c0 27.2 8.4 52.3 22.8 72.9c3.7 5.3 8.1 11.3 12.8 17.7c0 0 0 0 0 0c12.9 17.7 28.3 38.9 39.8 59.8c10.4 19 15.7 38.8 18.3 57.5L109 384c-2.2-12-5.9-23.7-11.8-34.5c-9.9-18-22.2-34.9-34.5-51.8c0 0 0 0 0 0s0 0 0 0c-5.2-7.1-10.4-14.2-15.4-21.4C27.6 247.9 16 213.3 16 176C16 78.8 94.8 0 192 0s176 78.8 176 176c0 37.3-11.6 71.9-31.4 100.3c-5 7.2-10.2 14.3-15.4 21.4c0 0 0 0 0 0s0 0 0 0c-12.3 16.8-24.6 33.7-34.5 51.8c-5.9 10.8-9.6 22.5-11.8 34.5l-48.6 0c2.6-18.7 7.9-38.6 18.3-57.5c11.5-20.9 26.9-42.1 39.8-59.8c0 0 0 0 0 0s0 0 0 0s0 0 0 0c4.7-6.4 9-12.4 12.7-17.7zM192 128c-26.5 0-48 21.5-48 48c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-44.2 35.8-80 80-80c8.8 0 16 7.2 16 16s-7.2 16-16 16zm0 384c-44.2 0-80-35.8-80-80l0-16 160 0 0 16c0 44.2-35.8 80-80 80z", + }, + important: { + label: "Important", + viewBox: "0 0 512 512", + path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z", + }, + warning: { + label: "Warning", + viewBox: "0 0 512 512", + path: "M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z", + }, + caution: { + label: "Caution", + viewBox: "0 0 512 512", + path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z", + }, + }; + const GITHUB_ALERT_MARKER_REGEX = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?:\s+|$)/i; + + function enhanceGitHubAlerts(container) { + if (!container) return; + + const blockquotes = container.querySelectorAll("blockquote"); + blockquotes.forEach((blockquote) => { + let firstParagraph = null; + for (const child of blockquote.children) { + if (child.tagName === "P") { + firstParagraph = child; + break; + } + } + if (!firstParagraph) return; + + const firstParagraphHtml = firstParagraph.innerHTML.trim(); + const markerMatch = firstParagraphHtml.match(GITHUB_ALERT_MARKER_REGEX); + if (!markerMatch) return; + + const alertType = markerMatch[1].toLowerCase(); + blockquote.classList.add("markdown-alert", `markdown-alert-${alertType}`); + + const title = document.createElement("p"); + title.className = "markdown-alert-title"; + const alertMeta = GITHUB_ALERT_META[alertType] || { label: markerMatch[1], path: "" }; + const icon = document.createElement("span"); + icon.className = "markdown-alert-icon"; + icon.setAttribute("aria-hidden", "true"); + + if (alertMeta.path) { + const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + svg.setAttribute("viewBox", alertMeta.viewBox || "0 0 512 512"); + const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); + path.setAttribute("d", alertMeta.path); + svg.appendChild(path); + icon.appendChild(svg); + } + + const label = document.createElement("span"); + label.textContent = alertMeta.label; + title.appendChild(icon); + title.appendChild(label); + + blockquote.insertBefore(title, blockquote.firstChild); + + const remainingHtml = firstParagraphHtml + .replace(GITHUB_ALERT_MARKER_REGEX, "") + .trim(); + if (remainingHtml) { + firstParagraph.innerHTML = remainingHtml; + } else { + firstParagraph.remove(); + } + }); + } + + function parseFrontmatter(markdown) { + const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---(\r?\n|$)/); + if (!match) return { frontmatter: null, body: markdown }; + try { + const data = jsyaml.load(match[1]) || {}; + return { frontmatter: data, body: markdown.slice(match[0].length) }; + } catch (e) { + console.warn('Frontmatter YAML parse error:', e); + return { frontmatter: null, body: markdown }; + } + } + + function renderFrontmatterValue(value) { + if (value === null || value === undefined) return ''; + if (value instanceof Date) { + const y = value.getUTCFullYear(); + const m = String(value.getUTCMonth() + 1).padStart(2, '0'); + const d = String(value.getUTCDate()).padStart(2, '0'); + return `${y}-${m}-${d}`; + } + if (Array.isArray(value)) { + const allPrimitive = value.every(v => v === null || typeof v !== 'object'); + if (allPrimitive) { + return value + .map(v => `${escapeHtml(String(v ?? ''))}`) + .join(''); + } + return `
${escapeHtml(jsyaml.dump(value).trimEnd())}
`; + } + if (typeof value === 'object') { + return `
${escapeHtml(jsyaml.dump(value).trimEnd())}
`; + } + return escapeHtml(String(value)); + } + + function renderFrontmatterTable(data) { + const rows = Object.entries(data).map(([key, value]) => + `${escapeHtml(key)}${renderFrontmatterValue(value)}` + ); + return `${rows.join('')}
`; + } + + function escapeHtml(str) { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + } + + const sampleMarkdown = `--- +title: Welcome to Markdown Viewer +description: A GitHub-style Markdown renderer with live preview, math, diagrams, and export support. +author: ThisIs-Developer +tags: ["markdown", "preview", "mermaid", "latex", "open-source"] +--- + +# Welcome to Markdown Viewer ## ✨ Key Features - **Live Preview** with GitHub styling @@ -765,13 +910,15 @@ This is a fully client-side application. Your content never leaves your browser function renderMarkdown() { try { - const markdown = markdownEditor.value; - const html = marked.parse(markdown); + const { frontmatter, body } = parseFrontmatter(markdownEditor.value); + const tableHtml = frontmatter ? renderFrontmatterTable(frontmatter) : ''; + const html = tableHtml + marked.parse(body); const sanitizedHtml = DOMPurify.sanitize(html, { ADD_TAGS: ['mjx-container'], ADD_ATTR: ['id', 'class', 'style'] }); markdownPreview.innerHTML = sanitizedHtml; + enhanceGitHubAlerts(markdownPreview); processEmojis(markdownPreview); @@ -825,6 +972,10 @@ This is a fully client-side application. Your content never leaves your browser return /\.(md|markdown)$/i.test(path || ""); } const MAX_GITHUB_FILES_SHOWN = 30; + const GITHUB_IMPORT_MIN_REQUEST_INTERVAL_MS = 800; + let lastGitHubImportRequestAt = 0; + const selectedGitHubImportPaths = new Set(); + let availableGitHubImportPaths = []; function getFileName(path) { return (path || "").split("/").pop() || "document.md"; @@ -839,6 +990,12 @@ This is a fully client-side application. Your content never leaves your browser } async function fetchGitHubJson(url) { + const now = Date.now(); + const waitTime = GITHUB_IMPORT_MIN_REQUEST_INTERVAL_MS - (now - lastGitHubImportRequestAt); + if (waitTime > 0) { + await new Promise((resolve) => setTimeout(resolve, waitTime)); + } + lastGitHubImportRequestAt = Date.now(); const response = await fetch(url, { headers: { Accept: "application/vnd.github+json" @@ -924,6 +1081,109 @@ This is a fully client-side application. Your content never leaves your browser .sort((a, b) => a.localeCompare(b)); } + function buildMarkdownFileTree(paths) { + const root = { folders: {}, files: [] }; + (paths || []).forEach((path) => { + const segments = (path || "").split("/").filter(Boolean); + if (!segments.length) return; + const fileName = segments.pop(); + let node = root; + segments.forEach((segment) => { + if (!node.folders[segment]) { + node.folders[segment] = { folders: {}, files: [] }; + } + node = node.folders[segment]; + }); + node.files.push({ name: fileName, path }); + }); + return root; + } + + function updateGitHubImportSelectedCount() { + if (!githubImportSelectedCount) return; + const count = selectedGitHubImportPaths.size; + githubImportSelectedCount.textContent = `${count} selected`; + } + + function updateGitHubSelectAllButtonLabel() { + if (!githubImportSelectAllBtn) return; + const total = availableGitHubImportPaths.length; + const allSelected = total > 0 && selectedGitHubImportPaths.size === total; + githubImportSelectAllBtn.textContent = allSelected ? "Clear All" : "Select All"; + } + + function syncGitHubSelectionToButtons() { + if (!githubImportTree) return; + Array.from(githubImportTree.querySelectorAll(".github-tree-file-btn")).forEach((btn) => { + const isSelected = selectedGitHubImportPaths.has(btn.dataset.path); + btn.classList.toggle("is-selected", isSelected); + btn.setAttribute("aria-pressed", isSelected ? "true" : "false"); + }); + } + + function setGitHubSelectedPaths(paths) { + selectedGitHubImportPaths.clear(); + (paths || []).forEach((path) => selectedGitHubImportPaths.add(path)); + updateGitHubImportSelectedCount(); + syncGitHubSelectionToButtons(); + updateGitHubSelectAllButtonLabel(); + } + + function toggleGitHubSelectedPath(path) { + if (!path) return; + if (selectedGitHubImportPaths.has(path)) { + selectedGitHubImportPaths.delete(path); + } else { + selectedGitHubImportPaths.add(path); + } + updateGitHubImportSelectedCount(); + syncGitHubSelectionToButtons(); + updateGitHubSelectAllButtonLabel(); + } + + function renderGitHubImportTree(paths) { + if (!githubImportTree || !githubImportFileSelect) return; + githubImportTree.innerHTML = ""; + const tree = buildMarkdownFileTree(paths); + + const createTreeBranch = function(node, parentPath) { + const list = document.createElement("ul"); + const folderNames = Object.keys(node.folders).sort((a, b) => a.localeCompare(b)); + folderNames.forEach((folderName) => { + const folderPath = parentPath ? `${parentPath}/${folderName}` : folderName; + const item = document.createElement("li"); + const folderLabel = document.createElement("span"); + folderLabel.className = "github-tree-folder-label"; + folderLabel.textContent = `📁 ${folderName}`; + item.appendChild(folderLabel); + item.appendChild(createTreeBranch(node.folders[folderName], folderPath)); + list.appendChild(item); + }); + + node.files + .sort((a, b) => a.path.localeCompare(b.path)) + .forEach((file) => { + const fileItem = document.createElement("li"); + const fileButton = document.createElement("button"); + fileButton.type = "button"; + fileButton.className = "github-tree-file-btn"; + fileButton.dataset.path = file.path; + fileButton.setAttribute("aria-pressed", "false"); + fileButton.textContent = `📄 ${file.name}`; + fileButton.addEventListener("click", function() { + toggleGitHubSelectedPath(file.path); + }); + fileItem.appendChild(fileButton); + list.appendChild(fileItem); + }); + + return list; + }; + + githubImportTree.appendChild(createTreeBranch(tree, "")); + syncGitHubSelectionToButtons(); + } + function setGitHubImportLoading(isLoading) { if (!githubImportSubmitBtn) return; if (isLoading) { @@ -959,6 +1219,15 @@ This is a fully client-side application. Your content never leaves your browser githubImportFileSelect.innerHTML = ""; githubImportFileSelect.style.display = "none"; githubImportFileSelect.disabled = false; + if (githubImportSelectionToolbar) { + githubImportSelectionToolbar.style.display = "none"; + } + availableGitHubImportPaths = []; + setGitHubSelectedPaths([]); + if (githubImportTree) { + githubImportTree.innerHTML = ""; + githubImportTree.style.display = "none"; + } githubImportSubmitBtn.dataset.step = "url"; delete githubImportSubmitBtn.dataset.owner; delete githubImportSubmitBtn.dataset.repo; @@ -987,22 +1256,27 @@ This is a fully client-side application. Your content never leaves your browser if (githubImportCancelBtn) { githubImportCancelBtn.disabled = disabled; } + if (githubImportSelectAllBtn) { + githubImportSelectAllBtn.disabled = disabled; + } }; const step = githubImportSubmitBtn.dataset.step || "url"; if (step === "select") { - const selectedPath = githubImportFileSelect.value; + const selectedPaths = Array.from(selectedGitHubImportPaths); const owner = githubImportSubmitBtn.dataset.owner; const repo = githubImportSubmitBtn.dataset.repo; const ref = githubImportSubmitBtn.dataset.ref; - if (!owner || !repo || !ref || !selectedPath) { - setGitHubImportMessage("Please select a file to import."); + if (!owner || !repo || !ref || !selectedPaths.length) { + setGitHubImportMessage("Please select at least one file to import."); return; } setGitHubImportLoading(true); setGitHubImportDialogDisabled(true); try { - const markdown = await fetchTextContent(buildRawGitHubUrl(owner, repo, ref, selectedPath)); - newTab(markdown, getFileName(selectedPath).replace(/\.(md|markdown)$/i, "")); + for (const selectedPath of selectedPaths) { + const markdown = await fetchTextContent(buildRawGitHubUrl(owner, repo, ref, selectedPath)); + newTab(markdown, getFileName(selectedPath).replace(/\.(md|markdown)$/i, "")); + } closeGitHubImportModal(); } catch (error) { console.error("GitHub import failed:", error); @@ -1057,22 +1331,31 @@ This is a fully client-side application. Your content never leaves your browser return; } - githubImportUrlInput.style.display = "none"; - githubImportFileSelect.style.display = "block"; githubImportFileSelect.innerHTML = ""; + githubImportUrlInput.style.display = "none"; + githubImportFileSelect.style.display = "none"; + if (githubImportSelectionToolbar) { + githubImportSelectionToolbar.style.display = "flex"; + } + if (githubImportTree) { + githubImportTree.style.display = "block"; + } shownFiles.forEach((filePath) => { const option = document.createElement("option"); option.value = filePath; option.textContent = filePath; githubImportFileSelect.appendChild(option); }); + availableGitHubImportPaths = shownFiles.slice(); + setGitHubSelectedPaths(shownFiles[0] ? [shownFiles[0]] : []); + renderGitHubImportTree(shownFiles); if (files.length > MAX_GITHUB_FILES_SHOWN) { setGitHubImportMessage(`Showing first ${MAX_GITHUB_FILES_SHOWN} of ${files.length} Markdown files.`, { isError: false }); } else { setGitHubImportMessage(""); } if (githubImportTitle) { - githubImportTitle.textContent = "Select a Markdown file to import"; + githubImportTitle.textContent = "Select Markdown file(s) to import"; } githubImportSubmitBtn.dataset.step = "select"; githubImportSubmitBtn.dataset.owner = parsed.owner; @@ -1553,6 +1836,13 @@ This is a fully client-side application. Your content never leaves your browser if (githubImportFileSelect) { githubImportFileSelect.addEventListener("keydown", handleGitHubImportInputKeydown); } + if (githubImportSelectAllBtn) { + githubImportSelectAllBtn.addEventListener("click", function() { + const allPaths = availableGitHubImportPaths.slice(); + const shouldSelectAll = selectedGitHubImportPaths.size !== allPaths.length; + setGitHubSelectedPaths(shouldSelectAll ? allPaths : []); + }); + } fileInput.addEventListener("change", function (e) { const file = e.target.files[0]; @@ -1582,6 +1872,10 @@ This is a fully client-side application. Your content never leaves your browser ADD_TAGS: ['mjx-container'], ADD_ATTR: ['id', 'class', 'style'] }); + const tempContainer = document.createElement("div"); + tempContainer.innerHTML = sanitizedHtml; + enhanceGitHubAlerts(tempContainer); + const enhancedHtml = tempContainer.innerHTML; const isDarkTheme = document.documentElement.getAttribute("data-theme") === "dark"; const cssTheme = isDarkTheme @@ -1625,6 +1919,40 @@ This is a fully client-side application. Your content never leaves your browser .hljs-addition { color: ${isDarkTheme ? "#aff5b4" : "#22863a"}; background-color: ${isDarkTheme ? "#033a16" : "#f0fff4"}; } .hljs-deletion { color: ${isDarkTheme ? "#ffdcd7" : "#b31d28"}; background-color: ${isDarkTheme ? "#67060c" : "#ffeef0"}; } + .markdown-alert { + padding: 0.5rem 1rem; + margin-bottom: 16px; + border-left: 0.25em solid; + border-radius: 0.375rem; + } + .markdown-alert > :last-child { + margin-bottom: 0; + } + .markdown-alert-title { + margin: 0 0 8px; + font-weight: 600; + line-height: 1.25; + display: flex; + align-items: center; + gap: 8px; + } + .markdown-alert-icon { + display: inline-flex; + width: 16px; + height: 16px; + } + .markdown-alert-icon svg { + width: 16px; + height: 16px; + fill: currentColor; + } + .markdown-alert-note { color: ${isDarkTheme ? "#4493f8" : "#0969da"}; border-left-color: ${isDarkTheme ? "#4493f8" : "#0969da"}; background-color: ${isDarkTheme ? "rgba(31, 111, 235, 0.15)" : "#ddf4ff"}; } + .markdown-alert-tip { color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; border-left-color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; background-color: ${isDarkTheme ? "rgba(35, 134, 54, 0.15)" : "#dafbe1"}; } + .markdown-alert-important { color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; border-left-color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; background-color: ${isDarkTheme ? "rgba(137, 87, 229, 0.15)" : "#fbefff"}; } + .markdown-alert-warning { color: ${isDarkTheme ? "#d29922" : "#9a6700"}; border-left-color: ${isDarkTheme ? "#d29922" : "#9a6700"}; background-color: ${isDarkTheme ? "rgba(210, 153, 34, 0.18)" : "#fff8c5"}; } + .markdown-alert-caution { color: ${isDarkTheme ? "#f85149" : "#cf222e"}; border-left-color: ${isDarkTheme ? "#f85149" : "#cf222e"}; background-color: ${isDarkTheme ? "rgba(248, 81, 73, 0.18)" : "#ffebe9"}; } + .markdown-alert > *:not(.markdown-alert-title) { color: ${isDarkTheme ? "#c9d1d9" : "#24292e"}; } + @media (max-width: 767px) { .markdown-body { padding: 15px; @@ -1634,7 +1962,7 @@ This is a fully client-side application. Your content never leaves your browser
- ${sanitizedHtml} + ${enhancedHtml}
`; @@ -2147,6 +2475,7 @@ This is a fully client-side application. Your content never leaves your browser const tempElement = document.createElement("div"); tempElement.className = "markdown-body pdf-export"; tempElement.innerHTML = sanitizedHtml; + enhanceGitHubAlerts(tempElement); tempElement.style.padding = "20px"; tempElement.style.width = "210mm"; tempElement.style.margin = "0 auto"; diff --git a/desktop-app/resources/styles.css b/desktop-app/resources/styles.css index e62cf8e..7795594 100644 --- a/desktop-app/resources/styles.css +++ b/desktop-app/resources/styles.css @@ -175,6 +175,102 @@ body { padding: 0.2em 0.4em; } +.markdown-body .markdown-alert { + padding: 0.5rem 1rem; + margin-bottom: 16px; + border-left: 0.25em solid; + border-radius: 0.375rem; +} + +.markdown-body .markdown-alert > :last-child { + margin-bottom: 0; +} + +.markdown-body .markdown-alert-title { + margin: 0 0 8px; + font-weight: 600; + line-height: 1.25; + display: flex; + align-items: center; + gap: 8px; +} + +.markdown-body .markdown-alert-icon { + display: inline-flex; + width: 16px; + height: 16px; +} + +.markdown-body .markdown-alert-icon svg { + width: 16px; + height: 16px; + fill: currentColor; +} + +.markdown-body .markdown-alert-note { + color: #0969da; + border-left-color: #0969da; + background-color: #ddf4ff; +} + +.markdown-body .markdown-alert-tip { + color: #1a7f37; + border-left-color: #1a7f37; + background-color: #dafbe1; +} + +.markdown-body .markdown-alert-important { + color: #8250df; + border-left-color: #8250df; + background-color: #fbefff; +} + +.markdown-body .markdown-alert-warning { + color: #9a6700; + border-left-color: #9a6700; + background-color: #fff8c5; +} + +.markdown-body .markdown-alert-caution { + color: #cf222e; + border-left-color: #cf222e; + background-color: #ffebe9; +} + +.markdown-body .markdown-alert > *:not(.markdown-alert-title) { + color: var(--preview-text-color); +} + +[data-theme="dark"] .markdown-body .markdown-alert-note { + color: #4493f8; + background-color: rgba(31, 111, 235, 0.15); + border-left-color: #4493f8; +} + +[data-theme="dark"] .markdown-body .markdown-alert-tip { + color: #3fb950; + background-color: rgba(35, 134, 54, 0.15); + border-left-color: #3fb950; +} + +[data-theme="dark"] .markdown-body .markdown-alert-important { + color: #ab7df8; + background-color: rgba(137, 87, 229, 0.15); + border-left-color: #ab7df8; +} + +[data-theme="dark"] .markdown-body .markdown-alert-warning { + color: #d29922; + background-color: rgba(210, 153, 34, 0.18); + border-left-color: #d29922; +} + +[data-theme="dark"] .markdown-body .markdown-alert-caution { + color: #f85149; + background-color: rgba(248, 81, 73, 0.18); + border-left-color: #f85149; +} + .toolbar { display: flex; gap: 8px; @@ -1656,10 +1752,12 @@ a:focus { } #github-import-modal .reset-modal-box { - width: min(720px, 92vw); - min-width: 320px; - padding: 28px 32px; - gap: 18px; + width: 60vw; + max-width: 60vw; + min-width: 340px; + padding: 30px 34px; + gap: 16px; + box-shadow: 0 20px 48px rgba(0, 0, 0, 0.22); } #github-import-modal .reset-modal-message { @@ -1675,6 +1773,80 @@ a:focus { font-size: 15px; } +#github-import-file-select { + min-height: 180px; +} + +.github-import-tree { + max-height: 420px; + overflow: auto; + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 12px; + background: var(--bg-color); +} + +.github-import-selection-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 10px 12px; + border: 1px solid var(--border-color); + border-radius: 8px; + background: var(--button-bg); +} + +.github-import-selected-count { + font-size: 14px; + font-weight: 600; + color: var(--text-color); +} + +.github-import-tree ul { + list-style: none; + margin: 0; + padding-left: 18px; +} + +.github-import-tree > ul { + padding-left: 4px; +} + +.github-import-tree li { + margin: 2px 0; +} + +.github-tree-folder-label { + display: inline-block; + font-size: 14px; + color: var(--text-secondary, #57606a); + margin-bottom: 4px; +} + +.github-tree-file-btn { + border: 0; + background: transparent; + color: var(--text-color); + cursor: pointer; + padding: 6px 8px; + border-radius: 6px; + text-align: left; + width: 100%; + font-size: 14px; +} + +.github-tree-file-btn:hover, +.github-tree-file-btn:focus-visible { + background: var(--button-hover); + outline: none; +} + +.github-tree-file-btn.is-selected { + background: rgba(56, 139, 253, 0.14); + color: var(--accent-color); +} + #github-import-modal .reset-modal-actions { gap: 12px; } @@ -1694,6 +1866,11 @@ a:focus { gap: 14px; } + .github-import-selection-toolbar { + flex-direction: column; + align-items: stretch; + } + #github-import-modal .reset-modal-message { font-size: 16px; } @@ -1706,3 +1883,65 @@ a:focus { width: 100%; } } + +.frontmatter-table { + border-collapse: collapse; + margin-bottom: 1.5em; + font-size: 0.9em; + width: auto; + max-width: 100%; +} + +.frontmatter-table th, +.frontmatter-table td { + border: 1px solid var(--border-color); + padding: 6px 13px; + vertical-align: top; + color: var(--text-color); +} + +.frontmatter-table tr:nth-child(odd) th, +.frontmatter-table tr:nth-child(odd) td { + background-color: var(--table-bg); +} + +.frontmatter-table tr:nth-child(even) th, +.frontmatter-table tr:nth-child(even) td { + background-color: var(--editor-bg); +} + +.frontmatter-table th { + font-weight: 600; + text-align: right; + white-space: nowrap; + vertical-align: middle; +} + +.frontmatter-table td { + text-align: left; +} + +.fm-complex { + margin: 0; + padding: 4px 6px; + font-size: 0.8em; + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; + white-space: pre-wrap; + word-break: break-word; + background: transparent; + border: none; + color: var(--text-color); +} + +.fm-tag { + display: inline-block; + padding: 2px 8px; + margin: 2px 3px 2px 0; + border: 1px solid var(--border-color); + border-radius: 2em; + font-size: 0.8em; + font-weight: 500; + color: var(--accent-color); + background-color: var(--button-bg); + white-space: nowrap; +} From 50734aee96712b73a933a3ccf8644a16008baea4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 05:04:02 +0000 Subject: [PATCH 3/4] Fix inline MathJax delimiters and revert unintended resource diffs Agent-Logs-Url: https://github.com/ThisIs-Developer/Markdown-Viewer/sessions/25e889c7-d501-4e74-9e49-01839bcf0feb Co-authored-by: ThisIs-Developer <109382325+ThisIs-Developer@users.noreply.github.com> --- desktop-app/resources/index.html | 9 + desktop-app/resources/js/script.js | 353 +---------------------------- desktop-app/resources/styles.css | 247 +------------------- index.html | 9 + 4 files changed, 34 insertions(+), 584 deletions(-) diff --git a/desktop-app/resources/index.html b/desktop-app/resources/index.html index e95266a..ad5cc61 100644 --- a/desktop-app/resources/index.html +++ b/desktop-app/resources/index.html @@ -45,6 +45,15 @@ + diff --git a/desktop-app/resources/js/script.js b/desktop-app/resources/js/script.js index cd33aa4..7ee9126 100644 --- a/desktop-app/resources/js/script.js +++ b/desktop-app/resources/js/script.js @@ -65,10 +65,6 @@ document.addEventListener("DOMContentLoaded", function () { const githubImportTitle = document.getElementById("github-import-title"); const githubImportUrlInput = document.getElementById("github-import-url"); const githubImportFileSelect = document.getElementById("github-import-file-select"); - const githubImportSelectionToolbar = document.getElementById("github-import-selection-toolbar"); - const githubImportSelectedCount = document.getElementById("github-import-selected-count"); - const githubImportSelectAllBtn = document.getElementById("github-import-select-all"); - const githubImportTree = document.getElementById("github-import-tree"); const githubImportError = document.getElementById("github-import-error"); const githubImportCancelBtn = document.getElementById("github-import-cancel"); const githubImportSubmitBtn = document.getElementById("github-import-submit"); @@ -136,148 +132,7 @@ document.addEventListener("DOMContentLoaded", function () { renderer: renderer, }); - const GITHUB_ALERT_META = { - note: { - label: "Note", - viewBox: "0 0 512 512", - path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z", - }, - tip: { - label: "Tip", - viewBox: "0 0 384 512", - path: "M297.2 248.9C311.6 228.3 320 203.2 320 176c0-70.7-57.3-128-128-128S64 105.3 64 176c0 27.2 8.4 52.3 22.8 72.9c3.7 5.3 8.1 11.3 12.8 17.7c0 0 0 0 0 0c12.9 17.7 28.3 38.9 39.8 59.8c10.4 19 15.7 38.8 18.3 57.5L109 384c-2.2-12-5.9-23.7-11.8-34.5c-9.9-18-22.2-34.9-34.5-51.8c0 0 0 0 0 0s0 0 0 0c-5.2-7.1-10.4-14.2-15.4-21.4C27.6 247.9 16 213.3 16 176C16 78.8 94.8 0 192 0s176 78.8 176 176c0 37.3-11.6 71.9-31.4 100.3c-5 7.2-10.2 14.3-15.4 21.4c0 0 0 0 0 0s0 0 0 0c-12.3 16.8-24.6 33.7-34.5 51.8c-5.9 10.8-9.6 22.5-11.8 34.5l-48.6 0c2.6-18.7 7.9-38.6 18.3-57.5c11.5-20.9 26.9-42.1 39.8-59.8c0 0 0 0 0 0s0 0 0 0s0 0 0 0c4.7-6.4 9-12.4 12.7-17.7zM192 128c-26.5 0-48 21.5-48 48c0 8.8-7.2 16-16 16s-16-7.2-16-16c0-44.2 35.8-80 80-80c8.8 0 16 7.2 16 16s-7.2 16-16 16zm0 384c-44.2 0-80-35.8-80-80l0-16 160 0 0 16c0 44.2-35.8 80-80 80z", - }, - important: { - label: "Important", - viewBox: "0 0 512 512", - path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z", - }, - warning: { - label: "Warning", - viewBox: "0 0 512 512", - path: "M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z", - }, - caution: { - label: "Caution", - viewBox: "0 0 512 512", - path: "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z", - }, - }; - const GITHUB_ALERT_MARKER_REGEX = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?:\s+|$)/i; - - function enhanceGitHubAlerts(container) { - if (!container) return; - - const blockquotes = container.querySelectorAll("blockquote"); - blockquotes.forEach((blockquote) => { - let firstParagraph = null; - for (const child of blockquote.children) { - if (child.tagName === "P") { - firstParagraph = child; - break; - } - } - if (!firstParagraph) return; - - const firstParagraphHtml = firstParagraph.innerHTML.trim(); - const markerMatch = firstParagraphHtml.match(GITHUB_ALERT_MARKER_REGEX); - if (!markerMatch) return; - - const alertType = markerMatch[1].toLowerCase(); - blockquote.classList.add("markdown-alert", `markdown-alert-${alertType}`); - - const title = document.createElement("p"); - title.className = "markdown-alert-title"; - const alertMeta = GITHUB_ALERT_META[alertType] || { label: markerMatch[1], path: "" }; - const icon = document.createElement("span"); - icon.className = "markdown-alert-icon"; - icon.setAttribute("aria-hidden", "true"); - - if (alertMeta.path) { - const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - svg.setAttribute("viewBox", alertMeta.viewBox || "0 0 512 512"); - const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); - path.setAttribute("d", alertMeta.path); - svg.appendChild(path); - icon.appendChild(svg); - } - - const label = document.createElement("span"); - label.textContent = alertMeta.label; - title.appendChild(icon); - title.appendChild(label); - - blockquote.insertBefore(title, blockquote.firstChild); - - const remainingHtml = firstParagraphHtml - .replace(GITHUB_ALERT_MARKER_REGEX, "") - .trim(); - if (remainingHtml) { - firstParagraph.innerHTML = remainingHtml; - } else { - firstParagraph.remove(); - } - }); - } - - function parseFrontmatter(markdown) { - const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---(\r?\n|$)/); - if (!match) return { frontmatter: null, body: markdown }; - try { - const data = jsyaml.load(match[1]) || {}; - return { frontmatter: data, body: markdown.slice(match[0].length) }; - } catch (e) { - console.warn('Frontmatter YAML parse error:', e); - return { frontmatter: null, body: markdown }; - } - } - - function renderFrontmatterValue(value) { - if (value === null || value === undefined) return ''; - if (value instanceof Date) { - const y = value.getUTCFullYear(); - const m = String(value.getUTCMonth() + 1).padStart(2, '0'); - const d = String(value.getUTCDate()).padStart(2, '0'); - return `${y}-${m}-${d}`; - } - if (Array.isArray(value)) { - const allPrimitive = value.every(v => v === null || typeof v !== 'object'); - if (allPrimitive) { - return value - .map(v => `${escapeHtml(String(v ?? ''))}`) - .join(''); - } - return `
${escapeHtml(jsyaml.dump(value).trimEnd())}
`; - } - if (typeof value === 'object') { - return `
${escapeHtml(jsyaml.dump(value).trimEnd())}
`; - } - return escapeHtml(String(value)); - } - - function renderFrontmatterTable(data) { - const rows = Object.entries(data).map(([key, value]) => - `${escapeHtml(key)}${renderFrontmatterValue(value)}` - ); - return `${rows.join('')}
`; - } - - function escapeHtml(str) { - return str - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - const sampleMarkdown = `--- -title: Welcome to Markdown Viewer -description: A GitHub-style Markdown renderer with live preview, math, diagrams, and export support. -author: ThisIs-Developer -tags: ["markdown", "preview", "mermaid", "latex", "open-source"] ---- - -# Welcome to Markdown Viewer + const sampleMarkdown = `# Welcome to Markdown Viewer ## ✨ Key Features - **Live Preview** with GitHub styling @@ -910,15 +765,13 @@ This is a fully client-side application. Your content never leaves your browser function renderMarkdown() { try { - const { frontmatter, body } = parseFrontmatter(markdownEditor.value); - const tableHtml = frontmatter ? renderFrontmatterTable(frontmatter) : ''; - const html = tableHtml + marked.parse(body); + const markdown = markdownEditor.value; + const html = marked.parse(markdown); const sanitizedHtml = DOMPurify.sanitize(html, { ADD_TAGS: ['mjx-container'], ADD_ATTR: ['id', 'class', 'style'] }); markdownPreview.innerHTML = sanitizedHtml; - enhanceGitHubAlerts(markdownPreview); processEmojis(markdownPreview); @@ -972,10 +825,6 @@ This is a fully client-side application. Your content never leaves your browser return /\.(md|markdown)$/i.test(path || ""); } const MAX_GITHUB_FILES_SHOWN = 30; - const GITHUB_IMPORT_MIN_REQUEST_INTERVAL_MS = 800; - let lastGitHubImportRequestAt = 0; - const selectedGitHubImportPaths = new Set(); - let availableGitHubImportPaths = []; function getFileName(path) { return (path || "").split("/").pop() || "document.md"; @@ -990,12 +839,6 @@ This is a fully client-side application. Your content never leaves your browser } async function fetchGitHubJson(url) { - const now = Date.now(); - const waitTime = GITHUB_IMPORT_MIN_REQUEST_INTERVAL_MS - (now - lastGitHubImportRequestAt); - if (waitTime > 0) { - await new Promise((resolve) => setTimeout(resolve, waitTime)); - } - lastGitHubImportRequestAt = Date.now(); const response = await fetch(url, { headers: { Accept: "application/vnd.github+json" @@ -1081,109 +924,6 @@ This is a fully client-side application. Your content never leaves your browser .sort((a, b) => a.localeCompare(b)); } - function buildMarkdownFileTree(paths) { - const root = { folders: {}, files: [] }; - (paths || []).forEach((path) => { - const segments = (path || "").split("/").filter(Boolean); - if (!segments.length) return; - const fileName = segments.pop(); - let node = root; - segments.forEach((segment) => { - if (!node.folders[segment]) { - node.folders[segment] = { folders: {}, files: [] }; - } - node = node.folders[segment]; - }); - node.files.push({ name: fileName, path }); - }); - return root; - } - - function updateGitHubImportSelectedCount() { - if (!githubImportSelectedCount) return; - const count = selectedGitHubImportPaths.size; - githubImportSelectedCount.textContent = `${count} selected`; - } - - function updateGitHubSelectAllButtonLabel() { - if (!githubImportSelectAllBtn) return; - const total = availableGitHubImportPaths.length; - const allSelected = total > 0 && selectedGitHubImportPaths.size === total; - githubImportSelectAllBtn.textContent = allSelected ? "Clear All" : "Select All"; - } - - function syncGitHubSelectionToButtons() { - if (!githubImportTree) return; - Array.from(githubImportTree.querySelectorAll(".github-tree-file-btn")).forEach((btn) => { - const isSelected = selectedGitHubImportPaths.has(btn.dataset.path); - btn.classList.toggle("is-selected", isSelected); - btn.setAttribute("aria-pressed", isSelected ? "true" : "false"); - }); - } - - function setGitHubSelectedPaths(paths) { - selectedGitHubImportPaths.clear(); - (paths || []).forEach((path) => selectedGitHubImportPaths.add(path)); - updateGitHubImportSelectedCount(); - syncGitHubSelectionToButtons(); - updateGitHubSelectAllButtonLabel(); - } - - function toggleGitHubSelectedPath(path) { - if (!path) return; - if (selectedGitHubImportPaths.has(path)) { - selectedGitHubImportPaths.delete(path); - } else { - selectedGitHubImportPaths.add(path); - } - updateGitHubImportSelectedCount(); - syncGitHubSelectionToButtons(); - updateGitHubSelectAllButtonLabel(); - } - - function renderGitHubImportTree(paths) { - if (!githubImportTree || !githubImportFileSelect) return; - githubImportTree.innerHTML = ""; - const tree = buildMarkdownFileTree(paths); - - const createTreeBranch = function(node, parentPath) { - const list = document.createElement("ul"); - const folderNames = Object.keys(node.folders).sort((a, b) => a.localeCompare(b)); - folderNames.forEach((folderName) => { - const folderPath = parentPath ? `${parentPath}/${folderName}` : folderName; - const item = document.createElement("li"); - const folderLabel = document.createElement("span"); - folderLabel.className = "github-tree-folder-label"; - folderLabel.textContent = `📁 ${folderName}`; - item.appendChild(folderLabel); - item.appendChild(createTreeBranch(node.folders[folderName], folderPath)); - list.appendChild(item); - }); - - node.files - .sort((a, b) => a.path.localeCompare(b.path)) - .forEach((file) => { - const fileItem = document.createElement("li"); - const fileButton = document.createElement("button"); - fileButton.type = "button"; - fileButton.className = "github-tree-file-btn"; - fileButton.dataset.path = file.path; - fileButton.setAttribute("aria-pressed", "false"); - fileButton.textContent = `📄 ${file.name}`; - fileButton.addEventListener("click", function() { - toggleGitHubSelectedPath(file.path); - }); - fileItem.appendChild(fileButton); - list.appendChild(fileItem); - }); - - return list; - }; - - githubImportTree.appendChild(createTreeBranch(tree, "")); - syncGitHubSelectionToButtons(); - } - function setGitHubImportLoading(isLoading) { if (!githubImportSubmitBtn) return; if (isLoading) { @@ -1219,15 +959,6 @@ This is a fully client-side application. Your content never leaves your browser githubImportFileSelect.innerHTML = ""; githubImportFileSelect.style.display = "none"; githubImportFileSelect.disabled = false; - if (githubImportSelectionToolbar) { - githubImportSelectionToolbar.style.display = "none"; - } - availableGitHubImportPaths = []; - setGitHubSelectedPaths([]); - if (githubImportTree) { - githubImportTree.innerHTML = ""; - githubImportTree.style.display = "none"; - } githubImportSubmitBtn.dataset.step = "url"; delete githubImportSubmitBtn.dataset.owner; delete githubImportSubmitBtn.dataset.repo; @@ -1256,27 +987,22 @@ This is a fully client-side application. Your content never leaves your browser if (githubImportCancelBtn) { githubImportCancelBtn.disabled = disabled; } - if (githubImportSelectAllBtn) { - githubImportSelectAllBtn.disabled = disabled; - } }; const step = githubImportSubmitBtn.dataset.step || "url"; if (step === "select") { - const selectedPaths = Array.from(selectedGitHubImportPaths); + const selectedPath = githubImportFileSelect.value; const owner = githubImportSubmitBtn.dataset.owner; const repo = githubImportSubmitBtn.dataset.repo; const ref = githubImportSubmitBtn.dataset.ref; - if (!owner || !repo || !ref || !selectedPaths.length) { - setGitHubImportMessage("Please select at least one file to import."); + if (!owner || !repo || !ref || !selectedPath) { + setGitHubImportMessage("Please select a file to import."); return; } setGitHubImportLoading(true); setGitHubImportDialogDisabled(true); try { - for (const selectedPath of selectedPaths) { - const markdown = await fetchTextContent(buildRawGitHubUrl(owner, repo, ref, selectedPath)); - newTab(markdown, getFileName(selectedPath).replace(/\.(md|markdown)$/i, "")); - } + const markdown = await fetchTextContent(buildRawGitHubUrl(owner, repo, ref, selectedPath)); + newTab(markdown, getFileName(selectedPath).replace(/\.(md|markdown)$/i, "")); closeGitHubImportModal(); } catch (error) { console.error("GitHub import failed:", error); @@ -1331,31 +1057,22 @@ This is a fully client-side application. Your content never leaves your browser return; } - githubImportFileSelect.innerHTML = ""; githubImportUrlInput.style.display = "none"; - githubImportFileSelect.style.display = "none"; - if (githubImportSelectionToolbar) { - githubImportSelectionToolbar.style.display = "flex"; - } - if (githubImportTree) { - githubImportTree.style.display = "block"; - } + githubImportFileSelect.style.display = "block"; + githubImportFileSelect.innerHTML = ""; shownFiles.forEach((filePath) => { const option = document.createElement("option"); option.value = filePath; option.textContent = filePath; githubImportFileSelect.appendChild(option); }); - availableGitHubImportPaths = shownFiles.slice(); - setGitHubSelectedPaths(shownFiles[0] ? [shownFiles[0]] : []); - renderGitHubImportTree(shownFiles); if (files.length > MAX_GITHUB_FILES_SHOWN) { setGitHubImportMessage(`Showing first ${MAX_GITHUB_FILES_SHOWN} of ${files.length} Markdown files.`, { isError: false }); } else { setGitHubImportMessage(""); } if (githubImportTitle) { - githubImportTitle.textContent = "Select Markdown file(s) to import"; + githubImportTitle.textContent = "Select a Markdown file to import"; } githubImportSubmitBtn.dataset.step = "select"; githubImportSubmitBtn.dataset.owner = parsed.owner; @@ -1836,13 +1553,6 @@ This is a fully client-side application. Your content never leaves your browser if (githubImportFileSelect) { githubImportFileSelect.addEventListener("keydown", handleGitHubImportInputKeydown); } - if (githubImportSelectAllBtn) { - githubImportSelectAllBtn.addEventListener("click", function() { - const allPaths = availableGitHubImportPaths.slice(); - const shouldSelectAll = selectedGitHubImportPaths.size !== allPaths.length; - setGitHubSelectedPaths(shouldSelectAll ? allPaths : []); - }); - } fileInput.addEventListener("change", function (e) { const file = e.target.files[0]; @@ -1872,10 +1582,6 @@ This is a fully client-side application. Your content never leaves your browser ADD_TAGS: ['mjx-container'], ADD_ATTR: ['id', 'class', 'style'] }); - const tempContainer = document.createElement("div"); - tempContainer.innerHTML = sanitizedHtml; - enhanceGitHubAlerts(tempContainer); - const enhancedHtml = tempContainer.innerHTML; const isDarkTheme = document.documentElement.getAttribute("data-theme") === "dark"; const cssTheme = isDarkTheme @@ -1919,40 +1625,6 @@ This is a fully client-side application. Your content never leaves your browser .hljs-addition { color: ${isDarkTheme ? "#aff5b4" : "#22863a"}; background-color: ${isDarkTheme ? "#033a16" : "#f0fff4"}; } .hljs-deletion { color: ${isDarkTheme ? "#ffdcd7" : "#b31d28"}; background-color: ${isDarkTheme ? "#67060c" : "#ffeef0"}; } - .markdown-alert { - padding: 0.5rem 1rem; - margin-bottom: 16px; - border-left: 0.25em solid; - border-radius: 0.375rem; - } - .markdown-alert > :last-child { - margin-bottom: 0; - } - .markdown-alert-title { - margin: 0 0 8px; - font-weight: 600; - line-height: 1.25; - display: flex; - align-items: center; - gap: 8px; - } - .markdown-alert-icon { - display: inline-flex; - width: 16px; - height: 16px; - } - .markdown-alert-icon svg { - width: 16px; - height: 16px; - fill: currentColor; - } - .markdown-alert-note { color: ${isDarkTheme ? "#4493f8" : "#0969da"}; border-left-color: ${isDarkTheme ? "#4493f8" : "#0969da"}; background-color: ${isDarkTheme ? "rgba(31, 111, 235, 0.15)" : "#ddf4ff"}; } - .markdown-alert-tip { color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; border-left-color: ${isDarkTheme ? "#3fb950" : "#1a7f37"}; background-color: ${isDarkTheme ? "rgba(35, 134, 54, 0.15)" : "#dafbe1"}; } - .markdown-alert-important { color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; border-left-color: ${isDarkTheme ? "#ab7df8" : "#8250df"}; background-color: ${isDarkTheme ? "rgba(137, 87, 229, 0.15)" : "#fbefff"}; } - .markdown-alert-warning { color: ${isDarkTheme ? "#d29922" : "#9a6700"}; border-left-color: ${isDarkTheme ? "#d29922" : "#9a6700"}; background-color: ${isDarkTheme ? "rgba(210, 153, 34, 0.18)" : "#fff8c5"}; } - .markdown-alert-caution { color: ${isDarkTheme ? "#f85149" : "#cf222e"}; border-left-color: ${isDarkTheme ? "#f85149" : "#cf222e"}; background-color: ${isDarkTheme ? "rgba(248, 81, 73, 0.18)" : "#ffebe9"}; } - .markdown-alert > *:not(.markdown-alert-title) { color: ${isDarkTheme ? "#c9d1d9" : "#24292e"}; } - @media (max-width: 767px) { .markdown-body { padding: 15px; @@ -1962,7 +1634,7 @@ This is a fully client-side application. Your content never leaves your browser
- ${enhancedHtml} + ${sanitizedHtml}
`; @@ -2475,7 +2147,6 @@ This is a fully client-side application. Your content never leaves your browser const tempElement = document.createElement("div"); tempElement.className = "markdown-body pdf-export"; tempElement.innerHTML = sanitizedHtml; - enhanceGitHubAlerts(tempElement); tempElement.style.padding = "20px"; tempElement.style.width = "210mm"; tempElement.style.margin = "0 auto"; diff --git a/desktop-app/resources/styles.css b/desktop-app/resources/styles.css index 7795594..e62cf8e 100644 --- a/desktop-app/resources/styles.css +++ b/desktop-app/resources/styles.css @@ -175,102 +175,6 @@ body { padding: 0.2em 0.4em; } -.markdown-body .markdown-alert { - padding: 0.5rem 1rem; - margin-bottom: 16px; - border-left: 0.25em solid; - border-radius: 0.375rem; -} - -.markdown-body .markdown-alert > :last-child { - margin-bottom: 0; -} - -.markdown-body .markdown-alert-title { - margin: 0 0 8px; - font-weight: 600; - line-height: 1.25; - display: flex; - align-items: center; - gap: 8px; -} - -.markdown-body .markdown-alert-icon { - display: inline-flex; - width: 16px; - height: 16px; -} - -.markdown-body .markdown-alert-icon svg { - width: 16px; - height: 16px; - fill: currentColor; -} - -.markdown-body .markdown-alert-note { - color: #0969da; - border-left-color: #0969da; - background-color: #ddf4ff; -} - -.markdown-body .markdown-alert-tip { - color: #1a7f37; - border-left-color: #1a7f37; - background-color: #dafbe1; -} - -.markdown-body .markdown-alert-important { - color: #8250df; - border-left-color: #8250df; - background-color: #fbefff; -} - -.markdown-body .markdown-alert-warning { - color: #9a6700; - border-left-color: #9a6700; - background-color: #fff8c5; -} - -.markdown-body .markdown-alert-caution { - color: #cf222e; - border-left-color: #cf222e; - background-color: #ffebe9; -} - -.markdown-body .markdown-alert > *:not(.markdown-alert-title) { - color: var(--preview-text-color); -} - -[data-theme="dark"] .markdown-body .markdown-alert-note { - color: #4493f8; - background-color: rgba(31, 111, 235, 0.15); - border-left-color: #4493f8; -} - -[data-theme="dark"] .markdown-body .markdown-alert-tip { - color: #3fb950; - background-color: rgba(35, 134, 54, 0.15); - border-left-color: #3fb950; -} - -[data-theme="dark"] .markdown-body .markdown-alert-important { - color: #ab7df8; - background-color: rgba(137, 87, 229, 0.15); - border-left-color: #ab7df8; -} - -[data-theme="dark"] .markdown-body .markdown-alert-warning { - color: #d29922; - background-color: rgba(210, 153, 34, 0.18); - border-left-color: #d29922; -} - -[data-theme="dark"] .markdown-body .markdown-alert-caution { - color: #f85149; - background-color: rgba(248, 81, 73, 0.18); - border-left-color: #f85149; -} - .toolbar { display: flex; gap: 8px; @@ -1752,12 +1656,10 @@ a:focus { } #github-import-modal .reset-modal-box { - width: 60vw; - max-width: 60vw; - min-width: 340px; - padding: 30px 34px; - gap: 16px; - box-shadow: 0 20px 48px rgba(0, 0, 0, 0.22); + width: min(720px, 92vw); + min-width: 320px; + padding: 28px 32px; + gap: 18px; } #github-import-modal .reset-modal-message { @@ -1773,80 +1675,6 @@ a:focus { font-size: 15px; } -#github-import-file-select { - min-height: 180px; -} - -.github-import-tree { - max-height: 420px; - overflow: auto; - border: 1px solid var(--border-color); - border-radius: 10px; - padding: 12px; - background: var(--bg-color); -} - -.github-import-selection-toolbar { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 10px 12px; - border: 1px solid var(--border-color); - border-radius: 8px; - background: var(--button-bg); -} - -.github-import-selected-count { - font-size: 14px; - font-weight: 600; - color: var(--text-color); -} - -.github-import-tree ul { - list-style: none; - margin: 0; - padding-left: 18px; -} - -.github-import-tree > ul { - padding-left: 4px; -} - -.github-import-tree li { - margin: 2px 0; -} - -.github-tree-folder-label { - display: inline-block; - font-size: 14px; - color: var(--text-secondary, #57606a); - margin-bottom: 4px; -} - -.github-tree-file-btn { - border: 0; - background: transparent; - color: var(--text-color); - cursor: pointer; - padding: 6px 8px; - border-radius: 6px; - text-align: left; - width: 100%; - font-size: 14px; -} - -.github-tree-file-btn:hover, -.github-tree-file-btn:focus-visible { - background: var(--button-hover); - outline: none; -} - -.github-tree-file-btn.is-selected { - background: rgba(56, 139, 253, 0.14); - color: var(--accent-color); -} - #github-import-modal .reset-modal-actions { gap: 12px; } @@ -1866,11 +1694,6 @@ a:focus { gap: 14px; } - .github-import-selection-toolbar { - flex-direction: column; - align-items: stretch; - } - #github-import-modal .reset-modal-message { font-size: 16px; } @@ -1883,65 +1706,3 @@ a:focus { width: 100%; } } - -.frontmatter-table { - border-collapse: collapse; - margin-bottom: 1.5em; - font-size: 0.9em; - width: auto; - max-width: 100%; -} - -.frontmatter-table th, -.frontmatter-table td { - border: 1px solid var(--border-color); - padding: 6px 13px; - vertical-align: top; - color: var(--text-color); -} - -.frontmatter-table tr:nth-child(odd) th, -.frontmatter-table tr:nth-child(odd) td { - background-color: var(--table-bg); -} - -.frontmatter-table tr:nth-child(even) th, -.frontmatter-table tr:nth-child(even) td { - background-color: var(--editor-bg); -} - -.frontmatter-table th { - font-weight: 600; - text-align: right; - white-space: nowrap; - vertical-align: middle; -} - -.frontmatter-table td { - text-align: left; -} - -.fm-complex { - margin: 0; - padding: 4px 6px; - font-size: 0.8em; - font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; - white-space: pre-wrap; - word-break: break-word; - background: transparent; - border: none; - color: var(--text-color); -} - -.fm-tag { - display: inline-block; - padding: 2px 8px; - margin: 2px 3px 2px 0; - border: 1px solid var(--border-color); - border-radius: 2em; - font-size: 0.8em; - font-weight: 500; - color: var(--accent-color); - background-color: var(--button-bg); - white-space: nowrap; -} diff --git a/index.html b/index.html index 4ffa716..c455045 100644 --- a/index.html +++ b/index.html @@ -45,6 +45,15 @@ + From 4144576011aa79dfe16e602eb341b443f273bda0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 05:06:11 +0000 Subject: [PATCH 4/4] Normalize script tag indentation in index files Agent-Logs-Url: https://github.com/ThisIs-Developer/Markdown-Viewer/sessions/25e889c7-d501-4e74-9e49-01839bcf0feb Co-authored-by: ThisIs-Developer <109382325+ThisIs-Developer@users.noreply.github.com> --- desktop-app/resources/index.html | 8 ++++---- index.html | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/desktop-app/resources/index.html b/desktop-app/resources/index.html index ad5cc61..e883ac4 100644 --- a/desktop-app/resources/index.html +++ b/desktop-app/resources/index.html @@ -60,10 +60,10 @@ - - - - + + + +
diff --git a/index.html b/index.html index c455045..407a507 100644 --- a/index.html +++ b/index.html @@ -60,10 +60,10 @@ - - - - + + + +