mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-09 06:06:08 +00:00
c5b5606bf5
- TextModal: route the Copy button label and the post-copy toast
through t('copy')/t('copied') instead of hardcoded English.
- PromptModal: route cancelText through t('cancel') and default okText
through t('confirm') so the import-inbound prompt stops showing
"Cancel" in non-English UI.
- InboundsPage: pass the All-Inbounds and All-Inbounds-Subs download
filenames through t(...) so each locale can localize them.
- en-US.json: add pages.inbounds.exportAllLinksFileName and
pages.inbounds.exportAllSubsFileName.
- All 12 non-English locales: translate streamTab and sniffingTab
(previously left as literal English) and add the two new filename
keys with appropriate translations.
All 13 locale files now have 1541 lines.
85 lines
2.2 KiB
TypeScript
85 lines
2.2 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
import { Input, Modal } from 'antd';
|
|
import type { InputRef } from 'antd';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
interface PromptModalProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
title: string;
|
|
okText?: string;
|
|
type?: 'input' | 'textarea';
|
|
initialValue?: string;
|
|
loading?: boolean;
|
|
onConfirm: (value: string) => void;
|
|
}
|
|
|
|
export default function PromptModal({
|
|
open,
|
|
onClose,
|
|
title,
|
|
okText,
|
|
type = 'input',
|
|
initialValue = '',
|
|
loading = false,
|
|
onConfirm,
|
|
}: PromptModalProps) {
|
|
const { t } = useTranslation();
|
|
const [value, setValue] = useState('');
|
|
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
|
|
const inputRef = useRef<InputRef | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (open) {
|
|
setValue(initialValue);
|
|
setTimeout(() => {
|
|
if (type === 'textarea') textareaRef.current?.focus();
|
|
else inputRef.current?.focus();
|
|
}, 50);
|
|
}
|
|
}, [open, initialValue, type]);
|
|
|
|
function onKeydown(e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) {
|
|
if (type !== 'textarea' && e.key === 'Enter') {
|
|
e.preventDefault();
|
|
onConfirm(value);
|
|
return;
|
|
}
|
|
if (type === 'textarea' && e.ctrlKey && e.key.toLowerCase() === 's') {
|
|
e.preventDefault();
|
|
onConfirm(value);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
open={open}
|
|
title={title}
|
|
okText={okText ?? t('confirm')}
|
|
cancelText={t('cancel')}
|
|
mask={{ closable: false }}
|
|
confirmLoading={loading}
|
|
onOk={() => onConfirm(value)}
|
|
onCancel={onClose}
|
|
destroyOnHidden
|
|
>
|
|
{type === 'textarea' ? (
|
|
<Input.TextArea
|
|
ref={(el) => { textareaRef.current = (el as unknown as { resizableTextArea?: { textArea: HTMLTextAreaElement } })?.resizableTextArea?.textArea ?? null; }}
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
autoSize={{ minRows: 10, maxRows: 20 }}
|
|
onKeyDown={onKeydown}
|
|
/>
|
|
) : (
|
|
<Input
|
|
ref={inputRef}
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
onKeyDown={onKeydown}
|
|
/>
|
|
)}
|
|
</Modal>
|
|
);
|
|
}
|