feat: modal windows

This commit is contained in:
2026-08-14 19:49:27 +07:00
parent 3d8b78ec52
commit 76f26430ba
13 changed files with 377 additions and 16 deletions

View File

@@ -0,0 +1,111 @@
import { useEffect } from 'react';
import { createPortal } from 'react-dom';
interface Client {
name: string;
href: string;
note?: string;
}
interface Platform {
name: string;
clients: Client[];
}
const PLATFORMS: Platform[] = [
{
name: 'iOS',
clients: [
{ name: 'Incy Client', href: 'https://apps.apple.com/us/app/incy/id6756943388', note: 'Приложение может быть недоступно в РФ, смените регион.' },
],
},
{
name: 'Windows',
clients: [
{ name: 'Happ', href: 'https://github.com/Happ-proxy/happ-desktop/releases/latest/download/setup-Happ.x64.exe' },
{
name: 'Throne',
href: 'https://github.com/throneproj/Throne/releases/latest',
note: 'При первом запуске: Настройки -> Подписка -> Разрешить отправку HWID.',
},
],
},
{
name: 'Android',
clients: [
{ name: 'Happ (Google Play)', href: 'https://play.google.com/store/apps/details?id=com.happproxy&pli=1' },
{ name: 'Happ (APK)', href: 'https://github.com/Happ-proxy/happ-android/releases/latest/download/Happ.apk' },
{ name: 'v2raytun', href: 'https://play.google.com/store/apps/details?id=com.v2raytun.android&hl=ru' },
],
},
{
name: 'Linux',
clients: [
{
name: 'Throne',
href: 'https://github.com/throneproj/Throne/releases/latest',
note: 'При первом запуске: Настройки -> Подписка -> Разрешить отправку HWID.',
},
],
},
];
interface ClientLinksModalProps {
open: boolean;
onClose: () => void;
}
export function ClientLinksModal({ open, onClose }: ClientLinksModalProps) {
useEffect(() => {
if (!open) return;
const onKey = (event: KeyboardEvent) => {
if (event.key === 'Escape') onClose();
};
document.addEventListener('keydown', onKey);
document.body.style.overflow = 'hidden';
return () => {
document.removeEventListener('keydown', onKey);
document.body.style.overflow = '';
};
}, [onClose, open]);
if (!open) return null;
return createPortal(
<div
className="modal-veil is-open"
role="dialog"
aria-modal="true"
aria-labelledby="client-links-title"
onClick={(event) => {
if (event.target === event.currentTarget) onClose();
}}
>
<div className="modal client-links-modal" role="document">
<div className="modal-kicker">Подключение устройства</div>
<h3 className="modal-title" id="client-links-title">
Выберите клиент
</h3>
<div className="client-platforms">
{PLATFORMS.map((platform) => (
<section className="client-platform" key={platform.name} aria-label={platform.name}>
<h4>{platform.name}</h4>
{platform.clients.map((client) => (
<div className="client-link" key={client.href}>
<a href={client.href} target="_blank" rel="noreferrer">
{client.name}
</a>
{client.note ? <p>{client.note}</p> : null}
</div>
))}
</section>
))}
</div>
<button type="button" className="btn" onClick={onClose} autoFocus>
Закрыть
</button>
</div>
</div>,
document.body,
);
}