diff --git a/src/components/Search.js b/src/components/Search.js index 8251a5d32..e52a1c917 100644 --- a/src/components/Search.js +++ b/src/components/Search.js @@ -11,6 +11,14 @@ const INDEX_NAME = 'tailwindcss' const API_KEY = '5fc87cef58bb80203d2207578309fab6' const APP_ID = 'KNPXZI5B0M' +function isTailwindUIURL(url) { + return url.startsWith('https://tailwindui.com') +} + +function isExternalURL(url) { + return url.startsWith('https://') +} + const SearchContext = createContext() export function SearchProvider({ children }) { @@ -40,6 +48,22 @@ export function SearchProvider({ children }) { onClose, }) + useEffect(() => { + // Prepend "Components" to Tailwind UI results that are shown in the "recent" view + if (!isOpen) { + let key = `__DOCSEARCH_RECENT_SEARCHES__${INDEX_NAME}` + try { + let data = JSON.parse(window.localStorage.getItem(key)) + for (let item of data) { + if (isTailwindUIURL(item.url) && !item.hierarchy.lvl1.startsWith('Components')) { + item.hierarchy.lvl1 = `Components / ${item.hierarchy.lvl1}` + } + } + window.localStorage.setItem(key, JSON.stringify(data)) + } catch {} + } + }, [isOpen]) + return ( <> @@ -57,59 +81,97 @@ export function SearchProvider({ children }) { {isOpen && createPortal( -
{ + let link = event.target.closest('a') + if (!link) return + if (isExternalURL(link.href) && link.target !== '_blank') { + event.preventDefault() + window.open(link.href, '_blank') + } }} - placeholder="Search documentation" - onClose={onClose} - indexName={INDEX_NAME} - apiKey={API_KEY} - appId={APP_ID} - navigator={{ - navigate({ itemUrl }) { - setIsOpen(false) - router.push(itemUrl) - }, - }} - hitComponent={Hit} - transformItems={(items) => { - return items.map((item, index) => { - // We transform the absolute URL into a relative URL to - // leverage Next's preloading. - const a = document.createElement('a') - a.href = item.url - - const hash = a.hash === '#content-wrapper' || a.hash === '#header' ? '' : a.hash - - if (item.hierarchy?.lvl0) { - item.hierarchy.lvl0 = item.hierarchy.lvl0.replace(/&/g, '&') - } - - if (item._highlightResult?.hierarchy?.lvl0?.value) { - item._highlightResult.hierarchy.lvl0.value = - item._highlightResult.hierarchy.lvl0.value.replace(/&/g, '&') - } - - return { - ...item, - url: `${a.pathname}${hash}`, - __is_result: () => true, - __is_parent: () => item.type === 'lvl1' && items.length > 1 && index === 0, - __is_child: () => - item.type !== 'lvl1' && - items.length > 1 && - items[0].type === 'lvl1' && - index !== 0, - __is_first: () => index === 1, - __is_last: () => index === items.length - 1 && index !== 0, - } - }) - }} - />, + > + { + return items.map((item, index) => { + // We transform the absolute URL into a relative URL to + // leverage Next's preloading. + const a = document.createElement('a') + a.href = item.url + + const hash = a.hash === '#content-wrapper' || a.hash === '#header' ? '' : a.hash + + if (item.hierarchy?.lvl0) { + item.hierarchy.lvl0 = item.hierarchy.lvl0.replace(/&/g, '&') + } + + if (item._highlightResult?.hierarchy?.lvl0?.value) { + item._highlightResult.hierarchy.lvl0.value = + item._highlightResult.hierarchy.lvl0.value.replace(/&/g, '&') + } + + let isTailwindUI = isTailwindUIURL(item.url) + + return { + ...item, + hierarchy: { + ...item.hierarchy, + ...(isTailwindUI + ? { lvl1: `${item.product} / ${item.product_category}` } + : {}), + }, + url: isTailwindUI ? item.url.split('#')[0] : `${a.pathname}${hash}`, + __is_result: () => true, + __is_parent: () => item.type === 'lvl1' && items.length > 1 && index === 0, + __is_child: () => + item.type !== 'lvl1' && + items.length > 1 && + items[0].type === 'lvl1' && + index !== 0, + __is_first: () => index === 1, + __is_last: () => index === items.length - 1 && index !== 0, + __is_tailwindui: () => isTailwindUI, + } + }) + }} + /> +
, document.body )} @@ -120,12 +182,14 @@ function Hit({ hit, children }) { return ( {children} diff --git a/src/css/docsearch.css b/src/css/docsearch.css index 698036e83..410f78729 100644 --- a/src/css/docsearch.css +++ b/src/css/docsearch.css @@ -267,6 +267,8 @@ .DocSearch-Hit-action { @apply w-6 h-6; + background-repeat: no-repeat; + background-position: center; background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m11 9 3 3-3 3' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); } @@ -523,3 +525,19 @@ .DocSearch-Hit-action + .DocSearch-Hit-action { @apply ml-3 pl-3 border-l border-slate-200 dark:border-slate-200/5; } + +.DocSearch-Hit--TailwindUI .DocSearch-Hit-icon { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='m6 9 6-3 6 3v6l-6 3-6-3V9Z' fill='%23e0e7ff' /%3E%3Cpath d='m6 9 6 3v7l-6-3V9Z' fill='%23a5b4fc' /%3E%3Cpath d='m18 9-6 3v7l6-3V9Z' fill='%23818cf8' /%3E%3C/svg%3E"); +} + +.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit--TailwindUI .DocSearch-Hit-icon { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='m6 9 6-3 6 3v6l-6 3-6-3V9Z' fill='%23fff' fill-opacity='.5' /%3E%3Cpath d='m6 9 6 3v7l-6-3V9Z' fill='%23fff' fill-opacity='.6' /%3E%3Cpath d='m18 9-6 3v7l6-3V9Z' fill='%23fff' /%3E%3C/svg%3E"); +} + +.DocSearch-Hit--TailwindUI .DocSearch-Hit-action { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' fill='none'%3E%3Cpath stroke='%23475569' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 1h3m0 0v3m0-3L5 5M3.5 1H3a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-.5'/%3E%3C/svg%3E"); +} + +.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit--TailwindUI .DocSearch-Hit-action { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' fill='none'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 1h3m0 0v3m0-3L5 5M3.5 1H3a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-.5'/%3E%3C/svg%3E"); +}