From 21ec77086b71e7de36a12ca0e39a2d7f4fab143e Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Wed, 15 May 2024 20:08:32 +0530 Subject: [PATCH 01/30] Add custom component for search modal --- src/theme/SearchBar/DropdownContent.js | 87 +++++++++++ src/theme/SearchBar/index.js | 207 +++++++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 src/theme/SearchBar/DropdownContent.js create mode 100644 src/theme/SearchBar/index.js diff --git a/src/theme/SearchBar/DropdownContent.js b/src/theme/SearchBar/DropdownContent.js new file mode 100644 index 00000000000..355262b6584 --- /dev/null +++ b/src/theme/SearchBar/DropdownContent.js @@ -0,0 +1,87 @@ +import React from 'react'; + +export const DropdownContent = ({ + facetList, + selectedFacets, + setSelectedFacets, +}) => { + const actualFacets = facetList[1]; + const handleCheckboxChange = (event) => { + const { value, checked } = event.target; + const updatedFacets = [...selectedFacets]; + const updatedFacetList = [...updatedFacets[1]]; + if (checked) { + if (!updatedFacetList.includes(value)) { + updatedFacetList.push(value); + } + } else { + const index = updatedFacetList.indexOf(value); + if (index > -1) { + updatedFacetList.splice(index, 1); + } + } + updatedFacets[1] = updatedFacetList; + setSelectedFacets(updatedFacets); + }; + + const handleSelectAll = (event) => { + const checked = event.target.checked; + const updatedFacets = [...selectedFacets]; + const updatedFacetList = checked ? actualFacets.slice() : []; + updatedFacets[1] = updatedFacetList; + setSelectedFacets(updatedFacets); + }; + return ( +
+ + + +
+ ); +}; \ No newline at end of file diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js new file mode 100644 index 00000000000..3ed722164ce --- /dev/null +++ b/src/theme/SearchBar/index.js @@ -0,0 +1,207 @@ +import React, { useCallback, useMemo, useRef, useState } from 'react'; +import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react'; +import Head from '@docusaurus/Head'; +import Link from '@docusaurus/Link'; +import { useHistory } from '@docusaurus/router'; +import { + isRegexpStringMatch, + useSearchLinkCreator, +} from '@docusaurus/theme-common'; +import { + useAlgoliaContextualFacetFilters, + useSearchResultUrlProcessor, +} from '@docusaurus/theme-search-algolia/client'; +import Translate from '@docusaurus/Translate'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import { createPortal } from 'react-dom'; +import translations from '@theme/SearchTranslations'; + +import { useSearch } from '../../utils/useSearch'; +import { DropdownContent } from './DropdownContent'; + +let DocSearchModal = null; +function Hit({ hit, children }) { + return {children}; +} + +function ResultsFooter({ state, onClose }) { + const createSearchLink = useSearchLinkCreator(); + return ( + + + {'See all {count} results'} + + + ); +} + +function mergeFacetFilters(f1, f2) { + const normalize = (f) => (typeof f === 'string' ? [f] : f); + return [...normalize(f1), ...normalize(f2)]; +} +function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { + const { selectedFacets, setSelectedFacets } = useSearch(); + + const { siteMetadata } = useDocusaurusContext(); + const processSearchResultUrl = useSearchResultUrlProcessor(); + const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters(); + const configFacetFilters = props.searchParameters?.facetFilters ?? []; + const facetFilters = contextualSearch + ? mergeFacetFilters(contextualSearchFacetFilters, configFacetFilters) + : configFacetFilters; + + const searchParameters = { + ...props.searchParameters, + facetFilters: selectedFacets, + }; + const history = useHistory(); + const searchContainer = useRef(null); + const searchButtonRef = useRef(null); + const [isOpen, setIsOpen] = useState(false); + const [initialQuery, setInitialQuery] = useState(undefined); + const importDocSearchModalIfNeeded = useCallback(() => { + if (DocSearchModal) { + return Promise.resolve(); + } + return Promise.all([ + import('@docsearch/react/modal'), + import('@docsearch/react/style'), + import('./styles.css'), + ]).then(([{ DocSearchModal: Modal }]) => { + DocSearchModal = Modal; + }); + }, []); + + const onOpen = useCallback(() => { + importDocSearchModalIfNeeded().then(() => { + searchContainer.current = document.createElement('div'); + document.body.insertBefore( + searchContainer.current, + document.body.firstChild, + ); + setIsOpen(true); + }); + + DropdownContent; + }, [importDocSearchModalIfNeeded, setIsOpen]); + + const onClose = useCallback(() => { + setIsOpen(false); + searchContainer.current?.remove(); + }, [setIsOpen]); + + const onInput = useCallback( + (event) => { + importDocSearchModalIfNeeded().then(() => { + setIsOpen(true); + setInitialQuery(event.key); + }); + }, + [importDocSearchModalIfNeeded, setIsOpen, setInitialQuery], + ); + + const navigator = useRef({ + navigate({ itemUrl }) { + if (isRegexpStringMatch(externalUrlRegex, itemUrl)) { + window.location.href = itemUrl; + } else { + history.push(itemUrl); + } + }, + }).current; + + const transformItems = useRef((items) => + props.transformItems + ? props.transformItems(items) + : items.map((item) => ({ + ...item, + url: processSearchResultUrl(item.url), + })), + ).current; + + const resultsFooterComponent = useMemo( + () => (footerProps) => , + [onClose], + ); + + const transformSearchClient = useCallback( + (searchClient) => { + searchClient.addAlgoliaAgent( + 'docusaurus', + siteMetadata.docusaurusVersion, + ); + return searchClient; + }, + [siteMetadata.docusaurusVersion], + ); + + useDocSearchKeyboardEvents({ + isOpen, + onOpen, + onClose, + onInput, + searchButtonRef, + }); + + const helloDiv = document.createElement('div'); + helloDiv.textContent = 'Hello!'; + return ( + <> + + + + + {isOpen && ( + + )} + + {isOpen && + DocSearchModal && + searchContainer.current && + createPortal( + + + , + searchContainer.current, + )} + + ); +} + +export default function SearchBar() { + const { siteConfig } = useDocusaurusContext(); + return ; +} \ No newline at end of file From 7475323986867e697014fca433982445e7ca96d2 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Wed, 15 May 2024 20:08:53 +0530 Subject: [PATCH 02/30] Add styles for custom search modal --- src/theme/SearchBar/styles.css | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/theme/SearchBar/styles.css diff --git a/src/theme/SearchBar/styles.css b/src/theme/SearchBar/styles.css new file mode 100644 index 00000000000..b1e70057f76 --- /dev/null +++ b/src/theme/SearchBar/styles.css @@ -0,0 +1,18 @@ +:root { + --docsearch-primary-color: var(--ifm-color-primary); + --docsearch-text-color: var(--ifm-font-color-base); + z-index: 700; +} + +.DocSearch-Button { + margin: 0; + transition: all var(--ifm-transition-fast) + var(--ifm-transition-timing-default); +} + +.DocSearch-Container { + z-index: 200; +} +.DocSearch-Modal { + top: 5px; +} \ No newline at end of file From 3e05305fb018a1d1fea5bf6891fb6a51611945b5 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Wed, 15 May 2024 20:09:18 +0530 Subject: [PATCH 03/30] Add list of filters for custom search based on facet tags --- src/utils/searchConstant.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/utils/searchConstant.ts diff --git a/src/utils/searchConstant.ts b/src/utils/searchConstant.ts new file mode 100644 index 00000000000..53942a26ef6 --- /dev/null +++ b/src/utils/searchConstant.ts @@ -0,0 +1,25 @@ +export const allFacets = [ + "language:en", + [ + "docusaurus_tag:default", + "docusaurus_tag:docs-apis-current", + "docusaurus_tag:docs-cli-wallet-1-0-current", + "docusaurus_tag:docs-maintain-current", + "docusaurus_tag:docs-iota-tips-current", + "docusaurus_tag:docs-community-current", + "docusaurus_tag:docs-get-started-current", + "docusaurus_tag:docs-learn-current", + "docusaurus_tag:docs-iota-sdk-1-0-current", + "docusaurus_tag:docs-build-current", + "docusaurus_tag:docs-identity-rs-1-1-current", + "docusaurus_tag:docs-identity-rs-1-2-current", + "docusaurus_tag:docs-isc-v1-0-0-rc-6-current", + "docusaurus_tag:docs-identity-rs-1-0-current", + "docusaurus_tag:docs-iota-sandbox-current", + "docusaurus_tag:docs-stronghold-rs-1-1-current", + "docusaurus_tag:docs-wasp-v1-0-0-rc-6-current", + "docusaurus_tag:docs-introduction-docs-stardust-current", + "docusaurus_tag:docs-chronicle-1-0-rc-2-current", + "docusaurus_tag:docs-hornet-2-0-current", + ], + ] \ No newline at end of file From 058ce2fc943b9faac489252b76d8731cf8402890 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Wed, 15 May 2024 20:10:04 +0530 Subject: [PATCH 04/30] Add context for search --- src/utils/useSearch.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/utils/useSearch.ts diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts new file mode 100644 index 00000000000..e67b2ece6b1 --- /dev/null +++ b/src/utils/useSearch.ts @@ -0,0 +1,13 @@ +import { createContext, useState } from "react"; +import { allFacets } from "./searchConstant"; + +export const useSearchContext = createContext(null); + +export function useSearch() { + const [selectedFacets, setSelectedFacets] = useState(allFacets); + + return { + selectedFacets, + setSelectedFacets, + }; +} \ No newline at end of file From eb4a6cd8750ec67da7f40b761acc8358a15294cf Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:37:05 +0530 Subject: [PATCH 05/30] Refactor styles for custom search filter dropdown --- src/theme/SearchBar/DropdownContent.js | 56 ++++++++++++-------------- src/theme/SearchBar/styles.css | 35 ++++++++-------- src/theme/SearchBar/styles.module.css | 40 ++++++++++++++++++ 3 files changed, 84 insertions(+), 47 deletions(-) create mode 100644 src/theme/SearchBar/styles.module.css diff --git a/src/theme/SearchBar/DropdownContent.js b/src/theme/SearchBar/DropdownContent.js index 355262b6584..c60e2bca55b 100644 --- a/src/theme/SearchBar/DropdownContent.js +++ b/src/theme/SearchBar/DropdownContent.js @@ -1,11 +1,12 @@ +/* eslint-disable */ + import React from 'react'; +import { facetNamesJson, allFacets } from '../../utils/searchConstant'; +import clsx from 'clsx'; +import styles from './styles.module.css'; -export const DropdownContent = ({ - facetList, - selectedFacets, - setSelectedFacets, -}) => { - const actualFacets = facetList[1]; +export const DropdownContent = ({ selectedFacets, setSelectedFacets }) => { + const actualFacets = allFacets[1]; const handleCheckboxChange = (event) => { const { value, checked } = event.target; const updatedFacets = [...selectedFacets]; @@ -32,32 +33,16 @@ export const DropdownContent = ({ setSelectedFacets(updatedFacets); }; return ( -
+
- -
    +
); -}; \ No newline at end of file +}; diff --git a/src/theme/SearchBar/styles.css b/src/theme/SearchBar/styles.css index b1e70057f76..2c2dd2ed735 100644 --- a/src/theme/SearchBar/styles.css +++ b/src/theme/SearchBar/styles.css @@ -1,18 +1,21 @@ :root { - --docsearch-primary-color: var(--ifm-color-primary); - --docsearch-text-color: var(--ifm-font-color-base); - z-index: 700; -} - -.DocSearch-Button { - margin: 0; - transition: all var(--ifm-transition-fast) - var(--ifm-transition-timing-default); -} - -.DocSearch-Container { - z-index: 200; -} -.DocSearch-Modal { - top: 5px; + --docsearch-primary-color: var(--ifm-color-primary); + --docsearch-text-color: var(--ifm-font-color-base); + z-index: 700; + } + + .DocSearch-Button { + margin: 0; + transition: all var(--ifm-transition-fast) + var(--ifm-transition-timing-default); + } + + .DocSearch-Container { + z-index: 200; + } + .DocSearch-Modal { + top: 61px; + } +.filterButton{ + width: 100px; } \ No newline at end of file diff --git a/src/theme/SearchBar/styles.module.css b/src/theme/SearchBar/styles.module.css new file mode 100644 index 00000000000..51443a6e9f0 --- /dev/null +++ b/src/theme/SearchBar/styles.module.css @@ -0,0 +1,40 @@ +.dropdown { + position: absolute; + right: 22%; + top: 245%; + cursor: pointer; +} +.dropdownMenu { + width: 15%; + position: fixed; + right: 35%; + top: 18.75%; + left: 69%; + padding: 15px; +} + +@media (max-width: 996px) { + .dropdown { + position: absolute; + right: 665%; + top: 459%; + } + + .dropdownMenu { + left: 65%; + } +} + +@media (max-width: 770px) { + .dropdown { + position: absolute; + right: 396%; + top: 253%; + } + + .dropdownMenu { + position: absolute; + top: 101%; + left: -4%; + } +} From b4141e89dee7750a050c3d4c10db6fbad70ad6f4 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:39:23 +0530 Subject: [PATCH 06/30] Refactor custom search modal --- src/theme/SearchBar/index.js | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js index 3ed722164ce..9e4409cae9a 100644 --- a/src/theme/SearchBar/index.js +++ b/src/theme/SearchBar/index.js @@ -1,4 +1,11 @@ -import React, { useCallback, useMemo, useRef, useState } from 'react'; +/* eslint-disable */ +import React, { + useCallback, + useMemo, + useRef, + useState, + useContext, +} from 'react'; import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react'; import Head from '@docusaurus/Head'; import Link from '@docusaurus/Link'; @@ -7,17 +14,13 @@ import { isRegexpStringMatch, useSearchLinkCreator, } from '@docusaurus/theme-common'; -import { - useAlgoliaContextualFacetFilters, - useSearchResultUrlProcessor, -} from '@docusaurus/theme-search-algolia/client'; +import { useSearchResultUrlProcessor } from '@docusaurus/theme-search-algolia/client'; import Translate from '@docusaurus/Translate'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import { createPortal } from 'react-dom'; import translations from '@theme/SearchTranslations'; - -import { useSearch } from '../../utils/useSearch'; import { DropdownContent } from './DropdownContent'; +import { SearchContext } from '@site/src/utils/SearchContext'; let DocSearchModal = null; function Hit({ hit, children }) { @@ -38,20 +41,10 @@ function ResultsFooter({ state, onClose }) { ); } -function mergeFacetFilters(f1, f2) { - const normalize = (f) => (typeof f === 'string' ? [f] : f); - return [...normalize(f1), ...normalize(f2)]; -} function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { - const { selectedFacets, setSelectedFacets } = useSearch(); - + const { selectedFacets, setSelectedFacets } = useContext(SearchContext); const { siteMetadata } = useDocusaurusContext(); const processSearchResultUrl = useSearchResultUrlProcessor(); - const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters(); - const configFacetFilters = props.searchParameters?.facetFilters ?? []; - const facetFilters = contextualSearch - ? mergeFacetFilters(contextualSearchFacetFilters, configFacetFilters) - : configFacetFilters; const searchParameters = { ...props.searchParameters, @@ -167,7 +160,6 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { /> {isOpen && ( From 6507c3bc9a690ce436a3bd3a8f7164b414d53833 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:41:11 +0530 Subject: [PATCH 07/30] Remove unwanted swizzle component --- src/theme/DocItem/Layout/index.tsx | 69 ---------------------- src/theme/DocItem/Layout/styles.module.css | 10 ---- 2 files changed, 79 deletions(-) delete mode 100644 src/theme/DocItem/Layout/index.tsx delete mode 100644 src/theme/DocItem/Layout/styles.module.css diff --git a/src/theme/DocItem/Layout/index.tsx b/src/theme/DocItem/Layout/index.tsx deleted file mode 100644 index bd5419b2661..00000000000 --- a/src/theme/DocItem/Layout/index.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/** - * SWIZZLED VERSION: 2.4.1 - * REASONS: - * - Add custom Banner component. - */ - -import React from 'react'; -import clsx from 'clsx'; -import { useWindowSize } from '@docusaurus/theme-common'; -import { useDoc } from '@docusaurus/theme-common/internal'; -import DocItemPaginator from '@theme/DocItem/Paginator'; -import DocVersionBanner from '@theme/DocVersionBanner'; -import DocVersionBadge from '@theme/DocVersionBadge'; -import DocItemFooter from '@theme/DocItem/Footer'; -import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile'; -import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop'; -import DocItemContent from '@theme/DocItem/Content'; -import DocBreadcrumbs from '@theme/DocBreadcrumbs'; -import type { Props } from '@theme/DocItem/Layout'; -import DocBanner from '@theme/DocBanner'; - -import styles from './styles.module.css'; - -/** - * Decide if the toc should be rendered, on mobile or desktop viewports - */ -function useDocTOC() { - const { frontMatter, toc } = useDoc(); - const windowSize = useWindowSize(); - - const hidden = frontMatter.hide_table_of_contents; - const canRender = !hidden && toc.length > 0; - - const mobile = canRender ? : undefined; - - const desktop = - canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? ( - - ) : undefined; - - return { - hidden, - mobile, - desktop, - }; -} - -export default function DocItemLayout({ children }: Props): JSX.Element { - const docTOC = useDocTOC(); - return ( -
-
- - -
-
- - - {docTOC.mobile} - {children} - -
- -
-
- {docTOC.desktop &&
{docTOC.desktop}
} -
- ); -} diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css deleted file mode 100644 index d5aaec1322c..00000000000 --- a/src/theme/DocItem/Layout/styles.module.css +++ /dev/null @@ -1,10 +0,0 @@ -.docItemContainer header + *, -.docItemContainer article > *:first-child { - margin-top: 0; -} - -@media (min-width: 997px) { - .docItemCol { - max-width: 75% !important; - } -} From 9e87bb4680bcd926ea3c94720e5e6f9bb9b39a17 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:41:44 +0530 Subject: [PATCH 08/30] Add custom search filter page --- src/theme/SearchPage/index.js | 475 +++++++++++++++++++++++++ src/theme/SearchPage/styles.module.css | 112 ++++++ 2 files changed, 587 insertions(+) create mode 100644 src/theme/SearchPage/index.js create mode 100644 src/theme/SearchPage/styles.module.css diff --git a/src/theme/SearchPage/index.js b/src/theme/SearchPage/index.js new file mode 100644 index 00000000000..15d0fe4325b --- /dev/null +++ b/src/theme/SearchPage/index.js @@ -0,0 +1,475 @@ + +/* eslint-disable */ +/* eslint-disable jsx-a11y/no-autofocus */ +import React, { + useContext, + useEffect, + useReducer, + useRef, + useState, +} from 'react'; +import clsx from 'clsx'; +import algoliaSearchHelper from 'algoliasearch-helper'; +import algoliaSearch from 'algoliasearch/lite'; +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import Head from '@docusaurus/Head'; +import Link from '@docusaurus/Link'; +import { useAllDocsData } from '@docusaurus/plugin-content-docs/client'; +import { + HtmlClassNameProvider, + useEvent, + usePluralForm, + useSearchQueryString, +} from '@docusaurus/theme-common'; +import { useTitleFormatter } from '@docusaurus/theme-common/internal'; +import Translate, { translate } from '@docusaurus/Translate'; +import { + useAlgoliaThemeConfig, + useSearchResultUrlProcessor, +} from '@docusaurus/theme-search-algolia/client'; +import Layout from '@theme/Layout'; +import styles from './styles.module.css'; +import { SearchContext } from '@site/src/utils/SearchContext'; +// Very simple pluralization: probably good enough for now +function useDocumentsFoundPlural() { + const { selectMessage } = usePluralForm(); + return (count) => + selectMessage( + count, + translate( + { + id: 'theme.SearchPage.documentsFound.plurals', + description: + 'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)', + message: 'One document found|{count} documents found', + }, + { count }, + ), + ); +} +function useDocsSearchVersionsHelpers() { + const allDocsData = useAllDocsData(); + // State of the version select menus / algolia facet filters + // docsPluginId -> versionName map + const [searchVersions, setSearchVersions] = useState(() => + Object.entries(allDocsData).reduce( + (acc, [pluginId, pluginData]) => ({ + ...acc, + [pluginId]: pluginData.versions[0].name, + }), + {}, + ), + ); + // Set the value of a single select menu + const setSearchVersion = (pluginId, searchVersion) => + setSearchVersions((s) => ({ ...s, [pluginId]: searchVersion })); + const versioningEnabled = Object.values(allDocsData).some( + (docsData) => docsData.versions.length > 1, + ); + return { + allDocsData, + versioningEnabled, + searchVersions, + setSearchVersion, + }; +} +// We want to display one select per versioned docs plugin instance +function SearchVersionSelectList({ docsSearchVersionsHelpers }) { + const versionedPluginEntries = Object.entries( + docsSearchVersionsHelpers.allDocsData, + ) + // Do not show a version select for unversioned docs plugin instances + .filter(([, docsData]) => docsData.versions.length > 1); + return ( +
+ {versionedPluginEntries.map(([pluginId, docsData]) => { + const labelPrefix = + versionedPluginEntries.length > 1 ? `${pluginId}: ` : ''; + return ( + + ); + })} +
+ ); +} +function SearchPageContent() { + const { + algolia: { appId, apiKey, indexName }, + } = useAlgoliaThemeConfig(); + const processSearchResultUrl = useSearchResultUrlProcessor(); + const documentsFoundPlural = useDocumentsFoundPlural(); + const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers(); + const [searchQuery, setSearchQuery] = useSearchQueryString(); + const { selectedFacets } = useContext(SearchContext); + const initialSearchResultState = { + items: [], + query: null, + totalResults: null, + totalPages: null, + lastPage: null, + hasMore: null, + loading: null, + }; + const [searchResultState, searchResultStateDispatcher] = useReducer( + (prevState, data) => { + switch (data.type) { + case 'reset': { + return initialSearchResultState; + } + case 'loading': { + return { ...prevState, loading: true }; + } + case 'update': { + if (searchQuery !== data.value.query) { + return prevState; + } + return { + ...data.value, + items: + data.value.lastPage === 0 + ? data.value.items + : prevState.items.concat(data.value.items), + }; + } + case 'advance': { + const hasMore = prevState.totalPages > prevState.lastPage + 1; + return { + ...prevState, + lastPage: hasMore ? prevState.lastPage + 1 : prevState.lastPage, + hasMore, + }; + } + default: + return prevState; + } + }, + initialSearchResultState, + ); + const algoliaClient = algoliaSearch(appId, apiKey); + const algoliaHelper = algoliaSearchHelper(algoliaClient, indexName, { + hitsPerPage: 15, + advancedSyntax: true, + disjunctiveFacets: ['language', 'docusaurus_tag'], + facetFilters: [...selectedFacets], + }); + algoliaHelper.on( + 'result', + ({ results: { query, hits, page, nbHits, nbPages } }) => { + if (query === '' || !Array.isArray(hits)) { + searchResultStateDispatcher({ type: 'reset' }); + return; + } + const sanitizeValue = (value) => + value.replace( + /algolia-docsearch-suggestion--highlight/g, + 'search-result-match', + ); + const items = hits.map( + ({ + url, + _highlightResult: { hierarchy }, + _snippetResult: snippet = {}, + }) => { + const titles = Object.keys(hierarchy).map((key) => + sanitizeValue(hierarchy[key].value), + ); + return { + title: titles.pop(), + url: processSearchResultUrl(url), + summary: snippet.content + ? `${sanitizeValue(snippet.content.value)}...` + : '', + breadcrumbs: titles, + }; + }, + ); + searchResultStateDispatcher({ + type: 'update', + value: { + items, + query, + totalResults: nbHits, + totalPages: nbPages, + lastPage: page, + hasMore: nbPages > page + 1, + loading: false, + }, + }); + }, + ); + const [loaderRef, setLoaderRef] = useState(null); + const prevY = useRef(0); + const observer = useRef( + ExecutionEnvironment.canUseIntersectionObserver && + new IntersectionObserver( + (entries) => { + const { + isIntersecting, + boundingClientRect: { y: currentY }, + } = entries[0]; + if (isIntersecting && prevY.current > currentY) { + searchResultStateDispatcher({ type: 'advance' }); + } + prevY.current = currentY; + }, + { threshold: 1 }, + ), + ); + const getTitle = () => + searchQuery + ? translate( + { + id: 'theme.SearchPage.existingResultsTitle', + message: 'Search results for "{query}"', + description: 'The search page title for non-empty query', + }, + { + query: searchQuery, + }, + ) + : translate({ + id: 'theme.SearchPage.emptyResultsTitle', + message: 'Search the documentation', + description: 'The search page title for empty query', + }); + const makeSearch = useEvent((page = 0) => { + Object.entries(docsSearchVersionsHelpers.searchVersions).forEach( + ([pluginId, searchVersion]) => { + algoliaHelper.addDisjunctiveFacetRefinement( + 'docusaurus_tag', + `docs-${pluginId}-${searchVersion}`, + ); + }, + ); + algoliaHelper.setQuery(searchQuery).setPage(page).search(); + }); + useEffect(() => { + if (!loaderRef) { + return undefined; + } + const currentObserver = observer.current; + if (currentObserver) { + currentObserver.observe(loaderRef); + return () => currentObserver.unobserve(loaderRef); + } + return () => true; + }, [loaderRef]); + useEffect(() => { + searchResultStateDispatcher({ type: 'reset' }); + if (searchQuery) { + searchResultStateDispatcher({ type: 'loading' }); + setTimeout(() => { + makeSearch(); + }, 300); + } + }, [searchQuery, docsSearchVersionsHelpers.searchVersions, makeSearch]); + useEffect(() => { + if (!searchResultState.lastPage || searchResultState.lastPage === 0) { + return; + } + makeSearch(searchResultState.lastPage); + }, [makeSearch, searchResultState.lastPage]); + return ( + + + {useTitleFormatter(getTitle())} + {/* + We should not index search pages + See https://github.com/facebook/docusaurus/pull/3233 + */} + + + +
+

{getTitle()}

+ +
e.preventDefault()}> +
+ setSearchQuery(e.target.value)} + value={searchQuery} + autoComplete='off' + autoFocus + /> +
+ + {docsSearchVersionsHelpers.versioningEnabled && ( + + )} + + +
+
+ {!!searchResultState.totalResults && + documentsFoundPlural(searchResultState.totalResults)} +
+ + +
+ + {searchResultState.items.length > 0 ? ( +
+ {searchResultState.items.map( + ({ title, url, summary, breadcrumbs }, i) => ( +
+

+ +

+ + {breadcrumbs.length > 0 && ( + + )} + + {summary && ( +

+ )} +

+ ), + )} +
+ ) : ( + [ + searchQuery && !searchResultState.loading && ( +

+ + No results were found + +

+ ), + !!searchResultState.loading && ( +
+ ), + ] + )} + + {searchResultState.hasMore && ( +
+ + Fetching new results... + +
+ )} +
+ + ); +} +export default function SearchPage() { + return ( + + {/* */} + + {/* */} + + ); +} diff --git a/src/theme/SearchPage/styles.module.css b/src/theme/SearchPage/styles.module.css new file mode 100644 index 00000000000..57de7498db6 --- /dev/null +++ b/src/theme/SearchPage/styles.module.css @@ -0,0 +1,112 @@ +.searchQueryInput, +.searchVersionInput { + border-radius: var(--ifm-global-radius); + border: 2px solid var(--ifm-toc-border-color); + font: var(--ifm-font-size-base) var(--ifm-font-family-base); + padding: 0.8rem; + width: 100%; + background: var(--docsearch-searchbox-focus-background); + color: var(--docsearch-text-color); + margin-bottom: 0.5rem; + transition: border var(--ifm-transition-fast) ease; +} + +.searchQueryInput:focus, +.searchVersionInput:focus { + border-color: var(--docsearch-primary-color); + outline: none; +} + +.searchQueryInput::placeholder { + color: var(--docsearch-muted-color); +} + +.searchResultsColumn { + font-size: 0.9rem; + font-weight: bold; +} + +.algoliaLogo { + max-width: 150px; +} + +.algoliaLogoPathFill { + fill: var(--ifm-font-color-base); +} + +.searchResultItem { + padding: 1rem 0; + border-bottom: 1px solid var(--ifm-toc-border-color); +} + +.searchResultItemHeading { + font-weight: 400; + margin-bottom: 0; +} + +.searchResultItemPath { + font-size: 0.8rem; + color: var(--ifm-color-content-secondary); + --ifm-breadcrumb-separator-size-multiplier: 1; +} + +.searchResultItemSummary { + margin: 0.5rem 0 0; + font-style: italic; +} + +@media only screen and (max-width: 996px) { + .searchQueryColumn { + max-width: 60% !important; + } + + .searchVersionColumn { + max-width: 40% !important; + } + + .searchResultsColumn { + max-width: 60% !important; + } + + .searchLogoColumn { + max-width: 40% !important; + padding-left: 0 !important; + } +} + +@media screen and (max-width: 576px) { + .searchQueryColumn { + max-width: 100% !important; + } + + .searchVersionColumn { + max-width: 100% !important; + padding-left: var(--ifm-spacing-horizontal) !important; + } +} + +.loadingSpinner { + width: 3rem; + height: 3rem; + border: 0.4em solid #eee; + border-top-color: var(--ifm-color-primary); + border-radius: 50%; + animation: loading-spin 1s linear infinite; + margin: 0 auto; +} + +@keyframes loading-spin { + 100% { + transform: rotate(360deg); + } +} + +.loader { + margin-top: 2rem; +} + +:global(.search-result-match) { + color: var(--docsearch-hit-color); + background: rgb(255 215 142 / 25%); + padding: 0.09em 0; +} From 5e2c99ea778eb0b15a41916f09125ad8a4742b07 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:42:59 +0530 Subject: [PATCH 09/30] Update list of filters for custom search based on facet tags --- src/utils/searchConstant.ts | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/utils/searchConstant.ts b/src/utils/searchConstant.ts index 53942a26ef6..28a1b9e7abf 100644 --- a/src/utils/searchConstant.ts +++ b/src/utils/searchConstant.ts @@ -11,10 +11,10 @@ export const allFacets = [ "docusaurus_tag:docs-learn-current", "docusaurus_tag:docs-iota-sdk-1-0-current", "docusaurus_tag:docs-build-current", + "docusaurus_tag:docs-identity-rs-1-0-current", "docusaurus_tag:docs-identity-rs-1-1-current", "docusaurus_tag:docs-identity-rs-1-2-current", "docusaurus_tag:docs-isc-v1-0-0-rc-6-current", - "docusaurus_tag:docs-identity-rs-1-0-current", "docusaurus_tag:docs-iota-sandbox-current", "docusaurus_tag:docs-stronghold-rs-1-1-current", "docusaurus_tag:docs-wasp-v1-0-0-rc-6-current", @@ -22,4 +22,28 @@ export const allFacets = [ "docusaurus_tag:docs-chronicle-1-0-rc-2-current", "docusaurus_tag:docs-hornet-2-0-current", ], - ] \ No newline at end of file + ] + + export const facetNamesJson = { + "docusaurus_tag:default": "Tutorial", + "docusaurus_tag:docs-apis-current": "Apis", + "docusaurus_tag:docs-cli-wallet-1-0-current": "Cli Wallet", + "docusaurus_tag:docs-maintain-current": "Maintain", + "docusaurus_tag:docs-iota-tips-current": "Tips", + "docusaurus_tag:docs-get-started-current": "Get Started", + "docusaurus_tag:docs-learn-current": "Learn", + "docusaurus_tag:docs-identity-rs-1-2-current": "Identity.rs 1.2", + "docusaurus_tag:docs-identity-rs-1-1-current": "Identity.rs 1.1", + "docusaurus_tag:docs-identity-rs-1-0-current": "Identity.rs", + "docusaurus_tag:docs-iota-sandbox-current": "Iota", + "docusaurus_tag:docs-build-current": "Sandbox", + "docusaurus_tag:docs-isc-v1-0-0-rc-6-current": "ISC", + "docusaurus_tag:docs-stronghold-rs-1-1-current": "Stronghold", + "docusaurus_tag:docs-iota-core-1-0-current": "Iota Core", + "docusaurus_tag:docs-wasp-v1-0-0-rc-6-current": "Wasp", + "docusaurus_tag:docs-iota-sdk-1-0-current": "Iota sdk", + "docusaurus_tag:docs-hornet-2-0-current": "Hornet", + "docusaurus_tag:docs-introduction-docs-stardust-current": "Stardust", + "docusaurus_tag:docs-chronicle-1-0-rc-2-current": "Chronicle", + "docusaurus_tag:docs-community-current": "Community", + }; \ No newline at end of file From 4f2aa50f25c8b65a1406163e0cdc957bfb433536 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:43:57 +0530 Subject: [PATCH 10/30] Refactor context for search modal and page --- src/theme/Root.js | 12 ++++++++++++ src/utils/SearchContext.js | 21 +++++++++++++++++++++ src/utils/useSearch.ts | 13 ------------- 3 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 src/theme/Root.js create mode 100644 src/utils/SearchContext.js delete mode 100644 src/utils/useSearch.ts diff --git a/src/theme/Root.js b/src/theme/Root.js new file mode 100644 index 00000000000..230c6b4526f --- /dev/null +++ b/src/theme/Root.js @@ -0,0 +1,12 @@ +/* eslint-disable */ + +import React from 'react'; +import { SearchProvider } from '@site/src/utils/SearchContext'; + +export default function Root({ children }) { + return ( + +
{children}
+
+ ); +} \ No newline at end of file diff --git a/src/utils/SearchContext.js b/src/utils/SearchContext.js new file mode 100644 index 00000000000..e036c05ea85 --- /dev/null +++ b/src/utils/SearchContext.js @@ -0,0 +1,21 @@ +/* eslint-disable */ + +import React, { createContext, useState } from 'react'; +import { allFacets } from './searchConstant'; + +export const SearchContext = createContext(null); + +export const SearchProvider = ({ children }) => { + const [selectedFacets, setSelectedFacets] = useState(allFacets); + + return ( + + {children} + + ); +}; diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts deleted file mode 100644 index e67b2ece6b1..00000000000 --- a/src/utils/useSearch.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createContext, useState } from "react"; -import { allFacets } from "./searchConstant"; - -export const useSearchContext = createContext(null); - -export function useSearch() { - const [selectedFacets, setSelectedFacets] = useState(allFacets); - - return { - selectedFacets, - setSelectedFacets, - }; -} \ No newline at end of file From 85422c14402fb16741540389059b268f01e394dd Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Fri, 17 May 2024 16:56:36 +0530 Subject: [PATCH 11/30] lint fix --- src/theme/Root.js | 2 +- src/theme/SearchBar/DropdownContent.js | 1 - src/theme/SearchBar/index.js | 2 +- src/theme/SearchBar/styles.css | 38 +++++------ src/theme/SearchPage/index.js | 1 - src/utils/searchConstant.ts | 94 +++++++++++++------------- 6 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/theme/Root.js b/src/theme/Root.js index 230c6b4526f..106d136116e 100644 --- a/src/theme/Root.js +++ b/src/theme/Root.js @@ -9,4 +9,4 @@ export default function Root({ children }) {
{children}
); -} \ No newline at end of file +} diff --git a/src/theme/SearchBar/DropdownContent.js b/src/theme/SearchBar/DropdownContent.js index c60e2bca55b..58a719ed41d 100644 --- a/src/theme/SearchBar/DropdownContent.js +++ b/src/theme/SearchBar/DropdownContent.js @@ -1,5 +1,4 @@ /* eslint-disable */ - import React from 'react'; import { facetNamesJson, allFacets } from '../../utils/searchConstant'; import clsx from 'clsx'; diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js index 9e4409cae9a..30058dd0331 100644 --- a/src/theme/SearchBar/index.js +++ b/src/theme/SearchBar/index.js @@ -196,4 +196,4 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { export default function SearchBar() { const { siteConfig } = useDocusaurusContext(); return ; -} \ No newline at end of file +} diff --git a/src/theme/SearchBar/styles.css b/src/theme/SearchBar/styles.css index 2c2dd2ed735..321e255e35e 100644 --- a/src/theme/SearchBar/styles.css +++ b/src/theme/SearchBar/styles.css @@ -1,21 +1,21 @@ :root { - --docsearch-primary-color: var(--ifm-color-primary); - --docsearch-text-color: var(--ifm-font-color-base); - z-index: 700; - } - - .DocSearch-Button { - margin: 0; - transition: all var(--ifm-transition-fast) - var(--ifm-transition-timing-default); - } - - .DocSearch-Container { - z-index: 200; - } - .DocSearch-Modal { - top: 61px; - } -.filterButton{ + --docsearch-primary-color: var(--ifm-color-primary); + --docsearch-text-color: var(--ifm-font-color-base); + z-index: 700; +} + +.DocSearch-Button { + margin: 0; + transition: all var(--ifm-transition-fast) + var(--ifm-transition-timing-default); +} + +.DocSearch-Container { + z-index: 200; +} +.DocSearch-Modal { + top: 61px; +} +.filterButton { width: 100px; -} \ No newline at end of file +} diff --git a/src/theme/SearchPage/index.js b/src/theme/SearchPage/index.js index 15d0fe4325b..0194ddc7c80 100644 --- a/src/theme/SearchPage/index.js +++ b/src/theme/SearchPage/index.js @@ -1,4 +1,3 @@ - /* eslint-disable */ /* eslint-disable jsx-a11y/no-autofocus */ import React, { diff --git a/src/utils/searchConstant.ts b/src/utils/searchConstant.ts index 28a1b9e7abf..eeef5eef108 100644 --- a/src/utils/searchConstant.ts +++ b/src/utils/searchConstant.ts @@ -1,49 +1,49 @@ export const allFacets = [ - "language:en", - [ - "docusaurus_tag:default", - "docusaurus_tag:docs-apis-current", - "docusaurus_tag:docs-cli-wallet-1-0-current", - "docusaurus_tag:docs-maintain-current", - "docusaurus_tag:docs-iota-tips-current", - "docusaurus_tag:docs-community-current", - "docusaurus_tag:docs-get-started-current", - "docusaurus_tag:docs-learn-current", - "docusaurus_tag:docs-iota-sdk-1-0-current", - "docusaurus_tag:docs-build-current", - "docusaurus_tag:docs-identity-rs-1-0-current", - "docusaurus_tag:docs-identity-rs-1-1-current", - "docusaurus_tag:docs-identity-rs-1-2-current", - "docusaurus_tag:docs-isc-v1-0-0-rc-6-current", - "docusaurus_tag:docs-iota-sandbox-current", - "docusaurus_tag:docs-stronghold-rs-1-1-current", - "docusaurus_tag:docs-wasp-v1-0-0-rc-6-current", - "docusaurus_tag:docs-introduction-docs-stardust-current", - "docusaurus_tag:docs-chronicle-1-0-rc-2-current", - "docusaurus_tag:docs-hornet-2-0-current", - ], - ] + 'language:en', + [ + 'docusaurus_tag:default', + 'docusaurus_tag:docs-apis-current', + 'docusaurus_tag:docs-cli-wallet-1-0-current', + 'docusaurus_tag:docs-maintain-current', + 'docusaurus_tag:docs-iota-tips-current', + 'docusaurus_tag:docs-community-current', + 'docusaurus_tag:docs-get-started-current', + 'docusaurus_tag:docs-learn-current', + 'docusaurus_tag:docs-iota-sdk-1-0-current', + 'docusaurus_tag:docs-build-current', + 'docusaurus_tag:docs-identity-rs-1-0-current', + 'docusaurus_tag:docs-identity-rs-1-1-current', + 'docusaurus_tag:docs-identity-rs-1-2-current', + 'docusaurus_tag:docs-isc-v1-0-0-rc-6-current', + 'docusaurus_tag:docs-iota-sandbox-current', + 'docusaurus_tag:docs-stronghold-rs-1-1-current', + 'docusaurus_tag:docs-wasp-v1-0-0-rc-6-current', + 'docusaurus_tag:docs-introduction-docs-stardust-current', + 'docusaurus_tag:docs-chronicle-1-0-rc-2-current', + 'docusaurus_tag:docs-hornet-2-0-current', + ], +]; - export const facetNamesJson = { - "docusaurus_tag:default": "Tutorial", - "docusaurus_tag:docs-apis-current": "Apis", - "docusaurus_tag:docs-cli-wallet-1-0-current": "Cli Wallet", - "docusaurus_tag:docs-maintain-current": "Maintain", - "docusaurus_tag:docs-iota-tips-current": "Tips", - "docusaurus_tag:docs-get-started-current": "Get Started", - "docusaurus_tag:docs-learn-current": "Learn", - "docusaurus_tag:docs-identity-rs-1-2-current": "Identity.rs 1.2", - "docusaurus_tag:docs-identity-rs-1-1-current": "Identity.rs 1.1", - "docusaurus_tag:docs-identity-rs-1-0-current": "Identity.rs", - "docusaurus_tag:docs-iota-sandbox-current": "Iota", - "docusaurus_tag:docs-build-current": "Sandbox", - "docusaurus_tag:docs-isc-v1-0-0-rc-6-current": "ISC", - "docusaurus_tag:docs-stronghold-rs-1-1-current": "Stronghold", - "docusaurus_tag:docs-iota-core-1-0-current": "Iota Core", - "docusaurus_tag:docs-wasp-v1-0-0-rc-6-current": "Wasp", - "docusaurus_tag:docs-iota-sdk-1-0-current": "Iota sdk", - "docusaurus_tag:docs-hornet-2-0-current": "Hornet", - "docusaurus_tag:docs-introduction-docs-stardust-current": "Stardust", - "docusaurus_tag:docs-chronicle-1-0-rc-2-current": "Chronicle", - "docusaurus_tag:docs-community-current": "Community", - }; \ No newline at end of file +export const facetNamesJson = { + 'docusaurus_tag:default': 'Tutorial', + 'docusaurus_tag:docs-apis-current': 'Apis', + 'docusaurus_tag:docs-cli-wallet-1-0-current': 'Cli Wallet', + 'docusaurus_tag:docs-maintain-current': 'Maintain', + 'docusaurus_tag:docs-iota-tips-current': 'Tips', + 'docusaurus_tag:docs-get-started-current': 'Get Started', + 'docusaurus_tag:docs-learn-current': 'Learn', + 'docusaurus_tag:docs-identity-rs-1-2-current': 'Identity.rs 1.2', + 'docusaurus_tag:docs-identity-rs-1-1-current': 'Identity.rs 1.1', + 'docusaurus_tag:docs-identity-rs-1-0-current': 'Identity.rs', + 'docusaurus_tag:docs-iota-sandbox-current': 'Iota', + 'docusaurus_tag:docs-build-current': 'Sandbox', + 'docusaurus_tag:docs-isc-v1-0-0-rc-6-current': 'ISC', + 'docusaurus_tag:docs-stronghold-rs-1-1-current': 'Stronghold', + 'docusaurus_tag:docs-iota-core-1-0-current': 'Iota Core', + 'docusaurus_tag:docs-wasp-v1-0-0-rc-6-current': 'Wasp', + 'docusaurus_tag:docs-iota-sdk-1-0-current': 'Iota sdk', + 'docusaurus_tag:docs-hornet-2-0-current': 'Hornet', + 'docusaurus_tag:docs-introduction-docs-stardust-current': 'Stardust', + 'docusaurus_tag:docs-chronicle-1-0-rc-2-current': 'Chronicle', + 'docusaurus_tag:docs-community-current': 'Community', +}; From 12110e079dfbc642a0f3562a0e8dade24618f43e Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Thu, 23 May 2024 11:49:21 +0530 Subject: [PATCH 12/30] Fix custom dropdown filter name --- src/theme/SearchBar/DropdownContent.js | 80 ------------- src/theme/SearchBar/FilterDropdown.js | 149 +++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 80 deletions(-) delete mode 100644 src/theme/SearchBar/DropdownContent.js create mode 100644 src/theme/SearchBar/FilterDropdown.js diff --git a/src/theme/SearchBar/DropdownContent.js b/src/theme/SearchBar/DropdownContent.js deleted file mode 100644 index 58a719ed41d..00000000000 --- a/src/theme/SearchBar/DropdownContent.js +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable */ -import React from 'react'; -import { facetNamesJson, allFacets } from '../../utils/searchConstant'; -import clsx from 'clsx'; -import styles from './styles.module.css'; - -export const DropdownContent = ({ selectedFacets, setSelectedFacets }) => { - const actualFacets = allFacets[1]; - const handleCheckboxChange = (event) => { - const { value, checked } = event.target; - const updatedFacets = [...selectedFacets]; - const updatedFacetList = [...updatedFacets[1]]; - if (checked) { - if (!updatedFacetList.includes(value)) { - updatedFacetList.push(value); - } - } else { - const index = updatedFacetList.indexOf(value); - if (index > -1) { - updatedFacetList.splice(index, 1); - } - } - updatedFacets[1] = updatedFacetList; - setSelectedFacets(updatedFacets); - }; - - const handleSelectAll = (event) => { - const checked = event.target.checked; - const updatedFacets = [...selectedFacets]; - const updatedFacetList = checked ? actualFacets.slice() : []; - updatedFacets[1] = updatedFacetList; - setSelectedFacets(updatedFacets); - }; - return ( -
- -
    - - {actualFacets.map((facet, index) => ( -
  • - -
  • - ))} -
-
- ); -}; diff --git a/src/theme/SearchBar/FilterDropdown.js b/src/theme/SearchBar/FilterDropdown.js new file mode 100644 index 00000000000..a11db263fbc --- /dev/null +++ b/src/theme/SearchBar/FilterDropdown.js @@ -0,0 +1,149 @@ +/* eslint-disable */ +import React, { forwardRef, useEffect } from 'react'; +import { + facetNamesJson, + allFacets, + subFilters, + subChildFilters, + buildSubFilters, + identitySubFilters, + maintainSubFilters, +} from '../../utils/searchConstant'; +import clsx from 'clsx'; +import styles from './styles.module.css'; + +export const FilterDropdown = forwardRef( + ({ selectedFacets, setSelectedFacets, styleProps = {} }, ref) => { + const actualFacets = allFacets[1]; + + const handleCheckboxChange = (event) => { + const { value, checked } = event.target; + let updatedFacetList = checked + ? [...selectedFacets[1], value] + : selectedFacets[1].filter((facet) => facet !== value); + + if (checked) { + // If a parent filter is checked, add its child filters + if (value === 'docusaurus_tag:docs-build-current') { + updatedFacetList = [ + ...new Set([...updatedFacetList, ...buildSubFilters]), + ]; + } else if (value === 'docusaurus_tag:docs-identity-rs-1-0-current') { + updatedFacetList = [ + ...new Set([...updatedFacetList, ...identitySubFilters]), + ]; + } else if (value === 'docusaurus_tag:docs-maintain-current') { + updatedFacetList = [ + ...new Set([...updatedFacetList, ...maintainSubFilters]), + ]; + } + } else { + // If a parent filter is unchecked, remove its child filters + if (value === 'docusaurus_tag:docs-build-current') { + updatedFacetList = updatedFacetList.filter( + (facet) => !buildSubFilters.includes(facet), + ); + } else if (value === 'docusaurus_tag:docs-identity-rs-1-0-current') { + updatedFacetList = updatedFacetList.filter( + (facet) => !identitySubFilters.includes(facet), + ); + } else if (value === 'docusaurus_tag:docs-maintain-current') { + updatedFacetList = updatedFacetList.filter( + (facet) => !maintainSubFilters.includes(facet), + ); + } + } + + setSelectedFacets([selectedFacets[0], updatedFacetList]); + }; + + const handleSelectAll = (event) => { + const checked = event.target.checked; + const updatedFacetList = checked ? actualFacets.slice() : []; + setSelectedFacets([selectedFacets[0], updatedFacetList]); + }; + + useEffect(() => { + // Check if all subfilters are selected, if yes, select the parent filter + const parentFilterStatus = { + 'docusaurus_tag:docs-maintain-current': maintainSubFilters.every( + (facet) => selectedFacets[1].includes(facet), + ), + 'docusaurus_tag:docs-build-current': buildSubFilters.every((facet) => + selectedFacets[1].includes(facet), + ), + 'docusaurus_tag:docs-identity-rs-1-0-current': identitySubFilters.every( + (facet) => selectedFacets[1].includes(facet), + ), + }; + + Object.keys(parentFilterStatus).forEach((parentFilter) => { + if ( + parentFilterStatus[parentFilter] && + !selectedFacets[1].includes(parentFilter) + ) { + setSelectedFacets((prevState) => [ + prevState[0], + [...prevState[1], parentFilter], + ]); + } + }); + }, [selectedFacets, setSelectedFacets]); + + return ( +
+ +
    + + {actualFacets.map((facet, index) => ( +
  • + +
  • + ))} +
+
+ ); + }, +); From 8e853e200c45c688fd9b896d1258341acf51ef4b Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Thu, 23 May 2024 11:50:41 +0530 Subject: [PATCH 13/30] Refractor custom dropdown filter Signed-off-by: Vivek Jain --- src/theme/SearchBar/index.js | 43 ++++++++++++++++++++++++++--------- src/theme/SearchPage/index.js | 18 +++++++++++---- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js index 30058dd0331..d2ff43b4456 100644 --- a/src/theme/SearchBar/index.js +++ b/src/theme/SearchBar/index.js @@ -5,6 +5,7 @@ import React, { useRef, useState, useContext, + useEffect, } from 'react'; import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react'; import Head from '@docusaurus/Head'; @@ -19,8 +20,9 @@ import Translate from '@docusaurus/Translate'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import { createPortal } from 'react-dom'; import translations from '@theme/SearchTranslations'; -import { DropdownContent } from './DropdownContent'; +import { FilterDropdown } from './FilterDropdown'; import { SearchContext } from '@site/src/utils/SearchContext'; +import { allFacets } from '@site/src/utils/searchConstant'; let DocSearchModal = null; function Hit({ hit, children }) { @@ -53,19 +55,20 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { const history = useHistory(); const searchContainer = useRef(null); const searchButtonRef = useRef(null); + const filterDropdownMenuRef = useRef(null); const [isOpen, setIsOpen] = useState(false); const [initialQuery, setInitialQuery] = useState(undefined); - const importDocSearchModalIfNeeded = useCallback(() => { + + const importDocSearchModalIfNeeded = useCallback(async (event) => { if (DocSearchModal) { return Promise.resolve(); } - return Promise.all([ + const [{ DocSearchModal: Modal }] = await Promise.all([ import('@docsearch/react/modal'), import('@docsearch/react/style'), import('./styles.css'), - ]).then(([{ DocSearchModal: Modal }]) => { - DocSearchModal = Modal; - }); + ]); + DocSearchModal = Modal; }, []); const onOpen = useCallback(() => { @@ -77,8 +80,6 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { ); setIsOpen(true); }); - - DropdownContent; }, [importDocSearchModalIfNeeded, setIsOpen]); const onClose = useCallback(() => { @@ -139,8 +140,27 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { searchButtonRef, }); - const helloDiv = document.createElement('div'); - helloDiv.textContent = 'Hello!'; + useEffect(() => { + if (!isOpen) return; + + const handleClickOutside = (event) => { + const filterDropdownMenu = document.querySelector('.dropdown__menu'); + if (filterDropdownMenu && filterDropdownMenu.contains(event.target)) + return; + if ( + searchContainer.current && + !searchContainer.current.contains(event.target) + ) { + setSelectedFacets(allFacets); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isOpen, onClose, setSelectedFacets]); + return ( <> @@ -159,9 +179,10 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) { translations={translations.button} /> {isOpen && ( - )} diff --git a/src/theme/SearchPage/index.js b/src/theme/SearchPage/index.js index 0194ddc7c80..d802ad8eb0b 100644 --- a/src/theme/SearchPage/index.js +++ b/src/theme/SearchPage/index.js @@ -29,6 +29,7 @@ import { import Layout from '@theme/Layout'; import styles from './styles.module.css'; import { SearchContext } from '@site/src/utils/SearchContext'; +import { FilterDropdown } from '../SearchBar/FilterDropdown'; // Very simple pluralization: probably good enough for now function useDocumentsFoundPlural() { const { selectMessage } = usePluralForm(); @@ -124,7 +125,7 @@ function SearchPageContent() { const documentsFoundPlural = useDocumentsFoundPlural(); const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers(); const [searchQuery, setSearchQuery] = useSearchQueryString(); - const { selectedFacets } = useContext(SearchContext); + const { selectedFacets, setSelectedFacets } = useContext(SearchContext); const initialSearchResultState = { items: [], query: null, @@ -286,7 +287,12 @@ function SearchPageContent() { makeSearch(); }, 300); } - }, [searchQuery, docsSearchVersionsHelpers.searchVersions, makeSearch]); + }, [ + searchQuery, + JSON.stringify(selectedFacets), + docsSearchVersionsHelpers.searchVersions, + makeSearch, + ]); useEffect(() => { if (!searchResultState.lastPage || searchResultState.lastPage === 0) { return; @@ -303,7 +309,11 @@ function SearchPageContent() { */} - +

{getTitle()}

@@ -466,9 +476,7 @@ function SearchPageContent() { export default function SearchPage() { return ( - {/* */} - {/* */} ); } From 607b2dfac95cd5207bbbac07b771822e9d7cdc75 Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Thu, 23 May 2024 11:53:16 +0530 Subject: [PATCH 14/30] Update styles for custom dropdown filter Signed-off-by: Vivek Jain --- src/theme/SearchBar/styles.module.css | 27 ++++++++++++++++++++++----- src/theme/SearchPage/index.js | 8 +++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/theme/SearchBar/styles.module.css b/src/theme/SearchBar/styles.module.css index 51443a6e9f0..3ce792f9f6f 100644 --- a/src/theme/SearchBar/styles.module.css +++ b/src/theme/SearchBar/styles.module.css @@ -3,16 +3,33 @@ right: 22%; top: 245%; cursor: pointer; + font-size: 14px; + font-weight: var(--ifm-font-weight-semibold); } .dropdownMenu { - width: 15%; - position: fixed; - right: 35%; - top: 18.75%; - left: 69%; + color: var(--ifm-navbar-link-color); + width: 210px; + position: absolute; padding: 15px; + height: 300px; + left: -35%; + top: 104%; +} +.dropdownMenu::-webkit-scrollbar { + width: 4px; + height: 4px; } +.dropdownMenu { + scrollbar-width: thin; +} + +.subFilters { + margin-left: 20px; +} +.subChildFilters { + margin-left: 35px; +} @media (max-width: 996px) { .dropdown { position: absolute; diff --git a/src/theme/SearchPage/index.js b/src/theme/SearchPage/index.js index d802ad8eb0b..132137ad911 100644 --- a/src/theme/SearchPage/index.js +++ b/src/theme/SearchPage/index.js @@ -310,7 +310,13 @@ function SearchPageContent() { From b52cbd5e5c811b9c3a80a0840758bba2356b3bab Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Thu, 23 May 2024 11:54:07 +0530 Subject: [PATCH 15/30] Add filter constants for custom dropdown filter Signed-off-by: Vivek Jain --- src/utils/searchConstant.ts | 63 +++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/src/utils/searchConstant.ts b/src/utils/searchConstant.ts index eeef5eef108..df5e818a965 100644 --- a/src/utils/searchConstant.ts +++ b/src/utils/searchConstant.ts @@ -1,42 +1,41 @@ export const allFacets = [ 'language:en', [ - 'docusaurus_tag:default', - 'docusaurus_tag:docs-apis-current', - 'docusaurus_tag:docs-cli-wallet-1-0-current', - 'docusaurus_tag:docs-maintain-current', - 'docusaurus_tag:docs-iota-tips-current', - 'docusaurus_tag:docs-community-current', 'docusaurus_tag:docs-get-started-current', 'docusaurus_tag:docs-learn-current', - 'docusaurus_tag:docs-iota-sdk-1-0-current', 'docusaurus_tag:docs-build-current', + 'docusaurus_tag:docs-iota-sdk-1-0-current', 'docusaurus_tag:docs-identity-rs-1-0-current', 'docusaurus_tag:docs-identity-rs-1-1-current', 'docusaurus_tag:docs-identity-rs-1-2-current', + 'docusaurus_tag:docs-stronghold-rs-1-1-current', + 'docusaurus_tag:docs-apis-current', + 'docusaurus_tag:docs-cli-wallet-1-0-current', + 'docusaurus_tag:docs-community-current', 'docusaurus_tag:docs-isc-v1-0-0-rc-6-current', 'docusaurus_tag:docs-iota-sandbox-current', - 'docusaurus_tag:docs-stronghold-rs-1-1-current', - 'docusaurus_tag:docs-wasp-v1-0-0-rc-6-current', 'docusaurus_tag:docs-introduction-docs-stardust-current', 'docusaurus_tag:docs-chronicle-1-0-rc-2-current', + 'docusaurus_tag:docs-maintain-current', 'docusaurus_tag:docs-hornet-2-0-current', + 'docusaurus_tag:docs-wasp-v1-0-0-rc-6-current', + 'docusaurus_tag:default', + 'docusaurus_tag:docs-iota-tips-current', ], ]; export const facetNamesJson = { + 'docusaurus_tag:docs-get-started-current': 'Get Started', + 'docusaurus_tag:docs-learn-current': 'Learn', 'docusaurus_tag:default': 'Tutorial', 'docusaurus_tag:docs-apis-current': 'Apis', 'docusaurus_tag:docs-cli-wallet-1-0-current': 'Cli Wallet', 'docusaurus_tag:docs-maintain-current': 'Maintain', - 'docusaurus_tag:docs-iota-tips-current': 'Tips', - 'docusaurus_tag:docs-get-started-current': 'Get Started', - 'docusaurus_tag:docs-learn-current': 'Learn', 'docusaurus_tag:docs-identity-rs-1-2-current': 'Identity.rs 1.2', 'docusaurus_tag:docs-identity-rs-1-1-current': 'Identity.rs 1.1', 'docusaurus_tag:docs-identity-rs-1-0-current': 'Identity.rs', 'docusaurus_tag:docs-iota-sandbox-current': 'Iota', - 'docusaurus_tag:docs-build-current': 'Sandbox', + 'docusaurus_tag:docs-build-current': 'Build', 'docusaurus_tag:docs-isc-v1-0-0-rc-6-current': 'ISC', 'docusaurus_tag:docs-stronghold-rs-1-1-current': 'Stronghold', 'docusaurus_tag:docs-iota-core-1-0-current': 'Iota Core', @@ -46,4 +45,42 @@ export const facetNamesJson = { 'docusaurus_tag:docs-introduction-docs-stardust-current': 'Stardust', 'docusaurus_tag:docs-chronicle-1-0-rc-2-current': 'Chronicle', 'docusaurus_tag:docs-community-current': 'Community', + 'docusaurus_tag:docs-iota-tips-current': 'Tips', }; +export const subFilters = [ + 'Wasp', + 'Hornet', + 'Identity.rs', + 'Cli Wallet', + 'Apis', + 'Stronghold', + 'Iota sdk', + 'ISC', + 'Iota', + 'Stardust', + 'Chronicle', + 'Community', +]; +export const subChildFilters = ['Identity.rs 1.2', 'Identity.rs 1.1']; +export const buildSubFilters = [ + 'docusaurus_tag:docs-iota-sdk-1-0-current', + 'docusaurus_tag:docs-identity-rs-1-0-current', + 'docusaurus_tag:docs-identity-rs-1-2-current', + 'docusaurus_tag:docs-identity-rs-1-1-current', + 'docusaurus_tag:docs-stronghold-rs-1-1-current', + 'docusaurus_tag:docs-apis-current', + 'docusaurus_tag:docs-cli-wallet-1-0-current', + 'docusaurus_tag:docs-community-current', + 'docusaurus_tag:docs-isc-v1-0-0-rc-6-current', + 'docusaurus_tag:docs-iota-sandbox-current', + 'docusaurus_tag:docs-introduction-docs-stardust-current', + 'docusaurus_tag:docs-chronicle-1-0-rc-2-current', +]; +export const identitySubFilters = [ + 'docusaurus_tag:docs-identity-rs-1-2-current', + 'docusaurus_tag:docs-identity-rs-1-1-current', +]; +export const maintainSubFilters = [ + 'docusaurus_tag:docs-wasp-v1-0-0-rc-6-current', + 'docusaurus_tag:docs-hornet-2-0-current', +]; From 5cc1abf114e5b21650f3ade4ca876064a877d82d Mon Sep 17 00:00:00 2001 From: Vivek Jain Date: Thu, 6 Jun 2024 18:41:22 +0530 Subject: [PATCH 16/30] Fix footer alignment in search page --- src/theme/Footer/index.tsx | 28 +++++++------- src/theme/Layout/Provider/index.js | 21 ++++++++++ src/theme/Layout/index.js | 53 ++++++++++++++++++++++++++ src/theme/Layout/styles.module.css | 21 ++++++++++ src/theme/SearchBar/FilterDropdown.js | 4 ++ src/theme/SearchPage/index.js | 50 +++++++++++++++--------- src/theme/SearchPage/styles.module.css | 6 +++ 7 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 src/theme/Layout/Provider/index.js create mode 100644 src/theme/Layout/index.js create mode 100644 src/theme/Layout/styles.module.css diff --git a/src/theme/Footer/index.tsx b/src/theme/Footer/index.tsx index 13983775d9d..a8edba90f4d 100644 --- a/src/theme/Footer/index.tsx +++ b/src/theme/Footer/index.tsx @@ -1,22 +1,20 @@ -/** - * SWIZZLED VERSION: 2.0.0-rc.1 - * REASONS: - * - The socials bar needed full width, so needed to be placed outside the default container. - */ - import React from 'react'; import Footer from '@theme-original/Footer'; -import type FooterType from '@theme/Footer'; -import type { WrapperProps } from '@docusaurus/types'; import Social from '@site/src/components/Social'; -type Props = WrapperProps; +type FooterProps = { + footerStyleProps?: React.CSSProperties; +}; -export default function FooterWrapper(props: Props): JSX.Element { +const FooterWrapper = ({ footerStyleProps }: FooterProps) => { return ( - <> -