aboutsummaryrefslogtreecommitdiff
path: root/components/toast.tsx
blob: 5bfc0ae783a8edb98d01b6ed3c31a5eb7353bcf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { CSSProperties, ReactNode, useState, createContext } from "react";

import CloseIcon from '@material-ui/icons/Close';

function ToastArea(props: {
	style?: CSSProperties
	children?: ReactNode
	rerender?: boolean;
}) {
	return <div id="ToastArea" style={{
		position: "fixed",
		whiteSpace: "nowrap",
		bottom: 12,
		left: "50%",
		transform: "translateX(-50%)",
		zIndex: 1,
		maxWidth: 600,
		width: "calc(100% - 48px - 48px)",
		margin: "0 24px",
		...props.style
	}}>{props.children}</div>
}

function Toast(props: {
	text?: string
	icon?: ReactNode
	children?: ReactNode
	type?: "normal"|"confirmation"|"error"
	style?: CSSProperties
}) {
	var [visible, setVisibility] = useState(true);

	setTimeout(() => setVisibility(false), 10e3);

	return visible && <div style={{
		padding: 0,
		marginBottom: 12,
		borderRadius: 8,
		boxShadow: "0 8px 12px -4px #00000033",
		color:
			props.type === "confirmation" ? "var(--background)" : "var(--text)",
		backgroundColor:
			props.type === "normal" ? "var(--background)" :
			props.type === "confirmation" ? "var(--disk-b)" :
			props.type === "error" ? "var(--disk-a)" : "var(--background)",
		...props.style
	}}>
		{
			props.children ||
			<div style={{ lineHeight: 0 }}>
				<div style={{
					fontSize: 0,
					margin: 16,
					display: "inline-block",
					verticalAlign: "top",
					width: 32, height: 32
				}}>{props.icon}</div>
				<h2 style={{
					margin: "20px 0",
					display: "inline-block",
					width: "calc(100% - 128px)",
					verticalAlign: "top",
					fontSize: 20,
					userSelect: "none"
				}}>{props.text}</h2>
				<div style={{
					padding: 20,
					display: "inline-block",
					cursor: "pointer"
				}} onClick={() => setVisibility(false)}>
					<CloseIcon/>
				</div>
			</div>
		}
	</div>
}

export var ToastContext = createContext<{ toast?: (message: string,
												   type: "confirmation"|"normal"|"error",
												   icon?: ReactNode ) => void }>({});
var toasts: Array<JSX.Element> = [];

export function ToastContextWrapper(props: { children?: ReactNode }) {
	var [dummyState, rerender] = useState(false);

	return <ToastContext.Provider value={{ toast: (message: string,
												   type: "confirmation"|"normal"|"error",
												   icon?: ReactNode ) => {
		toasts.push(<Toast type={type} text={message} icon={icon}/>);
		rerender(!dummyState);
	} }}>
		{ props.children }
		<ToastArea rerender={dummyState}>
			{toasts}
		</ToastArea>
	</ToastContext.Provider>
}