mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-26 07:44:59 +03:00
fix(frontend): make the panel usable with screen readers (#6907)
* fix(frontend): make the panel usable with screen readers * fix(frontend): keep mobile tab names and the inbound expiry hint Review of #6907 found two gaps in the screen-reader pass: - On phone-width screens catTabLabel renders only the icon and names the tab by putting aria-label on it, but callers now pass that icon with aria-hidden for the desktop label, so every Settings, Xray and Host category tab lost its name under TalkBack. catTabLabel now clears aria-hidden on the icon it uses as the name. - DateTimePicker forwarded id and aria-label but not aria-describedby, so the inbound expiry hint ("leave blank to never expire") was never attached. It now forwards it on both the Gregorian and Jalali input.
This commit is contained in:
@@ -100,7 +100,7 @@ function DonateButton({ ariaLabel }: { ariaLabel: string }) {
|
||||
aria-label={ariaLabel}
|
||||
title={ariaLabel}
|
||||
>
|
||||
<HeartOutlined />
|
||||
<HeartOutlined aria-hidden />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -115,7 +115,7 @@ function DocsButton({ ariaLabel }: { ariaLabel: string }) {
|
||||
aria-label={ariaLabel}
|
||||
title={ariaLabel}
|
||||
>
|
||||
<ReadOutlined />
|
||||
<ReadOutlined aria-hidden />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ function VersionBadge({ version, collapsed }: { version: string; collapsed?: boo
|
||||
aria-label={`GitHub ${label}`}
|
||||
title={label}
|
||||
>
|
||||
<GithubOutlined />
|
||||
<GithubOutlined aria-hidden />
|
||||
{!collapsed && <span className="sider-version-text">{label}</span>}
|
||||
</a>
|
||||
);
|
||||
@@ -151,7 +151,13 @@ function ThemeCycleButton({
|
||||
onCycle: () => void;
|
||||
ariaLabel: string;
|
||||
}) {
|
||||
const icon = !isDark ? <SunOutlined /> : !isUltra ? <MoonOutlined /> : <MoonFilled />;
|
||||
const icon = !isDark ? (
|
||||
<SunOutlined aria-hidden />
|
||||
) : !isUltra ? (
|
||||
<MoonOutlined aria-hidden />
|
||||
) : (
|
||||
<MoonFilled aria-hidden />
|
||||
);
|
||||
return (
|
||||
<button
|
||||
id={id}
|
||||
@@ -248,42 +254,46 @@ export default function AppSidebar() {
|
||||
const children: NonNullable<MenuProps['items']> = [
|
||||
{
|
||||
key: '/settings#general',
|
||||
icon: <SettingOutlined />,
|
||||
icon: <SettingOutlined aria-hidden />,
|
||||
label: t('pages.settings.panelSettings'),
|
||||
},
|
||||
{
|
||||
key: '/settings#security',
|
||||
icon: <SafetyOutlined />,
|
||||
icon: <SafetyOutlined aria-hidden />,
|
||||
label: t('pages.settings.securitySettings'),
|
||||
},
|
||||
{
|
||||
key: '/settings#telegram',
|
||||
icon: <MessageOutlined />,
|
||||
icon: <MessageOutlined aria-hidden />,
|
||||
label: t('pages.settings.TGBotSettings'),
|
||||
},
|
||||
{ key: '/settings#email', icon: <MailOutlined />, label: t('pages.settings.emailSettings') },
|
||||
{
|
||||
key: '/settings#email',
|
||||
icon: <MailOutlined aria-hidden />,
|
||||
label: t('pages.settings.emailSettings'),
|
||||
},
|
||||
{
|
||||
key: '/settings#discord',
|
||||
icon: <DiscordOutlined />,
|
||||
icon: <DiscordOutlined aria-hidden />,
|
||||
label: t('pages.settings.discordSettings'),
|
||||
},
|
||||
{
|
||||
key: '/settings#subscription',
|
||||
icon: <CloudServerOutlined />,
|
||||
icon: <CloudServerOutlined aria-hidden />,
|
||||
label: t('pages.settings.subSettings'),
|
||||
},
|
||||
];
|
||||
if (showSubFormats) {
|
||||
children.push({
|
||||
key: '/settings#subscription-formats',
|
||||
icon: <CodeOutlined />,
|
||||
icon: <CodeOutlined aria-hidden />,
|
||||
label: t('menu.subFormats'),
|
||||
});
|
||||
}
|
||||
if (showSubBalancers) {
|
||||
children.push({
|
||||
key: '/settings#subscription-balancers',
|
||||
icon: <ApartmentOutlined />,
|
||||
icon: <ApartmentOutlined aria-hidden />,
|
||||
label: t('pages.settings.subBalancers.menu'),
|
||||
});
|
||||
}
|
||||
@@ -292,10 +302,22 @@ export default function AppSidebar() {
|
||||
|
||||
const xrayChildren = useMemo<NonNullable<MenuProps['items']>>(
|
||||
() => [
|
||||
{ key: '/xray#basic', icon: <SettingOutlined />, label: t('pages.xray.basicTemplate') },
|
||||
{ key: '/xray#balancer', icon: <ClusterOutlined />, label: t('pages.xray.Balancers') },
|
||||
{ key: '/xray#dns', icon: <DatabaseOutlined />, label: 'DNS' },
|
||||
{ key: '/xray#advanced', icon: <CodeOutlined />, label: t('pages.xray.advancedTemplate') },
|
||||
{
|
||||
key: '/xray#basic',
|
||||
icon: <SettingOutlined aria-hidden />,
|
||||
label: t('pages.xray.basicTemplate'),
|
||||
},
|
||||
{
|
||||
key: '/xray#balancer',
|
||||
icon: <ClusterOutlined aria-hidden />,
|
||||
label: t('pages.xray.Balancers'),
|
||||
},
|
||||
{ key: '/xray#dns', icon: <DatabaseOutlined aria-hidden />, label: 'DNS' },
|
||||
{
|
||||
key: '/xray#advanced',
|
||||
icon: <CodeOutlined aria-hidden />,
|
||||
label: t('pages.xray.advancedTemplate'),
|
||||
},
|
||||
],
|
||||
[t],
|
||||
);
|
||||
@@ -394,7 +416,7 @@ export default function AppSidebar() {
|
||||
title={t(pinned ? 'menu.unpinSidebar' : 'menu.pinSidebar')}
|
||||
onClick={togglePinned}
|
||||
>
|
||||
{pinned ? <PushpinFilled /> : <PushpinOutlined />}
|
||||
{pinned ? <PushpinFilled aria-hidden /> : <PushpinOutlined aria-hidden />}
|
||||
</button>
|
||||
<DocsButton ariaLabel={t('menu.docs') || 'Documentation'} />
|
||||
<DonateButton ariaLabel={t('menu.donate') || 'Donate'} />
|
||||
@@ -421,7 +443,7 @@ export default function AppSidebar() {
|
||||
aria-label={t('commandPalette.title') || 'Command Palette (Ctrl + K)'}
|
||||
>
|
||||
<span className="sidebar-command-left">
|
||||
<SearchOutlined className="sidebar-command-icon" />
|
||||
<SearchOutlined aria-hidden className="sidebar-command-icon" />
|
||||
<span className="sidebar-command-text">
|
||||
{t('commandPalette.search') || 'Search...'}
|
||||
</span>
|
||||
@@ -488,7 +510,7 @@ export default function AppSidebar() {
|
||||
aria-label={t('close')}
|
||||
onClick={() => setDrawerOpen(false)}
|
||||
>
|
||||
<CloseOutlined />
|
||||
<CloseOutlined aria-hidden />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -503,7 +525,7 @@ export default function AppSidebar() {
|
||||
style={{ margin: '8px 12px 4px', width: 'calc(100% - 24px)' }}
|
||||
>
|
||||
<span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<SearchOutlined className="sidebar-command-icon" />
|
||||
<SearchOutlined aria-hidden className="sidebar-command-icon" />
|
||||
<span>{t('commandPalette.search') || 'Search...'}</span>
|
||||
</span>
|
||||
<span className="sidebar-command-kbd">
|
||||
@@ -547,7 +569,7 @@ export default function AppSidebar() {
|
||||
aria-label={t('menu.openMenu')}
|
||||
onClick={() => setDrawerOpen(true)}
|
||||
>
|
||||
<MenuOutlined />
|
||||
<MenuOutlined aria-hidden />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user