瀏覽代碼

Add Official Joystream updates section to home page (#1018)

* Add Official Joystream updates section to home page

* Change Watch all to See all, use Button component instead of router's Link
Rafał Pawłow 3 年之前
父節點
當前提交
484f4a9198

+ 3 - 0
.env

@@ -8,6 +8,7 @@ REACT_APP_DEVELOPMENT_QUERY_NODE_SUBSCRIPTION_URL=wss://sumer-dev-2.joystream.ap
 REACT_APP_DEVELOPMENT_ORION_URL=https://sumer-dev-2.joystream.app/orion/graphql
 REACT_APP_DEVELOPMENT_NODE_URL=wss://sumer-dev-2.joystream.app/rpc
 REACT_APP_DEVELOPMENT_FAUCET_URL=https://sumer-dev-2.joystream.app/members/register
+REACT_APP_DEVELOPMENT_OFFICIAL_JOYSTREAM_CHANNEL=12
 
 REACT_APP_PRODUCTION_QUERY_NODE_URL=https://hydra.joystream.org/graphql
 REACT_APP_PRODUCTION_QUERY_NODE_SUBSCRIPTION_URL=wss://hydra.joystream.org/graphql
@@ -15,9 +16,11 @@ REACT_APP_PRODUCTION_ORION_URL=https://orion.joystream.org/graphql
 REACT_APP_PRODUCTION_ASSET_LOGS_URL=https://orion.joystream.org/logs
 REACT_APP_PRODUCTION_NODE_URL=wss://rome-rpc-endpoint.joystream.org:9944/
 REACT_APP_PRODUCTION_FAUCET_URL=https://member-faucet.joystream.org/register
+REACT_APP_PRODUCTION_OFFICIAL_JOYSTREAM_CHANNEL=3
 
 REACT_APP_MOCKING_QUERY_NODE_URL=/mocked-query-node
 REACT_APP_MOCKING_QUERY_NODE_SUBSCRIPTION_URL=ws://127.0.0.1:9955
 REACT_APP_MOCKING_ORION_URL=/mocked-orion
 REACT_APP_MOCKING_NODE_URL=ws://127.0.0.1:9944
 REACT_APP_MOCKING_FAUCET_URL=/mocked-faucet
+REACT_APP_MOCKING_OFFICIAL_JOYSTREAM_CHANNEL=1

+ 36 - 0
src/components/OfficialJoystreamUpdate.tsx

@@ -0,0 +1,36 @@
+import styled from '@emotion/styled'
+import React from 'react'
+
+import { useVideos } from '@/api/hooks'
+import { VideoOrderByInput } from '@/api/queries'
+import { VideoGallery } from '@/components'
+import { readEnv } from '@/config/envs'
+import { sizes } from '@/shared/theme'
+
+const channelId = readEnv('OFFICIAL_JOYSTREAM_CHANNEL')
+const MAX_VIDEOS = 10
+
+export const OfficialJoystreamUpdate = () => {
+  const { videos, loading } = useVideos({
+    where: {
+      channelId_eq: channelId,
+    },
+    orderBy: VideoOrderByInput.CreatedAtDesc,
+    limit: MAX_VIDEOS,
+  })
+
+  return (
+    <Wrapper>
+      <VideoGallery
+        title="Official Joystream updates"
+        videos={videos || []}
+        seeAllUrl={`/channel/${channelId}`}
+        loading={loading}
+      />
+    </Wrapper>
+  )
+}
+
+const Wrapper = styled.div`
+  margin-top: ${sizes(18)};
+`

+ 3 - 0
src/components/VideoGallery.tsx

@@ -27,6 +27,7 @@ type VideoGalleryProps = {
   onRemoveButtonClick?: (id: string) => void
   onVideoNotFound?: (id: string) => void
   onVideoClick?: (id: string) => void
+  seeAllUrl?: string
 }
 
 const PLACEHOLDERS_COUNT = 12
@@ -55,6 +56,7 @@ export const VideoGallery: React.FC<VideoGalleryProps> = ({
   removeButton,
   onRemoveButtonClick,
   onVideoNotFound,
+  seeAllUrl,
 }) => {
   if (!loading && videos?.length === 0) {
     return null
@@ -74,6 +76,7 @@ export const VideoGallery: React.FC<VideoGalleryProps> = ({
       responsive={breakpoints}
       itemWidth={MIN_VIDEO_PREVIEW_WIDTH}
       dotsVisible
+      seeAllUrl={seeAllUrl}
     >
       {[...videos, ...placeholderItems]?.map((video, idx) => (
         <StyledVideoTile

+ 1 - 0
src/components/index.ts

@@ -23,3 +23,4 @@ export * from './NoConnectionIndicator'
 export * from './SignInSteps'
 export * from './StudioEntrypoint'
 export * from './PrivateRoute'
+export * from './OfficialJoystreamUpdate'

+ 1 - 1
src/shared/components/Carousel/Carousel.style.ts

@@ -18,8 +18,8 @@ type HasPadding = {
 export const Arrow = styled(IconButton)`
   z-index: ${zIndex.nearOverlay};
   cursor: pointer;
+  padding: ${sizes(2)};
   font-size: ${typography.sizes.subtitle2};
-  padding: 0;
 
   &.disabled {
     opacity: 0.5;

+ 11 - 0
src/shared/components/Gallery/Gallery.style.ts

@@ -1,5 +1,7 @@
 import styled from '@emotion/styled'
 
+import { Button } from '@/shared/components'
+
 import { sizes } from '../../theme'
 
 export const Container = styled.section`
@@ -13,3 +15,12 @@ export const CarouselArrowsContainer = styled.div`
   grid-column-gap: ${sizes(4)};
   margin-left: auto;
 `
+
+export const TitleWrapper = styled.div`
+  align-items: baseline;
+  display: flex;
+`
+
+export const SeeAllLink = styled(Button)`
+  margin-left: ${sizes(8)};
+`

+ 21 - 4
src/shared/components/Gallery/Gallery.tsx

@@ -2,9 +2,9 @@ import React, { ComponentProps, useRef } from 'react'
 
 import { GridHeadingContainer } from '@/shared/components'
 import { Arrow } from '@/shared/components/Carousel/Carousel.style'
-import { SvgGlyphChevronLeft, SvgGlyphChevronRight } from '@/shared/icons'
+import { SvgGlyphChevronLeft, SvgGlyphChevronRight, SvgPlayerPlay } from '@/shared/icons'
 
-import { CarouselArrowsContainer, Container } from './Gallery.style'
+import { CarouselArrowsContainer, Container, SeeAllLink, TitleWrapper } from './Gallery.style'
 
 import { Carousel, CarouselProps } from '../Carousel/Carousel'
 import { Text } from '../Text'
@@ -12,6 +12,7 @@ import { Text } from '../Text'
 export type GalleryProps = {
   title?: string
   className?: string
+  seeAllUrl?: string
 } & CarouselProps
 
 type ImperativeHandleData = {
@@ -19,7 +20,7 @@ type ImperativeHandleData = {
   getNextArrowProps: () => ComponentProps<typeof Arrow>
 }
 
-export const Gallery: React.FC<GalleryProps> = ({ title, className, ...carouselProps }) => {
+export const Gallery: React.FC<GalleryProps> = ({ title, className, seeAllUrl, ...carouselProps }) => {
   // TODO: this is the only place in the app that requires refs to buttons. Once we refactor this component, we can remove forwardRef from buttons
   const prevArrowRef = useRef<HTMLButtonElement>(null)
   const nextArrowRef = useRef<HTMLButtonElement>(null)
@@ -27,7 +28,23 @@ export const Gallery: React.FC<GalleryProps> = ({ title, className, ...carouselP
   return (
     <Container className={className}>
       <GridHeadingContainer>
-        {title && <Text variant="h4">{title}</Text>}
+        <TitleWrapper>
+          {title && <Text variant="h4">{title}</Text>}
+          {seeAllUrl && (
+            <>
+              <SeeAllLink
+                iconPlacement="left"
+                icon={<SvgPlayerPlay width={16} height={16} />}
+                textOnly
+                to={seeAllUrl}
+                size="large"
+                variant="primary"
+              >
+                See all
+              </SeeAllLink>
+            </>
+          )}
+        </TitleWrapper>
         <CarouselArrowsContainer>
           <Arrow {...carouselRef.current?.getPrevArrowProps()} ref={prevArrowRef} size="large" variant="secondary">
             <SvgGlyphChevronLeft />

+ 2 - 0
src/views/viewer/HomeView.tsx

@@ -8,6 +8,7 @@ import {
   InterruptedVideosGallery,
   LimitedWidthContainer,
   VideoHero,
+  OfficialJoystreamUpdate,
   ViewErrorFallback,
 } from '@/components'
 import { usePersonalDataStore } from '@/providers'
@@ -53,6 +54,7 @@ export const HomeView: React.FC = () => {
           createdAtGte={shouldShowFollowedChannels ? MIN_DATE_FOLLOWED_CHANNELS_VIDEOS : null}
           ready={!loading}
         />
+        <OfficialJoystreamUpdate />
       </Container>
     </LimitedWidthContainer>
   )