1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

Merge pull request #17 from muerwre/16-fix-hero

Fixed hero
This commit is contained in:
muerwre 2020-11-06 12:03:31 +07:00 committed by GitHub
commit 52acdb283e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 83 deletions

View file

@ -4,114 +4,92 @@ import classNames from 'classnames';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { getURL } from '~/utils/dom'; import { getURL } from '~/utils/dom';
import { withRouter, RouteComponentProps } from 'react-router'; import { withRouter, RouteComponentProps, useHistory } from 'react-router';
import { URLS, PRESETS } from '~/constants/urls'; import { URLS, PRESETS } from '~/constants/urls';
import { Icon } from '~/components/input/Icon'; import { Icon } from '~/components/input/Icon';
import { INode } from "~/redux/types";
type IProps = RouteComponentProps & { type IProps = RouteComponentProps & {
heroes: IFlowState['heroes']; heroes: IFlowState['heroes'];
}; };
const FlowHeroUnconnected: FC<IProps> = ({ heroes, history }) => { const FlowHeroUnconnected: FC<IProps> = ({ heroes }) => {
const [limit, setLimit] = useState(Math.min(heroes.length, 6)); const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []);
const [limit, setLimit] = useState(6);
const [current, setCurrent] = useState(0); const [current, setCurrent] = useState(0);
const [loaded, setLoaded] = useState([]); const [loaded, setLoaded] = useState<Partial<INode>[]>([]);
const timer = useRef(null)
const history = useHistory();
const timer = useRef(null); const onLoad = useCallback((i: number) => {
const onLoad = useCallback(id => () => setLoaded([...loaded, id]), [setLoaded, loaded]); setLoaded([...loaded, heroes[i]])
const onNext = useCallback(() => { }, [heroes, loaded, setLoaded])
clearTimeout(timer.current);
if (loaded.length <= 1) return; const items = Math.min(heroes.length, limit)
const index = loaded.findIndex(el => el === current);
setCurrent(index > loaded.length - 2 ? loaded[0] : loaded[index + 1]);
}, [loaded, current, setCurrent, timer]);
const onNextPress = useCallback(() => {
setLimit(Math.min(heroes.length, limit + 1));
onNext();
}, [onNext, heroes, limit, setLimit]);
const onPrevious = useCallback(() => {
clearTimeout(timer.current);
if (loaded.length <= 1) return;
const index = loaded.findIndex(el => el === current);
setCurrent(index > 0 ? loaded[index - 1] : loaded[loaded.length - 1]);
}, [loaded, current, setCurrent, timer]);
useEffect(() => {
timer.current = setTimeout(onNext, 5000);
}, [current, onNext]);
useEffect(() => {
if (current === 0 && loaded.length > 0) setCurrent(loaded[0]);
}, [loaded]);
useEffect(() => {
setLimit(limit > 0 ? Math.min(heroes.length, limit) : heroes.length);
}, [heroes, limit]);
const stopSliding = useCallback(() => {
clearTimeout(timer.current);
timer.current = setTimeout(onNext, 5000);
}, [timer, onNext]);
const onClick = useCallback(() => {
if (!current) return;
history.push(URLS.NODE_URL(current));
}, [current]);
const title = useMemo(() => { const title = useMemo(() => {
if (loaded.length === 0) return null; return loaded[current]?.title || '';
const item = heroes.find(hero => hero.id === current);
if (!item || !item.title) return null;
return item.title;
}, [loaded, current, heroes]); }, [loaded, current, heroes]);
const preset = useMemo(() => (window.innerWidth <= 768 ? PRESETS.cover : PRESETS.small_hero), []); const onNext = useCallback(() => {
if (heroes.length > limit) setLimit(limit + 1)
setCurrent(current < items - 1 ? current + 1 : 0)
}, [current, items, limit, heroes.length])
const onPrev = useCallback(() => setCurrent(current > 0 ? current - 1 : items - 1), [current, items])
const goToNode = useCallback(() => {
history.push(URLS.NODE_URL(loaded[current].id))
}, [current, loaded]);
useEffect(() => {
timer.current = setTimeout(onNext, 5000)
return () => clearTimeout(timer.current)
}, [current, timer.current])
useEffect(() => {
if (loaded.length === 1) onNext()
}, [loaded])
return ( return (
<div className={styles.wrap} onMouseOver={stopSliding} onFocus={stopSliding}> <div className={styles.wrap}>
{loaded && loaded.length > 0 && ( <div className={styles.loaders}>
{
heroes.slice(0, items).map((hero, i) => (
<img src={getURL({ url: hero.thumbnail }, preset)} key={hero.id} onLoad={() => onLoad(i)} />
))
}
</div>
{loaded.length > 0 && (
<div className={styles.info}> <div className={styles.info}>
<div className={styles.title_wrap}>{title}</div> <div className={styles.title_wrap}>{title}</div>
<div className={styles.buttons}> <div className={styles.buttons}>
<div className={styles.button} onClick={onPrevious}> <div className={styles.button} onClick={onPrev}>
<Icon icon="left" /> <Icon icon="left" />
</div> </div>
<div className={styles.button} onClick={onNextPress}> <div className={styles.button} onClick={onNext}>
<Icon icon="right" /> <Icon icon="right" />
</div> </div>
</div> </div>
</div> </div>
)} )}
{heroes.slice(0, limit).map(hero => ( {loaded.slice(0, limit).map((hero, index) => (
<div <div
className={classNames(styles.hero, { className={classNames(styles.hero, {
[styles.is_visible]: loaded.includes(hero.id), [styles.is_visible]: true,
[styles.is_active]: current === hero.id, [styles.is_active]: current === index,
})} })}
style={{ style={{
backgroundImage: `url("${getURL({ url: hero.thumbnail }, preset)}")`, backgroundImage: `url("${getURL({ url: hero.thumbnail }, preset)}")`,
}} }}
key={hero.id} key={hero.id}
onClick={onClick} onClick={goToNode}
> >
<img <img
src={getURL({ url: hero.thumbnail }, preset)} src={getURL({ url: hero.thumbnail }, preset)}
alt={hero.thumbnail} alt={hero.thumbnail}
onLoad={onLoad(hero.id)}
/> />
</div> </div>
))} ))}

View file

@ -109,25 +109,11 @@
} }
} }
// .title {
// flex: 0;
// height: 48px;
// display: flex;
// align-items: center;
// justify-content: center;
// padding: 0 $gap 0 0;
// background: red;
// border-radius: $radius;
// font: $font_hero_title;
// text-transform: uppercase;
// }
.buttons { .buttons {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 48px; height: 48px;
// background: rgba(0, 0, 0, 0.7);
flex-direction: row; flex-direction: row;
width: 96px; width: 96px;
border-radius: $radius; border-radius: $radius;
@ -145,3 +131,18 @@
} }
} }
} }
.loaders {
position: absolute;
top: 0;
left: 0;
opacity: 0;
pointer-events: none;
touch-action: none;
img {
position: absolute;
left: 0;
top: 0;
}
}