frontend/components/Banner/index.tsx (view raw)
1import {Icon} from '@material-ui/core';
2import Button from '@material-ui/core/Button';
3import {makeStyles} from '@material-ui/core/styles';
4import {useEffect} from 'react';
5import {useElementSize, useEventListener} from 'usehooks-ts';
6import Markdown from '../Markdown';
7import useBannerStore from '../../stores/useBannerStore';
8
9interface Props {
10 message: string;
11 open: boolean;
12 onClear?: () => void;
13}
14
15const Banner = (props: Props) => {
16 const {message, open, onClear} = props;
17 const classes = useStyles();
18 const [bannerRef, {height}] = useElementSize();
19 const setBannerHeight = useBannerStore(s => s.setBannerHeight);
20 const setBannerOffset = useBannerStore(s => s.setBannerOffset);
21 useEffect(() => setBannerHeight({height}), [height]);
22
23 if (typeof document != 'undefined') {
24 useEventListener('scroll', () => {
25 const y = window.scrollY;
26 if (y > height) {
27 setBannerOffset({offset: 0});
28 }
29 if (y <= height) {
30 setBannerOffset({offset: height - y});
31 }
32 });
33 }
34
35 if (!open) return null;
36
37 return (
38 <div className={classes.banner} ref={bannerRef}>
39 <Markdown className={classes.htmlReset}>{message}</Markdown>
40 <Button
41 className={classes.clear}
42 onClick={e => {
43 e.stopPropagation();
44 onClear();
45 }}
46 >
47 <Icon>close</Icon>
48 </Button>
49 </div>
50 );
51};
52
53const useStyles = makeStyles(theme => ({
54 banner: {
55 position: 'relative',
56 background: `linear-gradient(90deg, #FCDC61 20%, #78B2AC 90%)`,
57 width: '100%',
58 padding: '12px 60px',
59 textAlign: 'center',
60 zIndex: theme.zIndex.appBar - 1,
61 color: 'black',
62 },
63 clear: {
64 position: 'absolute',
65 right: '12px',
66 bottom: '0',
67 minWidth: '44px',
68 padding: '12px',
69 lineHeight: '1.4em',
70 },
71 htmlReset: {
72 '& a': {
73 color: 'inherit',
74 margin: 0,
75 },
76 '& p': {
77 margin: 0,
78 },
79 },
80}));
81
82export default Banner;