Parcourir la source

add navbar and category picker borders (#116)

Francesco il y a 4 ans
Parent
commit
e39e03051c

+ 1 - 0
package.json

@@ -96,6 +96,7 @@
     "react-app-rewired": "^2.1.6",
     "react-docgen-typescript-loader": "^3.7.1",
     "react-dom": "^16.13.1",
+    "react-intersection-observer": "^8.31.0",
     "react-player": "^2.2.0",
     "react-scripts": "4.0.1",
     "react-spring": "^8.0.27",

+ 2 - 1
src/components/Navbar/Navbar.style.tsx

@@ -14,7 +14,7 @@ export const StyledSearchbar = styled(Searchbar)`
   transition: max-width 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
   will-change: max-width;
 `
-export const NAVBAR_HEIGHT = 80
+export const NAVBAR_HEIGHT = 81
 export const Header = styled.header<NavbarStyleProps>`
   position: sticky;
   top: 0;
@@ -25,6 +25,7 @@ export const Header = styled.header<NavbarStyleProps>`
   width: 100%;
 
   grid-template-columns: 1fr 2fr;
+  border-bottom: 1px solid ${colors.gray[800]};
 
   padding: ${sizes(2)} ${sizes(3)};
   @media screen and (min-width: ${breakpoints.small}) {

+ 17 - 0
src/shared/components/CategoryPicker/CategoryPicker.style.ts

@@ -0,0 +1,17 @@
+import styled from '@emotion/styled'
+import Placeholder from '../Placeholder'
+import ToggleButton from '../ToggleButton'
+import { sizes, colors } from '@/shared/theme'
+
+export const Container = styled.div`
+  display: flex;
+  flex-wrap: wrap;
+`
+
+export const StyledPlaceholder = styled(Placeholder)`
+  margin: 0 ${sizes(3)} ${sizes(3)} 0;
+`
+
+export const StyledToggleButton = styled(ToggleButton)`
+  margin: 0 ${sizes(3)} ${sizes(3)} 0;
+`

+ 2 - 17
src/shared/components/CategoryPicker/CategoryPicker.tsx

@@ -1,7 +1,5 @@
-import React from 'react'
-import styled from '@emotion/styled'
-import { Placeholder, ToggleButton } from '..'
-import { sizes } from '@/shared/theme'
+import React, { useState, useRef } from 'react'
+import { Container, StyledToggleButton, StyledPlaceholder } from './CategoryPicker.style'
 import { CategoryFields } from '@/api/queries/__generated__/CategoryFields'
 
 type CategoryPickerProps = {
@@ -41,17 +39,4 @@ const CategoryPicker: React.FC<CategoryPickerProps> = ({
   return <Container className={className}>{content}</Container>
 }
 
-const Container = styled.div`
-  display: flex;
-  flex-wrap: wrap;
-`
-
-const StyledPlaceholder = styled(Placeholder)`
-  margin: 0 ${sizes(3)} ${sizes(3)} 0;
-`
-
-const StyledToggleButton = styled(ToggleButton)`
-  margin: 0 ${sizes(3)} ${sizes(3)} 0;
-`
-
 export default CategoryPicker

+ 41 - 0
src/views/BrowseView/BrowseView.style.ts

@@ -0,0 +1,41 @@
+import styled from '@emotion/styled'
+import { CategoryPicker, InfiniteVideoGrid, Text } from '@/shared/components'
+
+import { ReactComponent as BackgroundPattern } from '@/assets/browse-bg-pattern.svg'
+import { colors, sizes, zIndex } from '@/shared/theme'
+import { NAVBAR_HEIGHT } from '@/components/Navbar'
+
+type IsAtTop = {
+  isAtTop: boolean
+}
+
+export const GRID_TOP_PADDING = sizes(2, true)
+export const Header = styled(Text)`
+  margin: 0 0 ${sizes(10)} 0;
+`
+export const StyledCategoryPicker = styled(CategoryPicker)<IsAtTop>`
+  z-index: ${zIndex.overlay};
+  position: sticky;
+  /*Offset Category Picker by Navbar Height */
+  top: ${NAVBAR_HEIGHT}px;
+  padding: ${sizes(5)} ${sizes(8)} ${sizes(2)};
+  margin: 0 calc(-1 * var(--global-horizontal-padding));
+  background-color: ${colors.black};
+  border-bottom: 1px solid ${(props) => (props.isAtTop ? colors.black : colors.gray[800])};
+`
+export const StyledInfiniteVideoGrid = styled(InfiniteVideoGrid)`
+  padding-top: ${GRID_TOP_PADDING}px;
+`
+
+export const Container = styled.div`
+  position: relative;
+  padding-top: ${sizes(14)};
+`
+export const IntersectionTarget = styled.div`
+  min-height: 1px;
+`
+export const StyledBackgroundPattern = styled(BackgroundPattern)`
+  position: absolute;
+  right: 0;
+  z-index: ${zIndex.background};
+`

+ 19 - 32
src/views/BrowseView.tsx → src/views/BrowseView/BrowseView.tsx

@@ -1,14 +1,22 @@
-import React, { useState, useEffect, useRef } from 'react'
-import styled from '@emotion/styled'
+import React, { useState, useRef } from 'react'
+
 import { RouteComponentProps } from '@reach/router'
 import { ErrorBoundary } from '@sentry/react'
 import { useQuery } from '@apollo/client'
+import { useInView } from 'react-intersection-observer'
 
 import { ErrorFallback } from '@/components'
-import { CategoryPicker, InfiniteVideoGrid, Text } from '@/shared/components'
+import { Text } from '@/shared/components'
 import { NAVBAR_HEIGHT } from '@/components/Navbar'
-import { ReactComponent as BackgroundPattern } from '@/assets/browse-bg-pattern.svg'
-import { colors, sizes, zIndex } from '@/shared/theme'
+import {
+  StyledCategoryPicker,
+  Container,
+  StyledInfiniteVideoGrid,
+  IntersectionTarget,
+  Header,
+  StyledBackgroundPattern,
+  GRID_TOP_PADDING,
+} from './BrowseView.style'
 import { GET_CATEGORIES } from '@/api/queries'
 import { GetCategories } from '@/api/queries/__generated__/GetCategories'
 import { CategoryFields } from '@/api/queries/__generated__/CategoryFields'
@@ -23,7 +31,11 @@ const BrowseView: React.FC<RouteComponentProps> = () => {
       },
     }
   )
+
   const headerRef = useRef<HTMLHeadingElement>(null)
+  const { ref: targetRef, inView } = useInView({
+    rootMargin: `-${NAVBAR_HEIGHT - GRID_TOP_PADDING}px 0px 0px`,
+  })
   const handleCategoryChange = (category: CategoryFields, scrollTop = true) => {
     setSelectedCategoryId(category.id)
     if (headerRef.current && scrollTop) {
@@ -42,11 +54,13 @@ const BrowseView: React.FC<RouteComponentProps> = () => {
         Browse
       </Header>
       <Text variant="h5">Topics that may interest you</Text>
+      <IntersectionTarget ref={targetRef} />
       <StyledCategoryPicker
         categories={categoriesData?.categories}
         loading={categoriesLoading}
         selectedCategoryId={selectedCategoryId}
         onChange={handleCategoryChange}
+        isAtTop={inView}
       />
       <ErrorBoundary fallback={ErrorFallback}>
         <StyledInfiniteVideoGrid categoryId={selectedCategoryId || undefined} ready={!!selectedCategoryId} />
@@ -55,31 +69,4 @@ const BrowseView: React.FC<RouteComponentProps> = () => {
   )
 }
 
-const Container = styled.div`
-  position: relative;
-  padding-top: ${sizes(14)};
-`
-
-const StyledBackgroundPattern = styled(BackgroundPattern)`
-  position: absolute;
-  right: 0;
-  z-index: ${zIndex.background};
-`
-
-const Header = styled(Text)`
-  margin: 0 0 ${sizes(10)} 0;
-`
-
-const StyledCategoryPicker = styled(CategoryPicker)`
-  z-index: ${zIndex.overlay};
-  position: sticky;
-  /*Offset Category Picker by Navbar Height */
-  top: ${NAVBAR_HEIGHT}px;
-  padding: ${sizes(5)} ${sizes(8)} ${sizes(2)};
-  margin: 0 calc(-1 * var(--global-horizontal-padding));
-  background-color: ${colors.black};
-`
-const StyledInfiniteVideoGrid = styled(InfiniteVideoGrid)`
-  padding-top: ${sizes(2)};
-`
 export default BrowseView

+ 3 - 0
src/views/BrowseView/index.ts

@@ -0,0 +1,3 @@
+import BrowseView from './BrowseView'
+
+export default BrowseView

+ 5 - 0
yarn.lock

@@ -15594,6 +15594,11 @@ react-inspector@^4.0.0:
     is-dom "^1.0.9"
     prop-types "^15.6.1"
 
+react-intersection-observer@^8.31.0:
+  version "8.31.0"
+  resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.31.0.tgz#0ed21aaf93c4c0475b22b0ccaba6169076d01605"
+  integrity sha512-XraIC/tkrD9JtrmVA7ypEN1QIpKc52mXBH1u/bz/aicRLo8QQEJQAMUTb8mz4B6dqpPwyzgjrr7Ljv/2ACDtqw==
+
 react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
   version "16.13.1"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"