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