All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 25s
- Создан компонент RuleEditorDrawer для редактирования правил с поддержкой JSON. - Добавлен компонент ServersPage для отображения и управления серверами. - Реализован компонент SettingsPage для управления подписками и конфигурациями. - Создан компонент Sidebar для навигации по приложению. - Добавлен компонент StatusPane для отображения статуса сервера. - Реализован компонент Toasts для отображения уведомлений. - Создан компонент Topbar для отображения информации о текущем состоянии. - Добавлен модуль country.js для определения страны по тегу сервера. Refs: None
33 lines
1.0 KiB
JavaScript
33 lines
1.0 KiB
JavaScript
import React, { useEffect } from 'react';
|
||
|
||
export function Toasts({ items, onDismiss }) {
|
||
useEffect(() => {
|
||
const timers = items.map((t) =>
|
||
t.sticky ? null : setTimeout(() => onDismiss(t.id), t.duration || 4000),
|
||
);
|
||
return () => timers.forEach((t) => t && clearTimeout(t));
|
||
}, [items, onDismiss]);
|
||
|
||
if (!items.length) return null;
|
||
|
||
return (
|
||
<div className="toasts">
|
||
{items.map((t) => (
|
||
<div key={t.id} className={`toast ${t.kind || ''}`}>
|
||
<span className={`dot ${t.kind || ''}`} style={{ marginTop: 4 }} />
|
||
<div className="body">
|
||
<strong>{t.title}</strong>
|
||
{t.message && <small>{t.message}</small>}
|
||
{t.action && (
|
||
<button className="btn btn-link sm" onClick={t.action.onClick} style={{ marginTop: 4, padding: 0 }}>
|
||
{t.action.label}
|
||
</button>
|
||
)}
|
||
</div>
|
||
<button onClick={() => onDismiss(t.id)} title="Закрыть">×</button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|