From 244524e53fc3cf472350d75bf4cbd298557b0056 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sat, 6 Sep 2025 23:33:20 +0000
Subject: [PATCH] =?UTF-8?q?feat:=20Algolia=E3=82=B5=E3=83=BC=E3=83=81?=
=?UTF-8?q?=E3=82=92=E7=B5=B1=E5=90=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ヘッダーに検索窓を追加し、Algoliaを利用してブログ記事の全文検索を可能にします。
GitHub Actionsのワークフローを更新し、デプロイ前に自動でAlgoliaのインデックスが更新されるようにしました。
Algoliaの認証情報は環境変数とGitHub Secrets経由で設定する必要があります。
---
.github/workflows/deploy.yml | 9 +++++
components/Header.tsx | 22 +++++++++++-
deno.json | 3 +-
islands/Search.tsx | 59 +++++++++++++++++++++++++++++++++
scripts/update_algolia_index.ts | 35 +++++++++++++++++++
5 files changed, 126 insertions(+), 2 deletions(-)
create mode 100644 islands/Search.tsx
create mode 100644 scripts/update_algolia_index.ts
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 6becddf..7c97032 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -23,10 +23,19 @@ jobs:
with:
deno-version: v1.x
+ - name: Update Algolia Index
+ if: github.ref == 'refs/heads/main'
+ run: deno run -A scripts/update_algolia_index.ts
+ env:
+ ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
+ ALGOLIA_ADMIN_KEY: ${{ secrets.ALGOLIA_ADMIN_KEY }}
+ ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }}
+
- name: Build step
run: "deno task build"
- name: Upload to Deno Deploy
+ if: github.ref == 'refs/heads/main'
uses: denoland/deployctl@v1
with:
project: "9renpoto"
diff --git a/components/Header.tsx b/components/Header.tsx
index d9c177a..3227eb0 100644
--- a/components/Header.tsx
+++ b/components/Header.tsx
@@ -1,8 +1,19 @@
import IconActivity from "https://deno.land/x/tabler_icons_tsx@0.0.5/tsx/activity.tsx";
import Campfire from "https://deno.land/x/tabler_icons_tsx@0.0.5/tsx/campfire.tsx";
import IconRss from "https://deno.land/x/tabler_icons_tsx@0.0.5/tsx/rss.tsx";
+import Search from "@/islands/Search.tsx";
-export function Header({ title }: { title: string }) {
+interface HeaderProps {
+ title: string;
+ algolia?: {
+ appId: string;
+ searchKey: string;
+ indexName: string;
+ };
+}
+
+export function Header(props: HeaderProps) {
+ const { title, algolia } = props;
const menus = [
{ name: , href: "/rss.xml" },
{ name: , href: "https://9renpoto.github.io/upptime" },
@@ -27,6 +38,15 @@ export function Header({ title }: { title: string }) {
))}
+ {algolia && (
+
+
+
+ )}
);
diff --git a/deno.json b/deno.json
index 8e8870c..16ccae7 100644
--- a/deno.json
+++ b/deno.json
@@ -27,7 +27,8 @@
"@std/testing": "jsr:@std/testing@^0.225.3",
"preact": "https://esm.sh/preact@10.22.0",
"preact/": "https://esm.sh/preact@10.22.0/",
- "tailwindcss": "npm:tailwindcss@^3.4.6"
+ "tailwindcss": "npm:tailwindcss@^3.4.6",
+ "algoliasearch": "https://esm.sh/algoliasearch@4.20.0"
},
"lint": {
"rules": {
diff --git a/islands/Search.tsx b/islands/Search.tsx
new file mode 100644
index 0000000..a1e4543
--- /dev/null
+++ b/islands/Search.tsx
@@ -0,0 +1,59 @@
+import { useState, useEffect, useRef } from "preact/hooks";
+import algoliasearch from "algoliasearch/lite";
+
+interface SearchProps {
+ appId: string;
+ searchKey: string;
+ indexName: string;
+}
+
+interface Hit {
+ objectID: string;
+ title: string;
+ snippet: string;
+}
+
+export default function Search(props: SearchProps) {
+ const { appId, searchKey, indexName } = props;
+ const [query, setQuery] = useState("");
+ const [hits, setHits] = useState([]);
+ const searchInput = useRef(null);
+
+ const searchClient = algoliasearch(appId, searchKey);
+ const index = searchClient.initIndex(indexName);
+
+ useEffect(() => {
+ if (query.length > 0) {
+ index.search(query).then(({ hits }) => {
+ setHits(hits);
+ });
+ } else {
+ setHits([]);
+ }
+ }, [query]);
+
+ return (
+
+
setQuery(e.currentTarget.value)}
+ placeholder="Search..."
+ class="border rounded-lg px-2 py-1"
+ />
+ {hits.length > 0 && (
+
+ )}
+
+ );
+}
diff --git a/scripts/update_algolia_index.ts b/scripts/update_algolia_index.ts
new file mode 100644
index 0000000..2cca031
--- /dev/null
+++ b/scripts/update_algolia_index.ts
@@ -0,0 +1,35 @@
+import "https://deno.land/std@0.192.0/dotenv/load.ts";
+import algoliasearch from "algoliasearch";
+import { getPosts } from "@/utils/posts.ts";
+
+const appId = Deno.env.get("ALGOLIA_APP_ID");
+const adminKey = Deno.env.get("ALGOLIA_ADMIN_KEY");
+const indexName = Deno.env.get("ALGOLIA_INDEX_NAME");
+
+if (!appId || !adminKey || !indexName) {
+ console.error(
+ "ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY, and ALGOLIA_INDEX_NAME must be set",
+ );
+ Deno.exit(1);
+}
+
+const client = algoliasearch(appId, adminKey);
+const index = client.initIndex(indexName);
+
+const posts = await getPosts();
+
+const records = posts.map((post) => ({
+ objectID: post.slug,
+ title: post.title,
+ snippet: post.snippet,
+ content: post.content,
+ publishedAt: post.publishedAt.toISOString(),
+}));
+
+try {
+ await index.saveObjects(records);
+ console.log("Algolia index updated successfully!");
+} catch (error) {
+ console.error("Failed to update Algolia index:", error);
+ Deno.exit(1);
+}