feat: modal windows
This commit is contained in:
111
src/components/ClientLinksModal.tsx
Normal file
111
src/components/ClientLinksModal.tsx
Normal 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,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user