From 1f198db16d362b0c639e7c74ddaf00fe37929f92 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 3 Aug 2025 08:09:46 +0900 Subject: [PATCH] #89 --- frontend/src/components/WikiBody.tsx | 69 +++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/WikiBody.tsx b/frontend/src/components/WikiBody.tsx index 30727c7..06bc39e 100644 --- a/frontend/src/components/WikiBody.tsx +++ b/frontend/src/components/WikiBody.tsx @@ -1,14 +1,69 @@ +import axios from 'axios' +import toCamel from 'camelcase-keys' +import { useEffect, useState } from 'react' import ReactMarkdown from 'react-markdown' import { Link } from 'react-router-dom' +import { API_BASE_URL } from '@/config' + +import type { WikiPage } from '@/types' + type Props = { title: string body?: string } -export default ({ title, body }: Props) => ( - (['/', '.'].some (e => href?.startsWith (e)) - ? {children} - : {children})) }}> - {body || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`} - ) +export default ({ title, body }: Props) => { + const [pageNames, setPageNames] = useState ([]) + const [realBody, setRealBody] = useState ('') + + useEffect (() => { + const matchIndices = (target: string, keyword: string) => { + const indices: number[] = [] + let pos = 0 + + while (true) + { + const idx = target.indexOf (keyword, pos) + if (idx < 0) + break + indices.push (idx) + pos = idx + keyword.length + } + + return indices + } + + void (async () => { + try + { + const res = await axios.get (`${ API_BASE_URL }/wiki`) + const data = toCamel (res.data as any, { deep: true }) as WikiPage[] + setPageNames (data.map (page => page.title).sort ((a, b) => b.length - a.length)) + } + catch + { + setPageNames ([]) + } + }) () + + const linkIndices: [string, [number, number]][] = [] + pageNames.forEach (name => { + matchIndices (body ?? '', name).map (idx => [idx, idx + name.length]).forEach (([start, end]) => { + if (linkIndices.every (([, [st, ed]]) => (start < st || ed <= start) && (end < st || ed <= end))) + linkIndices.push ([name, [start, end]]) + }) + }) + linkIndices.sort (([, [a]], [, [b]]) => b - a) + linkIndices.forEach (([name, [start, end]]) => { + setRealBody (prev => `${ prev.slice (0, start) }[${ name }](/wiki/${ encodeURIComponent (name) })${ prev.slice (end) }`) + }) + }, []) + + return ( + (['/', '.'].some (e => href?.startsWith (e)) + ? {children} + : {children})) }}> + {realBody || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`} + ) +}