mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 16:56:56 +08:00
fix: 修复小屏幕设备上对话框高度过高无法滚动的问题 (#681)
This commit is contained in:
@@ -1288,16 +1288,23 @@ function SignalSourceModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
className="bg-gray-800 rounded-lg p-6 w-full max-w-lg relative"
|
className="bg-gray-800 rounded-lg w-full max-w-lg relative my-8"
|
||||||
style={{ background: '#1E2329' }}
|
style={{
|
||||||
|
background: '#1E2329',
|
||||||
|
maxHeight: 'calc(100vh - 4rem)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<h3 className="text-xl font-bold mb-4" style={{ color: '#EAECEF' }}>
|
<h3 className="text-xl font-bold mb-4" style={{ color: '#EAECEF' }}>
|
||||||
{t('signalSourceConfig', language)}
|
{t('signalSourceConfig', language)}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="px-6 pb-6">
|
||||||
|
<div
|
||||||
|
className="space-y-4 overflow-y-auto"
|
||||||
|
style={{ maxHeight: 'calc(100vh - 16rem)' }}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
className="block text-sm font-semibold mb-2"
|
className="block text-sm font-semibold mb-2"
|
||||||
@@ -1365,8 +1372,12 @@ function SignalSourceModal({
|
|||||||
<div>{t('signalSourceInfo3', language)}</div>
|
<div>{t('signalSourceInfo3', language)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3 mt-6">
|
<div
|
||||||
|
className="flex gap-3 mt-6 pt-4 sticky bottom-0"
|
||||||
|
style={{ background: '#1E2329' }}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
@@ -1447,12 +1458,18 @@ function ModelConfigModal({
|
|||||||
const availableModels = allModels || []
|
const availableModels = allModels || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
className="bg-gray-800 rounded-lg p-6 w-full max-w-lg relative"
|
className="bg-gray-800 rounded-lg w-full max-w-lg relative my-8"
|
||||||
|
style={{
|
||||||
|
background: '#1E2329',
|
||||||
|
maxHeight: 'calc(100vh - 4rem)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-between p-6 pb-4 sticky top-0 z-10"
|
||||||
style={{ background: '#1E2329' }}
|
style={{ background: '#1E2329' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
|
||||||
<h3 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
<h3 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
||||||
{editingModelId
|
{editingModelId
|
||||||
? t('editAIModel', language)
|
? t('editAIModel', language)
|
||||||
@@ -1471,7 +1488,11 @@ function ModelConfigModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="px-6 pb-6">
|
||||||
|
<div
|
||||||
|
className="space-y-4 overflow-y-auto"
|
||||||
|
style={{ maxHeight: 'calc(100vh - 16rem)' }}
|
||||||
|
>
|
||||||
{!editingModelId && (
|
{!editingModelId && (
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@@ -1623,7 +1644,10 @@ function ModelConfigModal({
|
|||||||
>
|
>
|
||||||
ℹ️ {t('information', language)}
|
ℹ️ {t('information', language)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs space-y-1" style={{ color: '#848E9C' }}>
|
<div
|
||||||
|
className="text-xs space-y-1"
|
||||||
|
style={{ color: '#848E9C' }}
|
||||||
|
>
|
||||||
<div>{t('modelConfigInfo1', language)}</div>
|
<div>{t('modelConfigInfo1', language)}</div>
|
||||||
<div>{t('modelConfigInfo2', language)}</div>
|
<div>{t('modelConfigInfo2', language)}</div>
|
||||||
<div>{t('modelConfigInfo3', language)}</div>
|
<div>{t('modelConfigInfo3', language)}</div>
|
||||||
@@ -1631,8 +1655,12 @@ function ModelConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3 mt-6">
|
<div
|
||||||
|
className="flex gap-3 mt-6 pt-4 sticky bottom-0"
|
||||||
|
style={{ background: '#1E2329' }}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
@@ -1872,12 +1900,18 @@ function ExchangeConfigModal({
|
|||||||
const availableExchanges = allExchanges || []
|
const availableExchanges = allExchanges || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4 overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
className="bg-gray-800 rounded-lg p-6 w-full max-w-lg relative"
|
className="bg-gray-800 rounded-lg w-full max-w-lg relative my-8"
|
||||||
|
style={{
|
||||||
|
background: '#1E2329',
|
||||||
|
maxHeight: 'calc(100vh - 4rem)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-between p-6 pb-4 sticky top-0 z-10"
|
||||||
style={{ background: '#1E2329' }}
|
style={{ background: '#1E2329' }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between mb-4">
|
|
||||||
<h3 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
<h3 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
|
||||||
{editingExchangeId
|
{editingExchangeId
|
||||||
? t('editExchange', language)
|
? t('editExchange', language)
|
||||||
@@ -1915,7 +1949,11 @@ function ExchangeConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="px-6 pb-6">
|
||||||
|
<div
|
||||||
|
className="space-y-4 overflow-y-auto"
|
||||||
|
style={{ maxHeight: 'calc(100vh - 16rem)' }}
|
||||||
|
>
|
||||||
{!editingExchangeId && (
|
{!editingExchangeId && (
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@@ -1935,11 +1973,13 @@ function ExchangeConfigModal({
|
|||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="">{t('pleaseSelectExchange', language)}</option>
|
<option value="">
|
||||||
|
{t('pleaseSelectExchange', language)}
|
||||||
|
</option>
|
||||||
{availableExchanges.map((exchange) => (
|
{availableExchanges.map((exchange) => (
|
||||||
<option key={exchange.id} value={exchange.id}>
|
<option key={exchange.id} value={exchange.id}>
|
||||||
{getShortName(exchange.name)} ({exchange.type.toUpperCase()}
|
{getShortName(exchange.name)} (
|
||||||
)
|
{exchange.type.toUpperCase()})
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@@ -1997,7 +2037,8 @@ function ExchangeConfigModal({
|
|||||||
style={{ color: '#EAECEF' }}
|
style={{ color: '#EAECEF' }}
|
||||||
>
|
>
|
||||||
<strong>币安用户必读:</strong>
|
<strong>币安用户必读:</strong>
|
||||||
使用「现货与合约交易」API,不要用「统一账户 API」
|
使用「现货与合约交易」API,不要用「统一账户
|
||||||
|
API」
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span style={{ color: '#8b949e' }}>
|
<span style={{ color: '#8b949e' }}>
|
||||||
@@ -2032,7 +2073,8 @@ function ExchangeConfigModal({
|
|||||||
style={{ paddingLeft: '0.5rem' }}
|
style={{ paddingLeft: '0.5rem' }}
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
登录币安 → 个人中心 → <strong>API 管理</strong>
|
登录币安 → 个人中心 →{' '}
|
||||||
|
<strong>API 管理</strong>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
创建 API → 选择「
|
创建 API → 选择「
|
||||||
@@ -2046,8 +2088,8 @@ function ExchangeConfigModal({
|
|||||||
)
|
)
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
IP 限制选「<strong>无限制</strong>」或添加服务器
|
IP 限制选「<strong>无限制</strong>
|
||||||
IP
|
」或添加服务器 IP
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
@@ -2167,7 +2209,10 @@ function ExchangeConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loadingIP ? (
|
{loadingIP ? (
|
||||||
<div className="text-xs" style={{ color: '#848E9C' }}>
|
<div
|
||||||
|
className="text-xs"
|
||||||
|
style={{ color: '#848E9C' }}
|
||||||
|
>
|
||||||
{t('loadingServerIP', language)}
|
{t('loadingServerIP', language)}
|
||||||
</div>
|
</div>
|
||||||
) : serverIP && serverIP.public_ip ? (
|
) : serverIP && serverIP.public_ip ? (
|
||||||
@@ -2201,6 +2246,128 @@ function ExchangeConfigModal({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Hyperliquid 交易所的字段 */}
|
||||||
|
{selectedExchange.id === 'hyperliquid' && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="block text-sm font-semibold mb-2"
|
||||||
|
style={{ color: '#EAECEF' }}
|
||||||
|
>
|
||||||
|
{t('privateKey', language)}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={apiKey}
|
||||||
|
onChange={(e) => setApiKey(e.target.value)}
|
||||||
|
placeholder={t('enterPrivateKey', language)}
|
||||||
|
className="w-full px-3 py-2 rounded"
|
||||||
|
style={{
|
||||||
|
background: '#0B0E11',
|
||||||
|
border: '1px solid #2B3139',
|
||||||
|
color: '#EAECEF',
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="text-xs mt-1"
|
||||||
|
style={{ color: '#848E9C' }}
|
||||||
|
>
|
||||||
|
{t('hyperliquidPrivateKeyDesc', language)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Aster 交易所的字段 */}
|
||||||
|
{selectedExchange.id === 'aster' && (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="block text-sm font-semibold mb-2 flex items-center gap-2"
|
||||||
|
style={{ color: '#EAECEF' }}
|
||||||
|
>
|
||||||
|
{t('user', language)}
|
||||||
|
<Tooltip content={t('asterUserDesc', language)}>
|
||||||
|
<HelpCircle
|
||||||
|
className="w-4 h-4 cursor-help"
|
||||||
|
style={{ color: '#F0B90B' }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={asterUser}
|
||||||
|
onChange={(e) => setAsterUser(e.target.value)}
|
||||||
|
placeholder={t('enterUser', language)}
|
||||||
|
className="w-full px-3 py-2 rounded"
|
||||||
|
style={{
|
||||||
|
background: '#0B0E11',
|
||||||
|
border: '1px solid #2B3139',
|
||||||
|
color: '#EAECEF',
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="block text-sm font-semibold mb-2 flex items-center gap-2"
|
||||||
|
style={{ color: '#EAECEF' }}
|
||||||
|
>
|
||||||
|
{t('signer', language)}
|
||||||
|
<Tooltip content={t('asterSignerDesc', language)}>
|
||||||
|
<HelpCircle
|
||||||
|
className="w-4 h-4 cursor-help"
|
||||||
|
style={{ color: '#F0B90B' }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={asterSigner}
|
||||||
|
onChange={(e) => setAsterSigner(e.target.value)}
|
||||||
|
placeholder={t('enterSigner', language)}
|
||||||
|
className="w-full px-3 py-2 rounded"
|
||||||
|
style={{
|
||||||
|
background: '#0B0E11',
|
||||||
|
border: '1px solid #2B3139',
|
||||||
|
color: '#EAECEF',
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="block text-sm font-semibold mb-2 flex items-center gap-2"
|
||||||
|
style={{ color: '#EAECEF' }}
|
||||||
|
>
|
||||||
|
{t('privateKey', language)}
|
||||||
|
<Tooltip content={t('asterPrivateKeyDesc', language)}>
|
||||||
|
<HelpCircle
|
||||||
|
className="w-4 h-4 cursor-help"
|
||||||
|
style={{ color: '#F0B90B' }}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={asterPrivateKey}
|
||||||
|
onChange={(e) => setAsterPrivateKey(e.target.value)}
|
||||||
|
placeholder={t('enterPrivateKey', language)}
|
||||||
|
className="w-full px-3 py-2 rounded"
|
||||||
|
style={{
|
||||||
|
background: '#0B0E11',
|
||||||
|
border: '1px solid #2B3139',
|
||||||
|
color: '#EAECEF',
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Hyperliquid 交易所的字段 */}
|
{/* Hyperliquid 交易所的字段 */}
|
||||||
{selectedExchange.id === 'hyperliquid' && (
|
{selectedExchange.id === 'hyperliquid' && (
|
||||||
<>
|
<>
|
||||||
@@ -2451,25 +2618,6 @@ function ExchangeConfigModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="flex items-center gap-2 text-sm">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={testnet}
|
|
||||||
onChange={(e) => setTestnet(e.target.checked)}
|
|
||||||
className="form-checkbox rounded"
|
|
||||||
style={{ accentColor: '#F0B90B' }}
|
|
||||||
/>
|
|
||||||
<span style={{ color: '#EAECEF' }}>
|
|
||||||
{t('useTestnet', language)}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
|
||||||
{t('testnetDescription', language)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -2488,7 +2636,10 @@ function ExchangeConfigModal({
|
|||||||
{t('securityWarning', language)}
|
{t('securityWarning', language)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs space-y-1" style={{ color: '#848E9C' }}>
|
<div
|
||||||
|
className="text-xs space-y-1"
|
||||||
|
style={{ color: '#848E9C' }}
|
||||||
|
>
|
||||||
{selectedExchange.id === 'aster' && (
|
{selectedExchange.id === 'aster' && (
|
||||||
<div>{t('asterUsdtWarning', language)}</div>
|
<div>{t('asterUsdtWarning', language)}</div>
|
||||||
)}
|
)}
|
||||||
@@ -2499,8 +2650,12 @@ function ExchangeConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3 mt-6">
|
<div
|
||||||
|
className="flex gap-3 mt-6 pt-4 sticky bottom-0"
|
||||||
|
style={{ background: '#1E2329' }}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
|
|||||||
@@ -259,13 +259,14 @@ export function TraderConfigModal({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 backdrop-blur-sm">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 backdrop-blur-sm p-4 overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
className="bg-[#1E2329] border border-[#2B3139] rounded-xl shadow-2xl max-w-3xl w-full mx-4 max-h-[90vh] overflow-y-auto"
|
className="bg-[#1E2329] border border-[#2B3139] rounded-xl shadow-2xl max-w-3xl w-full my-8"
|
||||||
|
style={{ maxHeight: 'calc(100vh - 4rem)' }}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between p-6 border-b border-[#2B3139] bg-gradient-to-r from-[#1E2329] to-[#252B35]">
|
<div className="flex items-center justify-between p-6 border-b border-[#2B3139] bg-gradient-to-r from-[#1E2329] to-[#252B35] sticky top-0 z-10 rounded-t-xl">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-[#F0B90B] to-[#E1A706] flex items-center justify-center">
|
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-[#F0B90B] to-[#E1A706] flex items-center justify-center">
|
||||||
<span className="text-lg">{isEditMode ? '✏️' : '➕'}</span>
|
<span className="text-lg">{isEditMode ? '✏️' : '➕'}</span>
|
||||||
@@ -288,7 +289,10 @@ export function TraderConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="p-6 space-y-8">
|
<div
|
||||||
|
className="p-6 space-y-8 overflow-y-auto"
|
||||||
|
style={{ maxHeight: 'calc(100vh - 16rem)' }}
|
||||||
|
>
|
||||||
{/* Basic Info */}
|
{/* Basic Info */}
|
||||||
<div className="bg-[#0B0E11] border border-[#2B3139] rounded-lg p-5">
|
<div className="bg-[#0B0E11] border border-[#2B3139] rounded-lg p-5">
|
||||||
<h3 className="text-lg font-semibold text-[#EAECEF] mb-5 flex items-center gap-2">
|
<h3 className="text-lg font-semibold text-[#EAECEF] mb-5 flex items-center gap-2">
|
||||||
@@ -761,7 +765,7 @@ export function TraderConfigModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<div className="flex justify-end gap-3 p-6 border-t border-[#2B3139] bg-gradient-to-r from-[#1E2329] to-[#252B35]">
|
<div className="flex justify-end gap-3 p-6 border-t border-[#2B3139] bg-gradient-to-r from-[#1E2329] to-[#252B35] sticky bottom-0 z-10 rounded-b-xl">
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="px-6 py-3 bg-[#2B3139] text-[#EAECEF] rounded-lg hover:bg-[#404750] transition-all duration-200 border border-[#404750]"
|
className="px-6 py-3 bg-[#2B3139] text-[#EAECEF] rounded-lg hover:bg-[#404750] transition-all duration-200 border border-[#404750]"
|
||||||
|
|||||||
Reference in New Issue
Block a user