mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
feat(a11y): cross-platform hardening + modal focus-trap from impeccable audit
Responsive / viewport: - add .min-h-viewport / .h-viewport utilities (100dvh + Telegram --tg-viewport-stable-height) - migrate min-h-screen / h-screen / 100vh across 18 files - reveal hover-only controls on focus-within + touch (desktop nav, admin settings) - grid breakpoints (TopUpAmount, Contests), larger touch targets, nav aria-labels Platform routing (Telegram WebView correctness): - clipboard -> copyToClipboard util with execCommand fallback (10 files) - window.open -> openTelegramLink / openLink (Profile, Referral, ChannelSubscriptionScreen) - window.confirm -> useNativeDialog (admin pages); PromoOffersSection -> useDestructiveConfirm - window.prompt -> usePrompt / PromptDialogHost (TipTap link editors) - ESLint no-restricted-properties guard against regressions (adapters/clipboard util exempt) Modal accessibility: - new useFocusTrap hook (focus trap, Esc, scroll lock, focus restore) - role=dialog / aria-modal / focus-trap: Polls, SuccessNotificationModal, AdminPolicies, AdminPromoGroups, AdminCampaigns, BroadcastPreview (Telegram + Email) - new global usePrompt store + PromptDialogHost
This commit is contained in:
@@ -6,6 +6,7 @@ import i18n from '../i18n';
|
||||
import { campaignsApi, CampaignListItem, CampaignBonusType } from '../api/campaigns';
|
||||
import { PlusIcon, EditIcon, TrashIcon, CheckIcon, XIcon, ChartIcon } from '../components/icons';
|
||||
import { usePlatform } from '../platform/hooks/usePlatform';
|
||||
import { useFocusTrap } from '../hooks/useFocusTrap';
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
|
||||
@@ -69,6 +70,9 @@ export default function AdminCampaigns() {
|
||||
const { capabilities } = usePlatform();
|
||||
|
||||
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null);
|
||||
const deleteDialogRef = useFocusTrap<HTMLDivElement>(deleteConfirm !== null, {
|
||||
onEscape: () => setDeleteConfirm(null),
|
||||
});
|
||||
|
||||
// Queries
|
||||
const {
|
||||
@@ -295,8 +299,20 @@ export default function AdminCampaigns() {
|
||||
{/* Delete Confirmation */}
|
||||
{deleteConfirm !== null && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<div className="w-full max-w-sm rounded-xl bg-dark-800 p-6">
|
||||
<h3 className="mb-2 text-lg font-semibold text-dark-100">
|
||||
<div
|
||||
className="absolute inset-0 bg-black/60"
|
||||
onClick={() => setDeleteConfirm(null)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div
|
||||
ref={deleteDialogRef}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="campaign-delete-title"
|
||||
tabIndex={-1}
|
||||
className="relative w-full max-w-sm rounded-xl bg-dark-800 p-6"
|
||||
>
|
||||
<h3 id="campaign-delete-title" className="mb-2 text-lg font-semibold text-dark-100">
|
||||
{t('admin.campaigns.confirm.deleteTitle')}
|
||||
</h3>
|
||||
<p className="mb-6 text-dark-400">{t('admin.campaigns.confirm.deleteText')}</p>
|
||||
|
||||
Reference in New Issue
Block a user