From 5c01f03df4d73afa156530aaaac76aac25fb45f7 Mon Sep 17 00:00:00 2001 From: "unique.mo" Date: Sun, 3 May 2020 21:16:20 +0800 Subject: [PATCH] feat: add Recommendation, Banner logic --- src/apis/personalized.ts | 18 ++++- src/apis/types/personalized.ts | 10 +++ src/hooks/useInterval.ts | 20 +++++ .../Banner/BannerItem/index.tsx | 23 ++++++ .../Banner/BannerItem/style.module.css | 36 +++++++++ .../Discovery/Recommendation/Banner/index.tsx | 77 +++++++++++++++++++ .../Recommendation/Banner/style.module.css | 53 +++++++++++++ .../Discovery/Recommendation/Slider/index.tsx | 9 --- src/pages/Discovery/Recommendation/index.tsx | 6 +- 9 files changed, 237 insertions(+), 15 deletions(-) create mode 100644 src/hooks/useInterval.ts create mode 100644 src/pages/Discovery/Recommendation/Banner/BannerItem/index.tsx create mode 100644 src/pages/Discovery/Recommendation/Banner/BannerItem/style.module.css create mode 100644 src/pages/Discovery/Recommendation/Banner/index.tsx create mode 100644 src/pages/Discovery/Recommendation/Banner/style.module.css delete mode 100644 src/pages/Discovery/Recommendation/Slider/index.tsx diff --git a/src/apis/personalized.ts b/src/apis/personalized.ts index 0dd3eee..754dcaf 100644 --- a/src/apis/personalized.ts +++ b/src/apis/personalized.ts @@ -1,9 +1,10 @@ import axios from 'helpers/axios' -import { IGetPersonalizedSongListRequest, ISongList, IMusic, IMV } from './types/personalized' +import { IGetPersonalizedSongListRequest, ISongList, IMusic, IMV, IBanner } from './types/personalized' type GetPersonalizedSongListFn = (params: IGetPersonalizedSongListRequest) => Promise type GetPersonalizedNewMusicFn = () => Promise type GetPersonalizedMVFn = () => Promise +type GetBannerFn = () => Promise const getPersonalizedSongList: GetPersonalizedSongListFn = async ({ limit }) => { const response = await axios({ @@ -35,8 +36,21 @@ const getPersonalizedMV: GetPersonalizedMVFn = async () => { return response.result } +const getBanner: GetBannerFn = async () => { + const response = await axios({ + method: 'get', + url: '/banner', + params: { + type: 0 + } + }) + + return response.banners +} + export default { getPersonalizedSongList, getPersonalizedNewMusic, - getPersonalizedMV + getPersonalizedMV, + getBanner } diff --git a/src/apis/types/personalized.ts b/src/apis/types/personalized.ts index 2e5d8d0..9bd6746 100644 --- a/src/apis/types/personalized.ts +++ b/src/apis/types/personalized.ts @@ -53,3 +53,13 @@ export interface IMV { subed: boolean, type: number } + +export interface IBanner { + exclusive: boolean, + imageUrl: string, + targetId: number, + targetType: number, + titleColor: string, + typeTitle: string, + url: string +} diff --git a/src/hooks/useInterval.ts b/src/hooks/useInterval.ts new file mode 100644 index 0000000..15d3c99 --- /dev/null +++ b/src/hooks/useInterval.ts @@ -0,0 +1,20 @@ +import { useEffect, useRef } from 'react' + +const useInterval = (callback: Function, delay?: number | null) => { + const savedCallback = useRef(() => {}) + + useEffect(() => { + savedCallback.current = callback + }) + + useEffect(() => { + if (delay !== null) { + const interval = setInterval(() => savedCallback.current(), delay || 0) + return () => clearInterval(interval) + } + + return undefined + }, [delay]) +} + +export default useInterval diff --git a/src/pages/Discovery/Recommendation/Banner/BannerItem/index.tsx b/src/pages/Discovery/Recommendation/Banner/BannerItem/index.tsx new file mode 100644 index 0000000..bd3bf2a --- /dev/null +++ b/src/pages/Discovery/Recommendation/Banner/BannerItem/index.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import cn from 'classnames' + +import styles from './style.module.css' + +interface IProps { + typeTitle: string, + imageUrl: string, + className?: string +} + +const BannerItem: React.FC = ({ typeTitle, imageUrl, className }) => { + return ( +
+ +
+ {typeTitle} +
+
+ ) +} + +export default BannerItem diff --git a/src/pages/Discovery/Recommendation/Banner/BannerItem/style.module.css b/src/pages/Discovery/Recommendation/Banner/BannerItem/style.module.css new file mode 100644 index 0000000..4829cdc --- /dev/null +++ b/src/pages/Discovery/Recommendation/Banner/BannerItem/style.module.css @@ -0,0 +1,36 @@ +@value colors: "~styles/colors.module.css"; +@value red from colors; + +.root { + width: 50%; + padding-top: 18.52%; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 5px; + position: absolute; + cursor: pointer; + top: 0; + left: 50%; + transform: translate(-50%, 0); + transition: transform 1s ease; + + img { + width: 100%; + height: 100%; + border-radius: 5px; + position: absolute; + top: 0; + left: 0; + } + + .type { + padding: 3px 10px; + position: absolute; + bottom: 0; + right: 0; + background-color: red; + color: #fff; + font-size: 0.9em; + border-top-left-radius: 5px; + border-bottom-right-radius: 5px; + } +} diff --git a/src/pages/Discovery/Recommendation/Banner/index.tsx b/src/pages/Discovery/Recommendation/Banner/index.tsx new file mode 100644 index 0000000..089d98c --- /dev/null +++ b/src/pages/Discovery/Recommendation/Banner/index.tsx @@ -0,0 +1,77 @@ +import React from 'react' +import { Spinner } from '@blueprintjs/core' +import cn from 'classnames' + +import BannerItem from './BannerItem' + +import useAsyncFn from 'hooks/useAsyncFn' +import useInterval from 'hooks/useInterval' +import personalizedApis from 'apis/personalized' + +import styles from './style.module.css' + +const { useEffect, useState, useMemo } = React + +const Banner = () => { + const [currentMid, setCurrentMid] = useState(0) + const [state, getBannerFn] = useAsyncFn(personalizedApis.getBanner) + const { value: banners = [], loading: isGettingBanner } = state + + useEffect(() => { + getBannerFn() + }, []) + + useInterval(() => { + if (!banners.length) { + return + } + setCurrentMid((currentMid + 1) % banners.length) + }, 3000) + + const bannersClassName = useMemo(() => { + const len = banners.length + const left = (currentMid - 1 + len) % len + const right = (currentMid + 1) % len + return { + [currentMid]: styles.middle, + [left]: styles.left, + [right]: styles.right + } + }, [currentMid, banners]) + + const handleMidChange = (index: number) => { + setCurrentMid(index) + } + + return (isGettingBanner + ? + :
+
+ {banners.map(({ imageUrl, typeTitle }, index) => { + const className = bannersClassName[index] || styles.hidden + return ( + + ) + })} +
+
+ {banners.map(({ imageUrl }, index) => { + return ( +
handleMidChange(index)} + /> + ) + })} +
+
+ ) +} + +export default Banner diff --git a/src/pages/Discovery/Recommendation/Banner/style.module.css b/src/pages/Discovery/Recommendation/Banner/style.module.css new file mode 100644 index 0000000..294fa43 --- /dev/null +++ b/src/pages/Discovery/Recommendation/Banner/style.module.css @@ -0,0 +1,53 @@ +@value colors: "~styles/colors.module.css"; +@value tipsColor, red from colors; + +.root { + position: relative; + padding-top: 22%; + margin-bottom: 20px; +} + +.banners { + width: 100%; + position: absolute; + top: 0; + left: 0; +} + +.middle { + transform: translate(-50%, 0) scale(1); + z-index: 2; +} + +.left { + transform: translate(-110%, 0) scale(0.8); +} + +.right { + transform: translate(10%, 0) scale(0.8); +} + +.hidden { + transform: translate(-50%, 0) scale(1); + visibility: hidden; +} + +.dots { + display: flex; + position: absolute; + bottom: 10px; + left: 50%; + transform: translate(-50%, 0); + + .dot { + width: 7px; + height: 7px; + margin-right: 10px; + border-radius: 50%; + background-color: tipsColor; + } + + .active { + background-color: red; + } +} diff --git a/src/pages/Discovery/Recommendation/Slider/index.tsx b/src/pages/Discovery/Recommendation/Slider/index.tsx deleted file mode 100644 index 31b94e7..0000000 --- a/src/pages/Discovery/Recommendation/Slider/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -const Slider = () => { - return ( -
slider
- ) -} - -export default Slider diff --git a/src/pages/Discovery/Recommendation/index.tsx b/src/pages/Discovery/Recommendation/index.tsx index c468fa8..c94236f 100644 --- a/src/pages/Discovery/Recommendation/index.tsx +++ b/src/pages/Discovery/Recommendation/index.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Slider from './Slider' +import Banner from './Banner' import SongList from './SongList' import LatestMusic from './LatestMusic' import MV from './MV' @@ -9,9 +9,7 @@ import styles from './style.module.css' const Recommendation = () => { return (
-
- -
+