feat(TextViewStatic): add item colors to @mentions

- Pass items and getItemColor to simpleMarkdownToHtml
- Item mentions now display with correct colors (item.color → tag color → layer default)
- Add font-weight: bold to hashtags and item mentions for consistency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Anton Tranelis 2026-01-14 16:54:39 +01:00
parent 33f99ce4a2
commit b944a7f401
2 changed files with 24 additions and 7 deletions

View File

@ -1,7 +1,9 @@
import { useRef, useEffect, useMemo } from 'react'
import { useEffect, useMemo, useRef } from 'react'
import { useNavigate } from 'react-router-dom'
import { useAddFilterTag } from '#components/Map/hooks/useFilter'
import { useGetItemColor } from '#components/Map/hooks/useItemColor'
import { useItems } from '#components/Map/hooks/useItems'
import { useTags } from '#components/Map/hooks/useTags'
import {
preprocessMarkdown,
@ -36,6 +38,8 @@ export const TextViewStatic = ({
}
const tags = useTags()
const items = useItems()
const getItemColor = useGetItemColor()
const addFilterTag = useAddFilterTag()
const navigate = useNavigate()
const containerRef = useRef<HTMLDivElement>(null)
@ -65,8 +69,8 @@ export const TextViewStatic = ({
const html = useMemo(() => {
if (!innerText) return ''
const processed = preprocessMarkdown(innerText)
return simpleMarkdownToHtml(processed, tags)
}, [innerText, tags])
return simpleMarkdownToHtml(processed, tags, { items, getItemColor })
}, [innerText, tags, items, getItemColor])
// Handle clicks for internal navigation and hashtags
useEffect(() => {

View File

@ -1,5 +1,6 @@
import { decodeTag } from '#utils/FormatTags'
import type { Item } from '#types/Item'
import type { Tag } from '#types/Tag'
/**
@ -7,7 +8,14 @@ import type { Tag } from '#types/Tag'
* Handles basic markdown syntax without requiring TipTap.
* Used for lightweight popup/card previews.
*/
export function simpleMarkdownToHtml(text: string, tags: Tag[]): string {
export function simpleMarkdownToHtml(
text: string,
tags: Tag[],
options?: {
items?: Item[]
getItemColor?: (item: Item | undefined, fallback?: string) => string
},
): string {
if (!text) return ''
let html = text
@ -44,15 +52,20 @@ export function simpleMarkdownToHtml(text: string, tags: Tag[]): string {
const tag = tags.find((t) => t.name.toLowerCase() === label.toLowerCase())
const color = tag?.color ?? 'inherit'
const decoded = decodeTag(`#${tagText}`)
return `<span data-hashtag data-label="${label}" class="hashtag" style="color: ${color}; cursor: pointer;">${decoded}</span>`
return `<span data-hashtag data-label="${label}" class="hashtag" style="color: ${color}; cursor: pointer; font-weight: bold;">${decoded}</span>`
},
)
// Convert item-mention spans to styled spans
// Convert item-mention spans to styled links with correct colors
html = html.replace(
/<span data-item-mention data-label="([^"]+)" data-id="([^"]+)">@([^<]+)<\/span>/g,
(_, label: string, id: string) => {
return `<a href="/item/${id}" class="item-mention" style="color: var(--color-primary, #3b82f6); cursor: pointer;">@${label}</a>`
// Find item and get its color
const item = options?.items?.find((i) => i.id === id)
const color = options?.getItemColor
? options.getItemColor(item, 'var(--color-primary, #3b82f6)')
: (item?.color ?? 'var(--color-primary, #3b82f6)')
return `<a href="/item/${id}" class="item-mention" style="color: ${color}; cursor: pointer; font-weight: bold;">@${label}</a>`
},
)