-
Notifications
You must be signed in to change notification settings - Fork 4
サイト内検索機能 #55
Comments
SSGだから外部サービスに頼るしかないのではなどと思ってますが |
たしかに… |
https://www.algolia.com/ |
|
#26 と重複?こっちは記事の絞り込み的なやつかな |
クレカ登録不要ならまあ上限いったらごめんなさいにすればいいかしらねえ #26 はブログ記事に限っての絞り込みなのでちょっと違います。こっちはブログ以外に焦点を当てた検索って感じ。例えば「投票について書かれてたルールページどこだっけ?」とか |
無料である程度使えるなら、とりあえず使ってみるのはありかねえ
issueの件名変えたほうが良きかねえ。ブログ記事の絞り込み機能とか。こっちは |
かえました |
:igyo: |
ドキュメント更新時にドキュメントを Algolia に投げるコードを書く感じかなあ https://sunday-morning.app/posts/2021-03-27-generate-contentful-algolia-index |
検索結果の表示と表示結果からの遷移を考えると、アンカーが付けられる各タイトル部分とそれ以下のドキュメントでインデックスつけたほうがよさそう。 |
とりあえずざっとMarkdownからASTつくってheadingとそれ以下のコンテンツに分ける処理 /* eslint-disable no-console */
import { fromMarkdown } from 'mdast-util-from-markdown'
import { gfmTable } from 'micromark-extension-gfm-table'
import { gfmTableFromMarkdown } from 'mdast-util-gfm-table'
import fs from 'node:fs'
import { toString } from 'mdast-util-to-string'
import { Content } from 'mdast-util-from-markdown/lib'
import { Logger } from '@book000/node-utils'
import matter from 'gray-matter'
const htmlCommentRegex = /<!--[\S\s]*?-->/g
async function parse(content: string) {
const ast = fromMarkdown(content, {
extensions: [gfmTable],
mdastExtensions: [gfmTableFromMarkdown],
})
// headingとそれ以下の内容を取得
const results: {
title: string | null
asts: Content[]
content: string | null
}[] = []
for (const node of ast.children) {
if (node.type === 'heading') {
// 前項目のコンテンツ処理
const last = results[results.length - 1]
if (last) {
last.content = toString(last.asts).replace(htmlCommentRegex, '').trim()
}
// 新しい項目追加
const title = toString(node)
results.push({
title,
asts: [],
content: null,
})
continue
}
// headingでない場合は前項目に追加
const last = results[results.length - 1]
if (last) {
last.asts.push(node)
} else {
results.push({
title: null,
asts: [node],
content: null,
})
}
}
return results
}
function getFiles(directory: string): string[] {
const files = fs.readdirSync(directory)
const results: string[] = []
for (const file of files) {
const path = `${directory}/${file}`
if (fs.statSync(path).isDirectory()) {
results.push(...getFiles(path))
} else {
results.push(path)
}
}
return results
}
async function main() {
const logger = Logger.configure('main')
const directory = './files'
const files = getFiles(directory)
const results: {
pageTitle: string
path: string
heading: string | null
content: string
}[] = []
for (const path of files) {
if (!path.endsWith('.md')) {
continue
}
logger.info(`Parsing ${path}...`)
const frontMatter = matter(fs.readFileSync(path, 'utf8'))
const parsed = await parse(frontMatter.content)
for (const p of parsed) {
if (!p.content) {
continue
}
results.push({
pageTitle: frontMatter.data.title,
path: path.replace(directory, '').replace('.md', ''),
heading: p.title,
content: p.content,
})
}
}
fs.writeFileSync('./results.json', JSON.stringify(results, null, 2), 'utf8')
}
;(async () => {
await main()
})() |
generateしたら 動かすためには |
DocSearch とやらを公開したら使うのがよさそう? |
そっちのが一般的なんかねえ。 |
ルールとか探すときにワード検索できたら楽ですよねってやつです
検索画面とか作るのがなかなかめんどくさそうですが…。
The text was updated successfully, but these errors were encountered: