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 | 19x 19x 19x 19x | import {
Dispatch,
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>(null);
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}>
<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,1fr)"
: "[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,1fr)"
: "[index] 55px [first] 14fr [popularity] 1fr [last] minmax(60px,2fr)"};
}
}
`}</style>
</div>
);
}
|