mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
plain item grid
This commit is contained in:
@@ -0,0 +1,92 @@
|
|||||||
|
.item-grid-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding-right: var(--theme-spacing-md);
|
||||||
|
container-name: grid-list;
|
||||||
|
container-type: inline-size;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-list-component {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
grid-auto-flow: row dense;
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-xs) {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-sm) {
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-md) {
|
||||||
|
grid-template-columns: repeat(10, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-lg) {
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-xl) {
|
||||||
|
grid-template-columns: repeat(14, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-2xl) {
|
||||||
|
grid-template-columns: repeat(16, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-3xl) {
|
||||||
|
grid-template-columns: repeat(18, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* display: flex; */
|
||||||
|
|
||||||
|
/* flex-wrap: wrap; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-component {
|
||||||
|
display: flex;
|
||||||
|
grid-column: span 2;
|
||||||
|
padding: var(--theme-spacing-sm);
|
||||||
|
|
||||||
|
/* box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex: none;
|
||||||
|
align-content: stretch;
|
||||||
|
width: 50%;
|
||||||
|
padding: var(--theme-spacing-sm);
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-xs) {
|
||||||
|
width: 33.33%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-sm) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-md) {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-lg) {
|
||||||
|
width: 14.28%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-xl) {
|
||||||
|
width: 12.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-2xl) {
|
||||||
|
width: 11.11%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: $breakpoint-3xl) {
|
||||||
|
width: 10%;
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width-content {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 10%);
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import clsx from 'clsx';
|
||||||
|
import { useOverlayScrollbars } from 'overlayscrollbars-react';
|
||||||
|
import {
|
||||||
|
CSSProperties,
|
||||||
|
forwardRef,
|
||||||
|
memo,
|
||||||
|
ReactNode,
|
||||||
|
Ref,
|
||||||
|
RefObject,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import { GridComponents, VirtuosoGrid, VirtuosoGridHandle } from 'react-virtuoso';
|
||||||
|
|
||||||
|
import styles from './item-grid.module.css';
|
||||||
|
|
||||||
|
import { ItemCard } from '/@/renderer/components/item-card/item-card';
|
||||||
|
|
||||||
|
const gridComponents: GridComponents<any> = {
|
||||||
|
Item: forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
{
|
||||||
|
children?: ReactNode;
|
||||||
|
className?: string;
|
||||||
|
context?: Record<string, unknown>;
|
||||||
|
'data-index': number;
|
||||||
|
enableExpanded?: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
|
virtuosoRef?: RefObject<VirtuosoGridHandle>;
|
||||||
|
}
|
||||||
|
>((props, ref) => {
|
||||||
|
const { children, 'data-index': index, enableExpanded, virtuosoRef } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(styles.gridItemComponent)} ref={ref}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
List: forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
{ children?: ReactNode; className?: string; style?: CSSProperties }
|
||||||
|
>((props, ref) => {
|
||||||
|
const { children, className, style, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.gridListComponent, className)}
|
||||||
|
ref={ref}
|
||||||
|
style={{ ...style }}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ItemGridProps<TData> {
|
||||||
|
data: TData[];
|
||||||
|
ref: Ref<VirtuosoGridHandle>;
|
||||||
|
totalItemCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ItemGrid = <TData,>({ data, ref, totalItemCount }: ItemGridProps<TData>) => {
|
||||||
|
const rootRef = useRef(null);
|
||||||
|
|
||||||
|
const [scroller, setScroller] = useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const [initialize, osInstance] = useOverlayScrollbars({
|
||||||
|
defer: true,
|
||||||
|
options: {
|
||||||
|
overflow: { x: 'hidden', y: 'scroll' },
|
||||||
|
paddingAbsolute: true,
|
||||||
|
scrollbars: {
|
||||||
|
autoHide: 'leave',
|
||||||
|
autoHideDelay: 500,
|
||||||
|
pointers: ['mouse', 'pen', 'touch'],
|
||||||
|
theme: 'feishin-os-scrollbar',
|
||||||
|
visibility: 'visible',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { current: root } = rootRef;
|
||||||
|
|
||||||
|
if (scroller && root) {
|
||||||
|
initialize({
|
||||||
|
elements: { viewport: scroller },
|
||||||
|
target: root,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => osInstance()?.destroy();
|
||||||
|
}, [scroller, initialize, osInstance]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={styles.itemGridContainer}
|
||||||
|
data-overlayscrollbars-initialize=""
|
||||||
|
ref={rootRef}
|
||||||
|
>
|
||||||
|
<VirtuosoGrid
|
||||||
|
components={gridComponents}
|
||||||
|
increaseViewportBy={200}
|
||||||
|
itemContent={itemContent}
|
||||||
|
ref={ref}
|
||||||
|
scrollerRef={setScroller}
|
||||||
|
totalCount={totalItemCount || data.length}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemContent = (index: number, item: any) => {
|
||||||
|
return <InnerItem index={index} item={item} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InnerItem = memo(({ index, item }: { index: number; item: any }) => {
|
||||||
|
return <ItemCard data={item} withControls />;
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user