From 330e233869fc3fea18f24522dc8a9e24c5aec4b8 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Thu, 7 Oct 2021 12:33:17 +0700 Subject: [PATCH] made new hero component --- .env.development | 5 +- package.json | 2 +- src/components/flow/FlowSwiperHero/index.tsx | 131 ++++++++++++++ .../flow/FlowSwiperHero/styles.module.scss | 168 ++++++++++++++++++ src/components/input/LoaderCircle/index.tsx | 9 +- .../LoaderCircleInner/styles.module.scss | 2 +- src/constants/api.ts | 2 - src/layouts/FlowLayout/index.tsx | 3 +- src/styles/_global.scss | 6 + yarn.lock | 8 +- 10 files changed, 321 insertions(+), 15 deletions(-) create mode 100644 src/components/flow/FlowSwiperHero/index.tsx create mode 100644 src/components/flow/FlowSwiperHero/styles.module.scss diff --git a/.env.development b/.env.development index 591b1148..cf60c666 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,3 @@ -REACT_APP_API_HOST: http://localhost:3334/ -REACT_APP_REMOTE_CURRENT: https://pig.staging.vault48.org/static/ +#REACT_APP_API_HOST=http://localhost:3334/ +REACT_APP_API_HOST=https://pig.staging.vault48.org/ +REACT_APP_REMOTE_CURRENT=https://pig.staging.vault48.org/static/ diff --git a/package.json b/package.json index a198a4e0..1b5a380e 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "redux-persist": "^5.10.0", "redux-saga": "^1.1.1", "sticky-sidebar": "^3.3.1", - "swiper": "^6.7.0", + "swiper": "^6.8.4", "throttle-debounce": "^2.1.0", "typescript": "^4.0.5", "typograf": "^6.11.3", diff --git a/src/components/flow/FlowSwiperHero/index.tsx b/src/components/flow/FlowSwiperHero/index.tsx new file mode 100644 index 00000000..84f7b7cb --- /dev/null +++ b/src/components/flow/FlowSwiperHero/index.tsx @@ -0,0 +1,131 @@ +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/swiper.scss'; +import 'swiper/components/effect-fade/effect-fade.scss'; +import 'swiper/components/lazy/lazy.scss'; +import styles from './styles.module.scss'; + +import SwiperCore, { EffectFade, Navigation, Lazy, Autoplay } from 'swiper'; +import { Icon } from '~/components/input/Icon'; +import { IFlowState } from '~/redux/flow/reducer'; +import { getURLFromString } from '~/utils/dom'; +import { PRESETS, URLS } from '~/constants/urls'; +import SwiperClass from 'swiper/types/swiper-class'; +import { LoaderCircle } from '~/components/input/LoaderCircle'; +import { useHistory } from 'react-router'; + +SwiperCore.use([EffectFade, Lazy, Autoplay, Navigation]); + +interface Props { + heroes: IFlowState['heroes']; +} + +export const FlowSwiperHero: FC = ({ heroes }) => { + const [controlledSwiper, setControlledSwiper] = useState(undefined); + const [currentIndex, setCurrentIndex] = useState(heroes.length); + const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []); + const history = useHistory(); + + const onNext = useCallback(() => { + controlledSwiper?.slideNext(1); + }, [controlledSwiper]); + + const onPrev = useCallback(() => { + controlledSwiper?.slidePrev(1); + }, [controlledSwiper]); + + const onIndexChange = useCallback((swiper: SwiperClass) => { + let activeIndex = swiper.activeIndex; + let slidesLen = swiper.slides.length; + + if (slidesLen === 0) { + return 0; + } + + if (swiper.params.loop) { + switch (swiper.activeIndex) { + case 0: + activeIndex = slidesLen - 3; + break; + case slidesLen - 1: + activeIndex = 0; + break; + default: + --activeIndex; + } + } + + setCurrentIndex(activeIndex); + }, []); + + const onClick = useCallback( + (sw: SwiperClass) => { + history.push(URLS.NODE_URL(heroes[sw.realIndex]?.id)); + }, + [history, heroes] + ); + + if (!heroes.length) { + return ( +
+ +
+ ); + } + + const title = heroes[currentIndex]?.title; + + return ( +
+
+
+
{title}
+ +
+ + + +
+
+
+ + + {heroes + .filter(node => node.thumbnail) + .map(node => ( + + + + ))} + +
+ ); +}; diff --git a/src/components/flow/FlowSwiperHero/styles.module.scss b/src/components/flow/FlowSwiperHero/styles.module.scss new file mode 100644 index 00000000..e72bf0da --- /dev/null +++ b/src/components/flow/FlowSwiperHero/styles.module.scss @@ -0,0 +1,168 @@ +@import '~/styles/variables'; + +.wrap { + width: 100%; + height: 100%; + position: relative; + cursor: pointer; +} + +.swiper { + @include outer_shadow; + width: 100%; + height: 100%; + border-radius: $radius; + + :global(.swiper-slide) { + object-fit: cover; + + img { + min-width: 150%; + } + } +} + +.slide { + width: 100%; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + padding: $gap; + z-index: 5; + pointer-events: none; + touch-action: none; + box-sizing: border-box; + border-radius: $radius; + + &::after { + content: ' '; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: url('../../../sprites/stripes.svg') rgba(0, 0, 0, 0.3); + z-index: -1; + pointer-events: none; + box-shadow: inset transparentize($color: white, $amount: 0.85) 0 1px; + touch-action: none; + border-radius: $radius; + } + + &::before { + content: ' '; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + 182deg, + transparentize($cell_shade, 1) 50%, + transparentize($cell_shade, 0) 95% + ); + z-index: 4; + pointer-events: none; + touch-action: none; + border-radius: $radius; + } +} + +img.preview { + transform: translate(-15%, 0); + transition: transform 7s linear, opacity 1s linear; + opacity: 0; + + :global(.swiper-slide-active) &, + :global(.swiper-slide-duplicate-active) & + { + transform: translate(-15%, -20%); + opacity: 1; + } +} + +.info { + display: flex; + position: absolute; + bottom: 0; + right: 0; + width: 100%; + padding: $gap; + box-sizing: border-box; + z-index: 5; + flex-direction: row; + align-items: flex-end; + pointer-events: none; + touch-action: none; +} + +.title { + @include clamp(2, 1.2 * 40px * 2); + flex: 1; + display: flex; + margin-right: $gap; + overflow: hidden; + font: $font_hero_title; + text-transform: uppercase; + text-overflow: ellipsis; + line-height: 1.2em; + word-break: break-word; + + @include tablet { + @include clamp(3, 1.2 * 32px); + white-space: initial; + word-wrap: break-word; + font: $font_32_bold; + max-height: 3.6em; + } + + @include phone { + white-space: initial; + word-wrap: break-word; + font: $font_24_bold; + max-height: 3.6em; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; + height: 58px; + flex-direction: row; + width: 128px; + border-radius: $radius; + pointer-events: all; + touch-action: auto; + margin: 0 -15px -10px 0; + + .button { + cursor: pointer; + flex: 0 0 58px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.5; + transition: opacity 0.5s; + + &:hover { + opacity: 1; + } + + svg { + width: 40px; + height: 40px; + } + } +} + +.loader { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: transparentize(white, 0.95); +} diff --git a/src/components/input/LoaderCircle/index.tsx b/src/components/input/LoaderCircle/index.tsx index 97b0b9c8..07952d05 100644 --- a/src/components/input/LoaderCircle/index.tsx +++ b/src/components/input/LoaderCircle/index.tsx @@ -3,14 +3,15 @@ import styles from './styles.module.scss'; import { describeArc } from '~/utils/dom'; import classNames from 'classnames'; import { LoaderCircleInner } from '~/components/input/LoaderCircleInner'; +import { SVGProps } from '~/utils/types'; -interface IProps { +interface IProps extends SVGProps { size?: number; className?: string; } -export const LoaderCircle: FC = ({ size = 24, className }) => ( -
- +export const LoaderCircle: FC = ({ size = 24, ...rest }) => ( +
+
); diff --git a/src/components/input/LoaderCircleInner/styles.module.scss b/src/components/input/LoaderCircleInner/styles.module.scss index 373c610f..6d50b1ca 100644 --- a/src/components/input/LoaderCircleInner/styles.module.scss +++ b/src/components/input/LoaderCircleInner/styles.module.scss @@ -1,5 +1,5 @@ .icon { - fill: transparentize(black, 0.6); + fill: currentColor; stroke: none; } diff --git a/src/constants/api.ts b/src/constants/api.ts index 490a76bb..7b61e9b7 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -1,8 +1,6 @@ import { IComment, INode, ITag } from '~/redux/types'; import { ISocialProvider } from '~/redux/auth/types'; -console.log('base at ', process.env.REACT_APP_API_HOST); - export const API = { BASE: process.env.REACT_APP_API_HOST, USER: { diff --git a/src/layouts/FlowLayout/index.tsx b/src/layouts/FlowLayout/index.tsx index 9d03bc87..ea2736e9 100644 --- a/src/layouts/FlowLayout/index.tsx +++ b/src/layouts/FlowLayout/index.tsx @@ -21,6 +21,7 @@ import { usePersistedState } from '~/utils/hooks/usePersistedState'; import classNames from 'classnames'; import { useFlowLayout } from '~/utils/hooks/flow/useFlowLayout'; import { useFlowPagination } from '~/utils/hooks/flow/useFlowPagination'; +import { FlowSwiperHero } from '~/components/flow/FlowSwiperHero'; const FlowLayout: FC = () => { const { nodes, heroes, recent, updated, isLoading, search } = useShallowSelect(selectFlow); @@ -59,7 +60,7 @@ const FlowLayout: FC = () => {
- +
diff --git a/src/styles/_global.scss b/src/styles/_global.scss index 8f755483..ae283a3b 100644 --- a/src/styles/_global.scss +++ b/src/styles/_global.scss @@ -108,3 +108,9 @@ a { ::-webkit-scrollbar-corner { background: transparent; } + +button { + border: none; + background-color: transparent; + outline: none; +} diff --git a/yarn.lock b/yarn.lock index 497b495f..31dac5f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10904,10 +10904,10 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" -swiper@^6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/swiper/-/swiper-6.7.0.tgz#ec971e703d03ef6196354140fbb22b074642bf5c" - integrity sha512-zCfvWn7H7mCq7jgVurckhAwkjPUeMCkdC4rA7lagvaD3mIrNhKiaYYo2+nkxMVpiaWuCQ38e44Mya/dKb7HpyQ== +swiper@^6.8.4: + version "6.8.4" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-6.8.4.tgz#938fed4144f4d7952fbf9c44e5832d133a4de794" + integrity sha512-O+buF9Q+sMA0H7luMS8R59hCaJKlpo8PXhQ6ZYu6Rn2v9OsFd4d1jmrv14QvxtQpKAvL/ZiovEeANI/uDGet7g== dependencies: dom7 "^3.0.0" ssr-window "^3.0.0"