Skip to content

Commit

Permalink
feat: virtualize songs list
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperChipsAhoy committed Sep 21, 2024
1 parent 0753145 commit 01ff20e
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 24 deletions.
117 changes: 93 additions & 24 deletions components/SongList.component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {

import {
useEffect,
useState
useMemo,
useRef,
useState,
useLayoutEffect,
useCallback
} from "react";

import {
Expand All @@ -25,8 +29,16 @@ import { motion } from "framer-motion";

import Image from "next/legacy/image";

import styled, { css } from "styled-components";

import { is_favorite_song, toggle_favorite_song } from "../config/controllers";

const PaddingDiv = styled.div.attrs(props => ({
style: {
height: `${props.paddingHeight}px`,
},
}))``;

export const bili2_icon = () => {
return (
<svg
Expand All @@ -38,7 +50,7 @@ export const bili2_icon = () => {
xmlns="http://www.w3.org/2000/svg"
>
<title>Bilibili icon</title>
<path d="M17.813 4.653h.854c1.51.054 2.769.578 3.773 1.574 1.004.995 1.524 2.249 1.56 3.76v7.36c-.036 1.51-.556 2.769-1.56 3.773s-2.262 1.524-3.773 1.56H5.333c-1.51-.036-2.769-.556-3.773-1.56S.036 18.858 0 17.347v-7.36c.036-1.511.556-2.765 1.56-3.76 1.004-.996 2.262-1.52 3.773-1.574h.774l-1.174-1.12a1.234 1.234 0 0 1-.373-.906c0-.356.124-.658.373-.907l.027-.027c.267-.249.573-.373.92-.373.347 0 .653.124.92.373L9.653 4.44c.071.071.134.142.187.213h4.267a.836.836 0 0 1 .16-.213l2.853-2.747c.267-.249.573-.373.92-.373.347 0 .662.151.929.4.267.249.391.551.391.907 0 .355-.124.657-.373.906zM5.333 7.24c-.746.018-1.373.276-1.88.773-.506.498-.769 1.13-.786 1.894v7.52c.017.764.28 1.395.786 1.893.507.498 1.134.756 1.88.773h13.334c.746-.017 1.373-.275 1.88-.773.506-.498.769-1.129.786-1.893v-7.52c-.017-.765-.28-1.396-.786-1.894-.507-.497-1.134-.755-1.88-.773zM8 11.107c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c0-.373.129-.689.386-.947.258-.257.574-.386.947-.386zm8 0c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c.017-.391.15-.711.4-.96.249-.249.56-.373.933-.373Z" />
<path d="M17.813 4.653h.854c1.51.054 2.769.578 3.773 1.574 1.004.995 1.524 2.249 1.56 3.76v7.36c-.036 1.51-.556 2.769-1.56 3.773s-2.262 1.524-3.773 1.56H5.333c-1.51-.036-2.769-.556-3.773-1.56S.036 18.858 0 17.347v-7.36c.036-1.511.556-2.765 1.56-3.76 1.004-.996 2.262-1.52 3.773-1.574h.774l-1.174-1.12a1.234 1.234 0 0 1-.373-.906c0-.356.124-.658.373-.907l.027-.027c.267-.249.573-.373.92-.373.347 0 .653.124.92.373L9.653 4.44c.071.071.134.142.187.213h4.267a.836.836 0 0 1 .16-.213l2.853-2.747c.267-.249.573-.373.92-.373.347 0 .662.151.929.4.267.249.391.551.391.907 0 .355-.124.657-.373.906zM5.333 7.24c-.746.018-1.373.276-1.88.773-.506.496-.769 1.13-.786 1.894v7.52c.017.764.28 1.395.786 1.893.507.496 1.134.756 1.88.773h13.334c.746-.017 1.373-.275 1.88-.773.506-.496.769-1.129.786-1.893v-7.52c-.017-.765-.28-1.396-.786-1.894-.507-.497-1.134-.755-1.88-.773zM8 11.107c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c0-.373.129-.689.386-.947.258-.257.574-.386.947-.386zm8 0c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c.017-.391.15-.711.4-.96.249-.249.56-.373.933-.373Z" />
</svg>
);
};
Expand Down Expand Up @@ -226,7 +238,7 @@ const CompactButtonList = ({ props: [song_info, song_idx, BVID, EffThis,] }) =>


export default function SongList
({ props: [List, EffThis,] }) {
({ props: [inputList, EffThis,] }) {
const song_table_default = () => (
<table>
<tbody>
Expand All @@ -237,6 +249,54 @@ export default function SongList
</table>
)

const [rowHeight, setRowHeight] = useState(60);
const [tableOffset, setTableOffset] = useState(0);
const [paddingBottom, setPaddingBottom] = useState(inputList.length * 80);
const [paddingTop, setPaddingTop] = useState(0);
const [visibleStart, setVisibleStart] = useState(0);
const [visibleLength, setVisibleLength] = useState(100);

const rowRef = useRef(null);
const tableRef = useRef(null);

const visibleData = useMemo(() => {
return inputList.slice(visibleStart, visibleStart + visibleLength);
}, [inputList, visibleLength, visibleStart]);

useEffect(() => {
if (rowRef.current) {
setRowHeight(rowRef.current.clientHeight);
}
if (tableRef.current) {
setTableOffset(tableRef.current.offsetTop);
}
}, []);

let scrollCallback = useCallback(() => {
if (tableRef.current) {
let offset = window.scrollY - tableOffset;
if (offset < 0) {
offset = 0;
}
const startIndex = Math.floor(offset / rowHeight);
setVisibleStart(startIndex);
const visibleLength = Math.ceil(window.innerHeight / rowHeight) + 1;
setVisibleLength(visibleLength);
setPaddingTop(startIndex * rowHeight);
setPaddingBottom(
(inputList.length - startIndex - visibleLength) * rowHeight
);
}
}, [inputList, rowHeight, tableOffset]);

useEffect(() => {
scrollCallback();
window.addEventListener("scroll", scrollCallback);
return () => {
window.removeEventListener("scroll", scrollCallback);
};
}, [scrollCallback]);

const song_table_normal = () => {
const song_table_row = (song_info, song_idx) => {
let out = {};
Expand Down Expand Up @@ -297,7 +357,9 @@ export default function SongList
rounded-lg
sm:hover:backdrop-blur-3xl
sm:hover:backdrop-brightness-125
transition-all duration-300`} key={song_info.index}>
transition-all duration-300`} key={song_info.index}
ref={rowRef}
>
<td className="song_table__name
group/tablename break-all
text-base sm:hover:cursor-main-cursor"
Expand Down Expand Up @@ -378,26 +440,33 @@ export default function SongList
}

return (
<table className="song_table w-[100%] min-w-fit
border-separate
border-spacing-y-3
sm:hover:cursor-main-cursor
[&_tr]:pt-1
[&_tr]:pr-0
[&_tr]:pb-0
[&_tr]:pl-2
[&_tr>td:hover]:bg-opacity-0
[&_tr>td]:sm:table-cell
[&_tr>td]:sm:text-left
[&_tr>td:hover]:sm:relative
[&_tr>td:hover]:sm:overflow-hidden
[&_tr>td:hover]:sm:text-label">
<tbody className="song_table__tbody overflow-hidden">
{List.map((x, idx) => song_table_row(x, idx))}
</tbody>
</table>
)
<div className="">
<table
className="song_table w-[100%] min-w-fit
border-separate
border-spacing-y-3
sm:hover:cursor-main-cursor
[&_tr]:pt-1
[&_tr]:pr-0
[&_tr]:pb-0
[&_tr]:pl-2
[&_tr>td:hover]:bg-opacity-0
[&_tr>td]:sm:table-cell
[&_tr>td]:sm:text-left
[&_tr>td:hover]:sm:relative
[&_tr>td:hover]:sm:overflow-hidden
[&_tr>td:hover]:sm:text-label"
ref={tableRef}
>
<tbody className="song_table__tbody overflow-hidden">
<tr style={{ width: `100%`, height: `${paddingTop}px` }}></tr>
{visibleData.map((x) => song_table_row(x, x.idx))}
<tr style={{ width: `100%`, height: `${paddingBottom}px` }}></tr>
</tbody>
</table>
</div>
);
}

return 0 < List.length ? song_table_normal() : song_table_default()
return 0 < inputList.length ? song_table_normal() : song_table_default()
}
4 changes: 4 additions & 0 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ const FilteredList = memo(function FilteredList({ props: [ filter_state, searchB
} else {
return 0;
}
})
.map((song, idx) => {
song.idx = idx;
return song;
});

EffThis.set_current_album(filteredSongList);
Expand Down

0 comments on commit 01ff20e

Please sign in to comment.