Skip to content

Commit 36c2418

Browse files
authored
feat: Webサイトに全文検索を実装 (typst-jp#157)
1 parent 7e4b7a5 commit 36c2418

File tree

9 files changed

+129
-16
lines changed

9 files changed

+129
-16
lines changed

website/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Develop
44

5+
> [!NOTE]
6+
> 全文検索のインデックスは[pagefind](https://pagefind.app/)で生成していますが、インデックスの出力先が`dist/`になっているため、現在は開発サーバーで全文検索が機能しません。検索機能関連の開発をする場合は、`bun run build`を実行してから、`bun run preview`でビルド後の状態を確認してください。
7+
58
```sh
69
bun run dev
710
```

website/bun.lockb

2.2 KB
Binary file not shown.

website/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"type": "module",
55
"scripts": {
66
"dev": "vite dev",
7-
"build": "vite build",
7+
"build": "vite build && bun run update-search-index",
88
"preview": "vite preview",
9+
"update-search-index": "pagefind --site ./dist/ --glob \"docs/**/*.html\"",
910
"check": "biome check .",
1011
"check:write": "biome check --write ."
1112
},
@@ -17,6 +18,7 @@
1718
"@tailwindcss/vite": "^4.1.5",
1819
"@types/bun": "latest",
1920
"hono": "^4.6.13",
21+
"pagefind": "^1.3.0",
2022
"tailwind-merge": "^3.3.0",
2123
"tailwindcss": "^4.1.5",
2224
"vite": "^6.2.5"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const SearchIcon = () => {
2+
return (
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
viewBox="0 0 24 24"
6+
fill="none"
7+
stroke="currentColor"
8+
stroke-width="2"
9+
stroke-linecap="round"
10+
stroke-linejoin="round"
11+
class="icon icon-tabler icons-tabler-outline icon-tabler-search"
12+
>
13+
<title>検索アイコン</title>
14+
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
15+
<path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
16+
<path d="M21 21l-6 -6" />
17+
</svg>
18+
);
19+
};

website/src/components/icons/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export { ChevronRightIcon } from "./ChevronRightIcon";
99
export { AlertTriangleIcon } from "./AlertTriangleIcon";
1010
export { MenuIcon } from "./MenuIcon";
1111
export { CloseIcon } from "./CloseIcon";
12+
export { SearchIcon } from "./SearchIcon";
1213

1314
// Simple Icons
1415
// https://simpleicons.org/

website/src/components/templates/BaseTemplate.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Breadcrumbs,
1212
Footer,
1313
Header,
14+
SearchWindow,
1415
SideNavigation,
1516
SiteNoticeBanner,
1617
TableOfContents,
@@ -118,7 +119,7 @@ export const BaseTemplate: FC<BaseTemplateProps> = ({
118119

119120
<body
120121
class="no-js docs has-outline min-h-screen flex flex-col"
121-
x-data="{ sidebarOpen: false }"
122+
x-data="{ sidebarOpen: false, searchOpen: false }"
122123
>
123124
<SiteNoticeBanner />
124125
<Header />
@@ -254,6 +255,32 @@ export const BaseTemplate: FC<BaseTemplateProps> = ({
254255
</div>
255256
</div>
256257

258+
<div
259+
class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-start justify-center pt-16"
260+
x-show="searchOpen"
261+
x-cloak
262+
x-transition:enter="ease-out duration-300"
263+
x-transition:enter-start="opacity-0"
264+
x-transition:enter-end="opacity-100"
265+
x-transition:leave="ease-in duration-200"
266+
x-transition:leave-start="opacity-100"
267+
x-transition:leave-end="opacity-0"
268+
x-on:click="searchOpen = false"
269+
>
270+
<div
271+
class="bg-white rounded-lg shadow-xl w-full max-w-2xl mx-4"
272+
x-on:click="$event.stopPropagation()"
273+
x-transition:enter="ease-out duration-300"
274+
x-transition:enter-start="opacity-0 scale-95"
275+
x-transition:enter-end="opacity-100 scale-100"
276+
x-transition:leave="ease-in duration-200"
277+
x-transition:leave-start="opacity-100 scale-100"
278+
x-transition:leave-end="opacity-0 scale-95"
279+
>
280+
<SearchWindow />
281+
</div>
282+
</div>
283+
257284
<Footer />
258285
</body>
259286
</html>

website/src/components/ui/common/Header.tsx

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
typstOfficialUrl,
66
version,
77
} from "../../../metadata";
8-
import { DiscordIcon, GitHubIcon, MenuIcon } from "../../icons";
8+
import { DiscordIcon, GitHubIcon, MenuIcon, SearchIcon } from "../../icons";
99
import { SiteTitle } from "./SiteTitle";
1010

1111
const VersionBadge = () => (
@@ -19,9 +19,21 @@ export const Header = () => {
1919
<>
2020
<header class="boring sticky top-0 z-40 bg-white border-b border-gray-200 hidden lg:block">
2121
<div class="flex justify-between items-center py-3 px-6">
22-
<div class="flex items-center">
23-
<SiteTitle />
24-
<VersionBadge />
22+
<div class="flex items-center gap-4">
23+
<div class="flex items-center">
24+
<SiteTitle />
25+
<VersionBadge />
26+
</div>
27+
<button
28+
type="button"
29+
class="flex items-center gap-2 px-4 py-2 text-sm text-gray-600 hover:text-gray-800 border border-gray-200 rounded-md hover:border-gray-300 transition-colors w-48"
30+
x-on:click="searchOpen = true"
31+
>
32+
<div class="w-4 h-4 text-gray-600">
33+
<SearchIcon />
34+
</div>
35+
<span class="text-left flex-1">検索...</span>
36+
</button>
2537
</div>
2638
<nav class="ml-auto">
2739
<ul class="flex items-center gap-4">
@@ -72,16 +84,28 @@ export const Header = () => {
7284
<SiteTitle />
7385
<VersionBadge />
7486
</div>
75-
<button
76-
type="button"
77-
class="p-1 bg-white rounded-md border border-gray-200"
78-
x-on:click="sidebarOpen = !sidebarOpen"
79-
aria-label="メニューを開く"
80-
>
81-
<div class="w-6 h-6 text-gray-600 hover:text-gray-800 transition-colors">
82-
<MenuIcon />
83-
</div>
84-
</button>
87+
<div class="flex items-center gap-2">
88+
<button
89+
type="button"
90+
class="p-2 text-gray-600 hover:text-gray-800 transition-colors"
91+
x-on:click="searchOpen = true"
92+
aria-label="検索を開く"
93+
>
94+
<div class="w-6 h-6 text-gray-600 hover:text-gray-800 transition-colors">
95+
<SearchIcon />
96+
</div>
97+
</button>
98+
<button
99+
type="button"
100+
class="p-1 bg-white rounded-md border border-gray-200"
101+
x-on:click="sidebarOpen = !sidebarOpen"
102+
aria-label="メニューを開く"
103+
>
104+
<div class="w-6 h-6 text-gray-600 hover:text-gray-800 transition-colors">
105+
<MenuIcon />
106+
</div>
107+
</button>
108+
</div>
85109
</div>
86110
</header>
87111
</>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import type { FC } from "hono/jsx";
2+
import { CloseIcon } from "../../icons";
3+
4+
export const SearchWindow: FC = () => {
5+
return (
6+
<div class="flex flex-col max-h-[80vh]">
7+
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
8+
<script src="/pagefind/pagefind-ui.js" />
9+
<div class="flex justify-between items-center p-4 border-b border-gray-200 flex-shrink-0">
10+
<h2 class="text-lg font-semibold">検索</h2>
11+
<button
12+
type="button"
13+
class="text-gray-400 hover:text-gray-600"
14+
x-on:click="searchOpen = false"
15+
aria-label="検索を閉じる"
16+
>
17+
<div class="w-6 h-6 text-gray-600 hover:text-gray-800 transition-colors">
18+
<CloseIcon />
19+
</div>
20+
</button>
21+
</div>
22+
<div class="p-4 overflow-y-auto flex-1">
23+
<div id="search" />
24+
</div>
25+
<script
26+
// biome-ignore lint/security/noDangerouslySetInnerHtml: pagefindで生成されたスクリプトを実行する
27+
dangerouslySetInnerHTML={{
28+
__html: `window.addEventListener('DOMContentLoaded', (event) => {
29+
new PagefindUI({ element: "#search", showSubResults: true });
30+
});
31+
`,
32+
}}
33+
/>
34+
</div>
35+
);
36+
};

website/src/components/ui/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export { SideNavigation, type SideNavigationProps } from "./SideNavigation";
55
export { Breadcrumbs, type BreadcrumbsProps } from "./Breadcrumbs";
66
export { TableOfContents, type TableOfContentsProps } from "./TableOfContents";
77
export { Footer } from "./Footer";
8+
export { SearchWindow } from "./SearchWindow";

0 commit comments

Comments
 (0)