feat: avoid removing notification when mouse hover
This commit is contained in:
@ -3,15 +3,22 @@ import type { Notification } from '../types/types';
|
|||||||
type Props = {
|
type Props = {
|
||||||
notifications: Notification[];
|
notifications: Notification[];
|
||||||
onRemove: (id: number) => void;
|
onRemove: (id: number) => void;
|
||||||
|
onHover: (id: number, hovering: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Notifications({ notifications, onRemove }: Props) {
|
export default function Notifications({
|
||||||
|
notifications,
|
||||||
|
onRemove,
|
||||||
|
onHover,
|
||||||
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="notifications">
|
<div className="notifications">
|
||||||
{notifications.map((n) => (
|
{notifications.map((n) => (
|
||||||
<div
|
<div
|
||||||
key={n.id}
|
key={n.id}
|
||||||
className={`notification ${n.type} ${n.removing ? 'notification-out' : ''}`}
|
className={`notification ${n.type} ${n.removing ? 'notification-out' : ''}`}
|
||||||
|
onMouseEnter={() => onHover(n.id, true)}
|
||||||
|
onMouseLeave={() => onHover(n.id, false)}
|
||||||
>
|
>
|
||||||
<span className="notification-message" title={n.message}>
|
<span className="notification-message" title={n.message}>
|
||||||
{n.message}
|
{n.message}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ function App() {
|
|||||||
const [dsps, setDsps] = useState<DSP[]>([]);
|
const [dsps, setDsps] = useState<DSP[]>([]);
|
||||||
const [selected, setSelected] = useState<number | null>(null);
|
const [selected, setSelected] = useState<number | null>(null);
|
||||||
const [page, setPage] = useState<AppPage>('home');
|
const [page, setPage] = useState<AppPage>('home');
|
||||||
const { notifications, notify, removeNotification } = useNotifications();
|
const { notifications, notify, removeNotification, hoverNotification } = useNotifications();
|
||||||
|
|
||||||
async function addDSP(dsp: Omit<DSP, 'id' | 'status'>) {
|
async function addDSP(dsp: Omit<DSP, 'id' | 'status'>) {
|
||||||
try {
|
try {
|
||||||
@ -126,7 +126,7 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
<Notifications notifications={notifications} onRemove={removeNotification} />
|
<Notifications notifications={notifications} onRemove={removeNotification} onHover={hoverNotification}/>
|
||||||
|
|
||||||
<TopBar
|
<TopBar
|
||||||
dsps={dsps}
|
dsps={dsps}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { NotificationType, Notification } from '../types/types';
|
import { NotificationType, Notification } from '../types/types';
|
||||||
|
|
||||||
export function useNotifications() {
|
export function useNotifications() {
|
||||||
const [notifications, setNotifications] = useState<Notification[]>([]);
|
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||||||
|
const hovered = useRef<Set<number>>(new Set());
|
||||||
|
|
||||||
const notify = useCallback(
|
const notify = useCallback(
|
||||||
(message: string, type: NotificationType = 'error', dspName?: string) => {
|
(message: string, type: NotificationType = 'error', dspName?: string) => {
|
||||||
@ -19,24 +20,42 @@ export function useNotifications() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
setTimeout(() => {
|
const removeLater = () => {
|
||||||
|
if (hovered.current.has(id)) {
|
||||||
|
setTimeout(removeLater, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
||||||
}, 5000);
|
};
|
||||||
|
|
||||||
|
setTimeout(removeLater, 5000);
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const removeNotification = useCallback((id: number) => {
|
const removeNotification = useCallback((id: number) => {
|
||||||
setNotifications((prev) => prev.map((n) => (n.id === id ? { ...n, removing: true } : n)));
|
setNotifications((prev) =>
|
||||||
|
prev.map((n) => (n.id === id ? { ...n, removing: true } : n))
|
||||||
|
);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
setNotifications((prev) => prev.filter((n) => n.id !== id));
|
||||||
}, 250);
|
}, 250);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const hoverNotification = useCallback((id: number, hovering: boolean) => {
|
||||||
|
if (hovering) {
|
||||||
|
hovered.current.add(id);
|
||||||
|
} else {
|
||||||
|
hovered.current.delete(id);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
notifications,
|
notifications,
|
||||||
notify,
|
notify,
|
||||||
removeNotification,
|
removeNotification,
|
||||||
|
hoverNotification,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user