From 7a2af3d013b0385c712a91fc0d8815eb7410502d Mon Sep 17 00:00:00 2001 From: jeffvli Date: Thu, 25 Sep 2025 00:53:46 -0700 Subject: [PATCH] plain item grid --- .../components/item-grid/item-grid.module.css | 92 +++++++++++++ .../components/item-grid/item-grid.tsx | 123 ++++++++++++++++++ 2 files changed, 215 insertions(+) create mode 100644 src/renderer/components/item-grid/item-grid.module.css create mode 100644 src/renderer/components/item-grid/item-grid.tsx diff --git a/src/renderer/components/item-grid/item-grid.module.css b/src/renderer/components/item-grid/item-grid.module.css new file mode 100644 index 000000000..80e816f11 --- /dev/null +++ b/src/renderer/components/item-grid/item-grid.module.css @@ -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%); +} diff --git a/src/renderer/components/item-grid/item-grid.tsx b/src/renderer/components/item-grid/item-grid.tsx new file mode 100644 index 000000000..c1e56ff0b --- /dev/null +++ b/src/renderer/components/item-grid/item-grid.tsx @@ -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 = { + Item: forwardRef< + HTMLDivElement, + { + children?: ReactNode; + className?: string; + context?: Record; + 'data-index': number; + enableExpanded?: boolean; + style?: CSSProperties; + virtuosoRef?: RefObject; + } + >((props, ref) => { + const { children, 'data-index': index, enableExpanded, virtuosoRef } = props; + + return ( +
+ {children} +
+ ); + }), + List: forwardRef< + HTMLDivElement, + { children?: ReactNode; className?: string; style?: CSSProperties } + >((props, ref) => { + const { children, className, style, ...rest } = props; + + return ( +
+ {children} +
+ ); + }), +}; + +interface ItemGridProps { + data: TData[]; + ref: Ref; + totalItemCount?: number; +} + +export const ItemGrid = ({ data, ref, totalItemCount }: ItemGridProps) => { + const rootRef = useRef(null); + + const [scroller, setScroller] = useState(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 ( +
+ +
+ ); +}; + +const itemContent = (index: number, item: any) => { + return ; +}; + +const InnerItem = memo(({ index, item }: { index: number; item: any }) => { + return ; +});