Jelajahi Sumber

create cover featured video layout

Klaudiusz Dembler 4 tahun lalu
induk
melakukan
c55f884595

+ 94 - 0
src/components/FeaturedVideoHeader/FeaturedVideoHeader.style.ts

@@ -0,0 +1,94 @@
+import styled from '@emotion/styled'
+import { fluidRange } from 'polished'
+
+import { Avatar, Button } from '@/shared/components'
+import { breakpoints, colors, spacing, typography } from '@/shared/theme'
+
+export const Container = styled.section`
+  position: relative;
+  @media screen and (min-width: ${breakpoints.medium}) {
+    margin-bottom: -100px;
+  }
+  @media screen and (min-width: ${breakpoints.large}) {
+    margin-bottom: -250px;
+  }
+`
+
+export const MediaWrapper = styled.div`
+  margin: 0 calc(-1 * var(--global-horizontal-padding));
+  width: calc(100% + calc(2 * var(--global-horizontal-padding)));
+`
+
+export const BackgroundImage = styled.div`
+  width: 100%;
+  height: 0;
+  padding-top: 56.25%;
+  background-repeat: no-repeat;
+  background-position: center;
+  background-attachment: local;
+  background-size: cover;
+  background-image: linear-gradient(0deg, black 0%, rgba(0, 0, 0, 0) 20%),
+    url(https://eu-central-1.linodeobjects.com/atlas-assets/featured-video-thumbnail.jpg);
+  @media screen and (min-width: ${breakpoints.medium}) {
+    background-image: linear-gradient(0deg, black 0%, rgba(0, 0, 0, 0) 70%),
+      url(https://eu-central-1.linodeobjects.com/atlas-assets/featured-video-thumbnail.jpg);
+  }
+`
+
+export const InfoContainer = styled.div`
+  position: relative;
+  margin-top: -${spacing.xxl};
+  padding-bottom: ${spacing.xs};
+
+  @media screen and (min-width: ${breakpoints.medium}) {
+    position: absolute;
+    margin: 0;
+    padding: 0;
+    bottom: 20%;
+    max-width: 60%;
+  }
+
+  @media screen and (min-width: ${breakpoints.large}) {
+    bottom: 35%;
+    max-width: 40%;
+  }
+`
+
+export const StyledAvatar = styled(Avatar)`
+  width: 64px;
+  height: 64px;
+  margin-bottom: ${spacing.m};
+  @media screen and (min-width: ${breakpoints.medium}) {
+    width: 88px;
+    height: 88px;
+    margin-bottom: ${spacing.m};
+  }
+`
+
+export const TitleContainer = styled.div`
+  margin-bottom: ${spacing.xxl};
+  @media screen and (min-width: ${breakpoints.medium}) {
+    margin-bottom: ${spacing.xxxl};
+  }
+
+  h2 {
+    ${fluidRange({ prop: 'fontSize', fromSize: '40px', toSize: '60px' })};
+    ${fluidRange({ prop: 'lineHeight', fromSize: '48px', toSize: '68px' })};
+    font-family: ${typography.fonts.headers};
+    font-weight: 700;
+    margin: 0 0 ${spacing.s} 0;
+    @media screen and (min-width: ${breakpoints.medium}) {
+      margin-bottom: ${spacing.m};
+    }
+  }
+
+  span {
+    ${fluidRange({ prop: 'fontSize', fromSize: '14px', toSize: '28px' })};
+    ${fluidRange({ prop: 'lineHeight', fromSize: '20px', toSize: '30px' })};
+    color: ${colors.white};
+  }
+`
+
+export const PlayButton = styled(Button)`
+  width: 116px;
+`

+ 30 - 0
src/components/FeaturedVideoHeader/FeaturedVideoHeader.tsx

@@ -0,0 +1,30 @@
+import React from 'react'
+import {
+  BackgroundImage,
+  Container,
+  InfoContainer,
+  MediaWrapper,
+  PlayButton,
+  StyledAvatar,
+  TitleContainer,
+} from './FeaturedVideoHeader.style'
+
+const FeaturedVideoHeader: React.FC = () => {
+  return (
+    <Container>
+      <MediaWrapper>
+        <BackgroundImage />
+      </MediaWrapper>
+      <InfoContainer>
+        <StyledAvatar img="https://eu-central-1.linodeobjects.com/atlas-assets/feautured-video-channel-avatar.png" />
+        <TitleContainer>
+          <h2>Ghost Signals</h2>
+          <span>How We Lost Trust In Authority, And Authority Taught Us To Distrust Ourselves</span>
+        </TitleContainer>
+        <PlayButton>Play</PlayButton>
+      </InfoContainer>
+    </Container>
+  )
+}
+
+export default FeaturedVideoHeader

+ 3 - 0
src/components/FeaturedVideoHeader/index.ts

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

+ 0 - 46
src/components/Hero.tsx

@@ -1,46 +0,0 @@
-import React from 'react'
-import { fluidRange } from 'polished'
-import { css } from '@emotion/core'
-import { Button, Header } from '@/shared/components'
-
-type HeroProps = {
-  backgroundImg: string
-}
-
-const Hero: React.FC<Partial<HeroProps>> = ({ backgroundImg }) => {
-  return (
-    <Header
-      title="A user governed video platform"
-      subtitle="Lorem ipsum sit amet, consectetur adipiscing elit. Proin non nisl sollicitudin, tempor diam."
-      backgroundImg={backgroundImg}
-      containerCss={css`
-        font-size: 18px;
-        line-height: 1.33;
-        & h1 {
-          ${fluidRange({ prop: 'fontSize', fromSize: '40px', toSize: '72px' })};
-          line-height: 0.94;
-        }
-        margin: 0 calc(-1 * var(--global-horizontal-padding));
-      `}
-    >
-      <div
-        css={css`
-          display: flex;
-          margin-top: 40px;
-          & > * {
-            margin-right: 1rem;
-          }
-        `}
-      >
-        <Button
-          containerCss={css`
-            width: 116px;
-          `}
-        >
-          Play
-        </Button>
-      </div>
-    </Header>
-  )
-}
-export default Hero

+ 1 - 1
src/components/index.ts

@@ -1,6 +1,6 @@
 export { default as LayoutWithRouting } from './LayoutWithRouting'
 export { default as VideoGallery } from './VideoGallery'
-export { default as Hero } from './Hero'
+export { default as FeaturedVideoHeader } from './FeaturedVideoHeader'
 export { default as ChannelGallery } from './ChannelGallery'
 export { default as Navbar } from './Navbar'
 export { default as VideoGrid } from './VideoGrid'

+ 0 - 44
src/shared/components/Header/Header.style.ts

@@ -1,44 +0,0 @@
-import { makeStyles, StyleFn } from '../../utils'
-import { colors, spacing } from '../../theme'
-
-export type HeaderStyleProps = {
-  backgroundImg?: string
-}
-
-const container: StyleFn = (_, { backgroundImg }) => ({
-  textAlign: 'left',
-  color: colors.white,
-  lineHeight: 1.33,
-  height: 584,
-  backgroundImage: `linear-gradient(0deg, black 0%, rgba(0,0,0,0) 100%), url(${backgroundImg})`,
-  backgroundSize: 'cover',
-  backgroundPosition: 'center',
-  display: 'flex',
-  flexDirection: 'column',
-  justifyContent: 'flex-end',
-})
-
-const content: StyleFn = () => ({
-  marginLeft: spacing.xxl,
-  marginBottom: 85,
-  maxWidth: '39.25rem',
-})
-
-const title: StyleFn = () => ({
-  lineHeight: 1.05,
-  letterSpacing: '-0.01em',
-  fontWeight: 'bold',
-  margin: 0,
-})
-
-const subtitle: StyleFn = () => ({
-  maxWidth: '34rem',
-  marginTop: spacing.m,
-})
-
-export const useCSS = (props: HeaderStyleProps) => ({
-  container: makeStyles([container])(props),
-  content: makeStyles([content])(props),
-  title: makeStyles([title])(props),
-  subtitle: makeStyles([subtitle])(props),
-})

+ 0 - 24
src/shared/components/Header/Header.tsx

@@ -1,24 +0,0 @@
-import React from 'react'
-import { SerializedStyles } from '@emotion/core'
-import { useCSS, HeaderStyleProps } from './Header.style'
-
-type HeaderProps = {
-  title: string
-  subtitle: string
-  backgroundImg: string
-  containerCss: SerializedStyles
-  children: React.ReactNode
-} & HeaderStyleProps
-
-export default function Header({ title, subtitle, children, backgroundImg, containerCss }: Partial<HeaderProps>) {
-  const styles = useCSS({ backgroundImg })
-  return (
-    <section css={[styles.container, containerCss]}>
-      <div css={styles.content}>
-        <h1 css={styles.title}>{title}</h1>
-        {subtitle && <p css={styles.subtitle}>{subtitle}</p>}
-        {children}
-      </div>
-    </section>
-  )
-}

+ 0 - 2
src/shared/components/Header/index.ts

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

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

@@ -2,7 +2,6 @@ export { default as Avatar } from './Avatar'
 export { default as Button } from './Button'
 export { default as Carousel } from './Carousel'
 export { default as Dropdown } from './Dropdown'
-export { default as Header } from './Header'
 export { default as Link } from './Link'
 export { default as NavButton } from './NavButton'
 export { default as RadioButton } from './RadioButton'

+ 5 - 5
src/views/HomeView.tsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import styled from '@emotion/styled'
-import { ChannelGallery, Hero, VideoGallery } from '@/components'
+import { ChannelGallery, FeaturedVideoHeader, VideoGallery } from '@/components'
 import { RouteComponentProps } from '@reach/router'
 import { useQuery } from '@apollo/client'
 import { InfiniteVideoGrid } from '@/shared/components'
@@ -8,8 +8,7 @@ import { GET_FEATURED_VIDEOS, GET_NEWEST_CHANNELS, GET_NEWEST_VIDEOS } from '@/a
 import { GetFeaturedVideos } from '@/api/queries/__generated__/GetFeaturedVideos'
 import { GetNewestVideos, GetNewestVideosVariables } from '@/api/queries/__generated__/GetNewestVideos'
 import { GetNewestChannels, GetNewestChannelsVariables } from '@/api/queries/__generated__/GetNewestChannels'
-
-const backgroundImg = 'https://eu-central-1.linodeobjects.com/atlas-assets/hero.jpeg'
+import { spacing } from '@/shared/theme'
 
 const NEWEST_VIDEOS_COUNT = 8
 const NEWEST_CHANNELS_COUNT = 8
@@ -32,7 +31,7 @@ const HomeView: React.FC<RouteComponentProps> = () => {
 
   return (
     <>
-      <Hero backgroundImg={backgroundImg} />
+      <FeaturedVideoHeader />
       <Container>
         <VideoGallery title="Newest videos" loading={newestVideosLoading} videos={newestVideos} />
         <VideoGallery
@@ -48,7 +47,8 @@ const HomeView: React.FC<RouteComponentProps> = () => {
 }
 
 const Container = styled.div`
-  margin: 1rem 0;
+  position: relative;
+  margin: ${spacing.xxxxl} 0;
   & > * {
     margin-bottom: 3rem;
   }