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