Color mode

Search

Client-side full-text search: a weighted, fuzzy search engine plus a keyboard driven search modal — no external search service required.

日本語

Overview

search() adds a SearchBar component and a browser entry point that opens a modal search dialog (Ctrl+K/Cmd+K or /). The engine searchItems() matches on title, slug, tags, headings, and body with weighted scoring:

Field Weight
slug 64
title 56
tags 44
headings 32
body 10

Exact matches score 3×, prefix matches 2×, and substrings 1×. When a query has 2+ characters and no substring match, a fuzzy subsequence match is used. Query text is normalized (lowercase, NFKC, and katakana full-width → half-width) before searching.

Each SearchItem also carries the resolved canonical permalink. It is not a scored field: slug remains the searchable identity key, while the modal navigates to permalink.

searchItems() is pure and exported, so it can be used server-side too — for example to generate a search-data.json index the modal fetches at runtime.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { searchPlugin } from "@riebeckite/plugin-search";
 
export default defineConfig({
  // ...
  plugins: [searchPlugin()],
});

searchPlugin() registers the plugin, bundles style.css, and declares initSearch as a client entry that wires up the modal on page load.

Render the component

tsx
import { SearchBar } from "@riebeckite/plugin-search";
 
// ...in your layout / renderer
return (
  <>
    <header>
      <SearchBar />
    </header>
    {/* ... */}
  </>
);

The modal fetches /search-data.json (an array of SearchItem) on first open and shows up to 8 results.

Search API

ts
import { searchItems, normalizeSearchQuery } from "@riebeckite/plugin-search";
 
const results = searchItems(items, "#obsidian");
  • searchItems(items, query) — returns results sorted by score, then title
  • normalizeSearchQuery(value) — normalizes and strips a leading # so tag searches match bare tag names
  • normalizeSearchText(value) — lowercase + NFKC + katakana fold

Exports

  • searchPlugin() — plugin factory
  • SearchBar — modal component (default export of components/search-bar.tsx)
  • initSearch — browser init (also via @riebeckite/plugin-search/client)
  • searchItems, normalizeSearchQuery, normalizeSearchText — search engine
  • Types: SearchItem, SearchField, SearchMatch, SearchResult

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/search/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Search
4 +
5 + Client-side full-text search: a weighted, fuzzy search engine plus a keyboard
6 + driven search modal — no external search service required.
7 +
8 + [日本語](./search.md)
9 +
10 + ## Overview
11 +
12 + `search()` adds a `SearchBar` component and a browser entry point that opens a
13 + modal search dialog (`Ctrl+K`/`Cmd+K` or `/`). The engine `searchItems()`
14 + matches on title, slug, tags, headings, and body with weighted scoring:
15 +
16 + | Field | Weight |
17 + | ----- | ------ |
18 + | `slug` | 64 |
19 + | `title` | 56 |
20 + | `tags` | 44 |
21 + | `headings` | 32 |
22 + | `body` | 10 |
23 +
24 + Exact matches score 3×, prefix matches 2×, and substrings 1×. When a query has
25 + 2+ characters and no substring match, a fuzzy subsequence match is used. Query
26 + text is normalized (lowercase, NFKC, and katakana full-width → half-width)
27 + before searching.
28 +
29 + Each `SearchItem` also carries the resolved canonical `permalink`. It is not a
30 + scored field: `slug` remains the searchable identity key, while the modal
31 + navigates to `permalink`.
32 +
33 + `searchItems()` is pure and exported, so it can be used server-side too — for
34 + example to generate a `search-data.json` index the modal fetches at runtime.
35 +
36 + ## Usage
37 +
38 + ```ts
39 + import { defineConfig } from "@riebeckite/core";
40 + import { searchPlugin } from "@riebeckite/plugin-search";
41 +
42 + export default defineConfig({
43 + // ...
44 + plugins: [searchPlugin()],
45 + });
46 + ```
47 +
48 + `searchPlugin()` registers the plugin, bundles `style.css`, and declares
49 + `initSearch` as a client entry that wires up the modal on page load.
50 +
51 + ### Render the component
52 +
53 + ```tsx
54 + import { SearchBar } from "@riebeckite/plugin-search";
55 +
56 + // ...in your layout / renderer
57 + return (
58 + <>
59 + <header>
60 + <SearchBar />
61 + </header>
62 + {/* ... */}
63 + </>
64 + );
65 + ```
66 +
67 + The modal fetches `/search-data.json` (an array of `SearchItem`) on first open
68 + and shows up to 8 results.
69 +
70 + ## Search API
71 +
72 + ```ts
73 + import { searchItems, normalizeSearchQuery } from "@riebeckite/plugin-search";
74 +
75 + const results = searchItems(items, "#obsidian");
76 + ```
77 +
78 + - `searchItems(items, query)` — returns results sorted by score, then title
79 + - `normalizeSearchQuery(value)` — normalizes and strips a leading `#` so tag
80 + searches match bare tag names
81 + - `normalizeSearchText(value)` — lowercase + NFKC + katakana fold
82 +
83 + ## Exports
84 +
85 + - `searchPlugin()` — plugin factory
86 + - `SearchBar` — modal component (default export of `components/search-bar.tsx`)
87 + - `initSearch` — browser init (also via `@riebeckite/plugin-search/client`)
88 + - `searchItems`, `normalizeSearchQuery`, `normalizeSearchText` — search engine
89 + - Types: `SearchItem`, `SearchField`, `SearchMatch`, `SearchResult`
90 +
91 + ## See also
92 +
93 + - [Plugin guide](../reference/plugin-api.en.md)
94 + - [`@riebeckite/plugin-garden-explorer`](./garden-explorer.en.md)
95 +