From 83ab381a6e4d0403be1279f7cdd45a9d405a78a4 Mon Sep 17 00:00:00 2001 From: Abhash Chakraborty Date: Thu, 30 Apr 2026 10:05:38 +0530 Subject: [PATCH 1/3] Algolia Setup --- .env.example | 6 +++++ docusaurus.config.ts | 58 ++++++++++++++++++++++++++++---------------- package-lock.json | 35 ++------------------------ 3 files changed, 45 insertions(+), 54 deletions(-) diff --git a/.env.example b/.env.example index 84ce222f..e7dc5764 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,12 @@ GITHUB_TOKEN=your_github_token_here # This must be set for the discussions section to fetch live data from GitHub # Create a Classic PAT with read:discussion scope at https://github.com/settings/tokens DOCUSAURUS_GIT_TOKEN=your_github_token_here +# Algolia DocSearch Configuration +# Request these from the maintainers after DocSearch is approved and crawled. +# The navbar search is enabled only when all three values are set. +ALGOLIA_APP_ID=your_algolia_app_id +ALGOLIA_SEARCH_API_KEY=your_algolia_search_api_key +ALGOLIA_INDEX_NAME=your_algolia_index_name # Shopify Configuration (for Merch Store) # Get these from: Shopify Admin > Settings > Apps and sales channels > Develop apps diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 212833d7..5b287df1 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -7,6 +7,24 @@ dotenv.config(); // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) +const algoliaAppId = process.env.ALGOLIA_APP_ID?.trim(); +const algoliaSearchApiKey = process.env.ALGOLIA_SEARCH_API_KEY?.trim(); +const algoliaIndexName = process.env.ALGOLIA_INDEX_NAME?.trim(); + +const hasAlgoliaDocSearch = Boolean( + algoliaAppId && algoliaSearchApiKey && algoliaIndexName, +); + +const hasPartialAlgoliaDocSearchConfig = Boolean( + algoliaAppId || algoliaSearchApiKey || algoliaIndexName, +); + +if (hasPartialAlgoliaDocSearchConfig && !hasAlgoliaDocSearch) { + console.warn( + "Algolia DocSearch is partially configured. Set ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, and ALGOLIA_INDEX_NAME to enable navbar search.", + ); +} + const config: Config = { title: "recode hive", tagline: "Learn, Build & Grow with Open Source", @@ -208,11 +226,14 @@ const config: Config = { }, ], }, - // Search disabled until Algolia is properly configured - // { - // type: "search", - // position: "right", - // }, + ...(hasAlgoliaDocSearch + ? [ + { + type: "search" as const, + position: "right" as const, + }, + ] + : []), { type: "html", position: "right", @@ -247,21 +268,16 @@ const config: Config = { theme: prismThemes.github, darkTheme: prismThemes.dracula, }, - // Disable Algolia search until properly configured - // algolia: { - // appId: "YOUR_APP_ID", - // apiKey: "YOUR_SEARCH_API_KEY", - // indexName: "YOUR_INDEX_NAME", - // contextualSearch: true, - // externalUrlRegex: "external\\.com|domain\\.com", - // replaceSearchResultPathname: { - // from: "/docs/", - // to: "/", - // }, - // searchParameters: {}, - // searchPagePath: "search", - // insights: false, - // }, + ...(hasAlgoliaDocSearch + ? { + algolia: { + appId: algoliaAppId!, + apiKey: algoliaSearchApiKey!, + indexName: algoliaIndexName!, + contextualSearch: true, + }, + } + : {}), } satisfies Preset.ThemeConfig, markdown: { @@ -280,7 +296,7 @@ const config: Config = { max: 1030, min: 640, steps: 2, - disableInDev: false, + disableInDev: true, }, ], ], diff --git a/package-lock.json b/package-lock.json index 09749607..4dc53770 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9808,7 +9808,7 @@ "version": "19.2.1", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", - "devOptional": true, + "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.2.0" @@ -21365,30 +21365,6 @@ "pathe": "^2.0.1" } }, - "node_modules/monaco-editor": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", - "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", - "license": "MIT", - "peer": true, - "dependencies": { - "dompurify": "3.2.7", - "marked": "14.0.0" - } - }, - "node_modules/monaco-editor/node_modules/marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", - "license": "MIT", - "peer": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/motion-dom": { "version": "12.38.0", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", @@ -25358,13 +25334,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/search-insights": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", - "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", - "license": "MIT", - "peer": true - }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -27149,7 +27118,7 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", From 0f1ace20876d75ea7543e1cb300bfb2e98a9a974 Mon Sep 17 00:00:00 2001 From: Abhash Chakraborty Date: Sat, 2 May 2026 09:07:45 +0530 Subject: [PATCH 2/3] fix: clarify Algolia docsearch configuration --- .env.example | 2 ++ docusaurus.config.ts | 4 ++-- package-lock.json | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index e7dc5764..49c73d68 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,8 @@ DOCUSAURUS_GIT_TOKEN=your_github_token_here # Algolia DocSearch Configuration # Request these from the maintainers after DocSearch is approved and crawled. # The navbar search is enabled only when all three values are set. +# ALGOLIA_INDEX_NAME must be the Algolia index name created by the crawler action, +# not the crawler/config identifier shown in the DocSearch admin UI. ALGOLIA_APP_ID=your_algolia_app_id ALGOLIA_SEARCH_API_KEY=your_algolia_search_api_key ALGOLIA_INDEX_NAME=your_algolia_index_name diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 5b287df1..35d2e448 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -21,7 +21,7 @@ const hasPartialAlgoliaDocSearchConfig = Boolean( if (hasPartialAlgoliaDocSearchConfig && !hasAlgoliaDocSearch) { console.warn( - "Algolia DocSearch is partially configured. Set ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, and ALGOLIA_INDEX_NAME to enable navbar search.", + "Algolia DocSearch is partially configured. Set ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, and the actual Algolia index name in ALGOLIA_INDEX_NAME to enable navbar search.", ); } @@ -296,7 +296,7 @@ const config: Config = { max: 1030, min: 640, steps: 2, - disableInDev: true, + disableInDev: false, }, ], ], diff --git a/package-lock.json b/package-lock.json index 4dc53770..19b13a5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -382,7 +382,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -21365,6 +21365,30 @@ "pathe": "^2.0.1" } }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, + "node_modules/monaco-editor/node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/motion-dom": { "version": "12.38.0", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", @@ -25334,6 +25358,13 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -25616,7 +25647,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", From 91b2938205a3f7aa9b47ce96e8a47adea3467741 Mon Sep 17 00:00:00 2001 From: Abhash Chakraborty Date: Mon, 4 May 2026 18:23:18 +0530 Subject: [PATCH 3/3] fix: use Algolia SiteSearch integration --- .env.example | 8 +- docusaurus.config.ts | 33 ++--- src/components/AlgoliaSiteSearch/index.tsx | 146 +++++++++++++++++++++ src/theme/Navbar/Content/index.tsx | 6 +- 4 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 src/components/AlgoliaSiteSearch/index.tsx diff --git a/.env.example b/.env.example index 7307d6c8..e5bad031 100644 --- a/.env.example +++ b/.env.example @@ -8,11 +8,11 @@ GITHUB_TOKEN=your_github_token_here # This must be set for the discussions section to fetch live data from GitHub # Create a Classic PAT with read:discussion scope at https://github.com/settings/tokens DOCUSAURUS_GIT_TOKEN=your_github_token_here -# Algolia DocSearch Configuration -# Request these from the maintainers after DocSearch is approved and crawled. +# Algolia SiteSearch Configuration +# Request these from the maintainers after the Algolia crawler is configured. # The navbar search is enabled only when all three values are set. -# ALGOLIA_INDEX_NAME must be the Algolia index name created by the crawler action, -# not the crawler/config identifier shown in the DocSearch admin UI. +# ALGOLIA_INDEX_NAME must be an actual Algolia index name, for example: +# www_recodehive_com_8oew5oqz0y_pages ALGOLIA_APP_ID=your_algolia_app_id ALGOLIA_SEARCH_API_KEY=your_algolia_search_api_key ALGOLIA_INDEX_NAME=your_algolia_index_name diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 96c577c5..2ad3d2b6 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -11,17 +11,17 @@ const algoliaAppId = process.env.ALGOLIA_APP_ID?.trim(); const algoliaSearchApiKey = process.env.ALGOLIA_SEARCH_API_KEY?.trim(); const algoliaIndexName = process.env.ALGOLIA_INDEX_NAME?.trim(); -const hasAlgoliaDocSearch = Boolean( +const hasAlgoliaSiteSearch = Boolean( algoliaAppId && algoliaSearchApiKey && algoliaIndexName, ); -const hasPartialAlgoliaDocSearchConfig = Boolean( +const hasPartialAlgoliaSiteSearchConfig = Boolean( algoliaAppId || algoliaSearchApiKey || algoliaIndexName, ); -if (hasPartialAlgoliaDocSearchConfig && !hasAlgoliaDocSearch) { +if (hasPartialAlgoliaSiteSearchConfig && !hasAlgoliaSiteSearch) { console.warn( - "Algolia DocSearch is partially configured. Set ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, and the actual Algolia index name in ALGOLIA_INDEX_NAME to enable navbar search.", + "Algolia SiteSearch is partially configured. Set ALGOLIA_APP_ID, ALGOLIA_SEARCH_API_KEY, and the actual Algolia index name in ALGOLIA_INDEX_NAME to enable navbar search.", ); } @@ -224,14 +224,6 @@ const config: Config = { }, ], }, - ...(hasAlgoliaDocSearch - ? [ - { - type: "search" as const, - position: "right" as const, - }, - ] - : []), { type: "html", position: "right", @@ -266,16 +258,6 @@ const config: Config = { theme: prismThemes.github, darkTheme: prismThemes.dracula, }, - ...(hasAlgoliaDocSearch - ? { - algolia: { - appId: algoliaAppId!, - apiKey: algoliaSearchApiKey!, - indexName: algoliaIndexName!, - contextualSearch: true, - }, - } - : {}), } satisfies Preset.ThemeConfig, markdown: { @@ -312,6 +294,13 @@ const config: Config = { EMAILJS_PUBLIC_KEY: process.env.EMAILJS_PUBLIC_KEY || "", EMAILJS_SERVICE_ID: process.env.EMAILJS_SERVICE_ID || "", EMAILJS_TEMPLATE_ID: process.env.EMAILJS_TEMPLATE_ID || "", + algoliaSiteSearch: hasAlgoliaSiteSearch + ? { + applicationId: algoliaAppId, + apiKey: algoliaSearchApiKey, + indexName: algoliaIndexName, + } + : null, hooks: { onBrokenMarkdownLinks: "warn", }, diff --git a/src/components/AlgoliaSiteSearch/index.tsx b/src/components/AlgoliaSiteSearch/index.tsx new file mode 100644 index 00000000..2bec1a04 --- /dev/null +++ b/src/components/AlgoliaSiteSearch/index.tsx @@ -0,0 +1,146 @@ +import React, { useEffect } from "react"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; + +const containerId = "algolia-sitesearch-navbar"; +const siteSearchScriptId = "algolia-sitesearch-script"; +const siteSearchStylesheetId = "algolia-sitesearch-stylesheet"; +const siteSearchScriptUrl = + "https://unpkg.com/@algolia/sitesearch@latest/dist/search.min.js"; +const siteSearchStylesheetUrl = + "https://unpkg.com/@algolia/sitesearch@latest/dist/search.min.css"; + +type SiteSearchConfig = { + applicationId?: unknown; + apiKey?: unknown; + indexName?: unknown; +}; + +declare global { + interface Window { + SiteSearch?: { + init: (config: { + container: string; + applicationId: string; + apiKey: string; + indexName: string; + attributes: { + primaryText: string; + secondaryText: string; + tertiaryText: string; + url: string; + image: string; + }; + darkMode: boolean; + }) => void; + }; + } +} + +function toConfigString(value: unknown): string { + return typeof value === "string" ? value.trim() : ""; +} + +function ensureSiteSearchStylesheet() { + if (document.getElementById(siteSearchStylesheetId)) { + return; + } + + const stylesheet = document.createElement("link"); + stylesheet.id = siteSearchStylesheetId; + stylesheet.rel = "stylesheet"; + stylesheet.href = siteSearchStylesheetUrl; + document.head.appendChild(stylesheet); +} + +function loadSiteSearchScript(): Promise { + if (window.SiteSearch?.init) { + return Promise.resolve(); + } + + const existingScript = document.getElementById( + siteSearchScriptId, + ) as HTMLScriptElement | null; + + if (existingScript) { + return new Promise((resolve, reject) => { + existingScript.addEventListener("load", () => resolve(), { once: true }); + existingScript.addEventListener("error", reject, { once: true }); + }); + } + + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.id = siteSearchScriptId; + script.src = siteSearchScriptUrl; + script.async = true; + script.addEventListener("load", () => resolve(), { once: true }); + script.addEventListener("error", reject, { once: true }); + document.head.appendChild(script); + }); +} + +export default function AlgoliaSiteSearch(): React.ReactElement | null { + const { siteConfig } = useDocusaurusContext(); + const config = siteConfig.customFields.algoliaSiteSearch as + | SiteSearchConfig + | undefined; + + const applicationId = toConfigString(config?.applicationId); + const apiKey = toConfigString(config?.apiKey); + const indexName = toConfigString(config?.indexName); + const isConfigured = Boolean(applicationId && apiKey && indexName); + + useEffect(() => { + if (!isConfigured) { + return; + } + + let cancelled = false; + + ensureSiteSearchStylesheet(); + loadSiteSearchScript() + .then(() => { + if (cancelled || !window.SiteSearch?.init) { + return; + } + + const container = document.getElementById(containerId); + if (!container) { + return; + } + + container.innerHTML = ""; + window.SiteSearch.init({ + container: `#${containerId}`, + applicationId, + apiKey, + indexName, + attributes: { + primaryText: "title", + secondaryText: "description", + tertiaryText: "headers", + url: "url", + image: "image", + }, + darkMode: document.documentElement.dataset.theme === "dark", + }); + }) + .catch((error) => { + console.error("Failed to initialize Algolia SiteSearch", error); + }); + + return () => { + cancelled = true; + }; + }, [apiKey, applicationId, indexName, isConfigured]); + + if (!isConfigured) { + return null; + } + + return ( +
+
+
+ ); +} diff --git a/src/theme/Navbar/Content/index.tsx b/src/theme/Navbar/Content/index.tsx index d0acaf98..8816967f 100644 --- a/src/theme/Navbar/Content/index.tsx +++ b/src/theme/Navbar/Content/index.tsx @@ -8,6 +8,7 @@ import { useThemeConfig, ErrorCauseBoundary } from "@docusaurus/theme-common"; import { splitNavbarItems } from "@docusaurus/theme-common/internal"; import NavbarItem, { type Props as NavbarItemConfig } from "@theme/NavbarItem"; import NavbarColorModeToggle from "@theme/Navbar/ColorModeToggle"; +import AlgoliaSiteSearch from "@site/src/components/AlgoliaSiteSearch"; // import SearchBar from '@theme/SearchBar'; import NavbarMobileSidebarToggle from "@theme/Navbar/MobileSidebar/Toggle"; import NavbarLogo from "@theme/Navbar/Logo"; @@ -80,10 +81,6 @@ export default function NavbarContent(): ReactNode { () => splitNavbarItems(items), [items], ); - const searchBarItem = useMemo( - () => items.find((item) => item.type === "search"), - [items], - ); return ( more flexible <> + {/* Search component disabled */} {/* {!searchBarItem && (