mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
commit
52acdb283e
2 changed files with 62 additions and 83 deletions
|
@ -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>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue