feat: show note emoji icon in wikilinks, relationships, and backlinks

Display the note's frontmatter emoji before its title in the editor
wikilink renderer, relationship LinkButtons, and backlinks panel for
consistent emoji visibility across the app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
lucaronin
2026-03-18 18:30:50 +01:00
parent a1600d5dee
commit 2f43b4bfeb
5 changed files with 77 additions and 8 deletions

View File

@@ -4,6 +4,7 @@ import { createReactInlineContentSpec } from '@blocknote/react'
import { resolveWikilinkColor as resolveColor } from '../utils/wikilinkColors'
import { resolveEntry } from '../utils/wikilink'
import type { VaultEntry } from '../types'
import { isEmoji } from '../utils/emoji'
// Module-level cache so the WikiLink renderer (defined outside React) can access entries
export const _wikilinkEntriesRef: { current: VaultEntry[] } = { current: [] }
@@ -12,15 +13,22 @@ function resolveWikilinkColor(target: string) {
return resolveColor(_wikilinkEntriesRef.current, target)
}
/** Resolve the display text for a wikilink target.
/** Resolve the display text and optional emoji for a wikilink target.
* Priority: pipe display text → entry title → humanised path stem */
function resolveDisplayText(target: string): string {
function resolveDisplayInfo(target: string): { text: string; emoji: string | null } {
const pipeIdx = target.indexOf('|')
if (pipeIdx !== -1) return target.slice(pipeIdx + 1)
if (pipeIdx !== -1) {
const entry = resolveEntry(_wikilinkEntriesRef.current, target.slice(0, pipeIdx))
const emoji = entry?.icon && isEmoji(entry.icon) ? entry.icon : null
return { text: target.slice(pipeIdx + 1), emoji }
}
const entry = resolveEntry(_wikilinkEntriesRef.current, target)
if (entry) return entry.title
if (entry) {
const emoji = entry.icon && isEmoji(entry.icon) ? entry.icon : null
return { text: entry.title, emoji }
}
const last = target.split('/').pop() ?? target
return last.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase())
return { text: last.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()), emoji: null }
}
export const WikiLink = createReactInlineContentSpec(
@@ -35,14 +43,15 @@ export const WikiLink = createReactInlineContentSpec(
render: (props) => {
const target = props.inlineContent.props.target
const { color, isBroken } = resolveWikilinkColor(target)
const displayText = resolveDisplayText(target)
const { text, emoji } = resolveDisplayInfo(target)
return (
<span
className={`wikilink${isBroken ? ' wikilink--broken' : ''}`}
data-target={target}
style={{ color }}
>
{displayText}
{emoji && <span className="wikilink-emoji">{emoji}{' '}</span>}
{text}
</span>
)
},