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