diff --git a/frontend/src/components/clients/ClientTrafficCell.tsx b/frontend/src/components/clients/ClientTrafficCell.tsx index ed2a5f3fb..a99f643da 100644 --- a/frontend/src/components/clients/ClientTrafficCell.tsx +++ b/frontend/src/components/clients/ClientTrafficCell.tsx @@ -64,6 +64,7 @@ export default function ClientTrafficCell({ {SizeFormatter.sizeFormat(display.used)} {display.isUnlimited ? ( - + ) : ( diff --git a/frontend/src/components/clients/ConfigBlock.css b/frontend/src/components/clients/ConfigBlock.css index c0b4193df..5a7567786 100644 --- a/frontend/src/components/clients/ConfigBlock.css +++ b/frontend/src/components/clients/ConfigBlock.css @@ -12,6 +12,10 @@ min-width: 0; } +body.light .config-block .ant-tag.ant-tag-filled.ant-tag-gold { + color: #874d00; +} + .config-block .ant-collapse-extra { display: flex; align-items: center; diff --git a/frontend/src/components/clients/ConfigBlock.tsx b/frontend/src/components/clients/ConfigBlock.tsx index 71bc6f5b9..dc7b87ac3 100644 --- a/frontend/src/components/clients/ConfigBlock.tsx +++ b/frontend/src/components/clients/ConfigBlock.tsx @@ -68,6 +68,7 @@ export default function ConfigBlock({ {messageContextHolder} { textareaRef.current = (el as unknown as { resizableTextArea?: { textArea: HTMLTextAreaElement } })?.resizableTextArea?.textArea ?? null; }} + aria-label={title} value={value} onChange={(e) => setValue(e.target.value)} autoSize={{ minRows: 10, maxRows: 20 }} @@ -80,6 +81,7 @@ export default function PromptModal({ ) : ( setValue(e.target.value)} onKeyDown={onKeydown} diff --git a/frontend/src/components/feedback/TextModal.tsx b/frontend/src/components/feedback/TextModal.tsx index 978f445a7..fcb73b218 100644 --- a/frontend/src/components/feedback/TextModal.tsx +++ b/frontend/src/components/feedback/TextModal.tsx @@ -75,6 +75,7 @@ export default function TextModal({ open, onClose, title, content, fileName = '' ) : ( (function JsonEd doc: value, extensions: [ basicSetup, + EditorView.contentAttributes.of({ 'aria-label': t('jsonEditor') }), keymap.of([indentWithTab]), json(), linter(jsonParseLinter()), diff --git a/frontend/src/components/form/rhf/FormField.tsx b/frontend/src/components/form/rhf/FormField.tsx index 0645d2418..89c1245e7 100644 --- a/frontend/src/components/form/rhf/FormField.tsx +++ b/frontend/src/components/form/rhf/FormField.tsx @@ -1,4 +1,4 @@ -import { cloneElement } from 'react'; +import { cloneElement, useId } from 'react'; import type { CSSProperties, ReactElement, ReactNode } from 'react'; import { Controller } from 'react-hook-form'; import type { Control, ControllerProps, FieldValues, Path } from 'react-hook-form'; @@ -48,6 +48,9 @@ export function FormField({ }: FormFieldProps) { const { t } = useTranslation(); const dottedName = toDotted(name) as Path; + const generatedId = useId(); + const explicitId = (children as ReactElement<{ id?: string }>).props.id; + const fieldId = explicitId ?? generatedId; return ( ({ ? t(fieldState.error.message, { defaultValue: fieldState.error.message }) : undefined; const childProps: Record = { + id: fieldId, [valueProp]: displayValue, onChange: (...args: unknown[]) => { const raw = normalizeAntdOnChange(args, valueProp); @@ -73,6 +77,7 @@ export function FormField({ return ( ( - + extra: ({ value, onChange, ariaLabel }) => ( + ), }, { key: 'memory.high', label: 'eventMemoryHigh', settingKey: 'smtpMemory', - extra: ({ value, onChange }) => ( - + extra: ({ value, onChange, ariaLabel }) => ( + ), }, ], diff --git a/frontend/src/components/ui/notifications/NotificationGroup.tsx b/frontend/src/components/ui/notifications/NotificationGroup.tsx index a9c881bac..aec981105 100644 --- a/frontend/src/components/ui/notifications/NotificationGroup.tsx +++ b/frontend/src/components/ui/notifications/NotificationGroup.tsx @@ -51,6 +51,7 @@ export function NotificationGroup({ config, selected, onToggle, onToggleAll, all {event.extra?.({ value: Number((allSetting as unknown as Record)[event.settingKey]) || 0, onChange: (v) => updateSetting({ [event.settingKey]: v }), + ariaLabel: t(`pages.settings.${event.label}`), })} ))} diff --git a/frontend/src/components/ui/notifications/TelegramNotifications.tsx b/frontend/src/components/ui/notifications/TelegramNotifications.tsx index 2ce63c4b1..21ba70c0b 100644 --- a/frontend/src/components/ui/notifications/TelegramNotifications.tsx +++ b/frontend/src/components/ui/notifications/TelegramNotifications.tsx @@ -37,16 +37,16 @@ const GROUPS: NotificationGroupConfig[] = [ key: 'cpu.high', label: 'eventCPUHigh', settingKey: 'tgCpu', - extra: ({ value, onChange }) => ( - + extra: ({ value, onChange, ariaLabel }) => ( + ), }, { key: 'memory.high', label: 'eventMemoryHigh', settingKey: 'tgMemory', - extra: ({ value, onChange }) => ( - + extra: ({ value, onChange, ariaLabel }) => ( + ), }, ], diff --git a/frontend/src/components/ui/notifications/types.ts b/frontend/src/components/ui/notifications/types.ts index baff64b95..208ee77a3 100644 --- a/frontend/src/components/ui/notifications/types.ts +++ b/frontend/src/components/ui/notifications/types.ts @@ -4,7 +4,7 @@ export interface NotificationEventConfig { key: string; label: string; settingKey: string; - extra?: (props: { value: number; onChange: (v: number | null) => void }) => ReactNode; + extra?: (props: { value: number; onChange: (v: number | null) => void; ariaLabel: string }) => ReactNode; } export interface NotificationGroupConfig { diff --git a/frontend/src/hooks/useTheme.tsx b/frontend/src/hooks/useTheme.tsx index 665e46f18..4ef11a081 100644 --- a/frontend/src/hooks/useTheme.tsx +++ b/frontend/src/hooks/useTheme.tsx @@ -78,13 +78,28 @@ const STATISTIC_TOKENS = { contentFontSize: 17, titleFontSize: 11, }; +const LIGHT_CONTRAST_TOKENS = { + colorTextDescription: 'rgba(0, 0, 0, 0.58)', + colorTextTertiary: 'rgba(0, 0, 0, 0.58)', + colorTextPlaceholder: '#767676', + colorError: '#cf1322', + colorErrorText: '#cf1322', + colorSuccessText: '#237804', +}; +const LIGHT_BUTTON_TOKENS = { + colorPrimary: '#0958d9', + colorPrimaryHover: '#2468e5', + colorPrimaryActive: '#073ea8', +}; export function buildAntdThemeConfig(isDark: boolean, isUltra: boolean): ThemeConfig { if (!isDark) { return { algorithm: antdTheme.defaultAlgorithm, + token: LIGHT_CONTRAST_TOKENS, components: { Statistic: STATISTIC_TOKENS, + Button: LIGHT_BUTTON_TOKENS, }, }; }