diff --git a/electron/lib/media/imageMedia.cjs b/electron/lib/media/imageMedia.cjs index d1f3b47a..324cb929 100644 --- a/electron/lib/media/imageMedia.cjs +++ b/electron/lib/media/imageMedia.cjs @@ -250,7 +250,68 @@ function buildPdfExportHtml({ title, markdownContent, baseHref, sourceDir, downs return renderImageHtmlWithAnnotation(defaultImage(tokens, idx, options, env, self), annotation); }; - const bodyHtml = markdown.render(markdownContent || ""); + function processCallouts(html) { + if (!html || typeof html !== "string" || !html.includes("]*>([\s\S]*?)<\/blockquote>/gi; + + return html.replace(bqRegex, (fullMatch, innerContent) => { + const headerMatch = innerContent.match(/^\s*(?:]*>\s*)?\[!([A-Za-z0-9_-]+)\]([^\n<]*)(?:)?/i); + if (!headerMatch) return fullMatch; + + const rawType = headerMatch[1].toUpperCase(); + const customTitle = headerMatch[2].trim(); + const config = calloutConfigs[rawType] || { + title: rawType.charAt(0) + rawType.slice(1).toLowerCase(), + icon: "📌", + class: "callout-note", + }; + + const displayTitle = customTitle || config.title; + + let bodyContent = innerContent.replace(headerMatch[0], "").trim(); + bodyContent = bodyContent.replace(/^<\/p>/i, "").trim(); + + if (bodyContent && !bodyContent.startsWith("

") && !bodyContent.startsWith("${bodyContent}`; + } + if (bodyContent && bodyContent.startsWith("

") && !bodyContent.endsWith("

")) { + bodyContent = `${bodyContent}

`; + } + + return `
+
+ ${config.icon} + ${displayTitle} +
+
+ ${bodyContent} +
+
`; + }); + } + + const bodyHtml = processCallouts(markdown.render(markdownContent || "")); return ` diff --git a/electron/lib/media/pdf.cjs b/electron/lib/media/pdf.cjs index ae082141..234d61a9 100644 --- a/electron/lib/media/pdf.cjs +++ b/electron/lib/media/pdf.cjs @@ -305,6 +305,52 @@ function buildPdfStyles({ compact = false } = {}) { .notely-image-annotation { left: 10px; top: 10px; } + /* Callouts styling for PDF export */ + .notely-callout { + margin: 14px 0; + padding: 12px 16px; + border-radius: 6px; + border-left: 4px solid #3b82f6; + background-color: rgba(59, 130, 246, 0.08); + break-inside: avoid-page; + page-break-inside: avoid; + } + .notely-callout-header { + display: flex; + align-items: center; + gap: 8px; + font-weight: 600; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 0.04em; + margin-bottom: 6px; + color: #1e40af; + } + .notely-callout-icon { + font-size: 14px; + line-height: 1; + } + .notely-callout-body { + font-size: 13px; + line-height: 1.6; + color: #0d1f26; + } + .notely-callout-body p:first-child { margin-top: 0; } + .notely-callout-body p:last-child { margin-bottom: 0; } + + .notely-callout.callout-note { border-left-color: #3b82f6; background-color: rgba(59, 130, 246, 0.08); } + .notely-callout.callout-note .notely-callout-header { color: #2563eb; } + .notely-callout.callout-warning { border-left-color: #f59e0b; background-color: rgba(245, 158, 11, 0.08); } + .notely-callout.callout-warning .notely-callout-header { color: #d97706; } + .notely-callout.callout-tip { border-left-color: #10b981; background-color: rgba(16, 185, 129, 0.08); } + .notely-callout.callout-tip .notely-callout-header { color: #059669; } + .notely-callout.callout-todo { border-left-color: #8b5cf6; background-color: rgba(139, 92, 246, 0.08); } + .notely-callout.callout-todo .notely-callout-header { color: #7c3aed; } + .notely-callout.callout-important { border-left-color: #06b6d4; background-color: rgba(6, 182, 212, 0.08); } + .notely-callout.callout-important .notely-callout-header { color: #0891b2; } + .notely-callout.callout-caution { border-left-color: #ef4444; background-color: rgba(239, 68, 68, 0.08); } + .notely-callout.callout-caution .notely-callout-header { color: #dc2626; } + @media print { pre, .markdown-code-pre { diff --git a/electron/lib/web/websiteRenderer.cjs b/electron/lib/web/websiteRenderer.cjs index aad68d74..72c0c526 100644 --- a/electron/lib/web/websiteRenderer.cjs +++ b/electron/lib/web/websiteRenderer.cjs @@ -370,14 +370,75 @@ function renderMarkdownWebsitePage(relMdPath, rawContent, options = {}) { activeSection = "cleansed"; } - let bodyHtml = `

${escapeHtml(parsed.title || path.basename(relMdPath, ".md"))}

${escapeHtml(relMdPath)}

${markdown.render(normalizedContent, { relMdPath })}
`; + function processCallouts(html) { + if (!html || typeof html !== "string" || !html.includes("]*>([\s\S]*?)<\/blockquote>/gi; + + return html.replace(bqRegex, (fullMatch, innerContent) => { + const headerMatch = innerContent.match(/^\s*(?:]*>\s*)?\[!([A-Za-z0-9_-]+)\]([^\n<]*)(?:)?/i); + if (!headerMatch) return fullMatch; + + const rawType = headerMatch[1].toUpperCase(); + const customTitle = headerMatch[2].trim(); + const config = calloutConfigs[rawType] || { + title: rawType.charAt(0) + rawType.slice(1).toLowerCase(), + icon: "📌", + class: "callout-note", + }; + + const displayTitle = customTitle || config.title; + + let bodyContent = innerContent.replace(headerMatch[0], "").trim(); + bodyContent = bodyContent.replace(/^<\/p>/i, "").trim(); + + if (bodyContent && !bodyContent.startsWith("

") && !bodyContent.startsWith("${bodyContent}`; + } + if (bodyContent && bodyContent.startsWith("

") && !bodyContent.endsWith("

")) { + bodyContent = `${bodyContent}

`; + } + + return `
+
+ ${config.icon} + ${displayTitle} +
+
+ ${bodyContent} +
+
`; + }); + } + + let bodyHtml = `

${escapeHtml(parsed.title || path.basename(relMdPath, ".md"))}

${escapeHtml(relMdPath)}

${processCallouts(markdown.render(normalizedContent, { relMdPath }))}
`; if (hasTabbedSections) { const headerHtml = buildMetadataHtml(parsed); const rawHtml = parsed.rawNotes - ? markdown.render(parsed.rawNotes, { relMdPath }) + ? processCallouts(markdown.render(parsed.rawNotes, { relMdPath })) : `

No raw notes captured yet.

`; const cleansedHtml = parsed.cleansed - ? markdown.render(parsed.cleansed, { relMdPath }) + ? processCallouts(markdown.render(parsed.cleansed, { relMdPath })) : `

No cleansed notes captured yet.

`; bodyHtml = ` @@ -499,6 +560,26 @@ function renderPdfNotePage(relMdPath, markdownContent, options = {}) { .content hr { border: 0; border-top: 1px solid var(--border); margin: 24px 0; } .empty { color: var(--ink-3); font-style: italic; } + /* Callout styling for website & pdf note views */ + .notely-callout { margin: 16px 0; padding: 12px 16px; border-radius: 8px; border-left: 4px solid #3b82f6; background-color: rgba(59, 130, 246, 0.08); box-shadow: 0 1px 3px rgba(0,0,0,0.04); } + .notely-callout-header { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 0.9em; text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px; color: #1e40af; } + .notely-callout-icon { font-size: 1.1em; line-height: 1; } + .notely-callout-body { font-size: 0.95em; line-height: 1.6; color: inherit; } + .notely-callout-body p:first-child { margin-top: 0; } + .notely-callout-body p:last-child { margin-bottom: 0; } + .notely-callout.callout-note { border-left-color: #3b82f6; background-color: rgba(59, 130, 246, 0.08); } + .notely-callout.callout-note .notely-callout-header { color: #2563eb; } + .notely-callout.callout-warning { border-left-color: #f59e0b; background-color: rgba(245, 158, 11, 0.08); } + .notely-callout.callout-warning .notely-callout-header { color: #d97706; } + .notely-callout.callout-tip { border-left-color: #10b981; background-color: rgba(16, 185, 129, 0.08); } + .notely-callout.callout-tip .notely-callout-header { color: #059669; } + .notely-callout.callout-todo { border-left-color: #8b5cf6; background-color: rgba(139, 92, 246, 0.08); } + .notely-callout.callout-todo .notely-callout-header { color: #7c3aed; } + .notely-callout.callout-important { border-left-color: #06b6d4; background-color: rgba(6, 182, 212, 0.08); } + .notely-callout.callout-important .notely-callout-header { color: #0891b2; } + .notely-callout.callout-caution { border-left-color: #ef4444; background-color: rgba(239, 68, 68, 0.08); } + .notely-callout.callout-caution .notely-callout-header { color: #dc2626; } + @page { margin: 18mm 16mm; } @media print { .page { padding: 0; max-width: none; } @@ -508,7 +589,7 @@ function renderPdfNotePage(relMdPath, markdownContent, options = {}) {
- ${contentToRender ? markdown.render(contentToRender, { relMdPath }) : `

${emptyMessage}

`} + ${contentToRender ? processCallouts(markdown.render(contentToRender, { relMdPath })) : `

${emptyMessage}

`}
diff --git a/src/components/MarkdownToolbar.jsx b/src/components/MarkdownToolbar.jsx index c7f3280e..22fc498f 100644 --- a/src/components/MarkdownToolbar.jsx +++ b/src/components/MarkdownToolbar.jsx @@ -932,65 +932,102 @@ export function MarkdownToolbar({ {snippet.key === "callout" && showCalloutPicker && (
-
- Callout Box +
+ Callout Box + 17 types +
+
+ {[ + { label: "Note", icon: "ℹ️", before: "> [!NOTE]\n> " }, + { label: "Info", icon: "ℹ️", before: "> [!INFO]\n> " }, + { label: "Warning", icon: "⚠️", before: "> [!WARNING]\n> " }, + { label: "Tip", icon: "💡", before: "> [!TIP]\n> " }, + { label: "Hint", icon: "💡", before: "> [!HINT]\n> " }, + { label: "Todo", icon: "📝", before: "> [!TODO]\n> " }, + { label: "Important", icon: "🌟", before: "> [!IMPORTANT]\n> " }, + { label: "Caution", icon: "🚫", before: "> [!CAUTION]\n> " }, + { label: "Danger", icon: "🚫", before: "> [!DANGER]\n> " }, + { label: "Error", icon: "🚫", before: "> [!ERROR]\n> " }, + { label: "Bug", icon: "🐛", before: "> [!BUG]\n> " }, + { label: "Success", icon: "✅", before: "> [!SUCCESS]\n> " }, + { label: "Question", icon: "❓", before: "> [!QUESTION]\n> " }, + { label: "Quote", icon: "💬", before: "> [!QUOTE]\n> " }, + { label: "Abstract", icon: "📋", before: "> [!ABSTRACT]\n> " }, + { label: "Summary", icon: "📋", before: "> [!SUMMARY]\n> " }, + { label: "Example", icon: "🔍", before: "> [!EXAMPLE]\n> " }, + ].map((item) => ( + + ))}
- {[ - { label: "Note", icon: "ℹ️", before: "> [!NOTE]\n> " }, - { label: "Warning", icon: "⚠️", before: "> [!WARNING]\n> " }, - { label: "Tip", icon: "💡", before: "> [!TIP]\n> " }, - { label: "Todo", icon: "📝", before: "> [!TODO]\n> " }, - { label: "Important", icon: "🌟", before: "> [!IMPORTANT]\n> " }, - { label: "Caution", icon: "🚫", before: "> [!CAUTION]\n> " }, - ].map((item) => ( - - ))}
)}
diff --git a/src/styles/base.css b/src/styles/base.css index 68872e71..2be639a2 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -121,17 +121,17 @@ button { min-width: 240px; max-width: 380px; padding: 10px 14px; - border-radius: 8px; - border: 1px solid #cad7d3; + border-radius: var(--radius-lg); + border: 1px solid var(--border-soft); background: var(--surface-elevated); color: var(--text-strong); - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); - font-size: 13px; + box-shadow: var(--shadow-lg); + font-size: var(--font-size-body-sm); line-height: 1.4; display: flex; align-items: center; - gap: 10px; - animation: toastSlideIn 0.25s cubic-bezier(0.16, 1, 0.3, 1) forwards; + gap: var(--space-4); + animation: toastSlideIn var(--motion-slow) forwards; } @keyframes toastSlideIn { @@ -146,56 +146,32 @@ button { } .toast-item.success { - border-color: #b7decf; - background: #ebfaf4; - color: #1b6654; + border-color: var(--status-success-border); + background: var(--status-success-bg); + color: var(--status-success-text); } .toast-item.info { - border-color: #bdd2e8; - background: #f1f7ff; - color: #23476e; + border-color: var(--status-info-border); + background: var(--status-info-bg); + color: var(--status-info-text); } .toast-item.warning { - border-color: #e8d3a2; - background: #fff7e8; - color: #73561d; + border-color: var(--status-warning-border); + background: var(--status-warning-bg); + color: var(--status-warning-text); } .toast-item.error { - border-color: #e8c2c2; - background: #fff3f3; - color: #8e1b1b; + border-color: var(--status-danger-border); + background: var(--status-danger-bg); + color: var(--status-danger-text); } [data-theme="dark"] .toast-item { border-color: var(--border-soft); background: var(--surface-bg); color: var(--text-strong); - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.4); -} - -[data-theme="dark"] .toast-item.success { - border-color: #1b6654; - background: #0f3025; - color: #b7decf; -} - -[data-theme="dark"] .toast-item.info { - border-color: #23476e; - background: #112338; - color: #bdd2e8; -} - -[data-theme="dark"] .toast-item.warning { - border-color: #73561d; - background: #3a2b0e; - color: #e8d3a2; -} - -[data-theme="dark"] .toast-item.error { - border-color: #8e1b1b; - background: #470d0d; - color: #e8c2c2; + box-shadow: var(--shadow-lg); } \ No newline at end of file diff --git a/src/styles/callouts.css b/src/styles/callouts.css index c8cd291b..06778b95 100644 --- a/src/styles/callouts.css +++ b/src/styles/callouts.css @@ -116,8 +116,13 @@ --callout-title-color: #f87171; } +.callout-picker-item { + justify-content: flex-start !important; + text-align: left !important; +} + .callout-picker-item:hover { - background-color: var(--accent-subtle, rgba(59, 130, 246, 0.12)) !important; - color: var(--accent-solid, #2563eb) !important; + background-color: var(--surface-accent, rgba(59, 130, 246, 0.12)) !important; + color: var(--text-strong) !important; } diff --git a/src/styles/components.css b/src/styles/components.css index f204c654..de856d52 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -198,8 +198,8 @@ .dashboard-empty { margin: 0; - color: #5f767e; - font-size: 12px; + color: var(--text-muted); + font-size: var(--font-size-label); } @media (max-width: 1080px) { @@ -877,16 +877,16 @@ } .detail-topbar .small-button:not(.active) { - border: 1px solid var(--border-soft) !important; - background: var(--surface-bg) !important; - color: var(--text-strong) !important; - font-weight: 600 !important; + border-color: var(--border-soft); + background: var(--surface-bg); + color: var(--text-strong); + font-weight: 600; } .detail-topbar .small-button:not(.active):hover:not(:disabled) { - border-color: var(--border-default) !important; - background: var(--surface-subtle) !important; - color: var(--text-strong) !important; + border-color: var(--border-default); + background: var(--surface-subtle); + color: var(--text-strong); } .detail-topbar svg { @@ -1662,7 +1662,7 @@ } .small-button.active { - border-color: #b8cec7; + border-color: var(--border-soft); background: var(--surface-accent); color: var(--accent-solid); font-weight: 600; @@ -1696,8 +1696,8 @@ .autosave-status { margin-top: -2px; margin-left: 2px; - color: #4e6a71; - font-size: 11px; + color: var(--text-muted); + font-size: var(--font-size-caption); font-weight: 500; } diff --git a/src/styles/layout.css b/src/styles/layout.css index 1795ebef..3ad8a598 100644 --- a/src/styles/layout.css +++ b/src/styles/layout.css @@ -234,48 +234,48 @@ } .help-doc-article-header { - border-bottom: 1px solid #e1ece8; - margin-bottom: 8px; - padding-bottom: 7px; + border-bottom: 1px solid var(--border-muted); + margin-bottom: var(--space-4); + padding-bottom: var(--space-3); } .help-doc-article-header h3 { margin: 0; - font-size: 15px; - color: #23444b; + font-size: var(--font-size-title); + color: var(--text-strong); } .help-doc-article-header p { - margin: 4px 0 0; - color: #557178; - font-size: 11px; + margin: var(--space-1) 0 0; + color: var(--text-muted); + font-size: var(--font-size-caption); } .help-doc-markdown h1, .help-doc-markdown h2, .help-doc-markdown h3 { - color: #23444b; - margin: 0 0 8px; + color: var(--text-strong); + margin: 0 0 var(--space-4); } .help-doc-markdown h1 { - font-size: 18px; + font-size: var(--font-size-heading-md); } .help-doc-markdown h2 { - font-size: 16px; - margin-top: 12px; + font-size: var(--font-size-title); + margin-top: var(--space-5); } .help-doc-markdown h3 { - font-size: 14px; - margin-top: 8px; + font-size: var(--font-size-body); + margin-top: var(--space-4); } .help-doc-markdown p, .help-doc-markdown li { - color: #355159; - font-size: 12px; + color: var(--text-muted); + font-size: var(--font-size-label); line-height: 1.4; } @@ -286,36 +286,36 @@ } .help-doc-markdown a { - color: #2d5f7f; + color: var(--accent-solid); } .help-doc-markdown table { width: 100%; min-width: 620px; - margin: 10px 0; + margin: var(--space-4) 0; border-collapse: collapse; - border: 1px solid #d7e3df; + border: 1px solid var(--border-muted); background: var(--surface-bg); - font-size: 11px; + font-size: var(--font-size-caption); } .help-doc-markdown th, .help-doc-markdown td { - border: 1px solid #d7e3df; - padding: 6px 8px; + border: 1px solid var(--border-muted); + padding: var(--space-3) var(--space-4); text-align: left; vertical-align: top; - color: #355159; + color: var(--text-muted); } .help-doc-markdown th { - background: #f2f8f6; - color: #23444b; + background: var(--surface-muted); + color: var(--text-strong); font-weight: 700; } .help-doc-markdown tbody tr:nth-child(even) { - background: #fbfdfc; + background: var(--surface-subtle); } @media (max-width: 960px) { @@ -330,14 +330,14 @@ .help-doc-empty { margin: 0; - color: #60797f; - font-size: 12px; + color: var(--text-subtle); + font-size: var(--font-size-label); } .help-center-content section { - border-top: 1px solid #e4ece8; - padding-top: 10px; - margin-top: 10px; + border-top: 1px solid var(--border-muted); + padding-top: var(--space-4); + margin-top: var(--space-4); } .help-center-content section:first-child { @@ -347,29 +347,29 @@ } .help-center-content h3 { - margin: 0 0 8px; + margin: 0 0 var(--space-4); font-size: var(--font-size-body); - color: #1d3d44; + color: var(--text-strong); } .help-center-content ul, .help-center-content ol { margin: 0; padding-left: 18px; - color: #314c53; + color: var(--text-muted); display: grid; - gap: 6px; + gap: var(--space-3); } .help-center-lead { - margin: 0 0 4px; - color: #244147; + margin: 0 0 var(--space-2); + color: var(--text-strong); font-size: var(--font-size-body-sm); } .help-center-version { margin: 0; - color: #4b666d; + color: var(--text-muted); font-size: var(--font-size-label); } @@ -410,12 +410,12 @@ margin: 0; font-size: 24px; letter-spacing: 0.01em; - color: #1f3e45; + color: var(--text-strong); } .about-version-subscript { margin: 1px 0 0; - color: #4d676e; + color: var(--text-muted); font-size: var(--font-size-label); } @@ -427,7 +427,7 @@ .about-copy { margin: 0; max-width: 460px; - color: #3f5b63; + color: var(--text-muted); font-size: var(--font-size-body-sm); line-height: 1.5; } @@ -436,7 +436,7 @@ width: min(420px, 100%); border: 1px solid var(--border-soft); border-radius: var(--radius-lg); - background: #fcfdfd; + background: var(--surface-bg); display: grid; gap: 0; overflow: hidden; @@ -449,8 +449,8 @@ display: flex; align-items: center; gap: 8px; - color: #2f4a52; - font-size: 12px; + color: var(--text-strong); + font-size: var(--font-size-label); border-top: 1px solid var(--border-soft); } @@ -464,7 +464,7 @@ } .about-detail-row a { - color: #2a6177; + color: var(--accent-solid); text-decoration: none; display: inline-flex; align-items: center; @@ -518,12 +518,12 @@ .splash-card h1 { margin: 14px 0 8px; font-size: var(--font-size-display); - color: #23424a; + color: var(--text-strong); } .splash-card p { margin: 0; - color: #46656d; + color: var(--text-muted); } .splash-progress { @@ -531,7 +531,7 @@ width: min(300px, 100%); height: 10px; border-radius: 999px; - border: 1px solid #b8d0c9; + border: 1px solid var(--border-soft); background: var(--surface-accent); overflow: hidden; } @@ -545,14 +545,14 @@ .splash-percent { margin-top: 0 !important; font-size: var(--font-size-body-sm); - color: #3f656f !important; + color: var(--text-strong) !important; font-weight: 700; } .splash-version { margin-top: 8px !important; font-size: var(--font-size-label); - color: #617b82 !important; + color: var(--text-muted) !important; } .command-palette-card { @@ -610,7 +610,7 @@ } .command-palette-group { - border-bottom: 1px solid #e5ece9; + border-bottom: 1px solid var(--border-muted); } .command-palette-group:last-child { @@ -634,7 +634,7 @@ .command-palette-item { width: 100%; border: 0; - border-bottom: 1px solid #edf2f0; + border-bottom: 1px solid var(--border-muted); background: var(--surface-bg); display: flex; align-items: center; @@ -671,10 +671,10 @@ .command-palette-pin-tag { padding: 2px 7px; - border: 1px solid #c8dad3; - border-radius: 999px; - background: #eef6f2; - color: #2d5d55; + border: 1px solid var(--status-success-border); + border-radius: var(--radius-pill); + background: var(--status-success-bg); + color: var(--status-success-text); font-size: 10px; font-weight: 700; letter-spacing: 0.02em; @@ -684,8 +684,8 @@ .command-palette-match { padding: 0 1px; border-radius: var(--radius-sm); - background: #d9ece4; - color: #0f2c32; + background: var(--search-match-bg); + color: var(--search-match-text); } .command-palette-item kbd { @@ -1154,27 +1154,6 @@ gap: 8px; } -.icon-button { - width: 30px; - height: 30px; - border: 1px solid var(--border-default); - border-radius: var(--radius-md); - background: var(--surface-bg); - color: var(--text-strong); - display: inline-flex; - align-items: center; - justify-content: center; - transition: - background var(--motion-fast), - border-color var(--motion-fast), - color var(--motion-fast); -} - -.icon-button:hover { - background: var(--surface-accent); - border-color: #b8cec7; - color: var(--accent-strong); -} .overlay-dialog-header h2 { margin: 0; @@ -1302,25 +1281,22 @@ display: inline-flex; align-items: center; justify-content: center; - gap: 8px; - height: 38px; - font-size: 0.88rem; + gap: var(--space-4); + min-height: var(--btn-height-md); + font-size: var(--font-size-body-sm); font-weight: 500; - border-radius: var(--radius-md, 6px); + border-radius: var(--radius-md); cursor: pointer; - transition: transform var(--motion-standard, 180ms ease), - background var(--motion-standard, 180ms ease), - border-color var(--motion-standard, 180ms ease), - box-shadow var(--motion-standard, 180ms ease); + transition: background var(--motion-standard), + border-color var(--motion-standard), + box-shadow var(--motion-standard); } .confirmation-dialog__actions > button:hover { - transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + box-shadow: var(--shadow-sm); } .confirmation-dialog__actions > button:active { - transform: translateY(0); box-shadow: none; } @@ -1332,14 +1308,14 @@ .confirmation-dialog__actions > button.primary-button:hover { background: var(--accent-strong); - color: var(--text-on-accent, #ffffff); - box-shadow: 0 4px 14px rgba(47, 93, 98, 0.3); + color: var(--text-on-accent); + box-shadow: var(--shadow-sm); } .confirmation-dialog__actions > button.danger:hover { - background: #c93b44; - color: #ffffff; - box-shadow: 0 4px 14px rgba(224, 69, 79, 0.35); + background: color-mix(in srgb, var(--accent-red) 88%, var(--text-strong)); + color: var(--text-on-accent); + box-shadow: var(--shadow-sm); } .workspace-export-intro { diff --git a/src/styles/media.css b/src/styles/media.css index 287888df..b228d5ae 100644 --- a/src/styles/media.css +++ b/src/styles/media.css @@ -1013,70 +1013,6 @@ overflow: visible; } -.small-button { - box-sizing: border-box; - display: inline-flex; - align-items: center; - gap: 5px; - margin: 0; - border: 1px solid #cbdad5; - background: #f7faf8; - color: #1a3a3e; - border-radius: 6px; - padding: 3px 8px; - font-size: 12px; - line-height: 1.2; - cursor: pointer; -} - -.small-button:hover:not(:disabled) { - border-color: #1a3a3e; - background: #eef5f2; -} - -.small-button:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.small-button.danger { - border-color: #e8c2c2; - background: #fff4f4; - color: #8e1b1b; -} - -.small-button.danger:hover:not(:disabled) { - border-color: #c35c5c; - background: #ffeaea; -} - -.small-button.icon-only { - width: 26px; - height: 26px; - aspect-ratio: 1 / 1; - padding: 0; - gap: 0; - justify-content: center; - border-radius: 4px; - flex-shrink: 0; - flex-grow: 0; -} - -.small-button.icon-only svg { - display: block; - flex-shrink: 0; -} - -.media-item-actions .small-button.icon-only { - width: 24px; - height: 24px; - aspect-ratio: 1 / 1; -} - -.media-item-actions .small-button.icon-only svg { - width: 12px; - height: 12px; -} .media-full-preview-overlay { position: fixed; @@ -1493,28 +1429,6 @@ color: var(--text-subtle); } -/* Small buttons */ -:root[data-theme="dark"] .small-button { - background: var(--surface-elevated); - border-color: var(--border-default); - color: var(--text-strong); -} - -:root[data-theme="dark"] .small-button:hover:not(:disabled) { - background: var(--surface-accent); - border-color: var(--border-soft); -} - -:root[data-theme="dark"] .small-button.danger { - background: var(--status-danger-bg); - border-color: var(--status-danger-border); - color: var(--status-danger-text); -} - -:root[data-theme="dark"] .small-button.danger:hover:not(:disabled) { - background: color-mix(in srgb, var(--status-danger-bg) 70%, var(--surface-bg)); - border-color: var(--status-danger-border); -} /* Full preview modal */ :root[data-theme="dark"] .media-full-preview-content { diff --git a/src/styles/titlebar.css b/src/styles/titlebar.css index c486943c..ff421f4d 100644 --- a/src/styles/titlebar.css +++ b/src/styles/titlebar.css @@ -69,7 +69,7 @@ border-radius: var(--radius-sm); cursor: pointer; font-weight: 500; - transition: background 0.1s ease, color 0.1s ease; + transition: background var(--motion-fast), color var(--motion-fast); height: 24px; display: flex; align-items: center; @@ -214,8 +214,7 @@ color: #ffffff !important; } -/* Make sure active windows have distinct contrast if needed */ -body.dark .titlebar-btn:hover { +:root[data-theme="dark"] .titlebar-btn:hover { background: rgba(255, 255, 255, 0.08); } diff --git a/src/styles/variables.css b/src/styles/variables.css index bdf70743..4bc11c2e 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -108,6 +108,10 @@ --kg-doc-border: #ca8a04; --kg-url-bg: #faf5ff; --kg-url-border: #9333ea; + --border-divider: var(--border-muted); + --text-link: var(--accent-solid); + --search-match-bg: color-mix(in srgb, var(--accent-solid) 18%, var(--surface-bg)); + --search-match-text: var(--text-strong); --kg-default-bg: #f3f4f6; --kg-default-border: #6b7280; diff --git a/src/utils/renderUtils.js b/src/utils/renderUtils.js index d5572f15..2129d52f 100644 --- a/src/utils/renderUtils.js +++ b/src/utils/renderUtils.js @@ -202,31 +202,49 @@ export function normalizeMarkdownLinks(content) { export function renderCallouts(html) { if (!html || typeof html !== "string" || !html.includes("]*>\s*]*>\s*\[!(NOTE|WARNING|TIP|TODO|IMPORTANT|CAUTION)\]([^\n<]*?)(?:|\n)?\s*([\s\S]*?)<\/blockquote>/gi; - const calloutConfigs = { NOTE: { title: "Note", icon: "ℹ️", class: "callout-note" }, + INFO: { title: "Info", icon: "ℹ️", class: "callout-note" }, WARNING: { title: "Warning", icon: "⚠️", class: "callout-warning" }, TIP: { title: "Tip", icon: "💡", class: "callout-tip" }, + HINT: { title: "Hint", icon: "💡", class: "callout-tip" }, TODO: { title: "Todo", icon: "📝", class: "callout-todo" }, IMPORTANT: { title: "Important", icon: "🌟", class: "callout-important" }, CAUTION: { title: "Caution", icon: "🚫", class: "callout-caution" }, + DANGER: { title: "Danger", icon: "🚫", class: "callout-caution" }, + ERROR: { title: "Error", icon: "🚫", class: "callout-caution" }, + BUG: { title: "Bug", icon: "🐛", class: "callout-caution" }, + SUCCESS: { title: "Success", icon: "✅", class: "callout-tip" }, + QUESTION: { title: "Question", icon: "❓", class: "callout-todo" }, + QUOTE: { title: "Quote", icon: "💬", class: "callout-note" }, + ABSTRACT: { title: "Abstract", icon: "📋", class: "callout-important" }, + SUMMARY: { title: "Summary", icon: "📋", class: "callout-important" }, + EXAMPLE: { title: "Example", icon: "🔍", class: "callout-note" }, }; - return html.replace(bqRegex, (_match, type, titleExtra, body) => { - const upperType = String(type).toUpperCase(); - const config = calloutConfigs[upperType] || { title: upperType, icon: "📌", class: "callout-note" }; + const bqRegex = /]*>([\s\S]*?)<\/blockquote>/gi; + + return html.replace(bqRegex, (fullMatch, innerContent) => { + const headerMatch = innerContent.match(/^\s*(?:]*>\s*)?\[!([A-Za-z0-9_-]+)\]([^\n<]*)(?:)?/i); + if (!headerMatch) return fullMatch; + + const rawType = headerMatch[1].toUpperCase(); + const customTitle = headerMatch[2].trim(); + const config = calloutConfigs[rawType] || { + title: rawType.charAt(0) + rawType.slice(1).toLowerCase(), + icon: "📌", + class: "callout-note", + }; - let displayTitle = (titleExtra || "").trim(); - if (!displayTitle) displayTitle = config.title; + const displayTitle = customTitle || config.title; - let bodyContent = (body || "").trim(); - bodyContent = bodyContent.replace(/^<\/p>\s*/i, "").replace(/^\s*/i, ""); + let bodyContent = innerContent.replace(headerMatch[0], "").trim(); + bodyContent = bodyContent.replace(/^<\/p>/i, "").trim(); - if (bodyContent && !bodyContent.startsWith("

")) { + if (bodyContent && !bodyContent.startsWith("

") && !bodyContent.startsWith("${bodyContent}`; } - if (bodyContent && !bodyContent.endsWith("

")) { + if (bodyContent && bodyContent.startsWith("

") && !bodyContent.endsWith("

")) { bodyContent = `${bodyContent}

`; }