/ src / components / navigation / navigation-items.ts
navigation-items.ts
 1  import {
 2      isSome,
 3      unwrapOptional as unwrap,
 4  } from '@jet/environment/types/optional';
 5  
 6  import type { NavigationItem } from '@amp/web-app-components/src/components/Navigation/types';
 7  import type { NavigationId } from '@amp/web-app-components/src/types';
 8  import type {
 9      WebNavigation,
10      WebNavigationLink,
11  } from '@jet-app/app-store/api/models/web-navigation';
12  
13  import {
14      isSystemImageArtwork,
15      getIconNameFromTemplate,
16  } from '~/components/SystemImage.svelte';
17  import { getIconComponentByName } from '../SFSymbol.svelte';
18  import type { Artwork } from '@jet-app/app-store/api/models';
19  import CategoryTabItem from '~/components/jet/web-navigation/CategoryTabItem.svelte';
20  
21  /**
22   * A {@linkcode NavigationItem} that includes the original {@linkcode WebNavigationLink}
23   * it was defined from, which is needed for the
24   */
25  export interface NavigationItemWithTab extends NavigationItem {
26      tab: WebNavigationLink;
27      artwork?: Artwork;
28      isActive?: boolean;
29  }
30  
31  export function navigationIdFromLink(link: WebNavigationLink): NavigationId {
32      const intent = unwrap(link.action.destination);
33  
34      return {
35          type: intent.$kind,
36          // `intent.$kind` will be unique for each `Intent` used here as they are
37          // each a different `LandingPageIntent`
38          resourceId: link.action.pageUrl ?? intent.$kind,
39      };
40  }
41  
42  /**
43   * Transform the "tabs" in the `WebNavigation` into a shape that works with our
44   * shared navigation side-bar components.
45   */
46  export function makeNavLinks(
47      tabs: WebNavigationLink[],
48      { shouldShowSearchTab = false },
49  ): NavigationItemWithTab[] {
50      return tabs
51          .filter((tab) => {
52              const isSearchTab =
53                  tab.action?.destination?.['$kind'].includes('search_Intent');
54  
55              // Allows for filtering our the search tab, which we use when the sidebar is visible,
56              // since there is a search input in the sidebar
57              return isSearchTab ? shouldShowSearchTab : true;
58          })
59          .map((tab) => {
60              const { action, artwork: tabArtwork } = tab;
61              const { artwork } = action || {};
62              const hasSystemImageArtwork =
63                  isSome(artwork) && isSystemImageArtwork(artwork);
64  
65              return {
66                  id: navigationIdFromLink(tab),
67                  label: unwrap(tab.action.title),
68                  url: action.pageUrl ?? undefined,
69                  icon: hasSystemImageArtwork
70                      ? getIconComponentByName(
71                            getIconNameFromTemplate(artwork.template),
72                        )
73                      : undefined,
74                  artwork: tabArtwork,
75                  component: !hasSystemImageArtwork ? CategoryTabItem : undefined,
76                  tab,
77              };
78          });
79  }