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) })。`}
+ )
+}