From ad7fee9ad6d9235e366388014e1ea167dc26bfd8 Mon Sep 17 00:00:00 2001 From: Anton Tranelis Date: Wed, 9 Jul 2025 10:24:06 +0200 Subject: [PATCH] added hashtags --- .../ItemPopupComponents/TextPreview.tsx | 99 +++++++++++++++++-- 1 file changed, 89 insertions(+), 10 deletions(-) diff --git a/lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextPreview.tsx b/lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextPreview.tsx index 33bfd868..71acb997 100644 --- a/lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextPreview.tsx +++ b/lib/src/Components/Map/Subcomponents/ItemPopupComponents/TextPreview.tsx @@ -1,19 +1,98 @@ -import { RichTextEditor } from '#components/Input/RichTextEditor/RichTextEditor' -import { fixUrls, mailRegex } from '#utils/ReplaceURLs' +/* eslint-disable @typescript-eslint/no-unsafe-call */ +import truncate from 'markdown-truncate' +import Markdown from 'react-markdown' +import rehypeRaw from 'rehype-raw' +import remarkBreaks from 'remark-breaks' +import remarkGfm from 'remark-gfm' + +import { useAddFilterTag } from '#components/Map/hooks/useFilter' +import { useGetItemTags, useTags } from '#components/Map/hooks/useTags' +import { decodeTag } from '#utils/FormatTags' import type { Item } from '#types/Item' export const TextPreview = ({ item }: { item: Item }) => { - let replacedText = '' + const getItemTags = useGetItemTags() if (!item.text) return null - else replacedText = fixUrls(item.text) + // Text auf ~100 Zeichen stutzen (inkl. Ellipse „…“) + const previewRaw = truncate( + removeGfmTables(convertImgTagsToMarkdown(removeMentionSpans(removeHashtags(item.text)))), + { + limit: 150, + ellipsis: true, + }, + ) as string - if (replacedText) { - replacedText = replacedText.replace(mailRegex, (url) => { - return `[${url}](mailto:${url})` - }) - } + const withExtraHashes = previewRaw.replace( + /^(#{1,6})\s/gm, + (_match: string, hashes: string): string => `${hashes}## `, + ) - return + return ( +
+ + {withExtraHashes} + + {getItemTags(item).map((tag) => ( + + ))} +
+ ) +} + +export const HashTag = ({ tag }: { tag: Tag }) => { + const tags = useTags() + const t = tags.find((t) => t.name.toLocaleLowerCase() === tag.name.toLocaleLowerCase()) + const addFilterTag = useAddFilterTag() + if (!t) return null + return ( + { + e.stopPropagation() + addFilterTag(t) + }} + > + {`#${decodeTag(tag.name)} `} + + ) +} + +export function removeMentionSpans(html: string): string { + const mentionSpanRegex = + /]*\bdata-type="mention")(?=[^>]*\bclass="mention")[^>]*>[\s\S]*?<\/span>/gi + return html.replace(mentionSpanRegex, '') +} + +export function removeHashtags(input: string): string { + const hashtagRegex = /(^|\s)(?!#{1,6}\s)(#[A-Za-z0-9_]+)\b/g + return input.replace(hashtagRegex, '$1').trim() +} + +export function convertImgTagsToMarkdown(input: string): string { + return input.replace(/]*>/gi, (imgTag) => { + const srcMatch = imgTag.match(/src\s*=\s*"([^"]+)"/i) + if (!srcMatch) { + return imgTag + } + const src = srcMatch[1] + + const altMatch = imgTag.match(/alt\s*=\s*"([^"]*)"/i) + const alt = altMatch ? altMatch[1] : '' + + const titleMatch = imgTag.match(/title\s*=\s*"([^"]*)"/i) + const title = titleMatch ? titleMatch[1] : '' + + return `![${alt}](${src}${title ? ` "${title}"` : ''})` + }) +} + +export function removeGfmTables(input: string): string { + const gfmTableRegex = + // eslint-disable-next-line security/detect-unsafe-regex + /^[ \t]*\|.*\|.*\r?\n^[ \t]*\|[ \t\-:|]+\r?\n(?:^[ \t]*\|.*\|.*(?:\r?\n|$))*/gm + return input.replace(gfmTableRegex, '') }