mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-25 15:25:01 +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:
@@ -67,7 +67,11 @@ export default function DiscordTab({ allSetting, updateSetting }: DiscordTabProp
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.panelSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -138,7 +142,7 @@ export default function DiscordTab({ allSetting, updateSetting }: DiscordTabProp
|
||||
<Space orientation="vertical" size={8} style={{ width: '100%', marginTop: 16 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
icon={<SendOutlined aria-hidden />}
|
||||
loading={testLoading}
|
||||
disabled={!allSetting.discordBotEnable}
|
||||
onClick={handleTestDiscord}
|
||||
@@ -159,7 +163,11 @@ export default function DiscordTab({ allSetting, updateSetting }: DiscordTabProp
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(<BellOutlined />, t('pages.settings.notifications'), isMobile),
|
||||
label: catTabLabel(
|
||||
<BellOutlined aria-hidden />,
|
||||
t('pages.settings.notifications'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
|
||||
@@ -56,7 +56,11 @@ export default function EmailTab({ allSetting, updateSetting }: EmailTabProps) {
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.smtpSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.smtpSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -184,7 +188,7 @@ export default function EmailTab({ allSetting, updateSetting }: EmailTabProps) {
|
||||
<Space orientation="vertical" size={8} style={{ width: '100%', marginTop: 16 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
icon={<SendOutlined aria-hidden />}
|
||||
loading={testLoading}
|
||||
onClick={handleTestSmtp}
|
||||
>
|
||||
@@ -213,7 +217,11 @@ export default function EmailTab({ allSetting, updateSetting }: EmailTabProps) {
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(<MailOutlined />, t('pages.settings.emailNotifications'), isMobile),
|
||||
label: catTabLabel(
|
||||
<MailOutlined aria-hidden />,
|
||||
t('pages.settings.emailNotifications'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
|
||||
@@ -180,7 +180,11 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.panelSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -349,7 +353,11 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(<BellOutlined />, t('pages.settings.notifications'), isMobile),
|
||||
label: catTabLabel(
|
||||
<BellOutlined aria-hidden />,
|
||||
t('pages.settings.notifications'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -386,7 +394,11 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: catTabLabel(<SafetyCertificateOutlined />, t('pages.settings.certs'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SafetyCertificateOutlined aria-hidden />,
|
||||
t('pages.settings.certs'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -414,7 +426,11 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: catTabLabel(<GlobalOutlined />, t('pages.settings.externalTraffic'), isMobile),
|
||||
label: catTabLabel(
|
||||
<GlobalOutlined aria-hidden />,
|
||||
t('pages.settings.externalTraffic'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -443,7 +459,11 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: catTabLabel(<ClockCircleOutlined />, t('pages.settings.dateAndTime'), isMobile),
|
||||
label: catTabLabel(
|
||||
<ClockCircleOutlined aria-hidden />,
|
||||
t('pages.settings.dateAndTime'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -476,7 +496,7 @@ export default function GeneralTab({ allSetting, updateSetting }: GeneralTabProp
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: catTabLabel(<ApartmentOutlined />, 'LDAP', isMobile),
|
||||
label: catTabLabel(<ApartmentOutlined aria-hidden />, 'LDAP', isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem paddings="small" title={t('pages.settings.ldap.enable')}>
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function HappSettingsContent({
|
||||
{
|
||||
key: 'routing',
|
||||
label: catTabLabel(
|
||||
<BranchesOutlined />,
|
||||
<BranchesOutlined aria-hidden />,
|
||||
t('pages.settings.subHappGroupRouting'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -136,7 +136,7 @@ export default function HappSettingsContent({
|
||||
title={t('pages.settings.subHappVisualBuilder')}
|
||||
description={t('pages.settings.subHappVisualBuilderDesc')}
|
||||
>
|
||||
<Button icon={<BuildOutlined />} onClick={() => setIsModalOpen(true)}>
|
||||
<Button icon={<BuildOutlined aria-hidden />} onClick={() => setIsModalOpen(true)}>
|
||||
{t('pages.settings.subHappVisualBuilder')}
|
||||
</Button>
|
||||
</SettingListItem>
|
||||
@@ -182,7 +182,7 @@ export default function HappSettingsContent({
|
||||
{
|
||||
key: 'appearance',
|
||||
label: catTabLabel(
|
||||
<DesktopOutlined />,
|
||||
<DesktopOutlined aria-hidden />,
|
||||
t('pages.settings.subHappGroupThemes'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -284,6 +284,7 @@ export default function HappSettingsContent({
|
||||
>
|
||||
<Space orientation="vertical" style={{ width: '100%' }}>
|
||||
<Input
|
||||
aria-label={t('pages.settings.subHappColorProfile')}
|
||||
value={allSetting.subHappColorProfile}
|
||||
placeholder='{"serverRowBackgroundColor":"#21003D67"} or resetcolors'
|
||||
onChange={(e) => updateSetting({ subHappColorProfile: e.target.value })}
|
||||
@@ -326,7 +327,7 @@ export default function HappSettingsContent({
|
||||
{
|
||||
key: 'network',
|
||||
label: catTabLabel(
|
||||
<ThunderboltOutlined />,
|
||||
<ThunderboltOutlined aria-hidden />,
|
||||
t('pages.settings.subHappGroupNetwork'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -493,7 +494,7 @@ export default function HappSettingsContent({
|
||||
{
|
||||
key: 'failover',
|
||||
label: catTabLabel(
|
||||
<CloudSyncOutlined />,
|
||||
<CloudSyncOutlined aria-hidden />,
|
||||
t('pages.settings.subHappGroupFailover'),
|
||||
isMobile,
|
||||
),
|
||||
|
||||
@@ -53,7 +53,11 @@ export default function IncySettingsContent({
|
||||
items={[
|
||||
{
|
||||
key: 'app',
|
||||
label: catTabLabel(<AppstoreOutlined />, t('pages.settings.subIncyGroupApp'), isMobile),
|
||||
label: catTabLabel(
|
||||
<AppstoreOutlined aria-hidden />,
|
||||
t('pages.settings.subIncyGroupApp'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -127,7 +131,7 @@ export default function IncySettingsContent({
|
||||
{
|
||||
key: 'banners',
|
||||
label: catTabLabel(
|
||||
<NotificationOutlined />,
|
||||
<NotificationOutlined aria-hidden />,
|
||||
t('pages.settings.subIncyGroupBanners'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -196,7 +200,7 @@ export default function IncySettingsContent({
|
||||
{
|
||||
key: 'privacy',
|
||||
label: catTabLabel(
|
||||
<SafetyOutlined />,
|
||||
<SafetyOutlined aria-hidden />,
|
||||
t('pages.settings.subIncyGroupPrivacy'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -291,7 +295,7 @@ export default function IncySettingsContent({
|
||||
{
|
||||
key: 'network',
|
||||
label: catTabLabel(
|
||||
<ThunderboltOutlined />,
|
||||
<ThunderboltOutlined aria-hidden />,
|
||||
t('pages.settings.subIncyGroupNetwork'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -450,7 +454,7 @@ export default function IncySettingsContent({
|
||||
{
|
||||
key: 'routing',
|
||||
label: catTabLabel(
|
||||
<BranchesOutlined />,
|
||||
<BranchesOutlined aria-hidden />,
|
||||
t('pages.settings.subIncyGroupRouting'),
|
||||
isMobile,
|
||||
),
|
||||
|
||||
@@ -8,6 +8,7 @@ interface SecretInputProps {
|
||||
placeholder: string;
|
||||
onChange: (value: string) => void;
|
||||
onClearArmedChange: (armed: boolean) => void;
|
||||
'aria-labelledby'?: string;
|
||||
}
|
||||
|
||||
export default function SecretInput({
|
||||
@@ -17,11 +18,13 @@ export default function SecretInput({
|
||||
placeholder,
|
||||
onChange,
|
||||
onClearArmedChange,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
}: SecretInputProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Space.Compact style={{ width: '100%' }}>
|
||||
<Input.Password
|
||||
aria-labelledby={ariaLabelledBy}
|
||||
value={value}
|
||||
placeholder={configured && !clearArmed ? placeholder : ''}
|
||||
onChange={(e) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useId, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
Button,
|
||||
@@ -74,6 +74,7 @@ const TFA_INITIAL: TfaState = {
|
||||
|
||||
export default function SecurityTab({ allSetting, updateSetting, saveSetting }: SecurityTabProps) {
|
||||
const { t } = useTranslation();
|
||||
const uid = useId();
|
||||
const { isMobile } = useMediaQuery();
|
||||
const [modal, modalContextHolder] = Modal.useModal();
|
||||
const [messageApi, messageContextHolder] = message.useMessage();
|
||||
@@ -308,7 +309,11 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<UserOutlined />, t('pages.settings.security.admin'), isMobile),
|
||||
label: catTabLabel(
|
||||
<UserOutlined aria-hidden />,
|
||||
t('pages.settings.security.admin'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem paddings="small" title={t('pages.settings.oldUsername')}>
|
||||
@@ -351,7 +356,7 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(
|
||||
<SafetyOutlined />,
|
||||
<SafetyOutlined aria-hidden />,
|
||||
t('pages.settings.security.twoFactor'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -367,7 +372,7 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: catTabLabel(<ApiOutlined />, t('pages.nodes.apiToken'), isMobile),
|
||||
label: catTabLabel(<ApiOutlined aria-hidden />, t('pages.nodes.apiToken'), isMobile),
|
||||
children: (
|
||||
<div className="api-token-section">
|
||||
<div className="api-token-header">
|
||||
@@ -387,7 +392,9 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
<div className="api-token-row-head">
|
||||
<div className="api-token-name-wrap">
|
||||
<div className="api-token-name-line">
|
||||
<span className="api-token-name">{row.name}</span>
|
||||
<span id={`${uid}-token-${row.id}`} className="api-token-name">
|
||||
{row.name}
|
||||
</span>
|
||||
<Tag color={scopeMeta[row.scope].color}>
|
||||
{scopeMeta[row.scope].label}
|
||||
</Tag>
|
||||
@@ -399,6 +406,7 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
<div className="api-token-actions">
|
||||
<Switch
|
||||
size="small"
|
||||
aria-labelledby={`${uid}-token-${row.id}`}
|
||||
checked={row.enabled}
|
||||
onChange={() => toggleTokenEnabled(row)}
|
||||
/>
|
||||
@@ -431,8 +439,13 @@ export default function SecurityTab({ allSetting, updateSetting, saveSetting }:
|
||||
onCancel={() => setCreateOpen(false)}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label={t('pages.settings.security.apiTokenName') || 'Name'} required>
|
||||
<Form.Item
|
||||
label={t('pages.settings.security.apiTokenName') || 'Name'}
|
||||
htmlFor={`${uid}-tokenName`}
|
||||
required
|
||||
>
|
||||
<Input
|
||||
id={`${uid}-tokenName`}
|
||||
value={createName}
|
||||
maxLength={64}
|
||||
placeholder={
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useEffect, useId, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Form, Input, InputNumber, Modal, Select, Switch, message } from 'antd';
|
||||
import { Controller, FormProvider, useForm, useWatch } from 'react-hook-form';
|
||||
@@ -59,6 +59,7 @@ export default function SubBalancerFormModal({
|
||||
onConfirm,
|
||||
}: SubBalancerFormModalProps) {
|
||||
const { t } = useTranslation();
|
||||
const uid = useId();
|
||||
const [messageApi, messageContextHolder] = message.useMessage();
|
||||
const methods = useForm<SubBalancerFormValues>({ defaultValues: initialState(balancer) });
|
||||
const isEdit = balancer != null;
|
||||
@@ -199,6 +200,7 @@ export default function SubBalancerFormModal({
|
||||
return (
|
||||
<div key={id} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span
|
||||
id={`${uid}-weight-${id}`}
|
||||
title={option?.title}
|
||||
style={{
|
||||
minWidth: 0,
|
||||
@@ -214,6 +216,8 @@ export default function SubBalancerFormModal({
|
||||
name={`memberWeights.${id}`}
|
||||
render={({ field }) => (
|
||||
<InputNumber
|
||||
aria-labelledby={`${uid}-weight-${id}`}
|
||||
aria-describedby={`${uid}-weights-hint`}
|
||||
min={0.1}
|
||||
step={0.1}
|
||||
precision={1}
|
||||
@@ -227,6 +231,9 @@ export default function SubBalancerFormModal({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<span id={`${uid}-weights-hint`} hidden>
|
||||
{t('pages.settings.subBalancers.weightsHelp')}
|
||||
</span>
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
|
||||
@@ -156,7 +156,12 @@ export default function SubscriptionBalancersTab({
|
||||
width: 80,
|
||||
align: 'center' as const,
|
||||
render: (_: unknown, r: SubBalancer) => (
|
||||
<Switch size="small" checked={r.enabled} onChange={() => toggleEnabled(r)} />
|
||||
<Switch
|
||||
size="small"
|
||||
aria-label={t('pages.settings.subBalancers.enabled')}
|
||||
checked={r.enabled}
|
||||
onChange={() => toggleEnabled(r)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -168,7 +173,7 @@ export default function SubscriptionBalancersTab({
|
||||
<Button
|
||||
aria-label={t('edit')}
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
icon={<EditOutlined aria-hidden />}
|
||||
title={t('edit')}
|
||||
onClick={() => {
|
||||
setEditing(r);
|
||||
@@ -181,7 +186,12 @@ export default function SubscriptionBalancersTab({
|
||||
cancelText={t('cancel')}
|
||||
onConfirm={() => remove(r.id)}
|
||||
>
|
||||
<Button aria-label={t('delete')} size="small" danger icon={<DeleteOutlined />} />
|
||||
<Button
|
||||
aria-label={t('delete')}
|
||||
size="small"
|
||||
danger
|
||||
icon={<DeleteOutlined aria-hidden />}
|
||||
/>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
@@ -212,7 +222,7 @@ export default function SubscriptionBalancersTab({
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
icon={<PlusOutlined aria-hidden />}
|
||||
onClick={() => {
|
||||
setEditing(null);
|
||||
setModalOpen(true);
|
||||
@@ -332,7 +342,7 @@ export default function SubscriptionBalancersTab({
|
||||
{
|
||||
key: 'balancers',
|
||||
label: catTabLabel(
|
||||
<DeploymentUnitOutlined />,
|
||||
<DeploymentUnitOutlined aria-hidden />,
|
||||
t('pages.settings.subBalancers.tabBalancers'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -341,7 +351,7 @@ export default function SubscriptionBalancersTab({
|
||||
{
|
||||
key: 'observatory',
|
||||
label: catTabLabel(
|
||||
<RadarChartOutlined />,
|
||||
<RadarChartOutlined aria-hidden />,
|
||||
t('pages.settings.subBalancers.tabObservatory'),
|
||||
isMobile,
|
||||
),
|
||||
|
||||
@@ -158,7 +158,11 @@ export default function SubscriptionFormatsTab({
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.panelSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<div className="subscription-format-sections">
|
||||
{allSetting.subJsonEnable && (
|
||||
@@ -167,7 +171,7 @@ export default function SubscriptionFormatsTab({
|
||||
className="subscription-format-card"
|
||||
title={
|
||||
<span className="subscription-format-card-title">
|
||||
<FileTextOutlined />
|
||||
<FileTextOutlined aria-hidden />
|
||||
{t('pages.settings.subJsonEnableTitle')}
|
||||
</span>
|
||||
}
|
||||
@@ -261,7 +265,7 @@ export default function SubscriptionFormatsTab({
|
||||
className="subscription-format-card"
|
||||
title={
|
||||
<span className="subscription-format-card-title">
|
||||
<NodeIndexOutlined />
|
||||
<NodeIndexOutlined aria-hidden />
|
||||
{t('pages.settings.subClashEnableTitle')}
|
||||
</span>
|
||||
}
|
||||
@@ -322,7 +326,7 @@ export default function SubscriptionFormatsTab({
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(
|
||||
<RocketOutlined />,
|
||||
<RocketOutlined aria-hidden />,
|
||||
t('pages.settings.subFormats.finalMask'),
|
||||
isMobile,
|
||||
),
|
||||
@@ -342,7 +346,7 @@ export default function SubscriptionFormatsTab({
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: catTabLabel(<PartitionOutlined />, t('pages.settings.mux'), isMobile),
|
||||
label: catTabLabel(<PartitionOutlined aria-hidden />, t('pages.settings.mux'), isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -396,7 +400,7 @@ export default function SubscriptionFormatsTab({
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: catTabLabel(<SendOutlined />, t('pages.settings.direct'), isMobile),
|
||||
label: catTabLabel(<SendOutlined aria-hidden />, t('pages.settings.direct'), isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -445,7 +449,7 @@ export default function SubscriptionFormatsTab({
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: catTabLabel(<StopOutlined />, t('pages.settings.block'), isMobile),
|
||||
label: catTabLabel(<StopOutlined aria-hidden />, t('pages.settings.block'), isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
|
||||
@@ -48,7 +48,11 @@ export default function SubscriptionGeneralTab({
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.panelSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -153,7 +157,11 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(<InfoCircleOutlined />, t('pages.settings.information'), isMobile),
|
||||
label: catTabLabel(
|
||||
<InfoCircleOutlined aria-hidden />,
|
||||
t('pages.settings.information'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -273,7 +281,7 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: catTabLabel(<IdcardOutlined />, t('pages.settings.profile'), isMobile),
|
||||
label: catTabLabel(<IdcardOutlined aria-hidden />, t('pages.settings.profile'), isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -379,7 +387,11 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: catTabLabel(<SafetyCertificateOutlined />, t('pages.settings.certs'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SafetyCertificateOutlined aria-hidden />,
|
||||
t('pages.settings.certs'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -407,7 +419,7 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: catTabLabel(<BranchesOutlined />, 'Happ', isMobile),
|
||||
label: catTabLabel(<BranchesOutlined aria-hidden />, 'Happ', isMobile),
|
||||
children: (
|
||||
<HappSettingsContent
|
||||
allSetting={allSetting}
|
||||
@@ -419,7 +431,7 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: catTabLabel(<NodeIndexOutlined />, 'Clash / Mihomo', isMobile),
|
||||
label: catTabLabel(<NodeIndexOutlined aria-hidden />, 'Clash / Mihomo', isMobile),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -452,7 +464,7 @@ export default function SubscriptionGeneralTab({
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: catTabLabel(<CompassOutlined />, 'Incy', isMobile),
|
||||
label: catTabLabel(<CompassOutlined aria-hidden />, 'Incy', isMobile),
|
||||
children: (
|
||||
<IncySettingsContent
|
||||
allSetting={allSetting}
|
||||
|
||||
@@ -65,7 +65,11 @@ export default function TelegramTab({ allSetting, updateSetting }: TelegramTabPr
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: catTabLabel(<SettingOutlined />, t('pages.settings.panelSettings'), isMobile),
|
||||
label: catTabLabel(
|
||||
<SettingOutlined aria-hidden />,
|
||||
t('pages.settings.panelSettings'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
@@ -133,7 +137,7 @@ export default function TelegramTab({ allSetting, updateSetting }: TelegramTabPr
|
||||
<Space orientation="vertical" size={8} style={{ width: '100%', marginTop: 16 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<SendOutlined />}
|
||||
icon={<SendOutlined aria-hidden />}
|
||||
loading={testLoading}
|
||||
onClick={handleTestTgBot}
|
||||
>
|
||||
@@ -153,7 +157,11 @@ export default function TelegramTab({ allSetting, updateSetting }: TelegramTabPr
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: catTabLabel(<BellOutlined />, t('pages.settings.notifications'), isMobile),
|
||||
label: catTabLabel(
|
||||
<BellOutlined aria-hidden />,
|
||||
t('pages.settings.notifications'),
|
||||
isMobile,
|
||||
),
|
||||
children: (
|
||||
<>
|
||||
<SettingListItem
|
||||
|
||||
@@ -6,9 +6,13 @@ import { Tooltip } from 'antd';
|
||||
old top tab bar's icons-only behaviour. */
|
||||
export function catTabLabel(icon: ReactNode, text: ReactNode, iconsOnly: boolean): ReactNode {
|
||||
if (iconsOnly) {
|
||||
// Callers hide the icon for the desktop label; here it is the tab's only name.
|
||||
const labelledIcon =
|
||||
typeof text === 'string' && isValidElement(icon)
|
||||
? cloneElement(icon as ReactElement<{ 'aria-label'?: string }>, { 'aria-label': text })
|
||||
? cloneElement(icon as ReactElement<{ 'aria-label'?: string; 'aria-hidden'?: boolean }>, {
|
||||
'aria-label': text,
|
||||
'aria-hidden': undefined,
|
||||
})
|
||||
: icon;
|
||||
return <Tooltip title={text}>{labelledIcon}</Tooltip>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user