Merge pull request #5219 from ConnectAI-E/feature/access

修复ChatGPTNextWeb页面的无障碍问题
This commit is contained in:
Dogtiti 2024-08-08 13:59:16 +08:00 committed by GitHub
commit 036358de7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 108 additions and 5 deletions

View File

@ -18,6 +18,7 @@ export function IconButton(props: {
tabIndex?: number; tabIndex?: number;
autoFocus?: boolean; autoFocus?: boolean;
style?: CSSProperties; style?: CSSProperties;
aria?: string;
}) { }) {
return ( return (
<button <button
@ -34,9 +35,11 @@ export function IconButton(props: {
tabIndex={props.tabIndex} tabIndex={props.tabIndex}
autoFocus={props.autoFocus} autoFocus={props.autoFocus}
style={props.style} style={props.style}
aria-label={props.aria}
> >
{props.icon && ( {props.icon && (
<div <div
aria-label={props.text || props.title}
className={ className={
styles["icon-button-icon"] + styles["icon-button-icon"] +
` ${props.type === "primary" && "no-dark"}` ` ${props.type === "primary" && "no-dark"}`
@ -47,7 +50,12 @@ export function IconButton(props: {
)} )}
{props.text && ( {props.text && (
<div className={styles["icon-button-text"]}>{props.text}</div> <div
aria-label={props.text || props.title}
className={styles["icon-button-text"]}
>
{props.text}
</div>
)} )}
</button> </button>
); );

View File

@ -1337,6 +1337,8 @@ function _Chat() {
<IconButton <IconButton
icon={<RenameIcon />} icon={<RenameIcon />}
bordered bordered
title={Locale.Chat.EditMessage.Title}
aria={Locale.Chat.EditMessage.Title}
onClick={() => setIsEditingMessage(true)} onClick={() => setIsEditingMessage(true)}
/> />
</div> </div>
@ -1356,6 +1358,8 @@ function _Chat() {
<IconButton <IconButton
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered bordered
title={Locale.Chat.Actions.FullScreen}
aria={Locale.Chat.Actions.FullScreen}
onClick={() => { onClick={() => {
config.update( config.update(
(config) => (config.tightBorder = !config.tightBorder), (config) => (config.tightBorder = !config.tightBorder),
@ -1407,6 +1411,7 @@ function _Chat() {
<div className={styles["chat-message-edit"]}> <div className={styles["chat-message-edit"]}>
<IconButton <IconButton
icon={<EditIcon />} icon={<EditIcon />}
aria={Locale.Chat.Actions.Edit}
onClick={async () => { onClick={async () => {
const newMessage = await showPrompt( const newMessage = await showPrompt(
Locale.Chat.Actions.Edit, Locale.Chat.Actions.Edit,

View File

@ -9,6 +9,7 @@ interface InputRangeProps {
min: string; min: string;
max: string; max: string;
step: string; step: string;
aria: string;
} }
export function InputRange({ export function InputRange({
@ -19,11 +20,13 @@ export function InputRange({
min, min,
max, max,
step, step,
aria,
}: InputRangeProps) { }: InputRangeProps) {
return ( return (
<div className={styles["input-range"] + ` ${className ?? ""}`}> <div className={styles["input-range"] + ` ${className ?? ""}`}>
{title || value} {title || value}
<input <input
aria-label={aria}
type="range" type="range"
title={title} title={title}
value={value} value={value}

View File

@ -127,6 +127,8 @@ export function MaskConfig(props: {
onClose={() => setShowPicker(false)} onClose={() => setShowPicker(false)}
> >
<div <div
tabIndex={0}
aria-label={Locale.Mask.Config.Avatar}
onClick={() => setShowPicker(true)} onClick={() => setShowPicker(true)}
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
> >
@ -139,6 +141,7 @@ export function MaskConfig(props: {
</ListItem> </ListItem>
<ListItem title={Locale.Mask.Config.Name}> <ListItem title={Locale.Mask.Config.Name}>
<input <input
aria-label={Locale.Mask.Config.Name}
type="text" type="text"
value={props.mask.name} value={props.mask.name}
onInput={(e) => onInput={(e) =>
@ -153,6 +156,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.HideContext.SubTitle} subTitle={Locale.Mask.Config.HideContext.SubTitle}
> >
<input <input
aria-label={Locale.Mask.Config.HideContext.Title}
type="checkbox" type="checkbox"
checked={props.mask.hideContext} checked={props.mask.hideContext}
onChange={(e) => { onChange={(e) => {
@ -169,6 +173,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.Share.SubTitle} subTitle={Locale.Mask.Config.Share.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Mask.Config.Share.Title}
icon={<CopyIcon />} icon={<CopyIcon />}
text={Locale.Mask.Config.Share.Action} text={Locale.Mask.Config.Share.Action}
onClick={copyMaskLink} onClick={copyMaskLink}
@ -182,6 +187,7 @@ export function MaskConfig(props: {
subTitle={Locale.Mask.Config.Sync.SubTitle} subTitle={Locale.Mask.Config.Sync.SubTitle}
> >
<input <input
aria-label={Locale.Mask.Config.Sync.Title}
type="checkbox" type="checkbox"
checked={props.mask.syncGlobalConfig} checked={props.mask.syncGlobalConfig}
onChange={async (e) => { onChange={async (e) => {

View File

@ -17,6 +17,7 @@ export function ModelConfigList(props: {
<> <>
<ListItem title={Locale.Settings.Model}> <ListItem title={Locale.Settings.Model}>
<Select <Select
aria-label={Locale.Settings.Model}
value={value} value={value}
onChange={(e) => { onChange={(e) => {
const [model, providerName] = e.currentTarget.value.split("@"); const [model, providerName] = e.currentTarget.value.split("@");
@ -40,6 +41,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.Temperature.SubTitle} subTitle={Locale.Settings.Temperature.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.Temperature.Title}
value={props.modelConfig.temperature?.toFixed(1)} value={props.modelConfig.temperature?.toFixed(1)}
min="0" min="0"
max="1" // lets limit it to 0-1 max="1" // lets limit it to 0-1
@ -59,6 +61,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.TopP.SubTitle} subTitle={Locale.Settings.TopP.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.TopP.Title}
value={(props.modelConfig.top_p ?? 1).toFixed(1)} value={(props.modelConfig.top_p ?? 1).toFixed(1)}
min="0" min="0"
max="1" max="1"
@ -78,6 +81,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.MaxTokens.SubTitle} subTitle={Locale.Settings.MaxTokens.SubTitle}
> >
<input <input
aria-label={Locale.Settings.MaxTokens.Title}
type="number" type="number"
min={1024} min={1024}
max={512000} max={512000}
@ -100,6 +104,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.PresencePenalty.SubTitle} subTitle={Locale.Settings.PresencePenalty.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.PresencePenalty.Title}
value={props.modelConfig.presence_penalty?.toFixed(1)} value={props.modelConfig.presence_penalty?.toFixed(1)}
min="-2" min="-2"
max="2" max="2"
@ -121,6 +126,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.FrequencyPenalty.SubTitle} subTitle={Locale.Settings.FrequencyPenalty.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.FrequencyPenalty.Title}
value={props.modelConfig.frequency_penalty?.toFixed(1)} value={props.modelConfig.frequency_penalty?.toFixed(1)}
min="-2" min="-2"
max="2" max="2"
@ -142,6 +148,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.InjectSystemPrompts.SubTitle} subTitle={Locale.Settings.InjectSystemPrompts.SubTitle}
> >
<input <input
aria-label={Locale.Settings.InjectSystemPrompts.Title}
type="checkbox" type="checkbox"
checked={props.modelConfig.enableInjectSystemPrompts} checked={props.modelConfig.enableInjectSystemPrompts}
onChange={(e) => onChange={(e) =>
@ -159,6 +166,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.InputTemplate.SubTitle} subTitle={Locale.Settings.InputTemplate.SubTitle}
> >
<input <input
aria-label={Locale.Settings.InputTemplate.Title}
type="text" type="text"
value={props.modelConfig.template} value={props.modelConfig.template}
onChange={(e) => onChange={(e) =>
@ -175,6 +183,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.HistoryCount.SubTitle} subTitle={Locale.Settings.HistoryCount.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.HistoryCount.Title}
title={props.modelConfig.historyMessageCount.toString()} title={props.modelConfig.historyMessageCount.toString()}
value={props.modelConfig.historyMessageCount} value={props.modelConfig.historyMessageCount}
min="0" min="0"
@ -193,6 +202,7 @@ export function ModelConfigList(props: {
subTitle={Locale.Settings.CompressThreshold.SubTitle} subTitle={Locale.Settings.CompressThreshold.SubTitle}
> >
<input <input
aria-label={Locale.Settings.CompressThreshold.Title}
type="number" type="number"
min={500} min={500}
max={4000} max={4000}
@ -208,6 +218,7 @@ export function ModelConfigList(props: {
</ListItem> </ListItem>
<ListItem title={Locale.Memory.Title} subTitle={Locale.Memory.Send}> <ListItem title={Locale.Memory.Title} subTitle={Locale.Memory.Send}>
<input <input
aria-label={Locale.Memory.Title}
type="checkbox" type="checkbox"
checked={props.modelConfig.sendMemory} checked={props.modelConfig.sendMemory}
onChange={(e) => onChange={(e) =>

View File

@ -192,6 +192,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<Select <Select
aria-label={item.name}
value={props.data[item.value]} value={props.data[item.value]}
onChange={(e) => { onChange={(e) => {
props.onChange(item.value, e.currentTarget.value); props.onChange(item.value, e.currentTarget.value);
@ -216,6 +217,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<input <input
aria-label={item.name}
type="number" type="number"
min={item.min} min={item.min}
max={item.max} max={item.max}
@ -235,6 +237,7 @@ export function ControlParam(props: {
required={item.required} required={item.required}
> >
<input <input
aria-label={item.name}
type="text" type="text"
value={props.data[item.value]} value={props.data[item.value]}
style={{ maxWidth: "100%", width: "100%" }} style={{ maxWidth: "100%", width: "100%" }}

View File

@ -133,6 +133,7 @@ export function Sd() {
{showMaxIcon && ( {showMaxIcon && (
<div className="window-action-button"> <div className="window-action-button">
<IconButton <IconButton
aria={Locale.Chat.Actions.FullScreen}
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />} icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered bordered
onClick={() => { onClick={() => {

View File

@ -246,6 +246,7 @@ function DangerItems() {
subTitle={Locale.Settings.Danger.Reset.SubTitle} subTitle={Locale.Settings.Danger.Reset.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Settings.Danger.Reset.Title}
text={Locale.Settings.Danger.Reset.Action} text={Locale.Settings.Danger.Reset.Action}
onClick={async () => { onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) { if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) {
@ -260,6 +261,7 @@ function DangerItems() {
subTitle={Locale.Settings.Danger.Clear.SubTitle} subTitle={Locale.Settings.Danger.Clear.SubTitle}
> >
<IconButton <IconButton
aria={Locale.Settings.Danger.Clear.Title}
text={Locale.Settings.Danger.Clear.Action} text={Locale.Settings.Danger.Clear.Action}
onClick={async () => { onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) { if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) {
@ -513,6 +515,7 @@ function SyncItems() {
> >
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<IconButton <IconButton
aria={Locale.Settings.Sync.CloudState + Locale.UI.Config}
icon={<ConfigIcon />} icon={<ConfigIcon />}
text={Locale.UI.Config} text={Locale.UI.Config}
onClick={() => { onClick={() => {
@ -543,6 +546,7 @@ function SyncItems() {
> >
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<IconButton <IconButton
aria={Locale.Settings.Sync.LocalState + Locale.UI.Export}
icon={<UploadIcon />} icon={<UploadIcon />}
text={Locale.UI.Export} text={Locale.UI.Export}
onClick={() => { onClick={() => {
@ -550,6 +554,7 @@ function SyncItems() {
}} }}
/> />
<IconButton <IconButton
aria={Locale.Settings.Sync.LocalState + Locale.UI.Import}
icon={<DownloadIcon />} icon={<DownloadIcon />}
text={Locale.UI.Import} text={Locale.UI.Import}
onClick={() => { onClick={() => {
@ -687,6 +692,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.CustomEndpoint.SubTitle} subTitle={Locale.Settings.Access.CustomEndpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.CustomEndpoint.Title}
type="checkbox" type="checkbox"
checked={accessStore.useCustomConfig} checked={accessStore.useCustomConfig}
onChange={(e) => onChange={(e) =>
@ -706,6 +712,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.OpenAI.Endpoint.SubTitle} subTitle={Locale.Settings.Access.OpenAI.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.OpenAI.Endpoint.Title}
type="text" type="text"
value={accessStore.openaiUrl} value={accessStore.openaiUrl}
placeholder={OPENAI_BASE_URL} placeholder={OPENAI_BASE_URL}
@ -721,6 +728,8 @@ export function Settings() {
subTitle={Locale.Settings.Access.OpenAI.ApiKey.SubTitle} subTitle={Locale.Settings.Access.OpenAI.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria={Locale.Settings.ShowPassword}
aria-label={Locale.Settings.Access.OpenAI.ApiKey.Title}
value={accessStore.openaiApiKey} value={accessStore.openaiApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.OpenAI.ApiKey.Placeholder} placeholder={Locale.Settings.Access.OpenAI.ApiKey.Placeholder}
@ -744,6 +753,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Azure.Endpoint.Title}
type="text" type="text"
value={accessStore.azureUrl} value={accessStore.azureUrl}
placeholder={Azure.ExampleEndpoint} placeholder={Azure.ExampleEndpoint}
@ -759,6 +769,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Azure.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Azure.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Azure.ApiKey.Title}
value={accessStore.azureApiKey} value={accessStore.azureApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Azure.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Azure.ApiKey.Placeholder}
@ -774,6 +785,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Azure.ApiVerion.SubTitle} subTitle={Locale.Settings.Access.Azure.ApiVerion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Azure.ApiVerion.Title}
type="text" type="text"
value={accessStore.azureApiVersion} value={accessStore.azureApiVersion}
placeholder="2023-08-01-preview" placeholder="2023-08-01-preview"
@ -798,6 +810,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Google.Endpoint.Title}
type="text" type="text"
value={accessStore.googleUrl} value={accessStore.googleUrl}
placeholder={Google.ExampleEndpoint} placeholder={Google.ExampleEndpoint}
@ -813,6 +826,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Google.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Google.ApiKey.Title}
value={accessStore.googleApiKey} value={accessStore.googleApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Google.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Google.ApiKey.Placeholder}
@ -828,6 +842,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.ApiVersion.SubTitle} subTitle={Locale.Settings.Access.Google.ApiVersion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Google.ApiVersion.Title}
type="text" type="text"
value={accessStore.googleApiVersion} value={accessStore.googleApiVersion}
placeholder="2023-08-01-preview" placeholder="2023-08-01-preview"
@ -843,6 +858,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Google.GoogleSafetySettings.SubTitle} subTitle={Locale.Settings.Access.Google.GoogleSafetySettings.SubTitle}
> >
<Select <Select
aria-label={Locale.Settings.Access.Google.GoogleSafetySettings.Title}
value={accessStore.googleSafetySettings} value={accessStore.googleSafetySettings}
onChange={(e) => { onChange={(e) => {
accessStore.update( accessStore.update(
@ -873,6 +889,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Anthropic.Endpoint.Title}
type="text" type="text"
value={accessStore.anthropicUrl} value={accessStore.anthropicUrl}
placeholder={Anthropic.ExampleEndpoint} placeholder={Anthropic.ExampleEndpoint}
@ -888,6 +905,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Anthropic.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Anthropic.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Anthropic.ApiKey.Title}
value={accessStore.anthropicApiKey} value={accessStore.anthropicApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Anthropic.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Anthropic.ApiKey.Placeholder}
@ -903,6 +921,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Anthropic.ApiVerion.SubTitle} subTitle={Locale.Settings.Access.Anthropic.ApiVerion.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Anthropic.ApiVerion.Title}
type="text" type="text"
value={accessStore.anthropicApiVersion} value={accessStore.anthropicApiVersion}
placeholder={Anthropic.Vision} placeholder={Anthropic.Vision}
@ -924,6 +943,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.Endpoint.SubTitle} subTitle={Locale.Settings.Access.Baidu.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Baidu.Endpoint.Title}
type="text" type="text"
value={accessStore.baiduUrl} value={accessStore.baiduUrl}
placeholder={Baidu.ExampleEndpoint} placeholder={Baidu.ExampleEndpoint}
@ -939,6 +959,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Baidu.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Baidu.ApiKey.Title}
value={accessStore.baiduApiKey} value={accessStore.baiduApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Baidu.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Baidu.ApiKey.Placeholder}
@ -954,6 +975,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Baidu.SecretKey.SubTitle} subTitle={Locale.Settings.Access.Baidu.SecretKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Baidu.SecretKey.Title}
value={accessStore.baiduSecretKey} value={accessStore.baiduSecretKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Baidu.SecretKey.Placeholder} placeholder={Locale.Settings.Access.Baidu.SecretKey.Placeholder}
@ -975,6 +997,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.Endpoint.SubTitle} subTitle={Locale.Settings.Access.Tencent.Endpoint.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.Tencent.Endpoint.Title}
type="text" type="text"
value={accessStore.tencentUrl} value={accessStore.tencentUrl}
placeholder={Tencent.ExampleEndpoint} placeholder={Tencent.ExampleEndpoint}
@ -990,6 +1013,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Tencent.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Tencent.ApiKey.Title}
value={accessStore.tencentSecretId} value={accessStore.tencentSecretId}
type="text" type="text"
placeholder={Locale.Settings.Access.Tencent.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Tencent.ApiKey.Placeholder}
@ -1005,6 +1029,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Tencent.SecretKey.SubTitle} subTitle={Locale.Settings.Access.Tencent.SecretKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Tencent.SecretKey.Title}
value={accessStore.tencentSecretKey} value={accessStore.tencentSecretKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Tencent.SecretKey.Placeholder} placeholder={Locale.Settings.Access.Tencent.SecretKey.Placeholder}
@ -1029,6 +1054,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.ByteDance.Endpoint.Title}
type="text" type="text"
value={accessStore.bytedanceUrl} value={accessStore.bytedanceUrl}
placeholder={ByteDance.ExampleEndpoint} placeholder={ByteDance.ExampleEndpoint}
@ -1044,6 +1070,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.ByteDance.ApiKey.SubTitle} subTitle={Locale.Settings.Access.ByteDance.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.ByteDance.ApiKey.Title}
value={accessStore.bytedanceApiKey} value={accessStore.bytedanceApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.ByteDance.ApiKey.Placeholder} placeholder={Locale.Settings.Access.ByteDance.ApiKey.Placeholder}
@ -1068,6 +1095,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Alibaba.Endpoint.Title}
type="text" type="text"
value={accessStore.alibabaUrl} value={accessStore.alibabaUrl}
placeholder={Alibaba.ExampleEndpoint} placeholder={Alibaba.ExampleEndpoint}
@ -1083,6 +1111,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Alibaba.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Alibaba.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Alibaba.ApiKey.Title}
value={accessStore.alibabaApiKey} value={accessStore.alibabaApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Alibaba.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Alibaba.ApiKey.Placeholder}
@ -1107,6 +1136,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Moonshot.Endpoint.Title}
type="text" type="text"
value={accessStore.moonshotUrl} value={accessStore.moonshotUrl}
placeholder={Moonshot.ExampleEndpoint} placeholder={Moonshot.ExampleEndpoint}
@ -1122,6 +1152,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Moonshot.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Moonshot.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Moonshot.ApiKey.Title}
value={accessStore.moonshotApiKey} value={accessStore.moonshotApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Moonshot.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Moonshot.ApiKey.Placeholder}
@ -1146,6 +1177,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Stability.Endpoint.Title}
type="text" type="text"
value={accessStore.stabilityUrl} value={accessStore.stabilityUrl}
placeholder={Stability.ExampleEndpoint} placeholder={Stability.ExampleEndpoint}
@ -1161,6 +1193,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Stability.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Stability.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Stability.ApiKey.Title}
value={accessStore.stabilityApiKey} value={accessStore.stabilityApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Stability.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Stability.ApiKey.Placeholder}
@ -1184,6 +1217,7 @@ export function Settings() {
} }
> >
<input <input
aria-label={Locale.Settings.Access.Iflytek.Endpoint.Title}
type="text" type="text"
value={accessStore.iflytekUrl} value={accessStore.iflytekUrl}
placeholder={Iflytek.ExampleEndpoint} placeholder={Iflytek.ExampleEndpoint}
@ -1199,6 +1233,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Iflytek.ApiKey.SubTitle} subTitle={Locale.Settings.Access.Iflytek.ApiKey.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Iflytek.ApiKey.Title}
value={accessStore.iflytekApiKey} value={accessStore.iflytekApiKey}
type="text" type="text"
placeholder={Locale.Settings.Access.Iflytek.ApiKey.Placeholder} placeholder={Locale.Settings.Access.Iflytek.ApiKey.Placeholder}
@ -1215,6 +1250,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Iflytek.ApiSecret.SubTitle} subTitle={Locale.Settings.Access.Iflytek.ApiSecret.SubTitle}
> >
<PasswordInput <PasswordInput
aria-label={Locale.Settings.Access.Iflytek.ApiSecret.Title}
value={accessStore.iflytekApiSecret} value={accessStore.iflytekApiSecret}
type="text" type="text"
placeholder={Locale.Settings.Access.Iflytek.ApiSecret.Placeholder} placeholder={Locale.Settings.Access.Iflytek.ApiSecret.Placeholder}
@ -1244,6 +1280,7 @@ export function Settings() {
<div className="window-action-button"></div> <div className="window-action-button"></div>
<div className="window-action-button"> <div className="window-action-button">
<IconButton <IconButton
aria={Locale.UI.Close}
icon={<CloseIcon />} icon={<CloseIcon />}
onClick={() => navigate(Path.Home)} onClick={() => navigate(Path.Home)}
bordered bordered
@ -1267,6 +1304,8 @@ export function Settings() {
open={showEmojiPicker} open={showEmojiPicker}
> >
<div <div
aria-label={Locale.Settings.Avatar}
tabIndex={0}
className={styles.avatar} className={styles.avatar}
onClick={() => { onClick={() => {
setShowEmojiPicker(!showEmojiPicker); setShowEmojiPicker(!showEmojiPicker);
@ -1304,6 +1343,7 @@ export function Settings() {
<ListItem title={Locale.Settings.SendKey}> <ListItem title={Locale.Settings.SendKey}>
<Select <Select
aria-label={Locale.Settings.SendKey}
value={config.submitKey} value={config.submitKey}
onChange={(e) => { onChange={(e) => {
updateConfig( updateConfig(
@ -1322,6 +1362,7 @@ export function Settings() {
<ListItem title={Locale.Settings.Theme}> <ListItem title={Locale.Settings.Theme}>
<Select <Select
aria-label={Locale.Settings.Theme}
value={config.theme} value={config.theme}
onChange={(e) => { onChange={(e) => {
updateConfig( updateConfig(
@ -1339,6 +1380,7 @@ export function Settings() {
<ListItem title={Locale.Settings.Lang.Name}> <ListItem title={Locale.Settings.Lang.Name}>
<Select <Select
aria-label={Locale.Settings.Lang.Name}
value={getLang()} value={getLang()}
onChange={(e) => { onChange={(e) => {
changeLang(e.target.value as any); changeLang(e.target.value as any);
@ -1357,6 +1399,7 @@ export function Settings() {
subTitle={Locale.Settings.FontSize.SubTitle} subTitle={Locale.Settings.FontSize.SubTitle}
> >
<InputRange <InputRange
aria={Locale.Settings.FontSize.Title}
title={`${config.fontSize ?? 14}px`} title={`${config.fontSize ?? 14}px`}
value={config.fontSize} value={config.fontSize}
min="12" min="12"
@ -1376,6 +1419,7 @@ export function Settings() {
subTitle={Locale.Settings.FontFamily.SubTitle} subTitle={Locale.Settings.FontFamily.SubTitle}
> >
<input <input
aria-label={Locale.Settings.FontFamily.Title}
type="text" type="text"
value={config.fontFamily} value={config.fontFamily}
placeholder={Locale.Settings.FontFamily.Placeholder} placeholder={Locale.Settings.FontFamily.Placeholder}
@ -1392,6 +1436,7 @@ export function Settings() {
subTitle={Locale.Settings.AutoGenerateTitle.SubTitle} subTitle={Locale.Settings.AutoGenerateTitle.SubTitle}
> >
<input <input
aria-label={Locale.Settings.AutoGenerateTitle.Title}
type="checkbox" type="checkbox"
checked={config.enableAutoGenerateTitle} checked={config.enableAutoGenerateTitle}
onChange={(e) => onChange={(e) =>
@ -1408,6 +1453,7 @@ export function Settings() {
subTitle={Locale.Settings.SendPreviewBubble.SubTitle} subTitle={Locale.Settings.SendPreviewBubble.SubTitle}
> >
<input <input
aria-label={Locale.Settings.SendPreviewBubble.Title}
type="checkbox" type="checkbox"
checked={config.sendPreviewBubble} checked={config.sendPreviewBubble}
onChange={(e) => onChange={(e) =>
@ -1428,6 +1474,7 @@ export function Settings() {
subTitle={Locale.Settings.Mask.Splash.SubTitle} subTitle={Locale.Settings.Mask.Splash.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Mask.Splash.Title}
type="checkbox" type="checkbox"
checked={!config.dontShowMaskSplashScreen} checked={!config.dontShowMaskSplashScreen}
onChange={(e) => onChange={(e) =>
@ -1445,6 +1492,7 @@ export function Settings() {
subTitle={Locale.Settings.Mask.Builtin.SubTitle} subTitle={Locale.Settings.Mask.Builtin.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Mask.Builtin.Title}
type="checkbox" type="checkbox"
checked={config.hideBuiltinMasks} checked={config.hideBuiltinMasks}
onChange={(e) => onChange={(e) =>
@ -1463,6 +1511,7 @@ export function Settings() {
subTitle={Locale.Settings.Prompt.Disable.SubTitle} subTitle={Locale.Settings.Prompt.Disable.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Prompt.Disable.Title}
type="checkbox" type="checkbox"
checked={config.disablePromptHint} checked={config.disablePromptHint}
onChange={(e) => onChange={(e) =>
@ -1482,6 +1531,7 @@ export function Settings() {
)} )}
> >
<IconButton <IconButton
aria={Locale.Settings.Prompt.List + Locale.Settings.Prompt.Edit}
icon={<EditIcon />} icon={<EditIcon />}
text={Locale.Settings.Prompt.Edit} text={Locale.Settings.Prompt.Edit}
onClick={() => setShowPromptModal(true)} onClick={() => setShowPromptModal(true)}
@ -1503,6 +1553,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.Provider.SubTitle} subTitle={Locale.Settings.Access.Provider.SubTitle}
> >
<Select <Select
aria-label={Locale.Settings.Access.Provider.Title}
value={accessStore.provider} value={accessStore.provider}
onChange={(e) => { onChange={(e) => {
accessStore.update( accessStore.update(
@ -1567,6 +1618,7 @@ export function Settings() {
subTitle={Locale.Settings.Access.CustomModel.SubTitle} subTitle={Locale.Settings.Access.CustomModel.SubTitle}
> >
<input <input
aria-label={Locale.Settings.Access.CustomModel.Title}
type="text" type="text"
value={config.customModels} value={config.customModels}
placeholder="model1,model2,model3" placeholder="model1,model2,model3"

View File

@ -297,12 +297,20 @@ export function SideBar(props: { className?: string }) {
</div> </div>
<div className={styles["sidebar-action"]}> <div className={styles["sidebar-action"]}>
<Link to={Path.Settings}> <Link to={Path.Settings}>
<IconButton icon={<SettingsIcon />} shadow /> <IconButton
aria={Locale.Settings.Title}
icon={<SettingsIcon />}
shadow
/>
</Link> </Link>
</div> </div>
<div className={styles["sidebar-action"]}> <div className={styles["sidebar-action"]}>
<a href={REPO_URL} target="_blank" rel="noopener noreferrer"> <a href={REPO_URL} target="_blank" rel="noopener noreferrer">
<IconButton icon={<GithubIcon />} shadow /> <IconButton
aria={Locale.Export.MessageFromChatGPT}
icon={<GithubIcon />}
shadow
/>
</a> </a>
</div> </div>
</> </>

View File

@ -265,9 +265,10 @@ export function Input(props: InputProps) {
); );
} }
export function PasswordInput(props: HTMLProps<HTMLInputElement>) { export function PasswordInput(
props: HTMLProps<HTMLInputElement> & { aria?: string },
) {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
function changeVisibility() { function changeVisibility() {
setVisible(!visible); setVisible(!visible);
} }
@ -275,6 +276,7 @@ export function PasswordInput(props: HTMLProps<HTMLInputElement>) {
return ( return (
<div className={"password-input-container"}> <div className={"password-input-container"}>
<IconButton <IconButton
aria={props.aria}
icon={visible ? <EyeIcon /> : <EyeOffIcon />} icon={visible ? <EyeIcon /> : <EyeOffIcon />}
onClick={changeVisibility} onClick={changeVisibility}
className={"password-eye"} className={"password-eye"}

View File

@ -42,6 +42,7 @@ const cn = {
PinToastAction: "查看", PinToastAction: "查看",
Delete: "删除", Delete: "删除",
Edit: "编辑", Edit: "编辑",
FullScreen: "全屏",
}, },
Commands: { Commands: {
new: "新建聊天", new: "新建聊天",
@ -132,6 +133,7 @@ const cn = {
Settings: { Settings: {
Title: "设置", Title: "设置",
SubTitle: "所有设置选项", SubTitle: "所有设置选项",
ShowPassword: "显示密码",
Danger: { Danger: {
Reset: { Reset: {

View File

@ -44,6 +44,7 @@ const en: LocaleType = {
PinToastAction: "View", PinToastAction: "View",
Delete: "Delete", Delete: "Delete",
Edit: "Edit", Edit: "Edit",
FullScreen: "FullScreen",
}, },
Commands: { Commands: {
new: "Start a new chat", new: "Start a new chat",
@ -135,6 +136,7 @@ const en: LocaleType = {
Settings: { Settings: {
Title: "Settings", Title: "Settings",
SubTitle: "All Settings", SubTitle: "All Settings",
ShowPassword: "ShowPassword",
Danger: { Danger: {
Reset: { Reset: {
Title: "Reset All Settings", Title: "Reset All Settings",