1import { DocsLogo, PlanEnterpriseIcon, iconSize, theme } from '@expo/styleguide'; 2import { Command } from 'cmdk'; 3 4import type { AlgoliaItemType } from '../types'; 5import { getContentHighlightHTML, getHighlightHTML, isEASPath, openLink } from '../utils'; 6import { FootnoteSection } from './FootnoteSection'; 7import { FootnoteArrowIcon, GuideIcon } from './icons'; 8import { contentStyle, footnoteStyle, itemIconWrapperStyle, itemStyle } from './styles'; 9 10import versions from '~/public/static/constants/versions.json'; 11import { CALLOUT, FOOTNOTE } from '~/ui/components/Text'; 12 13const { LATEST_VERSION } = versions; 14 15type Props = { 16 item: AlgoliaItemType; 17 onSelect?: () => void; 18}; 19 20const isDev = process.env.NODE_ENV === 'development'; 21 22const ItemIcon = ({ url }: { url: string }) => { 23 if (url.includes('/versions/')) { 24 return <DocsLogo width={iconSize.md} color={theme.icon.secondary} />; 25 } else if (isEASPath(url)) { 26 return <PlanEnterpriseIcon color={theme.icon.secondary} />; 27 } 28 return <GuideIcon />; 29}; 30 31const getFootnotePrefix = (url: string) => { 32 if (url.includes('/versions/')) { 33 return 'API Reference'; 34 } else if (isEASPath(url)) { 35 return 'Expo Application Services'; 36 } else { 37 return 'Guides'; 38 } 39}; 40 41const ItemFootnotePrefix = ({ url, isNested = false }: { url: string; isNested?: boolean }) => { 42 return isNested ? ( 43 <> 44 <span css={footnoteStyle}>{getFootnotePrefix(url)}</span> 45 <FootnoteArrowIcon /> 46 </> 47 ) : ( 48 <FOOTNOTE css={footnoteStyle}>{getFootnotePrefix(url)}</FOOTNOTE> 49 ); 50}; 51 52const transformUrl = (url: string) => { 53 if (url.includes(LATEST_VERSION)) { 54 url = url.replace(LATEST_VERSION, 'latest'); 55 } 56 if (isDev) { 57 url = url.replace('https://docs.expo.dev/', 'http://localhost:3002/'); 58 } 59 return url; 60}; 61 62export const ExpoDocsItem = ({ item, onSelect }: Props) => { 63 const { lvl0, lvl2, lvl3, lvl4, lvl6 } = item.hierarchy; 64 return ( 65 <Command.Item 66 value={`expodocs-${item.objectID}`} 67 onSelect={() => { 68 openLink(transformUrl(item.url)); 69 onSelect && onSelect(); 70 }}> 71 <div css={itemStyle}> 72 <div css={itemIconWrapperStyle}> 73 <ItemIcon url={item.url} /> 74 </div> 75 <div> 76 {lvl6 && ( 77 <> 78 <CALLOUT weight="medium" {...getHighlightHTML(item, 'lvl6')} /> 79 <FOOTNOTE css={footnoteStyle}> 80 <ItemFootnotePrefix url={item.url} isNested /> 81 <span {...getHighlightHTML(item, 'lvl0')} /> 82 <FootnoteSection item={item} levelKey="lvl2" /> 83 <FootnoteSection item={item} levelKey="lvl3" /> 84 <FootnoteSection item={item} levelKey="lvl4" /> 85 </FOOTNOTE> 86 </> 87 )} 88 {!lvl6 && lvl4 && ( 89 <> 90 <CALLOUT weight="medium" {...getHighlightHTML(item, 'lvl4')} /> 91 <FOOTNOTE css={footnoteStyle}> 92 <ItemFootnotePrefix url={item.url} isNested /> 93 <span {...getHighlightHTML(item, 'lvl0')} /> 94 <FootnoteSection item={item} levelKey="lvl2" /> 95 <FootnoteSection item={item} levelKey="lvl3" /> 96 </FOOTNOTE> 97 </> 98 )} 99 {!lvl6 && !lvl4 && lvl3 && ( 100 <> 101 <CALLOUT weight="medium" {...getHighlightHTML(item, 'lvl3')} /> 102 <FOOTNOTE css={footnoteStyle}> 103 <ItemFootnotePrefix url={item.url} isNested /> 104 <span {...getHighlightHTML(item, 'lvl0')} /> 105 <FootnoteSection item={item} levelKey="lvl2" /> 106 </FOOTNOTE> 107 </> 108 )} 109 {!lvl6 && !lvl4 && !lvl3 && lvl2 && ( 110 <> 111 <CALLOUT weight="medium" {...getHighlightHTML(item, 'lvl2')} /> 112 <FOOTNOTE css={footnoteStyle}> 113 <ItemFootnotePrefix url={item.url} isNested /> 114 <span {...getHighlightHTML(item, 'lvl0')} /> 115 </FOOTNOTE> 116 </> 117 )} 118 {!lvl6 && !lvl4 && !lvl3 && !lvl2 && lvl0 && ( 119 <> 120 <CALLOUT weight="medium" {...getHighlightHTML(item, 'lvl0')} /> 121 <ItemFootnotePrefix url={item.url} /> 122 </> 123 )} 124 <FOOTNOTE theme="secondary" {...getContentHighlightHTML(item)} css={contentStyle} /> 125 </div> 126 </div> 127 </Command.Item> 128 ); 129}; 130