diff --git a/docusaurus.config.js b/docusaurus.config.js index 40cbc23d..246decb9 100755 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -61,16 +61,7 @@ module.exports = { defaultLanguage: "javascript", additionalLanguages: ["solidity"], }, - algolia: { - // need to update this - indexName: "privado", - appId: process.env.ALGOLIA_APP_ID, - apiKey: process.env.ALGOLIA_API_KEY, - contextualSearch: true, - algoliaOptions: { - attributesToSnippet: ["content:20"], - }, - }, + // Algolia search replaced with Pagefind navbar: { hideOnScroll: true, logo: { @@ -197,6 +188,9 @@ module.exports = { crossorigin: "anonymous", }, ], + plugins: [ + './plugins/pagefind-plugin.js', + ], presets: [ [ "@docusaurus/preset-classic", diff --git a/package-lock.json b/package-lock.json index 5cc0145a..2e4be7c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,9 @@ "rehype-katex": "^5.0.0", "remark-math": "^3.0.0" }, + "devDependencies": { + "pagefind": "^1.0.0" + }, "engines": { "node": ">=20", "npm": ">=10" @@ -2593,15 +2596,6 @@ "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.0.tgz", "integrity": "sha512-pieeipSOW4sQ0+bE5UFC51AOZp9NGxg89wAlZ1BAQFaiRAGK1IKUaPQ0UGZeNctJXyqZ1UvBtOQh2HH+U5GtmA==" }, - "node_modules/@docsearch/js": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.0.tgz", - "integrity": "sha512-PVuV629f5UcYRtBWqK7ID6vNL5647+2ADJypwTjfeBIrJfwPuHtzLy39hMGMfFK+0xgRyhTR0FZ83EkdEraBlg==", - "dependencies": { - "@docsearch/react": "3.8.0", - "preact": "^10.0.0" - } - }, "node_modules/@docsearch/react": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.0.tgz", @@ -3594,6 +3588,71 @@ "node": ">= 8" } }, + "node_modules/@pagefind/darwin-arm64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.3.0.tgz", + "integrity": "sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/darwin-x64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.3.0.tgz", + "integrity": "sha512-zlGHA23uuXmS8z3XxEGmbHpWDxXfPZ47QS06tGUq0HDcZjXjXHeLG+cboOy828QIV5FXsm9MjfkP5e4ZNbOkow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/linux-arm64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.3.0.tgz", + "integrity": "sha512-8lsxNAiBRUk72JvetSBXs4WRpYrQrVJXjlRRnOL6UCdBN9Nlsz0t7hWstRk36+JqHpGWOKYiuHLzGYqYAqoOnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/linux-x64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.3.0.tgz", + "integrity": "sha512-hAvqdPJv7A20Ucb6FQGE6jhjqy+vZ6pf+s2tFMNtMBG+fzcdc91uTw7aP/1Vo5plD0dAOHwdxfkyw0ugal4kcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/windows-x64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.3.0.tgz", + "integrity": "sha512-BR1bIRWOMqkf8IoU576YDhij1Wd/Zf2kX/kCI0b2qzCKC8wcc2GQJaaRMCpzvCCrmliO4vtJ6RITp/AnoYUUmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@polka/url": { "version": "1.0.0-next.24", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz", @@ -15845,6 +15904,22 @@ "node": ">=4" } }, + "node_modules/pagefind": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.3.0.tgz", + "integrity": "sha512-8KPLGT5g9s+olKMRTU9LFekLizkVIu9tes90O1/aigJ0T5LmyPqTzGJrETnSw3meSYg58YH7JTzhTTW/3z6VAw==", + "dev": true, + "bin": { + "pagefind": "lib/runner/bin.cjs" + }, + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.3.0", + "@pagefind/darwin-x64": "1.3.0", + "@pagefind/linux-arm64": "1.3.0", + "@pagefind/linux-x64": "1.3.0", + "@pagefind/windows-x64": "1.3.0" + } + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -16770,15 +16845,6 @@ "postcss": "^8.2.15" } }, - "node_modules/preact": { - "version": "10.24.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", - "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, "node_modules/prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", diff --git a/package.json b/package.json index ae0410f2..5bc10bed 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "build": "docusaurus build", + "build:pagefind": "pagefind --site build --output-path build/pagefind", "clear": "docusaurus clear", "deploy": "docusaurus deploy", "format": "prettier --write .", @@ -15,6 +16,7 @@ "dependencies": { "@docusaurus/core": "^2.4.3", "@docusaurus/preset-classic": "^2.4.3", + "browserslist": "^4.22.2", "classnames": "^2.3.2", "docusaurus": "^1.14.7", @@ -27,6 +29,9 @@ "react-gtm-module": "^2.0.11", "rehype-katex": "^5.0.0", "remark-math": "^3.0.0" + }, + "devDependencies": { + "pagefind": "^1.0.0" }, "browserslist": { "production": [ diff --git a/plugins/pagefind-plugin.js b/plugins/pagefind-plugin.js new file mode 100644 index 00000000..c96653c4 --- /dev/null +++ b/plugins/pagefind-plugin.js @@ -0,0 +1,23 @@ +const path = require('path'); +const { execSync } = require('child_process'); + +module.exports = function(context, options) { + return { + name: 'pagefind-plugin', + async postBuild({ siteDir, routesPaths, outDir }) { + try { + console.log('Building Pagefind index...'); + + execSync(`npx pagefind --site "${outDir}" --output-path "${outDir}/pagefind"`, { + stdio: 'inherit', + cwd: siteDir, + }); + + console.log('Pagefind index built successfully!'); + } catch (error) { + console.error('Error building Pagefind index:', error); + throw error; + } + }, + }; +}; diff --git a/src/css/custom.css b/src/css/custom.css index eced03bd..78bfa44c 100755 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -2371,12 +2371,43 @@ code { .navbar__items--right> :last-child { padding-right: 0; width: 300px; + transition: width 0.3s ease; +} + +@media (max-width: 1200px) { + .navbar__items--right> :last-child { + width: 250px; + } +} + +@media (max-width: 992px) { + .navbar__items--right> :last-child { + width: 200px; + } } @media (max-width: 768px) { .navbar__items.navbar__items--right> :last-child { padding-right: 0; - width: unset; + width: 160px; + } +} + +@media (max-width: 576px) { + .navbar__items.navbar__items--right> :last-child { + width: 140px; + } +} + +@media (max-width: 480px) { + .navbar__items.navbar__items--right> :last-child { + width: 120px; + } +} + +@media (max-width: 360px) { + .navbar__items.navbar__items--right> :last-child { + width: 100px; } } @@ -2507,7 +2538,7 @@ p { /*}*/ .navbar__items--right> :last-child { - width: 165px; + width: 250px; } } @@ -2801,4 +2832,886 @@ p { .faq-link:after { content: " \2197"; -} \ No newline at end of file +} + +/* Pagefind Search Styles */ +.pagefind-ui { + --pagefind-ui-scale: 0.8; + width: 100%; + max-width: 100%; +} + +[data-theme='dark'] .pagefind-ui { + --pagefind-ui-primary: #ffffff; + --pagefind-ui-text: #ffffff; + --pagefind-ui-background: #242526; + --pagefind-ui-border: #393a3c; + --pagefind-ui-tag: #10162f; + --pagefind-ui-border-width: 2px; + --pagefind-ui-border-radius: 8px; + --pagefind-ui-image-brightness: 80%; + --pagefind-ui-image-opacity: 0.8; +} + +[data-theme='dark'] .pagefind-ui__search-input { + background-color: var(--ifm-color-emphasis-200) !important; + border: 1px solid var(--ifm-color-emphasis-300) !important; + color: var(--ifm-color-content) !important; +} + +[data-theme='dark'] .pagefind-ui__search-input:focus { + border-color: var(--ifm-color-primary) !important; + box-shadow: 0 0 0 1px var(--ifm-color-primary) !important; +} + +[data-theme='dark'] .pagefind-ui__results-area { + background-color: var(--ifm-background-color) !important; + border: 1px solid var(--ifm-color-emphasis-300) !important; + border-radius: 8px !important; +} + +[data-theme='dark'] .pagefind-ui__result { + border-bottom: 1px solid var(--ifm-color-emphasis-300) !important; +} + +[data-theme='dark'] .pagefind-ui__result:hover { + background-color: var(--ifm-color-emphasis-100) !important; +} + +[data-theme='dark'] .pagefind-ui__result-title { + color: var(--ifm-color-primary) !important; +} + +[data-theme='dark'] .pagefind-ui__result-excerpt { + color: var(--ifm-color-content-secondary) !important; +} + +[data-theme='light'] .pagefind-ui { + --pagefind-ui-primary: #5468ff; + --pagefind-ui-text: #2e2e2e; + --pagefind-ui-background: #ffffff; + --pagefind-ui-border: #cccccc; + --pagefind-ui-tag: #eeeeee; + --pagefind-ui-border-width: 2px; + --pagefind-ui-border-radius: 8px; +} + +.pagefind-ui__results-area { + position: fixed !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + width: 90vw !important; + max-width: 900px !important; + max-height: 85vh !important; + min-height: 400px !important; + z-index: 10000 !important; + border-radius: 12px !important; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3) !important; + overflow: hidden !important; + animation: pagefind-modal-fade-in 0.3s ease-out !important; +} + +.pagefind-ui__results-area::before { + content: ''; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(4px); + z-index: -1; + animation: pagefind-backdrop-fade-in 0.3s ease-out; +} + +body.pagefind-modal-open { + overflow: hidden !important; + position: fixed !important; + width: 100% !important; +} + +.pagefind-ui__results-area::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, var(--ifm-color-primary), #9AFE5B); + border-radius: 12px 12px 0 0; +} + +@keyframes pagefind-modal-fade-in { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(0.9); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + +@keyframes pagefind-backdrop-fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.pagefind-ui__results-area .pagefind-ui__results-count { + position: relative; + padding: 16px 20px 12px 20px; + border-bottom: 1px solid var(--ifm-color-emphasis-300); + background: var(--ifm-background-color); + font-weight: 600; + font-size: 16px; + display: flex !important; + justify-content: space-between !important; + align-items: center !important; +} + +.pagefind-ui__results-area .pagefind-ui__results-count::before { + content: '📋 All results shown - Scroll to see more'; + font-size: 12px; + color: var(--ifm-color-primary); + font-weight: normal; + opacity: 0.8; +} + +.pagefind-ui__results-area .pagefind-ui__results.has-many-results::after { + content: '⬇️ Scroll for more results'; + position: absolute; + bottom: 10px; + left: 50%; + transform: translateX(-50%); + background: var(--ifm-color-primary); + color: var(--ifm-background-color); + padding: 8px 16px; + border-radius: 20px; + font-size: 12px; + font-weight: 600; + opacity: 0.9; + animation: scroll-pulse 2s infinite; +} + +@keyframes scroll-pulse { + 0%, 100% { opacity: 0.9; transform: translateX(-50%) scale(1); } + 50% { opacity: 1; transform: translateX(-50%) scale(1.05); } +} + +.pagefind-ui__results-area .pagefind-ui__results-count::after { + content: '×'; + position: absolute; + top: 12px; + right: 20px; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + font-weight: bold; + color: var(--ifm-color-content); + cursor: pointer; + border-radius: 50%; + transition: all 0.2s ease; + background: var(--ifm-color-emphasis-100); +} + +.pagefind-ui__results-area .pagefind-ui__results-count:hover::after { + background: var(--ifm-color-emphasis-200); + transform: scale(1.1); +} + +.pagefind-ui__results-area .pagefind-ui__results { + max-height: calc(85vh - 80px) !important; + overflow-y: scroll !important; + overflow-x: hidden !important; + padding: 0 !important; + position: relative !important; + scrollbar-gutter: stable !important; + display: block !important; + min-height: 300px !important; + height: auto !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar { + -webkit-appearance: none !important; + width: 12px !important; + display: block !important; +} + +.pagefind-ui__results-area .pagefind-ui__results > * { + display: block !important; + width: 100% !important; +} + +.pagefind-ui__results-area .pagefind-ui__results .pagefind-ui__result { + display: block !important; + visibility: visible !important; + opacity: 1 !important; + height: auto !important; + min-height: auto !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 20px; + background: linear-gradient(var(--ifm-background-color), transparent); + pointer-events: none; + opacity: 0; + transition: opacity 0.3s ease; + z-index: 1; +} + +.pagefind-ui__results-area .pagefind-ui__results.has-more-content::before { + opacity: 1; +} + +.pagefind-ui__results-area .pagefind-ui__results.has-more-content::after { + content: '↓'; + position: absolute; + bottom: 8px; + right: 20px; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: var(--ifm-color-primary); + background: var(--ifm-background-color); + border-radius: 50%; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + opacity: 1; + transition: all 0.3s ease; + z-index: 2; + animation: scroll-indicator-bounce 2s infinite; + pointer-events: none; +} + +.pagefind-ui__result { + padding: 16px 20px !important; + border-bottom: 1px solid var(--ifm-color-emphasis-200) !important; + transition: background-color 0.2s ease !important; + cursor: pointer !important; +} + +.pagefind-ui__result:hover { + background-color: var(--ifm-color-emphasis-50) !important; + transform: translateX(4px) !important; +} + +.pagefind-ui__result:active { + background-color: var(--ifm-color-emphasis-100) !important; + transform: translateX(2px) !important; +} + +.pagefind-ui__result-title { + font-size: 18px !important; + font-weight: 600 !important; + margin-bottom: 8px !important; + line-height: 1.4 !important; +} + +.pagefind-ui__result-excerpt { + font-size: 14px !important; + line-height: 1.6 !important; + color: var(--ifm-color-content-secondary) !important; + margin-bottom: 8px !important; +} + +.pagefind-ui__result-link { + font-size: 12px !important; + color: var(--ifm-color-primary) !important; + text-decoration: none !important; + opacity: 0.8 !important; +} + +.pagefind-ui__result-link:hover { + opacity: 1 !important; + text-decoration: underline !important; +} + +/* Enhanced responsive design */ +@media (max-width: 1200px) { + .pagefind-ui { + --pagefind-ui-scale: 0.75; + } + + .navbar__items .pagefind-ui { + width: 200px; + min-width: 200px; + } + + .pagefind-ui__results-area { + width: 85vw !important; + max-width: 700px !important; + } +} + +@media (max-width: 992px) { + .pagefind-ui { + --pagefind-ui-scale: 0.7; + } + + .navbar__items .pagefind-ui { + width: 180px; + min-width: 180px; + } + + .pagefind-ui__search-input { + font-size: 14px !important; + padding: 8px 12px !important; + } + + .pagefind-ui__results-area { + width: 90vw !important; + max-width: 600px !important; + max-height: 75vh !important; + } + + .pagefind-ui__result-title { + font-size: 16px !important; + } + + .pagefind-ui__result-excerpt { + font-size: 13px !important; + } +} + +@media (max-width: 768px) { + .pagefind-ui { + --pagefind-ui-scale: 0.65; + } + + .navbar__items .pagefind-ui { + width: 160px; + min-width: 160px; + } + + .pagefind-ui__search-input { + font-size: 13px !important; + padding: 6px 10px !important; + } + + .pagefind-ui__results-area { + width: 95vw !important; + max-width: none !important; + max-height: 70vh !important; + top: 45% !important; + transform: translate(-50%, -50%) !important; + } + + .pagefind-ui__results-area .pagefind-ui__results-count { + padding: 12px 16px 8px 16px; + font-size: 14px; + } + + .pagefind-ui__results-area .pagefind-ui__results-count::after { + top: 8px; + right: 16px; + width: 28px; + height: 28px; + font-size: 20px; + } + + .pagefind-ui__result { + padding: 12px 16px !important; + } + + .pagefind-ui__result-title { + font-size: 15px !important; + margin-bottom: 6px !important; + } + + .pagefind-ui__result-excerpt { + font-size: 12px !important; + margin-bottom: 6px !important; + } +} + +@media (max-width: 576px) { + .pagefind-ui { + --pagefind-ui-scale: 0.6; + } + + .navbar__items .pagefind-ui { + width: 140px; + min-width: 140px; + } + + .pagefind-ui__search-input { + font-size: 12px !important; + padding: 5px 8px !important; + } + + .pagefind-ui__results-area { + width: 98vw !important; + max-height: 65vh !important; + top: 40% !important; + border-radius: 8px !important; + } + + .pagefind-ui__results-area .pagefind-ui__results-count { + padding: 10px 12px 6px 12px; + font-size: 13px; + } + + .pagefind-ui__results-area .pagefind-ui__results-count::after { + top: 6px; + right: 12px; + width: 24px; + height: 24px; + font-size: 18px; + } + + .pagefind-ui__result { + padding: 10px 12px !important; + } + + .pagefind-ui__result-title { + font-size: 14px !important; + } + + .pagefind-ui__result-excerpt { + font-size: 11px !important; + } +} + +@media (max-width: 480px) { + .pagefind-ui { + --pagefind-ui-scale: 0.55; + } + + .navbar__items .pagefind-ui { + width: 120px; + min-width: 120px; + } + + .pagefind-ui__search-input { + font-size: 11px !important; + padding: 4px 6px !important; + } + + .pagefind-ui__results-area { + width: 100vw !important; + height: 100vh !important; + max-height: 100vh !important; + top: 0 !important; + left: 0 !important; + transform: none !important; + border-radius: 0 !important; + } + + .pagefind-ui__results-area .pagefind-ui__results-count { + padding: 12px 16px 8px 16px; + font-size: 14px; + } + + .pagefind-ui__results-area .pagefind-ui__results-count::after { + top: 8px; + right: 16px; + width: 32px; + height: 32px; + font-size: 22px; + } + + .pagefind-ui__result { + padding: 12px 16px !important; + } +} + +/* Fix for very small screens */ +@media (max-width: 360px) { + .pagefind-ui { + --pagefind-ui-scale: 0.5; + } + + .navbar__items .pagefind-ui { + width: 100px; + min-width: 100px; + } + + .pagefind-ui__results-area { + width: 100vw !important; + height: 100vh !important; + } + + .pagefind-ui__result { + padding: 10px 12px !important; + } + + .pagefind-ui__result-title { + font-size: 13px !important; + } + + .pagefind-ui__result-excerpt { + font-size: 10px !important; + } +} + +/* Fix for navbar integration */ +.navbar__items .pagefind-ui { + margin-left: auto; +} + +/* Improve search input responsiveness */ +.pagefind-ui__search-input { + width: 100% !important; + box-sizing: border-box !important; + transition: all 0.2s ease !important; + border-radius: 8px !important; +} + +.pagefind-ui__search-input:focus { + outline: none !important; + transform: scale(1.02) !important; + box-shadow: 0 0 0 3px rgba(154, 254, 91, 0.2) !important; +} + +.pagefind-ui__search-input:hover { + border-color: var(--ifm-color-primary) !important; +} + +@media (max-width: 768px) { + .pagefind-ui__search-input, + .pagefind-ui__result { + min-height: 44px !important; + } + + .pagefind-ui__result { + cursor: pointer !important; + } +} + +.pagefind-ui__search-input:disabled { + opacity: 0.6 !important; + cursor: not-allowed !important; +} + +.pagefind-ui__result-title { + font-weight: 600 !important; +} + +.pagefind-ui__result-excerpt { + opacity: 0.8 !important; +} + +.pagefind-ui__results-area, +.pagefind-ui__result { + transition: all 0.2s ease-in-out !important; +} + +@media (max-width: 768px) and (orientation: landscape) { + .pagefind-ui__results-area { + max-height: 60vh !important; + } +} + +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + .pagefind-ui__search-input { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +@media (prefers-reduced-motion: reduce) { + .pagefind-ui__search-input, + .pagefind-ui__results-area, + .pagefind-ui__result { + transition: none !important; + transform: none !important; + } + + .pagefind-ui__results-area { + animation: none !important; + } +} + +.pagefind-ui__search-input:focus-visible { + outline: 2px solid var(--ifm-color-primary) !important; + outline-offset: 2px !important; +} + +.pagefind-ui__result:focus-visible { + outline: 2px solid var(--ifm-color-primary) !important; + outline-offset: -2px !important; +} + +.pagefind-ui__results-area:focus-within { + outline: 2px solid var(--ifm-color-primary) !important; + outline-offset: 2px !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar { + width: 12px !important; + -webkit-appearance: none !important; + display: block !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-track { + background: #2a2a2a !important; + border-radius: 5px !important; + margin: 5px 0 !important; + border: 1px solid #444 !important; + display: block !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #9AFE5B, var(--ifm-color-primary)) !important; + border-radius: 5px !important; + border: 1px solid #666 !important; + transition: all 0.3s ease !important; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important; + display: block !important; + min-height: 40px !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-thumb:hover { + background: linear-gradient(180deg, var(--ifm-color-primary), #9AFE5B) !important; + transform: scaleX(1.3) !important; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4) !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-thumb:active { + background: #9AFE5B !important; + transform: scaleX(1.1) !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-corner { + background: #2a2a2a !important; + border-radius: 5px !important; +} + +.pagefind-ui__results-area .pagefind-ui__results { + scrollbar-width: thin !important; + scrollbar-color: #9AFE5B #2a2a2a !important; +} + +.pagefind-ui__results { + overflow-y: scroll !important; + scrollbar-width: thin !important; +} + +.pagefind-ui__results::-webkit-scrollbar { + width: 12px !important; + -webkit-appearance: none !important; + display: block !important; +} + +.pagefind-ui__results::-webkit-scrollbar-track { + background: #2a2a2a !important; + border-radius: 5px !important; + margin: 5px 0 !important; + border: 1px solid #444 !important; + display: block !important; +} + +.pagefind-ui__results::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, #9AFE5B, #9AFE5B) !important; + border-radius: 5px !important; + border: 1px solid #666 !important; + transition: all 0.3s ease !important; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) !important; + display: block !important; + min-height: 40px !important; +} + +.pagefind-ui__results::-webkit-scrollbar-thumb:hover { + background: linear-gradient(180deg, #9AFE5B, #74F526) !important; + transform: scaleX(1.3) !important; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4) !important; +} + +@media (max-width: 768px) { + .pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar { + width: 8px; + } + + .pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-track { + margin: 3px 0; + border-radius: 4px; + } + + .pagefind-ui__results-area .pagefind-ui__results-list::-webkit-scrollbar-thumb { + border-radius: 4px; + } +} + +@media (max-width: 480px) { + .pagefind-ui__results-area .pagefind-ui__results-list::-webkit-scrollbar { + width: 6px; + } + + .pagefind-ui__results-area .pagefind-ui__results-list::-webkit-scrollbar-track { + margin: 2px 0; + border-radius: 3px; + } + + .pagefind-ui__results-area .pagefind-ui__results::-webkit-scrollbar-thumb { + border-radius: 3px; + } +} + +.pagefind-ui__results-area .pagefind-ui__results { + scroll-behavior: smooth !important; + -webkit-overflow-scrolling: touch !important; + overflow-y: scroll !important; + overflow-x: hidden !important; +} + +.pagefind-ui__results-area .pagefind-ui__results, +.pagefind-ui__results, +.pagefind-ui .pagefind-ui__results { + overflow-y: scroll !important; + overflow-x: hidden !important; + max-height: calc(85vh - 80px) !important; + min-height: 300px !important; +} + +.pagefind-ui__results-area .pagefind-ui__results::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 30px; + background: linear-gradient(transparent, var(--ifm-background-color)); + pointer-events: none; + opacity: 0; + transition: opacity 0.3s ease; +} + +.pagefind-ui__results-area .pagefind-ui__results.has-more-content::after { + opacity: 1; +} + + + +@keyframes scroll-indicator-bounce { + 0%, 20%, 50%, 80%, 100% { + transform: translateY(0); + } + 40% { + transform: translateY(-3px); + } + 60% { + transform: translateY(-2px); + } +} + +.pagefind-ui__results-area .pagefind-ui__results-count { + display: flex !important; + justify-content: center !important; + align-items: center !important; + text-align: center !important; + width: 100% !important; +} + +.pagefind-ui__results-count { + display: flex !important; + justify-content: center !important; + align-items: center !important; + text-align: center !important; + width: 100% !important; +} + +.pagefind-ui__results-area .pagefind-ui__results-count span, +.pagefind-ui__results-count span { + text-align: center !important; + width: 100% !important; + display: block !important; +} + +.pagefind-ui__results-count { + padding: 16px 0 12px 0 !important; + text-align: center !important; +} + +.pagefind-ui__results-count * { + text-align: center !important; +} + +.pagefind-ui__results-area .pagefind-ui__results-count::before { + display: none !important; +} + +button.clear, +.clear-button, +.DocSearch-Reset, +.pagefind-ui__form .pagefind-ui__reset, +.pagefind-ui__search-clear, +.pagefind-ui__search-input + button, +.pagefind-ui__search-input ~ button { + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + text-align: center !important; + line-height: 1 !important; + min-width: 64px !important; +} + +.pagefind-ui .pagefind-ui__form button, +.pagefind-ui__form button[type="button"] { + display: flex !important; + align-items: center !important; + justify-content: center !important; + text-align: center !important; +} + +.pagefind-ui__search-clear { + padding: 0 !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + text-align: center !important; +} + +.search-overlay-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(3px); + z-index: 9998; + opacity: 0; + pointer-events: none; + transition: opacity .2s ease; +} + +.search-overlay-backdrop.is-open, +body.search-open .search-overlay-backdrop, +body.pagefind-modal-open .search-overlay-backdrop { + opacity: 1; + pointer-events: auto; +} + +.pagefind-ui__results-area { + z-index: 9999 !important; +} + +.search-overlay-backdrop { + z-index: 4000; +} + +body.pagefind-modal-open .navbar { + position: relative; + z-index: 5000 !important; +} + +body.pagefind-modal-open .pagefind-ui__results-area { + position: relative; + z-index: 5001 !important; +} + +.pagefind-ui__message{ + flex-direction: column; +} diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js new file mode 100644 index 00000000..799504de --- /dev/null +++ b/src/theme/SearchBar/index.js @@ -0,0 +1,227 @@ +import React, { useEffect, useRef, useState } from 'react'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import useIsBrowser from '@docusaurus/useIsBrowser'; + +export default function SearchBar() { + const { siteConfig } = useDocusaurusContext(); + const isBrowser = useIsBrowser(); + const searchRef = useRef(null); + const pagefindUIRef = useRef(null); + const overlayRef = useRef(null); + const [windowWidth, setWindowWidth] = useState(0); + + useEffect(() => { + if (!isBrowser) return; + + const updateWindowWidth = () => setWindowWidth(window.innerWidth); + updateWindowWidth(); + window.addEventListener('resize', updateWindowWidth); + + const closeModal = () => { + const searchInput = document.querySelector('.pagefind-ui__search-input'); + if (searchInput) { + searchInput.value = ''; + searchInput.dispatchEvent(new Event('input', { bubbles: true })); + } + document.body.classList.remove('pagefind-modal-open'); + }; + + const ensureOverlay = () => { + let overlay = document.querySelector('.search-overlay-backdrop'); + if (!overlay) { + overlay = document.createElement('div'); + overlay.className = 'search-overlay-backdrop'; + overlay.addEventListener('click', closeModal); // click outside closes + document.body.appendChild(overlay); + } + overlayRef.current = overlay; + }; + + const loadPagefind = async () => { + try { + if (!document.getElementById('pagefind-ui-script')) { + const script = document.createElement('script'); + script.id = 'pagefind-ui-script'; + script.src = '/pagefind/pagefind-ui.js'; + script.type = 'text/javascript'; + document.head.appendChild(script); + + const link = document.createElement('link'); + link.href = '/pagefind/pagefind-ui.css'; + link.rel = 'stylesheet'; + document.head.appendChild(link); + + // JS version (no ) + await new Promise((resolve, reject) => { + script.onload = () => resolve(); + script.onerror = () => reject(new Error('Failed to load pagefind-ui.js')); + }); + } + + if (!pagefindUIRef.current && searchRef.current && window.PagefindUI) { + pagefindUIRef.current = new window.PagefindUI({ + element: searchRef.current, + showSubResults: true, + resetStyles: false, + showImages: false, + pageSize: 1000, + translations: { placeholder: 'Search documentation...' }, + processResult: (result) => { + if (result.element) { + result.element.style.display = 'block'; + result.element.style.visibility = 'visible'; + result.element.style.opacity = '1'; + } + return result; + }, + }); + + if (pagefindUIRef.current && pagefindUIRef.current.options) { + pagefindUIRef.current.options.limit = 1000; + pagefindUIRef.current.options.showSubResults = true; + } + + setupModalEventListeners(); + ensureOverlay(); + } + } catch (error) { + console.warn('Pagefind not available:', error); + } + }; + + let observer = null; + const handleKeyDown = (event) => { + if (event.key === 'Escape') closeModal(); + }; + const handleClickOutside = (event) => { + const resultsArea = document.querySelector('.pagefind-ui__results-area'); + if ( + resultsArea && + !resultsArea.contains(event.target) && + !(searchRef.current && searchRef.current.contains(event.target)) + ) { + closeModal(); + } + }; + const handleCloseButtonClick = (event) => { + if (event.target.closest('.pagefind-ui__close')) { + closeModal(); + } + }; + + const setupModalEventListeners = () => { + // Toggle body class when results container appears/disappears + observer = new MutationObserver(() => { + const resultsArea = document.querySelector('.pagefind-ui__results-area'); + const visible = + resultsArea && + resultsArea.style.display !== 'none' && + getComputedStyle(resultsArea).display !== 'none'; + + if (visible) { + document.body.classList.add('pagefind-modal-open'); // overlay turns on via CSS + } else { + document.body.classList.remove('pagefind-modal-open'); + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); + + // Keep the results list scrollable and all results visible + const resultsList = document.querySelector('.pagefind-ui__results-list'); + if (resultsList) { + const checkScroll = () => { + const { scrollTop, scrollHeight, clientHeight } = resultsList; + const hasMore = scrollTop + clientHeight < scrollHeight - 10; + resultsList.classList.toggle('has-more-content', hasMore); + }; + const ensureAllResultsVisible = () => { + const results = resultsList.querySelectorAll('.pagefind-ui__result'); + results.forEach((r) => { + r.style.display = 'block'; + r.style.visibility = 'visible'; + r.style.opacity = '1'; + r.style.height = 'auto'; + r.style.minHeight = 'auto'; + }); + resultsList.style.overflowY = 'scroll'; + resultsList.style.overflowX = 'hidden'; + resultsList.style.maxHeight = 'calc(85vh - 80px)'; + resultsList.style.minHeight = '300px'; + resultsList.classList.toggle('has-many-results', results.length > 10); + setTimeout(() => { + resultsList.style.overflowY = 'scroll'; + resultsList.style.overflowX = 'hidden'; + }, 100); + }; + + checkScroll(); + ensureAllResultsVisible(); + + resultsList.addEventListener('scroll', checkScroll); + const contentObserver = new MutationObserver(() => { + checkScroll(); + ensureAllResultsVisible(); + }); + contentObserver.observe(resultsList, { childList: true, subtree: true }); + + // Make sure we clean up these two on unmount: + // We'll store references on the element itself to remove later if needed. + resultsList._pfCheckScroll = checkScroll; + resultsList._pfContentObserver = contentObserver; + } + + document.addEventListener('keydown', handleKeyDown); + document.addEventListener('click', handleClickOutside); + document.addEventListener('click', handleCloseButtonClick); + }; + + loadPagefind(); + + return () => { + window.removeEventListener('resize', updateWindowWidth); + document.removeEventListener('keydown', handleKeyDown); + document.removeEventListener('click', handleClickOutside); + document.removeEventListener('click', handleCloseButtonClick); + if (observer) observer.disconnect(); + const resultsList = document.querySelector('.pagefind-ui__results-list'); + if (resultsList && resultsList._pfContentObserver) { + resultsList.removeEventListener('scroll', resultsList._pfCheckScroll || (() => {})); + resultsList._pfContentObserver.disconnect(); + delete resultsList._pfCheckScroll; + delete resultsList._pfContentObserver; + } + if (overlayRef.current) { + overlayRef.current.remove(); + overlayRef.current = null; + } + if (pagefindUIRef.current) pagefindUIRef.current = null; + document.body.classList.remove('pagefind-modal-open'); + }; + }, [isBrowser]); + + const getSearchBarWidth = () => { + if (windowWidth >= 1200) return '300px'; + if (windowWidth >= 992) return '250px'; + if (windowWidth >= 768) return '200px'; + if (windowWidth >= 576) return '160px'; + if (windowWidth >= 480) return '140px'; + if (windowWidth >= 360) return '120px'; + return '100px'; + }; + + if (!isBrowser) return null; + + return ( +
+ ); +}