fix: reduce candidate coin limit to 10, fix Select scroll and flash

- Lower MaxCandidateCoins from 50 to 10 (backend)
- Update CoinSourceEditor: options 1-10, default 3, max static coins 10
- Fix NofxSelect dropdown closing on internal scroll
- Fix NofxSelect position flash on open (useLayoutEffect)
This commit is contained in:
Dean
2026-03-27 22:34:51 +08:00
committed by shinchan-zhai
parent f83f2b1c18
commit fbca4166a1
3 changed files with 32 additions and 29 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// Hard limits to prevent token explosion in AI requests // Hard limits to prevent token explosion in AI requests
const ( const (
MaxCandidateCoins = 50 MaxCandidateCoins = 10
MaxPositions = 3 MaxPositions = 3
MaxTimeframes = 4 MaxTimeframes = 4
MinKlineCount = 10 MinKlineCount = 10
@@ -33,16 +33,16 @@ export function CoinSourceEditor({
let totalLimit = 0 let totalLimit = 0
if (config.use_ai500) { if (config.use_ai500) {
sources.push(`AI500(${config.ai500_limit || 10})`) sources.push(`AI500(${config.ai500_limit || 3})`)
totalLimit += config.ai500_limit || 10 totalLimit += config.ai500_limit || 3
} }
if (config.use_oi_top) { if (config.use_oi_top) {
sources.push(`${ts(coinSource.oiIncreaseShort, language)}(${config.oi_top_limit || 10})`) sources.push(`${ts(coinSource.oiIncreaseShort, language)}(${config.oi_top_limit || 3})`)
totalLimit += config.oi_top_limit || 10 totalLimit += config.oi_top_limit || 3
} }
if (config.use_oi_low) { if (config.use_oi_low) {
sources.push(`${ts(coinSource.oiDecreaseShort, language)}(${config.oi_low_limit || 10})`) sources.push(`${ts(coinSource.oiDecreaseShort, language)}(${config.oi_low_limit || 3})`)
totalLimit += config.oi_low_limit || 10 totalLimit += config.oi_low_limit || 3
} }
if ((config.static_coins || []).length > 0) { if ((config.static_coins || []).length > 0) {
sources.push(`${ts(coinSource.custom, language)}(${config.static_coins?.length || 0})`) sources.push(`${ts(coinSource.custom, language)}(${config.static_coins?.length || 0})`)
@@ -71,7 +71,7 @@ export function CoinSourceEditor({
return xyzDexAssets.has(base) return xyzDexAssets.has(base)
} }
const MAX_STATIC_COINS = 50 const MAX_STATIC_COINS = 10
const showToast = (msg: string) => { const showToast = (msg: string) => {
const toast = document.createElement('div') const toast = document.createElement('div')
@@ -327,13 +327,13 @@ export function CoinSourceEditor({
{ts(coinSource.ai500Limit, language)}: {ts(coinSource.ai500Limit, language)}:
</span> </span>
<NofxSelect <NofxSelect
value={config.ai500_limit || 10} value={config.ai500_limit || 3}
onChange={(val) => onChange={(val) =>
!disabled && !disabled &&
onChange({ ...config, ai500_limit: parseInt(val) || 10 }) onChange({ ...config, ai500_limit: parseInt(val) || 3 })
} }
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
@@ -381,13 +381,13 @@ export function CoinSourceEditor({
{ts(coinSource.oiTopLimit, language)}: {ts(coinSource.oiTopLimit, language)}:
</span> </span>
<NofxSelect <NofxSelect
value={config.oi_top_limit || 10} value={config.oi_top_limit || 3}
onChange={(val) => onChange={(val) =>
!disabled && !disabled &&
onChange({ ...config, oi_top_limit: parseInt(val) || 10 }) onChange({ ...config, oi_top_limit: parseInt(val) || 3 })
} }
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
@@ -435,13 +435,13 @@ export function CoinSourceEditor({
{ts(coinSource.oiLowLimit, language)}: {ts(coinSource.oiLowLimit, language)}:
</span> </span>
<NofxSelect <NofxSelect
value={config.oi_low_limit || 10} value={config.oi_low_limit || 3}
onChange={(val) => onChange={(val) =>
!disabled && !disabled &&
onChange({ ...config, oi_low_limit: parseInt(val) || 10 }) onChange({ ...config, oi_low_limit: parseInt(val) || 3 })
} }
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-3 py-1.5 rounded bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
@@ -492,10 +492,10 @@ export function CoinSourceEditor({
<div className="flex items-center gap-2 mt-2 pl-6"> <div className="flex items-center gap-2 mt-2 pl-6">
<span className="text-xs text-nofx-text-muted">Limit:</span> <span className="text-xs text-nofx-text-muted">Limit:</span>
<NofxSelect <NofxSelect
value={config.ai500_limit || 10} value={config.ai500_limit || 3}
onChange={(val) => !disabled && onChange({ ...config, ai500_limit: parseInt(val) || 10 })} onChange={(val) => !disabled && onChange({ ...config, ai500_limit: parseInt(val) || 3 })}
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
@@ -532,10 +532,10 @@ export function CoinSourceEditor({
<div className="flex items-center gap-2 mt-2 pl-6"> <div className="flex items-center gap-2 mt-2 pl-6">
<span className="text-xs text-nofx-text-muted">Limit:</span> <span className="text-xs text-nofx-text-muted">Limit:</span>
<NofxSelect <NofxSelect
value={config.oi_top_limit || 10} value={config.oi_top_limit || 3}
onChange={(val) => !disabled && onChange({ ...config, oi_top_limit: parseInt(val) || 10 })} onChange={(val) => !disabled && onChange({ ...config, oi_top_limit: parseInt(val) || 3 })}
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
@@ -572,10 +572,10 @@ export function CoinSourceEditor({
<div className="flex items-center gap-2 mt-2 pl-6"> <div className="flex items-center gap-2 mt-2 pl-6">
<span className="text-xs text-nofx-text-muted">Limit:</span> <span className="text-xs text-nofx-text-muted">Limit:</span>
<NofxSelect <NofxSelect
value={config.oi_low_limit || 10} value={config.oi_low_limit || 3}
onChange={(val) => !disabled && onChange({ ...config, oi_low_limit: parseInt(val) || 10 })} onChange={(val) => !disabled && onChange({ ...config, oi_low_limit: parseInt(val) || 3 })}
disabled={disabled} disabled={disabled}
options={[3, 5, 10, 20, 30, 40, 50].map(n => ({ value: n, label: String(n) }))} options={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => ({ value: n, label: String(n) }))}
className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text" className="px-2 py-1 rounded text-xs bg-nofx-bg border border-nofx-gold/20 text-nofx-text"
/> />
</div> </div>
+6 -3
View File
@@ -1,4 +1,4 @@
import { useRef, useState, useEffect, useCallback } from 'react' import { useRef, useState, useLayoutEffect, useCallback } from 'react'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import { ChevronDown } from 'lucide-react' import { ChevronDown } from 'lucide-react'
import { cn } from '../../lib/cn' import { cn } from '../../lib/cn'
@@ -30,7 +30,7 @@ export function NofxSelect({ value, onChange, options, disabled, className, styl
setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width }) setPos({ top: rect.bottom + 4, left: rect.left, width: rect.width })
}, []) }, [])
useEffect(() => { useLayoutEffect(() => {
if (!open) return if (!open) return
updatePos() updatePos()
const handleClose = (e: MouseEvent) => { const handleClose = (e: MouseEvent) => {
@@ -39,7 +39,10 @@ export function NofxSelect({ value, onChange, options, disabled, className, styl
if (dropdownRef.current?.contains(target)) return if (dropdownRef.current?.contains(target)) return
setOpen(false) setOpen(false)
} }
const handleScroll = () => setOpen(false) const handleScroll = (e: Event) => {
if (dropdownRef.current?.contains(e.target as Node)) return
setOpen(false)
}
document.addEventListener('mousedown', handleClose) document.addEventListener('mousedown', handleClose)
window.addEventListener('scroll', handleScroll, true) window.addEventListener('scroll', handleScroll, true)
return () => { return () => {