このコミットが含まれているのは:
2025-08-19 01:48:01 +09:00
コミット 2550d31e3b
4個のファイルの変更76行の追加7行の削除
生成ファイル
+2 -1
ファイルの表示
@@ -25,7 +25,8 @@
"react-markdown": "^10.1.0",
"react-markdown-editor-lite": "^1.3.4",
"react-router-dom": "^6.30.0",
"tailwind-merge": "^3.3.0"
"tailwind-merge": "^3.3.0",
"unist-util-visit-parents": "^6.0.1"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
+2 -1
ファイルの表示
@@ -27,7 +27,8 @@
"react-markdown": "^10.1.0",
"react-markdown-editor-lite": "^1.3.4",
"react-router-dom": "^6.30.0",
"tailwind-merge": "^3.3.0"
"tailwind-merge": "^3.3.0",
"unist-util-visit-parents": "^6.0.1"
},
"devDependencies": {
"@eslint/js": "^9.25.0",
+6 -5
ファイルの表示
@@ -1,12 +1,13 @@
import axios from 'axios'
import toCamel from 'camelcase-keys'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import ReactMarkdown from 'react-markdown'
import { Link } from 'react-router-dom'
import SectionTitle from '@/components/common/SectionTitle'
import SubsectionTitle from '@/components/common/SubsectionTitle'
import { API_BASE_URL } from '@/config'
import remarkWikiAutoLink from '@/lib/remark-wiki-autolink'
import type { Components } from 'react-markdown'
@@ -34,6 +35,8 @@ export default ({ title, body }: Props) => {
const [pageNames, setPageNames] = useState<string[]> ([])
const [realBody, setRealBody] = useState<string> ('')
const remarkPlugins = useMemo (() => [remarkWikiAutoLink (pageNames)], [pageNames])
useEffect (() => {
if (!(body))
return
@@ -42,7 +45,7 @@ export default ({ title, body }: Props) => {
try
{
const res = await axios.get (`${ API_BASE_URL }/wiki`)
const data = toCamel (res.data as any, { deep: true }) as WikiPage[]
const data: WikiPage[] = toCamel (res.data as any, { deep: true })
setPageNames (data.map (page => page.title).sort ((a, b) => b.length - a.length))
}
catch
@@ -50,9 +53,7 @@ export default ({ title, body }: Props) => {
setPageNames ([])
}
}) ()
}, [])
useEffect (() => {
setRealBody ('')
}, [body])
@@ -97,7 +98,7 @@ export default ({ title, body }: Props) => {
}, [body, pageNames])
return (
<ReactMarkdown components={mdComponents}>
<ReactMarkdown components={mdComponents} remarkPlugins={remarkPlugins}>
{realBody || `このページは存在しません。[新規作成してください](/wiki/new?title=${ encodeURIComponent (title) })。`}
</ReactMarkdown>)
}
+66
ファイルの表示
@@ -0,0 +1,66 @@
import { visitParents } from 'unist-util-visit-parents'
import type { Parent, Root, RootContent, Text } from 'mdast'
const escapeForRegExp = (s: string) => s.replace (/[.*+?^${}()|[\]\\]/g, '\\$&')
export default (pageNames: string[], basePath = '/wiki'): ((tree: Root) => void) => {
const names = ([...(new Set(pageNames))]
.filter (Boolean)
.sort ((a, b) => b.length - a.length))
if (names.length === 0)
{
return () => {
;
}
}
const re = new RegExp (`(${ names.map (escapeForRegExp).join ('|') })`, 'g')
return (tree: Root) => {
visitParents (tree, 'text', (node: Text, ancestors: Parent[]) => {
if (ancestors.some (ancestor => ['link',
'linkReference',
'image',
'imageReference',
'code',
'inlineCode'].includes (ancestor.type)))
return
const value = node.value
re.lastIndex = 0
let match: RegExpExecArray | null
let last = 0
const parts: RootContent[] = []
while (match = re.exec (value))
{
const start = match.index
const end = start + match[0].length
if (start > last)
parts.push ({ type: 'text', value: value.slice (last, start) })
const name = match[0]
parts.push ({
type: 'link',
url: `${ basePath }/${ encodeURIComponent (name) }`,
title: null,
children: [{ type: 'text', value: name }],
data: { hProperties: { 'data-wiki': '1' } } })
last = end
}
if (parts.length === 0)
return
if (last < value.length)
parts.push ({ type: 'text', value: value.slice (last) })
const parent: Parent = ancestors[ancestors.length - 1]
const idx = parent.children.indexOf (node)
parent.children.splice (idx, 1, ...parts)
})
}
}