コミットを比較

...

2 コミット

作成者 SHA1 メッセージ 日付
みてるぞ 419f46dfda #89 2025-08-03 15:49:56 +09:00
みてるぞ 1f198db16d #89 2025-08-03 08:09:46 +09:00
+72 -2
ファイルの表示
@@ -1,14 +1,84 @@
import axios from 'axios'
import toCamel from 'camelcase-keys'
import { useEffect, useState } from 'react'
import ReactMarkdown from 'react-markdown' import ReactMarkdown from 'react-markdown'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { API_BASE_URL } from '@/config'
import type { WikiPage } from '@/types'
type Props = { title: string type Props = { title: string
body?: string } body?: string }
export default ({ title, body }: Props) => ( export default ({ title, body }: Props) => {
const [pageNames, setPageNames] = useState<string[]> ([])
const [realBody, setRealBody] = useState<string> ('')
useEffect (() => {
if (!(body))
return
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 ([])
}
}) ()
}, [])
useEffect (() => {
if (!(body))
return
const matchIndices = (target: string, keyword: string) => {
const indices: number[] = []
let pos = 0
let idx
while ((idx = target.indexOf (keyword, pos)) >= 0)
{
indices.push (idx)
pos = idx + keyword.length
}
return indices
}
const linkIndices = (text: string, names: string[]): [string, [number, number]][] => {
const result: [string, [number, number]][] = []
names.forEach (name => {
matchIndices (text, name).forEach (idx => {
const start = idx
const end = idx + name.length
const overlaps = result.some (([, [st, ed]]) => start < ed && end > st)
if (!(overlaps))
result.push ([name, [start, end]])
})
})
return result.sort (([, [a]], [, [b]]) => b - a)
}
setRealBody (
linkIndices (body, pageNames).reduce ((acc, [name, [start, end]]) => (
acc.slice (0, start)
+ `[${ name }](/wiki/${ encodeURIComponent (name) })`
+ acc.slice (end)), body))
}, [pageNames])
return (
<ReactMarkdown components={{ a: ( <ReactMarkdown components={{ a: (
({ href, children }) => (['/', '.'].some (e => href?.startsWith (e)) ({ href, children }) => (['/', '.'].some (e => href?.startsWith (e))
? <Link to={href!}>{children}</Link> ? <Link to={href!}>{children}</Link>
: <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>)) }}> : <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>)) }}>
{body || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`} {realBody || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`}
</ReactMarkdown>) </ReactMarkdown>)
}