mirror of https://github.com/usememos/memos
feat: implement masonry view
parent
a8713ec639
commit
d6be20b917
@ -0,0 +1,66 @@
|
|||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { Memo } from "@/types/proto/api/v1/memo_service";
|
||||||
|
import { cn } from "@/utils";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
memoList: Memo[];
|
||||||
|
renderer: (memo: Memo) => JSX.Element;
|
||||||
|
prefixElement?: JSX.Element;
|
||||||
|
listMode?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalState {
|
||||||
|
columns: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MINIMUM_MEMO_VIEWPORT_WIDTH = 512;
|
||||||
|
|
||||||
|
const MasonryView = (props: Props) => {
|
||||||
|
const [state, setState] = useState<LocalState>({
|
||||||
|
columns: 1,
|
||||||
|
});
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!containerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.listMode) {
|
||||||
|
setState({
|
||||||
|
columns: 1,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerWidth = containerRef.current.offsetWidth;
|
||||||
|
const scale = containerWidth / MINIMUM_MEMO_VIEWPORT_WIDTH;
|
||||||
|
setState({
|
||||||
|
columns: scale > 2 ? Math.floor(scale) : 1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResize();
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
return () => window.removeEventListener("resize", handleResize);
|
||||||
|
}, [props.listMode]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className={cn("w-full grid gap-2")}
|
||||||
|
style={{
|
||||||
|
gridTemplateColumns: `repeat(${state.columns}, 1fr)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Array.from({ length: state.columns }).map((_, columnIndex) => (
|
||||||
|
<div key={columnIndex} className="min-w-0 mx-auto w-full max-w-2xl">
|
||||||
|
{props.prefixElement && columnIndex === 0 && <div className="mb-2">{props.prefixElement}</div>}
|
||||||
|
{props.memoList.filter((_, index) => index % state.columns === columnIndex).map((memo) => props.renderer(memo))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MasonryView;
|
@ -0,0 +1,3 @@
|
|||||||
|
import MasonryView from "./MasonryView";
|
||||||
|
|
||||||
|
export default MasonryView;
|
Loading…
Reference in New Issue