Skip to content

Commit 8ada977

Browse files
fix: responsive slot details nav
1 parent bf30864 commit 8ada977

File tree

3 files changed

+98
-91
lines changed

3 files changed

+98
-91
lines changed

src/atoms.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,24 @@ export const setSlotStatusAtom = atom(
147147
},
148148
);
149149

150+
const selectedSlotNearbyOffset = 2;
151+
const selectedSlotNearbyYouLeadersAtom = atom<number[] | undefined>((get) => {
152+
const leaderSlots = get(leaderSlotsAtom);
153+
const selectedSlot = get(selectedSlotAtom);
154+
if (leaderSlots === undefined || selectedSlot === undefined) return undefined;
155+
const index = leaderSlots.indexOf(getSlotGroupLeader(selectedSlot));
156+
if (index === -1) return undefined;
157+
return leaderSlots.slice(
158+
Math.max(index - selectedSlotNearbyOffset, 0),
159+
index + selectedSlotNearbyOffset,
160+
);
161+
});
162+
150163
const slotCacheBounds = 1_000;
151164

152165
export const deleteSlotStatusBoundsAtom = atom(null, (get, set) => {
153166
const slotOverride = get(slotOverrideAtom);
154-
const selectedSlot = get(selectedSlotAtom);
155-
167+
const selectedSlotNearbyLeaders = get(selectedSlotNearbyYouLeadersAtom);
156168
const currentSlot = get(currentSlotAtom);
157169
const searchSlots = get(searchLeaderSlotsAtom);
158170
const leaderSlots = get(leaderSlotsAtom);
@@ -168,14 +180,11 @@ export const deleteSlotStatusBoundsAtom = atom(null, (get, set) => {
168180
const numberVal = Number(cachedStatusSlot);
169181
const slotGroupStart = getSlotGroupLeader(numberVal);
170182

171-
if (searchSlots?.length && searchSlots.includes(slotGroupStart)) {
183+
if (searchSlots?.includes(slotGroupStart)) {
172184
continue;
173185
}
174186

175-
if (
176-
selectedSlot !== undefined &&
177-
slotGroupStart === getSlotGroupLeader(selectedSlot)
178-
) {
187+
if (selectedSlotNearbyLeaders?.includes(slotGroupStart)) {
179188
continue;
180189
}
181190

src/features/SlotDetails/index.tsx

Lines changed: 65 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from "../Overview/SlotPerformance/atoms";
1212
import type { FC, SVGProps } from "react";
1313
import { useCallback, useEffect, useMemo, useState } from "react";
14-
import { useUnmount } from "react-use";
14+
import { useMedia, useUnmount } from "react-use";
1515
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
1616
import { useSlotInfo } from "../../hooks/useSlotInfo";
1717
import styles from "./slotDetails.module.css";
@@ -282,6 +282,7 @@ function SlotNavigation({ slot }: { slot: number }) {
282282
const mostRecentSlotLeader = useAtomValue(mostRecentSlotLeaderAtom);
283283

284284
const {
285+
previousSlotGroupLeader,
285286
previousSlotGroupLastSlot,
286287
isPreviousDisabled,
287288
nextSlotGroupLeader,
@@ -312,6 +313,7 @@ function SlotNavigation({ slot }: { slot: number }) {
312313
mostRecentSlotLeader + slotsPerLeader <= nextSlotGroupLeader;
313314

314315
return {
316+
previousSlotGroupLeader,
315317
previousSlotGroupLastSlot,
316318
isPreviousDisabled,
317319
nextSlotGroupLeader,
@@ -326,57 +328,64 @@ function SlotNavigation({ slot }: { slot: number }) {
326328
pb="1"
327329
style={{ top: navigationTop, zIndex: maxZIndex - 3 }}
328330
>
329-
<Flex
330-
className={clsx(
331-
styles.slotNavigation,
332-
styles.previousNavigation,
333-
isPreviousDisabled && styles.disabled,
334-
)}
335-
>
336-
{previousSlotGroupLastSlot && (
337-
<SlotStatus
338-
slot={previousSlotGroupLastSlot}
339-
searchSlot={previousSlotGroupLastSlot}
340-
disabled={isPreviousDisabled}
341-
/>
342-
)}
343-
</Flex>
344-
<Flex
345-
gap="1"
346-
flexGrow="1"
347-
flexShrink="1"
348-
wrap="wrap"
349-
className={styles.slotNavigation}
350-
>
351-
{Array.from({ length: slotsPerLeader }).map((_, slotIdx) => {
352-
const slotNumber = slot + slotIdx;
353-
return (
354-
<SlotStatus
355-
key={slotNumber}
356-
slot={slotNumber}
357-
searchSlot={slotNumber}
358-
/>
359-
);
360-
})}
361-
</Flex>
362-
<Flex
363-
className={clsx(
364-
styles.slotNavigation,
365-
styles.nextNavigation,
366-
isNextDisabled && styles.disabled,
367-
)}
368-
>
369-
{nextSlotGroupLeader && (
331+
<PreviousNextNavigation
332+
slot={previousSlotGroupLastSlot}
333+
searchSlot={previousSlotGroupLeader}
334+
isDisabled={isPreviousDisabled}
335+
isPrevious={true}
336+
/>
337+
<SelectedSlotGroup firstSlot={slot} />
338+
<PreviousNextNavigation
339+
slot={nextSlotGroupLeader}
340+
searchSlot={nextSlotGroupLeader}
341+
isDisabled={isNextDisabled}
342+
isPrevious={false}
343+
/>
344+
</Flex>
345+
);
346+
}
347+
348+
function SelectedSlotGroup({ firstSlot }: { firstSlot: number }) {
349+
return (
350+
<Flex gap="1" className={styles.slotNavigation}>
351+
{Array.from({ length: slotsPerLeader }).map((_, slotIdx) => {
352+
const slotNumber = firstSlot + slotIdx;
353+
return (
370354
<SlotStatus
371-
slot={nextSlotGroupLeader}
372-
searchSlot={nextSlotGroupLeader}
373-
disabled={isNextDisabled}
355+
key={slotNumber}
356+
slot={slotNumber}
357+
searchSlot={slotNumber}
374358
/>
375-
)}
376-
</Flex>
359+
);
360+
})}
377361
</Flex>
378362
);
379363
}
364+
function PreviousNextNavigation({
365+
slot,
366+
searchSlot,
367+
isDisabled,
368+
isPrevious,
369+
}: {
370+
slot?: number;
371+
searchSlot?: number;
372+
isDisabled?: boolean;
373+
isPrevious: boolean;
374+
}) {
375+
return (
376+
<div
377+
className={clsx(styles.slotNavigation, {
378+
[styles.previousNavigation]: isPrevious,
379+
[styles.nextNavigation]: !isPrevious,
380+
[styles.disabled]: isDisabled,
381+
})}
382+
>
383+
{slot !== undefined && searchSlot !== undefined && (
384+
<SlotStatus slot={slot} searchSlot={searchSlot} disabled={isDisabled} />
385+
)}
386+
</div>
387+
);
388+
}
380389

381390
function SlotHeader({ slot }: { slot: number }) {
382391
const { peer, isLeader, name } = useSlotInfo(slot);
@@ -407,10 +416,10 @@ function SlotStatus({
407416
searchSlot: number;
408417
disabled?: boolean;
409418
}) {
419+
const includeIcon = !useMedia("(max-width: 920px)");
410420
const selectedSlot = useAtomValue(selectedSlotAtom);
411421
const queryPublish = useSlotQueryPublish(slot);
412422
const isSelected = useMemo(() => slot === selectedSlot, [slot, selectedSlot]);
413-
414423
const isSkipped = useMemo(
415424
() => queryPublish.publish?.skipped,
416425
[queryPublish.publish?.skipped],
@@ -420,29 +429,19 @@ function SlotStatus({
420429
<Link
421430
to="/slotDetails"
422431
search={{ slot: searchSlot }}
423-
className={styles.link}
432+
className={clsx(styles.slotStatus, {
433+
[styles.selectedSlot]: isSelected,
434+
[styles.skippedSlot]: isSkipped,
435+
})}
424436
disabled={disabled || isSelected}
425437
>
426-
<Flex
427-
align="center"
428-
justify="center"
429-
className={clsx(
430-
styles.slotStatus,
431-
isSelected && styles.selectedSlot,
432-
isSkipped && styles.skippedSlot,
433-
)}
434-
>
435-
{slot !== undefined && (
436-
<Text style={disabled ? { cursor: "default" } : undefined}>
437-
{slot}
438-
</Text>
439-
)}
440-
{queryPublish.publish?.skipped ? (
438+
<Text className={styles.slotStatusText}>{slot}</Text>
439+
{includeIcon &&
440+
(isSkipped ? (
441441
<SkippedIcon size="large" />
442442
) : (
443443
<StatusIcon isCurrent={false} slot={slot} size="large" />
444-
)}
445-
</Flex>
444+
))}
446445
</Link>
447446
);
448447
}

src/features/SlotDetails/slotDetails.module.css

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,29 +46,35 @@
4646
}
4747

4848
.slot-navigation {
49-
padding: 3px;
50-
align-items: center;
51-
gap: 3px;
49+
flex: 4;
50+
padding: 2px;
5251
border-radius: 5px;
5352
border: 1px solid var(--slot-details-my-slots-color);
5453
border-top-width: 3px;
54+
min-width: 0;
5555

56-
& .link {
56+
.slot-status {
5757
text-decoration: none;
58+
display: flex;
5859
flex: 1;
59-
}
60-
61-
& .slot-status {
62-
padding: 3px 10px;
6360
justify-content: center;
6461
align-items: center;
62+
padding: 3px 10px;
6563
gap: 10px;
66-
flex: 1 0 0;
6764
font-size: 12px;
6865
font-weight: 400;
6966
border-radius: 3px;
7067
background: var(--slot-details-background-color);
7168
color: var(--slot-details-color);
69+
min-width: 0;
70+
71+
.slot-status-text {
72+
text-overflow: ellipsis;
73+
white-space: nowrap;
74+
overflow: hidden;
75+
direction: rtl;
76+
cursor: default;
77+
}
7278

7379
&.selected-slot {
7480
font-weight: 600;
@@ -87,30 +93,23 @@
8793

8894
&.previous-navigation,
8995
&.next-navigation {
90-
width: 125px;
96+
flex: 1;
9197

9298
&.disabled {
9399
border: 1px solid var(--slot-details-disabled-slot-border-color);
94100
}
95101

96-
& a {
97-
height: 100%;
98-
}
99-
100-
& .slot-status {
101-
height: 100%;
102+
.slot-status {
102103
font-size: 14px;
103104
font-weight: 600;
104105
}
105106
}
106107

107108
&.previous-navigation {
108-
justify-content: end;
109109
mask-image: linear-gradient(to right, transparent 0%, black 100%);
110110
}
111111

112112
&.next-navigation {
113-
justify-content: start;
114113
mask-image: linear-gradient(to left, transparent 0%, black 100%);
115114
}
116115
}

0 commit comments

Comments
 (0)