Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 19x 19x 19x 19x | import { Dispatch, MutableRefObject, ReactElement, SetStateAction, useEffect, useRef, useState, } from "react"; import { CardType } from "components/CardTrack"; import { Clock } from "components/icons"; import { useOnSmallScreen, useTranslations } from "hooks"; export default function TrackListHeader({ isPin, setIsPin, type: cardType, }: Readonly<{ isPin: boolean; setIsPin: Dispatch<SetStateAction<boolean>>; type: CardType; }>): ReactElement { const ref = useRef<HTMLDivElement>(); const { translations } = useTranslations(); const [type, setType] = useState<CardType>(cardType); const isSmallScreen = useOnSmallScreen((isSmall) => { setType(isSmall ? CardType.Presentation : cardType); }); useEffect(() => { const cachedRef = ref.current, observer = new IntersectionObserver( ([e]) => { if (e.intersectionRect.top >= 59) { setIsPin(true); } else { setIsPin(false); } }, { rootMargin: `0px 0px -${Math.max(0, (window.innerHeight || 0) - 60)}px 0px`, } ); observer.observe(cachedRef as Element); return function () { observer.unobserve(cachedRef as Element); }; }); return ( <div className="trackListHeader" ref={ref as MutableRefObject<HTMLDivElement>} > <span>#</span> <span>{translations.playlistHeader.title}</span> {type === "playlist" ? ( <> <span className="album">{translations.playlistHeader.album}</span> <span className="dataAdded"> {translations.playlistHeader.dateAdded} </span> </> ) : null} <span className="emptynow"></span> <span className="clock"> <Clock /> </span> <style jsx>{` .trackListHeader { border-bottom: 1px solid transparent; box-sizing: content-box; height: 36px; margin: ${isPin ? "0 -32px 8px" : "0 -16px 8px"}; padding: ${isPin ? "0 32px" : "0 16px"}; position: sticky; top: 60px; z-index: 2; display: grid; grid-gap: 16px; background-color: ${isPin ? "#181818" : "transparent"}; border-bottom: 1px solid #ffffff1a; grid-template-columns: ${type === "playlist" ? "[index] 48px [first] 14fr [var1] 8fr [var2] 3fr [popularity] 1fr [last] minmax(180px,2fr)" : type === "album" ? "[index] 48px [first] 14fr [popularity] 1fr [last] minmax(180px,2fr)" : "[index] 55px [first] 14fr [popularity] 1fr [last] minmax(180px,2fr)"}; } .trackListHeader span { display: flex; align-items: center; font-size: 0.75rem; color: #ffffffb3; font-family: sans-serif; } .trackListHeader span:nth-of-type(1) { font-size: 16px; justify-self: center; margin-left: 16px; } .trackListHeader span:nth-of-type(2) { margin-left: ${isSmallScreen ? "0" : "70px"}; } .clock { justify-content: center; } @media (max-width: 768px) { .trackListHeader { grid-template-columns: ${type === "playlist" ? "[index] 48px [first] 14fr [var1] 8fr [var2] 3fr [popularity] 1fr [last] minmax(60px,2fr)" : type === "album" ? "[index] 48px [first] 14fr [popularity] 1fr [last] minmax(60px,2fr)" : "[index] 55px [first] 14fr [popularity] 1fr [last] minmax(60px,2fr)"}; } } `}</style> </div> ); } |