this repo has no description
1import { getContext, setContext } from 'svelte';
2
3import type { TodayPage } from '@jet-app/app-store/api/models';
4import {
5 type TodayCardShelf,
6 isTodayCardShelf,
7} from '~/components/jet/shelf/TodayCardShelf.svelte';
8
9/**
10 * Describes the configuration of the card layout within a {@linkcode TodayCardShelf}
11 */
12interface LayoutConfiguration {
13 wrap: {
14 shouldStretchFirstCard: boolean;
15 };
16 nowrap: {
17 shouldStretchFirstCard: boolean;
18 };
19}
20
21const LAYOUT_CONFIGURATION_FALLBACK: LayoutConfiguration = Object.freeze({
22 wrap: {
23 shouldStretchFirstCard: true,
24 },
25 nowrap: {
26 shouldStretchFirstCard: true,
27 },
28});
29
30type TodayCardLayoutStore = WeakMap<TodayCardShelf, LayoutConfiguration>;
31type TodayCardLayoutStoreContext = TodayCardLayoutStore | undefined;
32
33const TODAY_CARD_LAYOUT_CONTEXT_ID = 'today-card-layout-context';
34
35/**
36 * Store the {@linkcode LayoutConfiguration} for each {@linkcode TodayCardShelf} in a
37 * {@linkcode TodayPage} in "context", so it can be retrieved at the shelf-component level
38 *
39 * This is necessary because the layout of the cards within each shelf of a {@linkcode TodayPage}
40 * is only knowable given information about the shelves that were rendered before it
41 *
42 * The information about the shelf layout is persisted through the "context" API so that the
43 * rendering of a {@linkcode TodayPage} can defer to the "default" page component, which requires
44 * that we pass no additional arguments into each shelf component
45 *
46 * {@linkcode getTodayCardLayoutConfiguration} can be used to look up the {@linkcode LayoutConfiguration}
47 * stored for a given {@linkcode TodayCardShelf}
48 */
49export function setTodayCardLayoutContext(page: Pick<TodayPage, 'shelves'>) {
50 const store: TodayCardLayoutStore = new WeakMap();
51
52 let shouldStretchFirstCardMultiline = false;
53 let shouldStretchFirstCardInline = false;
54
55 for (const shelf of page.shelves) {
56 // Skip any non-`TodayCard` shelves
57 if (!isTodayCardShelf(shelf)) {
58 continue;
59 }
60
61 store.set(shelf, {
62 wrap: {
63 shouldStretchFirstCard: shouldStretchFirstCardMultiline,
64 },
65 nowrap: {
66 shouldStretchFirstCard: shouldStretchFirstCardInline,
67 },
68 });
69
70 // In the multi-line card configuration, shelves with two or three cards in them will
71 // require that the next shelf swaps to stretching the cards at the opposite end
72 if (shelf.items.length === 2 || shelf.items.length === 3) {
73 shouldStretchFirstCardMultiline = !shouldStretchFirstCardMultiline;
74 }
75
76 // In the "inline" card configuration, each shelf should always alternate which end the
77 // card is stretched on
78 shouldStretchFirstCardInline = !shouldStretchFirstCardInline;
79 }
80
81 setContext<TodayCardLayoutStoreContext>(
82 TODAY_CARD_LAYOUT_CONTEXT_ID,
83 store,
84 );
85}
86
87/**
88 * Retrieve the {@linkcode LayoutConfiguration} for a given {@linkcode TodayCardShelf}
89 */
90export function getTodayCardLayoutConfiguration(
91 shelf: TodayCardShelf,
92): LayoutConfiguration {
93 const todayCardLayout = getContext<TodayCardLayoutStoreContext>(
94 TODAY_CARD_LAYOUT_CONTEXT_ID,
95 );
96
97 return todayCardLayout?.get(shelf) ?? LAYOUT_CONFIGURATION_FALLBACK;
98}