Add notifications at the top right of the screen.
This commit is contained in:
		
							parent
							
								
									ed4e766650
								
							
						
					
					
						commit
						64a77d077c
					
				
					 7 changed files with 363 additions and 11 deletions
				
			
		| 
						 | 
					@ -33,6 +33,8 @@ import {DemoModal} from "./DemoModal";
 | 
				
			||||||
import {useCallableModal} from "../src/Components/Modals/Modals";
 | 
					import {useCallableModal} from "../src/Components/Modals/Modals";
 | 
				
			||||||
import {ModalType} from "../src/Components/Modals/ModalsTypes";
 | 
					import {ModalType} from "../src/Components/Modals/ModalsTypes";
 | 
				
			||||||
import {Buttons} from "../src/Components/Buttons/Buttons";
 | 
					import {Buttons} from "../src/Components/Buttons/Buttons";
 | 
				
			||||||
 | 
					import {useNotify} from "../src/Components/Notifications/Notifications";
 | 
				
			||||||
 | 
					import {Notification, NotificationType} from "../src/Components/Notifications/Notification";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function DemoApp()
 | 
					export function DemoApp()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -48,6 +50,8 @@ export function DemoApp()
 | 
				
			||||||
	// Easy modal.
 | 
						// Easy modal.
 | 
				
			||||||
	const easyModal = useCallableModal((type: ModalType = ModalType.NONE) => <DemoModal type={type} />);
 | 
						const easyModal = useCallableModal((type: ModalType = ModalType.NONE) => <DemoModal type={type} />);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const notify = useNotify();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const [datetime, setDatetime] = useState(null);
 | 
						const [datetime, setDatetime] = useState(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const [selected, setSelected] = useState(null);
 | 
						const [selected, setSelected] = useState(null);
 | 
				
			||||||
| 
						 | 
					@ -506,11 +510,11 @@ export function DemoApp()
 | 
				
			||||||
			<h2>Notifications</h2>
 | 
								<h2>Notifications</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			<Card>
 | 
								<Card>
 | 
				
			||||||
				<button>Information notification</button>
 | 
									<button onClick={() => { notify(<Notification type={NotificationType.INFO}>Test notification</Notification>); }}>Information notification</button>
 | 
				
			||||||
				<button className={"success"}>Success notification</button>
 | 
									<button className={"success"} onClick={() => { notify(<Notification type={NotificationType.SUCCESS}>Test notification</Notification>); }}>Success notification</button>
 | 
				
			||||||
				<button className={"warning"}>Warning notification</button>
 | 
									<button className={"warning"} onClick={() => { notify(<Notification type={NotificationType.WARNING}>Test notification</Notification>); }}>Warning notification</button>
 | 
				
			||||||
				<button className={"error"}>Error notification</button>
 | 
									<button className={"error"} onClick={() => { notify(<Notification type={NotificationType.ERROR}>Test notification</Notification>); }}>Error notification</button>
 | 
				
			||||||
				<button className={"flat"}>Generic notification</button>
 | 
									<button className={"flat"} onClick={() => { notify(<Notification>Test notification</Notification>); }}>Generic notification</button>
 | 
				
			||||||
			</Card>
 | 
								</Card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		</Application>
 | 
							</Application>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ import { IconContext } from "@phosphor-icons/react";
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import {createBrowserRouter, RouterProvider} from "react-router-dom";
 | 
					import {createBrowserRouter, RouterProvider} from "react-router-dom";
 | 
				
			||||||
import {Curtains} from "../Components/Curtains/Curtains";
 | 
					import {Curtains} from "../Components/Curtains/Curtains";
 | 
				
			||||||
 | 
					import {NotificationsProvider} from "../Components/Notifications/Notifications";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Main Kernel UI app component which initializes everything.
 | 
					 * Main Kernel UI app component which initializes everything.
 | 
				
			||||||
| 
						 | 
					@ -17,11 +18,13 @@ export function Kernel({header, footer, router}: {
 | 
				
			||||||
			size: 16,
 | 
								size: 16,
 | 
				
			||||||
			weight: "bold",
 | 
								weight: "bold",
 | 
				
			||||||
		}}>
 | 
							}}>
 | 
				
			||||||
 | 
								<NotificationsProvider>
 | 
				
			||||||
				<Curtains>
 | 
									<Curtains>
 | 
				
			||||||
					{header}
 | 
										{header}
 | 
				
			||||||
					<RouterProvider router={router} />
 | 
										<RouterProvider router={router} />
 | 
				
			||||||
					{footer}
 | 
										{footer}
 | 
				
			||||||
				</Curtains>
 | 
									</Curtains>
 | 
				
			||||||
 | 
								</NotificationsProvider>
 | 
				
			||||||
		</IconContext.Provider>
 | 
							</IconContext.Provider>
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								src/Components/Notifications/Notification.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/Components/Notifications/Notification.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					import React, {useCallback, useContext} from "react";
 | 
				
			||||||
 | 
					import {classes} from "../../Utils";
 | 
				
			||||||
 | 
					import {NotificationContext, NotificationsContext} from "./Notifications";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notifications types enumeration.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export enum NotificationType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						NONE = "none",
 | 
				
			||||||
 | 
						INFO = "info",
 | 
				
			||||||
 | 
						SUCCESS = "success",
 | 
				
			||||||
 | 
						WARNING = "warning",
 | 
				
			||||||
 | 
						ERROR = "error",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notification component.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function Notification({type, children}: React.PropsWithChildren<{
 | 
				
			||||||
 | 
						type?: NotificationType;
 | 
				
			||||||
 | 
					}>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Default type is NONE.
 | 
				
			||||||
 | 
						type = type ?? NotificationType.NONE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get notifications context.
 | 
				
			||||||
 | 
						const {close} = useContext(NotificationsContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get current notification UUID.
 | 
				
			||||||
 | 
						const {uuid, closed} = useContext(NotificationContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize close notification function.
 | 
				
			||||||
 | 
						const closeNotification = useCallback(() => { close(uuid); }, [uuid]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (
 | 
				
			||||||
 | 
							<li className={classes("notification", type, closed ? "closed" : undefined)} onMouseDown={closeNotification}>
 | 
				
			||||||
 | 
								{children}
 | 
				
			||||||
 | 
							</li>
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										217
									
								
								src/Components/Notifications/Notifications.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/Components/Notifications/Notifications.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,217 @@
 | 
				
			||||||
 | 
					import React, {startTransition, useCallback, useContext, useEffect, useMemo, useRef, useState} from "react";
 | 
				
			||||||
 | 
					import ReactDOM from "react-dom";
 | 
				
			||||||
 | 
					import {v4 as uuidv4} from "uuid";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notification UUID type.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type NotificationUuid = string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notification data.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface NotificationData
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * The notification content.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						content: React.ReactNode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Type of notification emitter function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type EmitNotificationFunction = (content: React.ReactNode) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Type of notification close function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type RemoveNotificationFunction = (uuid: NotificationUuid) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Type of notification close function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type CloseNotificationFunction = (uuid: NotificationUuid) => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Type of notification closed state function.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type IsNotificationClosedFunction = (uuid: NotificationUuid) => boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Interface of notifications state.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface NotificationsContextState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Notification function.
 | 
				
			||||||
 | 
						 * @param content Notification content.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						notify: EmitNotificationFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Close notification function.
 | 
				
			||||||
 | 
						 * @param uuid UUID of notification to close.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						close: CloseNotificationFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Is given notification closed?
 | 
				
			||||||
 | 
						 * @param uuid UUID of notification to get closed state.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						isClosed: IsNotificationClosedFunction;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const NotificationsContext = React.createContext<NotificationsContextState>({
 | 
				
			||||||
 | 
						notify() {},
 | 
				
			||||||
 | 
						close() {},
 | 
				
			||||||
 | 
						isClosed() { return false; },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Hook to emit a notification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function useNotify(): EmitNotificationFunction
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return useContext(NotificationsContext).notify;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notifications provider.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function NotificationsProvider({children}: React.PropsWithChildren<{}>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Notifications.
 | 
				
			||||||
 | 
						const [notifications, setNotifications] = useState<Record<NotificationUuid, NotificationData>>({});
 | 
				
			||||||
 | 
						// Keeping track of closed notifications that are still on (while transitioning out).
 | 
				
			||||||
 | 
						const [closedNotifications, setClosedNotifications] = useState<Record<NotificationUuid, boolean>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize remove notification function.
 | 
				
			||||||
 | 
						const remove = useRef<RemoveNotificationFunction>();
 | 
				
			||||||
 | 
						remove.current = useCallback((uuid) => {
 | 
				
			||||||
 | 
							// Copy the notifications list.
 | 
				
			||||||
 | 
							const newNotifications = {...notifications};
 | 
				
			||||||
 | 
							const newClosedNotifications = {...closedNotifications};
 | 
				
			||||||
 | 
							// Remove the given notification from the list.
 | 
				
			||||||
 | 
							delete newNotifications[uuid];
 | 
				
			||||||
 | 
							delete newClosedNotifications[uuid];
 | 
				
			||||||
 | 
							// Set the new notifications list.
 | 
				
			||||||
 | 
							setNotifications(newNotifications);
 | 
				
			||||||
 | 
							setClosedNotifications(newClosedNotifications);
 | 
				
			||||||
 | 
						}, [notifications, setNotifications, closedNotifications, setClosedNotifications]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize close notification function with animation.
 | 
				
			||||||
 | 
						const close = useRef<CloseNotificationFunction>();
 | 
				
			||||||
 | 
						close.current = useCallback((uuid) => {
 | 
				
			||||||
 | 
							// Add the given curtain UUID to the list of closed curtains.
 | 
				
			||||||
 | 
							setClosedNotifications({
 | 
				
			||||||
 | 
								...closedNotifications,
 | 
				
			||||||
 | 
								[uuid]: true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Remove the notification 300ms later.
 | 
				
			||||||
 | 
							window.setTimeout(() => {
 | 
				
			||||||
 | 
								// Remove the curtain.
 | 
				
			||||||
 | 
								remove.current(uuid);
 | 
				
			||||||
 | 
							}, 300);
 | 
				
			||||||
 | 
						}, [remove, closedNotifications, setClosedNotifications]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize isClosed notification function.
 | 
				
			||||||
 | 
						const isClosed = useRef<IsNotificationClosedFunction>();
 | 
				
			||||||
 | 
						isClosed.current = useCallback((uuid) => (!!closedNotifications?.[uuid]), [closedNotifications]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize notify function.
 | 
				
			||||||
 | 
						const notify = useRef<EmitNotificationFunction>();
 | 
				
			||||||
 | 
						notify.current = useCallback((content: React.ReactNode) => {
 | 
				
			||||||
 | 
							// Generate a new notification UUID for the new notification.
 | 
				
			||||||
 | 
							const notificationUuid = uuidv4();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Add the notification to the list of notifications, with the generated UUID.
 | 
				
			||||||
 | 
							setNotifications({
 | 
				
			||||||
 | 
								...notifications,
 | 
				
			||||||
 | 
								[notificationUuid]: {
 | 
				
			||||||
 | 
									content: content,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Close notification 10s later.
 | 
				
			||||||
 | 
							setTimeout(() => {
 | 
				
			||||||
 | 
								close.current(notificationUuid);
 | 
				
			||||||
 | 
							}, 10000);
 | 
				
			||||||
 | 
						}, [notifications, setNotifications]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Initialize context state from action functions.
 | 
				
			||||||
 | 
						const contextState = useMemo(() => ({
 | 
				
			||||||
 | 
							notify: (content: React.ReactNode) => notify.current(content),
 | 
				
			||||||
 | 
							close: (uuid: NotificationUuid) => close.current(uuid),
 | 
				
			||||||
 | 
							isClosed: (uuid: NotificationUuid) => isClosed.current(uuid),
 | 
				
			||||||
 | 
						}), [notify, isClosed]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (
 | 
				
			||||||
 | 
							<NotificationsContext.Provider value={contextState}>
 | 
				
			||||||
 | 
								{children}
 | 
				
			||||||
 | 
								<NotificationsPortal notifications={notifications} />
 | 
				
			||||||
 | 
							</NotificationsContext.Provider>
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Curtains portal manager.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function NotificationsPortal({notifications}: {
 | 
				
			||||||
 | 
						notifications: Record<NotificationUuid, NotificationData>;
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ReactDOM.createPortal((
 | 
				
			||||||
 | 
							<ul className={"notifications"}>
 | 
				
			||||||
 | 
								{ // Show notifications list.
 | 
				
			||||||
 | 
									Object.entries(notifications).map(([uuid, notificationData]) => (
 | 
				
			||||||
 | 
										<NotificationInstance key={uuid} uuid={uuid}>
 | 
				
			||||||
 | 
											{notificationData.content}
 | 
				
			||||||
 | 
										</NotificationInstance>
 | 
				
			||||||
 | 
									))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							</ul>
 | 
				
			||||||
 | 
						), document.body);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A notification context.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const NotificationContext = React.createContext<{
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Notification UUID.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						uuid: NotificationUuid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Notification closed state.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						closed: boolean;
 | 
				
			||||||
 | 
					}>(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Notification component.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function NotificationInstance({uuid, children}: React.PropsWithChildren<{
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Notification UUID.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						uuid: NotificationUuid;
 | 
				
			||||||
 | 
					}>)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Get notifications context.
 | 
				
			||||||
 | 
						const {isClosed} = useContext(NotificationsContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (
 | 
				
			||||||
 | 
							<NotificationContext.Provider value={{
 | 
				
			||||||
 | 
								uuid: uuid,
 | 
				
			||||||
 | 
								closed: isClosed(uuid),
 | 
				
			||||||
 | 
							}}>
 | 
				
			||||||
 | 
								{children}
 | 
				
			||||||
 | 
							</NotificationContext.Provider>
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
@import "components/_loaders";
 | 
					@import "components/_loaders";
 | 
				
			||||||
@import "components/_menus";
 | 
					@import "components/_menus";
 | 
				
			||||||
@import "components/_modal";
 | 
					@import "components/_modal";
 | 
				
			||||||
 | 
					@import "components/_notifications";
 | 
				
			||||||
@import "components/_pagination";
 | 
					@import "components/_pagination";
 | 
				
			||||||
@import "components/_select";
 | 
					@import "components/_select";
 | 
				
			||||||
@import "components/_steps";
 | 
					@import "components/_steps";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ body.dimmed
 | 
				
			||||||
{ // Disable scroll and blur the content when the body is dimmed.
 | 
					{ // Disable scroll and blur the content when the body is dimmed.
 | 
				
			||||||
	overflow: hidden;
 | 
						overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> *:not(.curtain)
 | 
						> *:not(.curtain):not(.notifications)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		transition: filter 0.4s ease-in;
 | 
							transition: filter 0.4s ease-in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								src/styles/components/_notifications.less
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/styles/components/_notifications.less
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					body > ul.notifications
 | 
				
			||||||
 | 
					{ // Notifications list.
 | 
				
			||||||
 | 
						position: fixed;
 | 
				
			||||||
 | 
						top: 0;
 | 
				
			||||||
 | 
						right: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						margin: 0 1em 1em;
 | 
				
			||||||
 | 
						padding: 0;
 | 
				
			||||||
 | 
						width: 20em;
 | 
				
			||||||
 | 
						max-width: 66%;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list-style: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						z-index: 2000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						> li.notification
 | 
				
			||||||
 | 
						{ // A single notification.
 | 
				
			||||||
 | 
							margin: 1em auto;
 | 
				
			||||||
 | 
							padding: 1em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							border-radius: 0.25em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							box-shadow: 0 0 0.5em 0 var(--foreground-shadow);
 | 
				
			||||||
 | 
							background: var(--background);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Show an animation when entering screen.
 | 
				
			||||||
 | 
							animation: notification-in 0.3s ease-in;
 | 
				
			||||||
 | 
							transform-origin: center;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							&.closed
 | 
				
			||||||
 | 
							{ // Added when the notification is closing and will soon be removed from DOM.
 | 
				
			||||||
 | 
								transition: transform 0.3s ease-out, filter 0.3s ease-out, opacity 0.3s ease-out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								transform: scale(1.15);
 | 
				
			||||||
 | 
								filter: blur(0.25em);
 | 
				
			||||||
 | 
								opacity: 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								pointer-events: none;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							&.info
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								border: solid var(--primary-darker) thin;
 | 
				
			||||||
 | 
								background: var(--primary);
 | 
				
			||||||
 | 
								color: var(--background);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							&.success
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								border: solid var(--green-darker) thin;
 | 
				
			||||||
 | 
								background: var(--green);
 | 
				
			||||||
 | 
								color: var(--background);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							&.warning
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								border: solid var(--orange-darker) thin;
 | 
				
			||||||
 | 
								background: var(--orange);
 | 
				
			||||||
 | 
								color: var(--background);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							&.error
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								border: solid var(--red-darker) thin;
 | 
				
			||||||
 | 
								background: var(--red);
 | 
				
			||||||
 | 
								color: var(--background);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes notification-in
 | 
				
			||||||
 | 
					{ // Screen enter animation.
 | 
				
			||||||
 | 
						from
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							transform: scale(1.15);
 | 
				
			||||||
 | 
							filter: blur(0.25em);
 | 
				
			||||||
 | 
							opacity: 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						to
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							transform: scale(1);
 | 
				
			||||||
 | 
							filter: blur(0);
 | 
				
			||||||
 | 
							opacity: 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue