Browse Source

Add Grid Element

Francesco Baccetti 4 years ago
parent
commit
8e54abbae6

+ 1 - 0
packages/app/package.json

@@ -72,6 +72,7 @@
     "redux": "^4.0.5",
     "storybook-addon-jsx": "^7.1.15",
     "use-resize-observer": "^6.1.0",
+    "uuid": "^8.3.0",
     "video.js": "^7.8.3"
   },
   "browserslist": {

+ 2 - 8
packages/app/src/components/VideoGrid.tsx

@@ -5,13 +5,7 @@ import { navigate } from '@reach/router'
 import routes from '@/config/routes'
 import { spacing } from '@/shared/theme'
 import { VideoFields } from '@/api/queries/__generated__/VideoFields'
-import { VideoPreview } from '@/shared/components'
-
-const Grid = styled.div`
-  display: grid;
-  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
-  grid-gap: ${spacing.xl};
-`
+import { VideoPreview, Grid } from '@/shared/components'
 
 const StyledVideoPreview = styled(VideoPreview)`
   margin: 0 auto;
@@ -22,7 +16,7 @@ type VideoGridProps = {
 }
 const VideoGrid: React.FC<VideoGridProps> = ({ videos }) => {
   return (
-    <Grid>
+    <Grid gap={spacing.xl} onResize={(siz) => console.log(siz)}>
       {videos.map((v, idx) => (
         <StyledVideoPreview
           key={idx}

+ 34 - 0
packages/app/src/shared/components/Grid/Grid.tsx

@@ -0,0 +1,34 @@
+import React from 'react'
+import styled from '@emotion/styled'
+import useResizeObserver from 'use-resize-observer'
+
+const Container = styled.div<GridProps>`
+  display: grid;
+  gap: ${(props) => props.gap};
+  grid-template-columns: repeat(${(props) => `auto-${props.repeat}`}, minmax(min(270px, 100%), 1fr));
+`
+
+type GridProps = {
+  gap?: number | string
+  repeat?: 'fit' | 'fill'
+  className?: string
+  onResize?: (sizes: number[]) => void
+}
+const Grid: React.FC<GridProps> = ({ children, className, repeat = 'fit', onResize, ...props }) => {
+  const { ref: gridRef } = useResizeObserver<HTMLDivElement>({
+    onResize: () => {
+      if (onResize && gridRef.current) {
+        const computedStyles = window.getComputedStyle(gridRef.current)
+        const columnSizes = computedStyles.gridTemplateColumns.split(' ').map(parseFloat)
+        onResize(columnSizes)
+      }
+    },
+  })
+
+  return (
+    <Container {...props} repeat={repeat} className={className} ref={gridRef}>
+      {children}
+    </Container>
+  )
+}
+export default Grid

+ 2 - 0
packages/app/src/shared/components/Grid/index.ts

@@ -0,0 +1,2 @@
+import Grid from './Grid'
+export default Grid

+ 5 - 10
packages/app/src/shared/components/InfiniteVideoGrid/InfiniteVideoGrid.tsx

@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'
 import styled from '@emotion/styled'
 import { VideoFields } from '@/api/queries/__generated__/VideoFields'
 import { spacing, typography } from '../../theme'
-import { VideoPreview, VideoPreviewBase } from '..'
+import { VideoPreview, VideoPreviewBase, Grid } from '..'
 import sizes from '@/shared/theme/sizes'
 import { debounce } from 'lodash'
 
@@ -26,8 +26,7 @@ const InfiniteVideoGrid: React.FC<InfiniteVideoGridProps> = ({
   initialLoading,
   className,
 }) => {
-  // TODO: base this on the container width and some responsive items/row
-  const videosPerRow = VIDEOS_PER_ROW
+  const [videosPerRow, setVideosPerRow] = useState(VIDEOS_PER_ROW)
 
   const loadedVideosCount = videos?.length || 0
   const videoRowsCount = Math.floor(loadedVideosCount / videosPerRow)
@@ -91,7 +90,9 @@ const InfiniteVideoGrid: React.FC<InfiniteVideoGridProps> = ({
   return (
     <section className={className}>
       {title && <Title>{title}</Title>}
-      <Grid videosPerRow={videosPerRow}>{gridContent}</Grid>
+      <Grid gap={spacing.xl} onResize={(sizes) => setVideosPerRow(sizes.length)}>
+        {gridContent}
+      </Grid>
     </section>
   )
 }
@@ -111,10 +112,4 @@ const StyledVideoPreviewBase = styled(VideoPreviewBase)`
   width: 100%;
 `
 
-const Grid = styled.div<{ videosPerRow: number }>`
-  display: grid;
-  grid-template-columns: repeat(${({ videosPerRow }) => videosPerRow}, 1fr);
-  grid-gap: ${spacing.xl};
-`
-
 export default InfiniteVideoGrid

+ 1 - 0
packages/app/src/shared/components/index.ts

@@ -28,3 +28,4 @@ export { default as Icon } from './Icon'
 export { default as Searchbar } from './Searchbar'
 export { default as TabsMenu } from './TabsMenu'
 export { default as CategoryPicker } from './CategoryPicker'
+export { default as Grid } from './Grid'

+ 5 - 0
yarn.lock

@@ -19627,6 +19627,11 @@ uuid@^7.0.3:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
   integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
 
+uuid@^8.3.0:
+  version "8.3.0"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
+  integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
+
 v8-compile-cache@^2.0.3:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"