Search
minista には全文検索をサポートする 2 つの機能が備わっています。一つは HTML を解析してインデックス化された JSON を生成する機能。もう一つは JSON をもとに検索するビルトインコンポーネント。
HTML と出力される JSON の関係は以下の通りです。
<!-- dist/docs/css.html -->
<head>
<title>CSS</title>
</head>
<body>
<h1>CSS</h1>
<div data-search>
<h2 id="cms">CMS</h2>
<p>CMSで使うCSS。</p>
</div>
</body>
// dist/assets/search.json
{
"words": ["CMS", "CSS", "。", "う", "で", "使"],
"hits": [0, 1],
"pages": [
{
"path": "/docs/css",
"title": [1],
"toc": [[0, "cms"]],
"content": [0, 0, 4, 5, 3, 1, 2]
}
]
}
words
にすべての文字が種類ごとに収納されており index で参照が可能hits
が[0, 1]
なので、検索対象の文字は「CMS」と「CSS」pages
は各ページデータ(title
は「CSS」、見出し IDcms
の content は 0 番目)content
には「CMS CMS で使う CSS。」の index が配列形式で格納
Build JSON
Search コンポーネントを使用していると自動的に開発時・本番ビルドで JSON が生成されます。コンフィグのデフォルト値は以下の通りです。サイトに合わせて必要な部分を調整します。
export default {
search: {
outDir: "assets",
outName: "search",
include: ["**/*"],
exclude: ["/404"],
baseUrl: "",
trimTitle: "",
targetSelector: "[data-search]",
hit: {
minLength: 3,
number: false,
english: true,
hiragana: false,
katakana: true,
kanji: true,
},
},
}
cache
true
にすると、前回作った JSON を再利用します。※開発時のみ
include
検索対象にしたいディレクトリやファイルを配列と glob 形式を使って設定できます。デフォルトの ["**/*"]
はすべてのページが検索対象になりますので ["posts/**/*"]
などで絞り込むことをお勧めします。
exclude
検索対象から省きたいディレクトリやファイルを配列と glob 形式を使って設定できます。
trimTitle
検索したページのタイトルから任意の文字列を削除します。主にサイトタイトルを消す用途で使います。
targetSelector
検索対象ページのインデックス化するセレクターを設定します。
hit
検索にヒットする単語の最低文字数 minLength
や、ヒットする文字の種類を設定します。
Built-in Component
検索用のコンポーネント <Search />
が同封されているので生成した JSON をすぐに使えます。
CAUTION
<Search />
は Partial Hydration 化した場所でのみ使えます- 固有のスタイルは付属していません(試用 CSS)
まずは、ページかコンポーネントのどこかで Partial Hydration の場所を作り、その中で <Search />
を使います。jsonPath
が必須で search.json
の場所を入力します。
// src/pages/index.tsx
import BlockSearch from "../components/block-search?ph"
export default function () {
return <BlockSearch />
}
// src/components/block-search.tsx
import { Search } from "minista"
export default function () {
return (
<Search
jsonPath="/assets/search.json"
placeholder="Search..."
className="block-search"
searchFieldClassName="block-search-field"
searchListClassName="block-search-list"
/>
)
}
SearchProps
type SearchResult = {
path: string
content: string
}
type SearchProps = {
placeholder?: string
minHitLength?: number
maxHitPages?: number
maxHitWords?: number
searchFieldClassName?: string
searchFieldInsertBeforeElement?: React.ReactElement
searchFieldInsertAfterElement?: React.ReactElement
searchListClassName?: string
attributes?: React.HTMLAttributes<HTMLElement>
} & React.HTMLAttributes<HTMLElement>
type SearchFieldProps = {
placeholder?: string
minHitLength?: number
maxHitPages?: number
maxHitWords?: number
insertBeforeElement?: React.ReactElement
insertAfterElement?: React.ReactElement
setSearchValues?: React.Dispatch<React.SetStateAction<string[]>>
setSearchHitValues?: React.Dispatch<React.SetStateAction<string[]>>
setSearchResults?: React.Dispatch<React.SetStateAction<SearchResult[]>>
attributes?: React.HTMLAttributes<HTMLElement>
} & React.HTMLAttributes<HTMLElement>
type SearchListProps = {
searchValues?: string[]
searchHitValues?: string[]
searchResults?: SearchResult[]
attributes?: React.HTMLAttributes<HTMLElement>
} & React.HTMLAttributes<HTMLElement>