mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
feat(a11y,i18n): more modal focus-traps + Telegram theme/language sync
Modal a11y: - focus-trap + role=dialog/aria-modal/aria-labelledby on AdminRoles delete confirm and AdminBanSystem user-detail modal (+ close aria-label) Telegram theme/language sync (first run only, explicit choice always wins): - getTelegramColorScheme() / getTelegramLanguageCode() helpers in useTelegramSDK - useTheme initial state follows the Telegram client color scheme when no stored theme - applyTelegramLanguage() adopts the Telegram client language when no stored choice, called from main.tsx after SDK init (launch params unavailable before init)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AdminBackButton } from '../components/admin/AdminBackButton';
|
||||
import { useFocusTrap } from '../hooks/useFocusTrap';
|
||||
import {
|
||||
banSystemApi,
|
||||
type BanSystemStatus,
|
||||
@@ -198,6 +199,9 @@ export default function AdminBanSystem() {
|
||||
const [stats, setStats] = useState<BanSystemStats | null>(null);
|
||||
const [users, setUsers] = useState<BanUsersListResponse | null>(null);
|
||||
const [selectedUser, setSelectedUser] = useState<BanUserDetailResponse | null>(null);
|
||||
const userDetailRef = useFocusTrap<HTMLDivElement>(selectedUser !== null, {
|
||||
onEscape: () => setSelectedUser(null),
|
||||
});
|
||||
const [punishments, setPunishments] = useState<BanPunishmentsListResponse | null>(null);
|
||||
const [nodes, setNodes] = useState<BanNodesListResponse | null>(null);
|
||||
const [agents, setAgents] = useState<BanAgentsListResponse | null>(null);
|
||||
@@ -1498,15 +1502,21 @@ export default function AdminBanSystem() {
|
||||
onClick={() => setSelectedUser(null)}
|
||||
>
|
||||
<div
|
||||
ref={userDetailRef}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="ban-user-detail-title"
|
||||
tabIndex={-1}
|
||||
className="max-h-[80vh] w-full max-w-2xl overflow-y-auto rounded-xl border border-dark-700 bg-dark-800"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center justify-between border-b border-dark-700 p-4">
|
||||
<h3 className="text-lg font-semibold text-dark-100">
|
||||
<h3 id="ban-user-detail-title" className="text-lg font-semibold text-dark-100">
|
||||
{t('banSystem.userDetail.title')}
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => setSelectedUser(null)}
|
||||
aria-label={t('common.close')}
|
||||
className="text-dark-400 hover:text-dark-200"
|
||||
>
|
||||
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
|
||||
@@ -6,6 +6,7 @@ import { rbacApi } from '@/api/rbac';
|
||||
import { PermissionGate } from '@/components/auth/PermissionGate';
|
||||
import { usePermissionStore } from '@/store/permissions';
|
||||
import { usePlatform } from '@/platform/hooks/usePlatform';
|
||||
import { useFocusTrap } from '@/hooks/useFocusTrap';
|
||||
|
||||
const BackIcon = () => (
|
||||
<svg
|
||||
@@ -64,6 +65,9 @@ export default function AdminRoles() {
|
||||
|
||||
const [deleteConfirm, setDeleteConfirm] = useState<number | null>(null);
|
||||
const [formError, setFormError] = useState<string | null>(null);
|
||||
const deleteDialogRef = useFocusTrap<HTMLDivElement>(deleteConfirm !== null, {
|
||||
onEscape: () => setDeleteConfirm(null),
|
||||
});
|
||||
|
||||
// Queries
|
||||
const {
|
||||
@@ -248,8 +252,15 @@ export default function AdminRoles() {
|
||||
onClick={() => setDeleteConfirm(null)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="relative w-full max-w-sm rounded-xl border border-dark-700 bg-dark-800 p-6">
|
||||
<h3 className="mb-2 text-lg font-semibold text-dark-100">
|
||||
<div
|
||||
ref={deleteDialogRef}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="role-delete-title"
|
||||
tabIndex={-1}
|
||||
className="relative w-full max-w-sm rounded-xl border border-dark-700 bg-dark-800 p-6"
|
||||
>
|
||||
<h3 id="role-delete-title" className="mb-2 text-lg font-semibold text-dark-100">
|
||||
{t('admin.roles.confirm.title')}
|
||||
</h3>
|
||||
<p className="mb-6 text-dark-400">{t('admin.roles.confirm.text')}</p>
|
||||
|
||||
Reference in New Issue
Block a user