From 5dcdcd8a6b2a983af46d37f5e89d522402badcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Fri, 17 Jul 2026 11:12:33 +0800 Subject: [PATCH] fix: restore internal note links and reading rhythm --- src/components/Editor.css | 6 ++-- src/components/EditorTheme.css | 32 ++++++++++++++++-- .../useEditorLinkActivation.test.tsx | 25 ++++++++++++++ src/components/useEditorLinkActivation.ts | 33 ++++++++++++++++++- src/theme.json | 20 +++++------ 5 files changed, 99 insertions(+), 17 deletions(-) diff --git a/src/components/Editor.css b/src/components/Editor.css index 11a0813..910def1 100644 --- a/src/components/Editor.css +++ b/src/components/Editor.css @@ -87,10 +87,10 @@ grid-template-columns: 4px minmax(0, 1fr); gap: 12px; width: 100%; - margin: 0.45rem 0; - padding: 11px 13px 11px 0; + margin: 0.8rem 0; + padding: 15px 16px 15px 0; border: 1px solid color-mix(in srgb, var(--tolaria-callout-accent) 28%, var(--border)); - border-radius: 8px; + border-radius: 10px; background: var(--tolaria-callout-bg); } diff --git a/src/components/EditorTheme.css b/src/components/EditorTheme.css index 862e474..3885574 100644 --- a/src/components/EditorTheme.css +++ b/src/components/EditorTheme.css @@ -350,6 +350,12 @@ cursor: text; } +.editor__blocknote-container .bn-editor a[href*=".md"] { + cursor: pointer; + text-decoration-thickness: 1px; + text-underline-offset: 0.18em; +} + /* --- Wikilinks (override from Editor.css with theme vars) --- */ .editor__blocknote-container .wikilink { color: var(--inline-styles-wikilink-color); @@ -657,9 +663,15 @@ body.tldraw-whiteboard-fullscreen-open { background-color: var(--editor-code-block-background) !important; border: 1px solid var(--editor-code-block-border); color: var(--editor-code-block-text) !important; + border-radius: 10px; + box-shadow: 0 1px 0 color-mix(in srgb, var(--editor-code-block-border) 55%, transparent); position: relative; } +.editor__blocknote-container .bn-block-outer:has(> .bn-block > [data-content-type="codeBlock"]) { + margin-block: 10px 16px; +} + .editor__code-block-copy { position: absolute; z-index: 4; @@ -681,6 +693,8 @@ body.tldraw-whiteboard-fullscreen-open { .editor__blocknote-container .bn-block-content[data-content-type="codeBlock"] > pre { color: inherit; + scrollbar-color: color-mix(in srgb, var(--accent-blue) 48%, transparent) transparent; + scrollbar-width: thin; } .editor__blocknote-container .bn-block-content[data-content-type="codeBlock"] > div > select { @@ -706,12 +720,24 @@ body.tldraw-whiteboard-fullscreen-open { /* --- Blockquote --- */ .editor__blocknote-container [data-content-type="blockquote"], .editor__blocknote-container blockquote { - border-inline-start: var(--blockquote-border-left-width) solid var(--blockquote-border-left-color); - padding-inline-start: var(--blockquote-padding-left); + background: color-mix(in srgb, var(--accent-blue) 12%, var(--bg-primary)); + border: 1px solid color-mix(in srgb, var(--accent-blue) 28%, var(--border-primary)); + border-inline-start: 4px solid var(--blockquote-border-left-color); + border-radius: 10px; + padding: 16px 18px; margin-top: var(--blockquote-margin-vertical); margin-bottom: var(--blockquote-margin-vertical); color: var(--blockquote-color); - font-style: var(--blockquote-font-style); + font-style: normal; +} + +.editor__blocknote-container .bn-block-outer:has(> .bn-block > [data-content-type="table"]) { + margin-block: 12px 18px; +} + +.editor__blocknote-container [data-content-type="table"] table { + border-radius: 8px; + overflow: hidden; } /* --- Table --- */ diff --git a/src/components/useEditorLinkActivation.test.tsx b/src/components/useEditorLinkActivation.test.tsx index ab3b62a..bbfcaee 100644 --- a/src/components/useEditorLinkActivation.test.tsx +++ b/src/components/useEditorLinkActivation.test.tsx @@ -128,6 +128,31 @@ describe('useEditorLinkActivation', () => { expect(modifiedClick.defaultPrevented).toBe(true) }) + it('opens relative Markdown note links inside Tolaria on a plain click', async () => { + const { container, onNavigateWikilink } = renderHarness() + const link = appendUrl(container, '../Migration/Related%20Page%20abc123.md#current-status') + + const plainClick = dispatchMouseEvent(link, 'click') + + expect(plainClick.defaultPrevented).toBe(true) + expect(mockOpenLocalFile).not.toHaveBeenCalled() + await Promise.resolve() + expect(onNavigateWikilink).toHaveBeenCalledWith('../Migration/Related Page abc123') + }) + + it('consumes Markdown note link mousedown before editor internals can select it', async () => { + const { container, onNavigateWikilink } = renderHarness() + const link = appendUrl(container, 'docs/Related.md') + + const mouseDown = dispatchMouseEvent(link, 'mousedown') + const click = dispatchMouseEvent(link, 'click') + + expect(mouseDown.defaultPrevented).toBe(true) + expect(click.defaultPrevented).toBe(true) + await Promise.resolve() + expect(onNavigateWikilink).toHaveBeenCalledWith('docs/Related') + }) + it('opens modified URL mousedown before editor internals see stale link nodes', () => { const { container } = renderHarness() const link = appendUrl(container, 'https://example.com') diff --git a/src/components/useEditorLinkActivation.ts b/src/components/useEditorLinkActivation.ts index f29c624..79a2dad 100644 --- a/src/components/useEditorLinkActivation.ts +++ b/src/components/useEditorLinkActivation.ts @@ -26,6 +26,24 @@ function resolveAnchorHref(target: HTMLElement) { return target.closest('a[href]')?.getAttribute('href')?.trim() ?? null } +function decodeLinkPath(path: string) { + try { + return decodeURIComponent(path) + } catch { + return path + } +} + +function resolveMarkdownNoteTarget(href: string) { + const path = href.split(/[?#]/u, 1)[0]?.trim() ?? '' + if (!path || path.startsWith('//') || /^[a-z][a-z\d+.-]*:/iu.test(path)) return null + + const decodedPath = decodeLinkPath(path).replace(/\\/gu, '/') + if (!/\.md(?:own)?$/iu.test(decodedPath)) return null + + return decodedPath.replace(/\.md(?:own)?$/iu, '') +} + function blurActiveEditable(container: HTMLElement) { const active = document.activeElement if (!(active instanceof HTMLElement) || !container.contains(active)) return @@ -84,7 +102,15 @@ function handleEditorLinkClick( } const href = resolveAnchorHref(target) - if (href) activateUrl(event, href, vaultPath) + if (!href) return + + const markdownTarget = resolveMarkdownNoteTarget(href) + if (markdownTarget) { + activateWikilink(event, container, markdownTarget, onNavigateWikilink) + return + } + + activateUrl(event, href, vaultPath) } function handleEditorLinkMouseDown(event: MouseEvent, vaultPath?: string): string | null { @@ -97,6 +123,11 @@ function handleEditorLinkMouseDown(event: MouseEvent, vaultPath?: string): strin } const href = resolveAnchorHref(target) + if (href && resolveMarkdownNoteTarget(href)) { + consumeEditorLinkEvent(event) + return null + } + if (hasFollowModifier(event) && href) { activateUrl(event, href, vaultPath) return href diff --git a/src/theme.json b/src/theme.json index 84b5e4c..92999d2 100644 --- a/src/theme.json +++ b/src/theme.json @@ -1,12 +1,12 @@ { "editor": { "fontFamily": "'Inter', -apple-system, BlinkMacSystemFont, sans-serif", - "fontSize": 15, - "lineHeight": 1.5, - "maxWidth": 820, + "fontSize": 16, + "lineHeight": 1.65, + "maxWidth": 880, "paddingHorizontal": 40, - "paddingVertical": 20, - "paragraphSpacing": 8, + "paddingVertical": 28, + "paragraphSpacing": 12, "dividerFollowedByHeadingMarginTop": 8 }, "headings": { @@ -80,11 +80,11 @@ "code": { "fontFamily": "'SF Mono', 'Fira Code', monospace", "fontSize": 14, - "backgroundColor": "var(--bg-hover-subtle)", - "paddingHorizontal": 4, + "backgroundColor": "color-mix(in srgb, var(--accent-blue) 11%, var(--bg-hover-subtle))", + "paddingHorizontal": 5, "paddingVertical": 2, "borderRadius": 3, - "color": "var(--text-secondary)" + "color": "var(--accent-blue)" }, "link": { "color": "var(--accent-blue)", @@ -100,8 +100,8 @@ "blockquote": { "borderLeftWidth": 3, "borderLeftColor": "var(--accent-blue)", - "paddingLeft": 16, - "marginVertical": 12, + "paddingLeft": 18, + "marginVertical": 16, "color": "var(--text-secondary)", "fontStyle": "italic" },