Browse Source

Wrap all video content pages into single template (#1248)

* Wrap all video content pages into single template

* lint fix

* fix header styles

* PR FIX

* PR FIX 2
Rafał Pawłow 3 years ago
parent
commit
884b1a60c3

+ 89 - 0
src/components/templates/VideoContentTemplate.tsx

@@ -0,0 +1,89 @@
+import styled from '@emotion/styled'
+import React from 'react'
+
+import { LimitedWidthContainer } from '@/components/LimitedWidthContainer'
+import { absoluteRoutes } from '@/config/routes'
+import {
+  CallToActionButton,
+  CallToActionButtonProps,
+  CallToActionWrapper,
+} from '@/shared/components/CallToActionButton'
+import { Text } from '@/shared/components/Text'
+import { SvgNavChannels, SvgNavHome, SvgNavNew, SvgNavPopular } from '@/shared/icons'
+import { media, sizes, typography } from '@/shared/theme'
+
+type CtaData = 'home' | 'new' | 'channels' | 'popular'
+
+type VideoContentTemplateProps = {
+  title?: string
+  cta?: CtaData[]
+}
+
+const CTA_MAP: Record<string, CallToActionButtonProps> = {
+  home: {
+    label: 'Home',
+    to: absoluteRoutes.viewer.index(),
+    colorVariant: 'yellow',
+    icon: <SvgNavHome />,
+  },
+  new: {
+    label: 'New & Noteworthy',
+    to: absoluteRoutes.viewer.new(),
+    colorVariant: 'green',
+    icon: <SvgNavNew />,
+  },
+  channels: {
+    label: 'Browse channels',
+    to: absoluteRoutes.viewer.channels(),
+    colorVariant: 'blue',
+    icon: <SvgNavChannels />,
+  },
+  popular: {
+    label: 'Popular on Joystream',
+    to: absoluteRoutes.viewer.popular(),
+    colorVariant: 'red',
+    icon: <SvgNavPopular />,
+  },
+}
+
+export const VideoContentTemplate: React.FC<VideoContentTemplateProps> = ({ children, title, cta }) => {
+  const ctaContent =
+    cta &&
+    cta.map((item, idx) => (
+      <CallToActionButton
+        key={`cta-${idx}`}
+        label={CTA_MAP[item].label}
+        to={CTA_MAP[item].to}
+        colorVariant={CTA_MAP[item].colorVariant}
+        icon={CTA_MAP[item].icon}
+      />
+    ))
+
+  return (
+    <StyledViewWrapper big>
+      {title && <Header variant="h3">{title}</Header>}
+      {children}
+      {cta && <CallToActionWrapper>{ctaContent}</CallToActionWrapper>}
+    </StyledViewWrapper>
+  )
+}
+
+const Header = styled(Text)`
+  margin: ${sizes(16)} 0;
+  font-size: ${typography.sizes.h3};
+
+  ${media.large} {
+    font-size: ${typography.sizes.h2};
+    line-height: ${typography.lineHeights.h2};
+  }
+`
+
+const StyledViewWrapper = styled(LimitedWidthContainer)`
+  padding-bottom: ${sizes(16)};
+
+  > section {
+    :not(:first-of-type) {
+      margin-top: ${sizes(32)};
+    }
+  }
+`

+ 3 - 44
src/views/viewer/ChannelsView/ChannelsView.tsx

@@ -1,57 +1,16 @@
-import styled from '@emotion/styled'
 import React from 'react'
 import React from 'react'
 
 
 import { DiscoverChannels } from '@/components/DiscoverChannels'
 import { DiscoverChannels } from '@/components/DiscoverChannels'
 import { InfiniteChannelWithVideosGrid } from '@/components/InfiniteGrids'
 import { InfiniteChannelWithVideosGrid } from '@/components/InfiniteGrids'
 import { TopTenChannels } from '@/components/TopTenChannels'
 import { TopTenChannels } from '@/components/TopTenChannels'
-import { ViewWrapper } from '@/components/ViewWrapper'
-import { absoluteRoutes } from '@/config/routes'
-import { CallToActionButton, CallToActionWrapper } from '@/shared/components/CallToActionButton'
-import { Text } from '@/shared/components/Text'
-import { SvgNavHome, SvgNavNew, SvgNavPopular } from '@/shared/icons'
-import { sizes } from '@/shared/theme'
+import { VideoContentTemplate } from '@/components/templates/VideoContentTemplate'
 
 
 export const ChannelsView: React.FC = () => {
 export const ChannelsView: React.FC = () => {
   return (
   return (
-    <StyledViewWrapper>
-      <Header variant="h2">Browse channels</Header>
+    <VideoContentTemplate title="Browse channels" cta={['popular', 'new', 'home']}>
       <TopTenChannels />
       <TopTenChannels />
       <DiscoverChannels />
       <DiscoverChannels />
       <InfiniteChannelWithVideosGrid title="Channels in your language" languageSelector onDemand />
       <InfiniteChannelWithVideosGrid title="Channels in your language" languageSelector onDemand />
-      <CallToActionWrapper>
-        <CallToActionButton
-          label="Popular on Joystream"
-          to={absoluteRoutes.viewer.popular()}
-          colorVariant="red"
-          icon={<SvgNavPopular />}
-        />
-        <CallToActionButton
-          label="New & Noteworthy"
-          to={absoluteRoutes.viewer.new()}
-          colorVariant="green"
-          icon={<SvgNavNew />}
-        />
-        <CallToActionButton
-          label="Home"
-          to={absoluteRoutes.viewer.index()}
-          colorVariant="yellow"
-          icon={<SvgNavHome />}
-        />
-      </CallToActionWrapper>
-    </StyledViewWrapper>
+    </VideoContentTemplate>
   )
   )
 }
 }
-
-const Header = styled(Text)`
-  margin: ${sizes(16)} 0;
-`
-
-const StyledViewWrapper = styled(ViewWrapper)`
-  padding-bottom: ${sizes(16)};
-
-  > section {
-    :not(:first-of-type) {
-      margin-top: ${sizes(32)};
-    }
-  }
-`

+ 3 - 25
src/views/viewer/HomeView.tsx

@@ -5,15 +5,13 @@ import { useMostViewedVideosIds } from '@/api/hooks'
 import useVideosConnection from '@/api/hooks/videosConnection'
 import useVideosConnection from '@/api/hooks/videosConnection'
 import { DiscoverChannels } from '@/components/DiscoverChannels'
 import { DiscoverChannels } from '@/components/DiscoverChannels'
 import { InfiniteVideoGrid } from '@/components/InfiniteGrids'
 import { InfiniteVideoGrid } from '@/components/InfiniteGrids'
-import { LimitedWidthContainer } from '@/components/LimitedWidthContainer'
 import { OfficialJoystreamUpdate } from '@/components/OfficialJoystreamUpdate'
 import { OfficialJoystreamUpdate } from '@/components/OfficialJoystreamUpdate'
 import { TopTenThisWeek } from '@/components/TopTenThisWeek'
 import { TopTenThisWeek } from '@/components/TopTenThisWeek'
 import { VideoHero } from '@/components/VideoHero'
 import { VideoHero } from '@/components/VideoHero'
 import { ViewErrorFallback } from '@/components/ViewErrorFallback'
 import { ViewErrorFallback } from '@/components/ViewErrorFallback'
+import { VideoContentTemplate } from '@/components/templates/VideoContentTemplate'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
 import { usePersonalDataStore } from '@/providers/personalData'
 import { usePersonalDataStore } from '@/providers/personalData'
-import { CallToActionButton, CallToActionWrapper } from '@/shared/components/CallToActionButton'
-import { SvgNavChannels, SvgNavNew, SvgNavPopular } from '@/shared/icons'
 import { sizes, transitions } from '@/shared/theme'
 import { sizes, transitions } from '@/shared/theme'
 import { SentryLogger } from '@/utils/logs'
 import { SentryLogger } from '@/utils/logs'
 
 
@@ -48,7 +46,7 @@ export const HomeView: React.FC = () => {
   }
   }
 
 
   return (
   return (
-    <LimitedWidthContainer big>
+    <VideoContentTemplate cta={['popular', 'new', 'channels']}>
       <VideoHero />
       <VideoHero />
       <Container className={transitions.names.slide}>
       <Container className={transitions.names.slide}>
         {!followedLoading && followedChannelsVideosCount ? (
         {!followedLoading && followedChannelsVideosCount ? (
@@ -71,28 +69,8 @@ export const HomeView: React.FC = () => {
         <OfficialJoystreamUpdate />
         <OfficialJoystreamUpdate />
         <DiscoverChannels additionalLink={{ name: 'Browse channels', url: absoluteRoutes.viewer.channels() }} />
         <DiscoverChannels additionalLink={{ name: 'Browse channels', url: absoluteRoutes.viewer.channels() }} />
         <InfiniteVideoGrid title="All content" onDemand />
         <InfiniteVideoGrid title="All content" onDemand />
-        <CallToActionWrapper>
-          <CallToActionButton
-            label="Popular on Joystream"
-            to={absoluteRoutes.viewer.popular()}
-            colorVariant="red"
-            icon={<SvgNavPopular />}
-          />
-          <CallToActionButton
-            label="New & Noteworthy"
-            to={absoluteRoutes.viewer.new()}
-            colorVariant="green"
-            icon={<SvgNavNew />}
-          />
-          <CallToActionButton
-            label="Browse channels"
-            to={absoluteRoutes.viewer.channels()}
-            colorVariant="blue"
-            icon={<SvgNavChannels />}
-          />
-        </CallToActionWrapper>
       </Container>
       </Container>
-    </LimitedWidthContainer>
+    </VideoContentTemplate>
   )
   )
 }
 }
 
 

+ 3 - 39
src/views/viewer/NewView/NewView.tsx

@@ -1,48 +1,12 @@
-import styled from '@emotion/styled'
 import React from 'react'
 import React from 'react'
 
 
 import { InfiniteVideoGrid } from '@/components/InfiniteGrids'
 import { InfiniteVideoGrid } from '@/components/InfiniteGrids'
 import { PromisingNewChannels } from '@/components/PromisingNewChannels'
 import { PromisingNewChannels } from '@/components/PromisingNewChannels'
-import { ViewWrapper } from '@/components/ViewWrapper'
-import { absoluteRoutes } from '@/config/routes'
-import { CallToActionButton, CallToActionWrapper } from '@/shared/components/CallToActionButton'
-import { Text } from '@/shared/components/Text'
-import { SvgNavChannels, SvgNavHome, SvgNavPopular } from '@/shared/icons'
-import { sizes } from '@/shared/theme'
+import { VideoContentTemplate } from '@/components/templates/VideoContentTemplate'
 
 
 export const NewView: React.FC = () => (
 export const NewView: React.FC = () => (
-  <StyledViewWrapper>
-    <Header variant="h2">New & Noteworthy</Header>
+  <VideoContentTemplate title="New & Noteworthy" cta={['home', 'channels', 'popular']}>
     <InfiniteVideoGrid title="Videos worth watching" isFeatured onDemand titleLoader />
     <InfiniteVideoGrid title="Videos worth watching" isFeatured onDemand titleLoader />
     <PromisingNewChannels />
     <PromisingNewChannels />
-    <CallToActionWrapper>
-      <CallToActionButton label="Home" to={absoluteRoutes.viewer.index()} colorVariant="yellow" icon={<SvgNavHome />} />
-      <CallToActionButton
-        label="Browse channels"
-        to={absoluteRoutes.viewer.channels()}
-        colorVariant="blue"
-        icon={<SvgNavChannels />}
-      />
-      <CallToActionButton
-        label="Popular on Joystream"
-        to={absoluteRoutes.viewer.popular()}
-        colorVariant="red"
-        icon={<SvgNavPopular />}
-      />
-    </CallToActionWrapper>
-  </StyledViewWrapper>
+  </VideoContentTemplate>
 )
 )
-
-const Header = styled(Text)`
-  margin: ${sizes(16)} 0;
-`
-
-const StyledViewWrapper = styled(ViewWrapper)`
-  padding-bottom: ${sizes(16)};
-
-  > section {
-    :not(:first-of-type) {
-      margin-top: ${sizes(32)};
-    }
-  }
-`

+ 3 - 43
src/views/viewer/PopularView/PopularView.tsx

@@ -1,4 +1,3 @@
-import styled from '@emotion/styled'
 import React, { FC } from 'react'
 import React, { FC } from 'react'
 
 
 import { useMostViewedVideosAllTimeIds } from '@/api/hooks'
 import { useMostViewedVideosAllTimeIds } from '@/api/hooks'
@@ -7,12 +6,8 @@ import { useMostViewedChannelsAllTimeIds } from '@/api/hooks'
 import { InfiniteChannelWithVideosGrid, InfiniteVideoGrid } from '@/components/InfiniteGrids'
 import { InfiniteChannelWithVideosGrid, InfiniteVideoGrid } from '@/components/InfiniteGrids'
 import { VideoGallery } from '@/components/VideoGallery'
 import { VideoGallery } from '@/components/VideoGallery'
 import { ViewErrorFallback } from '@/components/ViewErrorFallback'
 import { ViewErrorFallback } from '@/components/ViewErrorFallback'
-import { ViewWrapper } from '@/components/ViewWrapper'
+import { VideoContentTemplate } from '@/components/templates/VideoContentTemplate'
 import { absoluteRoutes } from '@/config/routes'
 import { absoluteRoutes } from '@/config/routes'
-import { CallToActionButton, CallToActionWrapper } from '@/shared/components/CallToActionButton'
-import { Text } from '@/shared/components/Text'
-import { SvgNavChannels, SvgNavHome, SvgNavNew } from '@/shared/icons'
-import { sizes } from '@/shared/theme'
 import { SentryLogger } from '@/utils/logs'
 import { SentryLogger } from '@/utils/logs'
 
 
 export const PopularView: FC = () => {
 export const PopularView: FC = () => {
@@ -42,8 +37,7 @@ export const PopularView: FC = () => {
   }
   }
 
 
   return (
   return (
-    <StyledViewWrapper>
-      <Header variant="h2">Popular on Joystream</Header>
+    <VideoContentTemplate title="Popular on Joystream" cta={['new', 'home', 'channels']}>
       <VideoGallery hasRanking title="Top 10 this month" videos={videos} loading={loading} />
       <VideoGallery hasRanking title="Top 10 this month" videos={videos} loading={loading} />
       <InfiniteVideoGrid title="Popular videos" idIn={mostViewedVideosIds} ready={!mostViewedVideosLoading} onDemand />
       <InfiniteVideoGrid title="Popular videos" idIn={mostViewedVideosIds} ready={!mostViewedVideosLoading} onDemand />
       <InfiniteChannelWithVideosGrid
       <InfiniteChannelWithVideosGrid
@@ -52,40 +46,6 @@ export const PopularView: FC = () => {
         idIn={mostViewedChannelsAllTimeIds}
         idIn={mostViewedChannelsAllTimeIds}
         additionalLink={{ name: 'Browse channels', url: absoluteRoutes.viewer.channels() }}
         additionalLink={{ name: 'Browse channels', url: absoluteRoutes.viewer.channels() }}
       />
       />
-      <CallToActionWrapper>
-        <CallToActionButton
-          label="New & Noteworthy"
-          to={absoluteRoutes.viewer.new()}
-          colorVariant="green"
-          icon={<SvgNavNew />}
-        />
-        <CallToActionButton
-          label="Home"
-          to={absoluteRoutes.viewer.index()}
-          colorVariant="yellow"
-          icon={<SvgNavHome />}
-        />
-        <CallToActionButton
-          label="Browse channels"
-          to={absoluteRoutes.viewer.channels()}
-          colorVariant="blue"
-          icon={<SvgNavChannels />}
-        />
-      </CallToActionWrapper>
-    </StyledViewWrapper>
+    </VideoContentTemplate>
   )
   )
 }
 }
-
-const Header = styled(Text)`
-  margin: ${sizes(17)} 0;
-`
-
-const StyledViewWrapper = styled(ViewWrapper)`
-  padding-bottom: ${sizes(16)};
-
-  > section {
-    :not(:first-of-type) {
-      margin-top: ${sizes(32)};
-    }
-  }
-`