ui: tighten dashboard copy and fix layout issues
This commit is contained in:
@@ -9,7 +9,6 @@ import { swrFetch } from '@/lib/cache'
|
||||
import PostRow from '@/components/dashboard/PostCards'
|
||||
import SystemControl from '@/components/signals/SystemControl'
|
||||
import InfoTip from '@/components/ui/InfoTip'
|
||||
import SignalMonitor from '@/components/dashboard/SignalMonitor'
|
||||
|
||||
// MacroPanel is 631 lines with heavy indicator math — split it out.
|
||||
const MacroPanel = dynamic(() => import('@/components/btc/MacroPanel'), {
|
||||
@@ -84,18 +83,9 @@ export default function MacroVibesPage({
|
||||
<div className="page">
|
||||
<div className="page-head">
|
||||
<div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
|
||||
<h1 className="page-title" style={{ margin: 0 }}>{isZh ? '宏观氛围' : 'Macro Vibes'}</h1>
|
||||
<span style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 4,
|
||||
padding: '2px 8px', borderRadius: 6, fontSize: 11, fontWeight: 700,
|
||||
background: 'var(--bg-sunk)',
|
||||
color: 'var(--ink-3)', border: '1px solid var(--line)',
|
||||
letterSpacing: '0.04em',
|
||||
}}>
|
||||
{isZh ? '手动开仓 · Bot 托管' : 'You open · bot manages'}
|
||||
</span>
|
||||
</div>
|
||||
{/* No "You open · bot manages" badge — the SystemControl strip right
|
||||
below says the same thing verbatim ("You open · bot manages exit"). */}
|
||||
<h1 className="page-title" style={{ margin: 0 }}>{isZh ? '宏观氛围' : 'Macro Vibes'}</h1>
|
||||
</div>
|
||||
<span className="chip"><span className="live-dot" />Live</span>
|
||||
</div>
|
||||
@@ -133,14 +123,17 @@ export default function MacroVibesPage({
|
||||
users are reasoning about the broader risk regime. The Funding tab
|
||||
has its own live funding panel below. */}
|
||||
{tab === 'bottom' && <MacroPanel />}
|
||||
{/* SignalMonitor (ETH/LINK Breakout Monitor) unmounted 2026-06-12: the
|
||||
backend scanner is disabled (services/funding_signal.py _enabled=False,
|
||||
operator-only toggle), so the panel only ever showed "Paused / No
|
||||
signals yet" — and breakout scanning is unrelated to funding reversal
|
||||
anyway. Component kept at components/dashboard/SignalMonitor.tsx;
|
||||
remount here if the scanner is ever re-enabled. */}
|
||||
{tab === 'funding' && (
|
||||
<>
|
||||
<FundingPanel
|
||||
isZh={isZh}
|
||||
initialSnapshot={initialFundingSnapshot}
|
||||
/>
|
||||
<SignalMonitor />
|
||||
</>
|
||||
<FundingPanel
|
||||
isZh={isZh}
|
||||
initialSnapshot={initialFundingSnapshot}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', margin: '16px 0 12px' }}>
|
||||
@@ -317,14 +310,10 @@ function FundingPanel({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{snap.history && snap.history.length > 1 && (
|
||||
<FundingSparkline
|
||||
history={snap.history}
|
||||
cadenceHours={snap.cadence_hours ?? 8}
|
||||
extremeCumPct={thr}
|
||||
isZh={isZh}
|
||||
/>
|
||||
)}
|
||||
{/* 7-day sparkline removed: the y-range was forced to include the ±threshold
|
||||
lines, so in normal regimes the curve rendered as a flat line on the zero
|
||||
axis with ~80% of the plot being empty danger-zone shading. The stat boxes
|
||||
above (latest / 24h avg / 30d cumulative / signal state) carry the signal. */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -352,73 +341,6 @@ function StatBox({ label, value, color, sub, hint }: {
|
||||
)
|
||||
}
|
||||
|
||||
// Tiny inline SVG sparkline of the last 7 days of funding cycles.
|
||||
// `extremeCumPct` is the 30d cumulative threshold (e.g. 3.0). To project it as
|
||||
// a per-cycle reference line we divide by the number of cycles in 30 days at
|
||||
// the venue's cadence (24h × 30d / cadence_h). This is the per-cycle rate that
|
||||
// — sustained for 30 days — would hit the extreme bucket.
|
||||
function FundingSparkline({ history, cadenceHours, extremeCumPct, isZh }: {
|
||||
history: { t: number; rate_pct: number }[]
|
||||
cadenceHours: number
|
||||
extremeCumPct: number
|
||||
isZh: boolean
|
||||
}) {
|
||||
const W = 600, H = 90, PAD = 6
|
||||
const cyclesIn30d = Math.max(1, (30 * 24) / Math.max(cadenceHours, 0.5))
|
||||
const perCycleThr = extremeCumPct / cyclesIn30d // e.g. 3% / 90 ≈ 0.033%
|
||||
|
||||
const rates = history.map(h => h.rate_pct)
|
||||
// Ensure threshold lines are always visible in the y-range
|
||||
const minR = Math.min(...rates, -perCycleThr * 1.2)
|
||||
const maxR = Math.max(...rates, perCycleThr * 1.2)
|
||||
const span = maxR - minR || 1
|
||||
const x = (i: number) => PAD + (i / (history.length - 1)) * (W - 2 * PAD)
|
||||
const y = (r: number) => PAD + (1 - (r - minR) / span) * (H - 2 * PAD)
|
||||
const zeroY = y(0)
|
||||
const posThrY = y(perCycleThr)
|
||||
const negThrY = y(-perCycleThr)
|
||||
const path = history.map((h, i) => `${i === 0 ? 'M' : 'L'} ${x(i)} ${y(h.rate_pct)}`).join(' ')
|
||||
const last = history[history.length - 1]
|
||||
// Color the dot by whether the latest cycle is inside the danger band
|
||||
const inDanger = Math.abs(last.rate_pct) >= perCycleThr
|
||||
const dotColor = inDanger
|
||||
? (last.rate_pct > 0 ? 'var(--down)' : 'var(--up)')
|
||||
: 'var(--amber, #f59e0b)'
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{
|
||||
display: 'flex', justifyContent: 'space-between',
|
||||
fontSize: 10, color: 'var(--ink-4)', marginBottom: 4,
|
||||
}}>
|
||||
<span>{isZh ? '7 日资金费率(单周期 %)' : '7-day funding (per-cycle %)'}</span>
|
||||
<span>{isZh ? `危险区间:每周期 ±${perCycleThr.toFixed(3)}%` : `danger band: ±${perCycleThr.toFixed(3)}% / cycle`}</span>
|
||||
</div>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: H, display: 'block' }}>
|
||||
{/* danger zones — shaded above +thr and below -thr */}
|
||||
<rect x={PAD} y={PAD} width={W - 2 * PAD} height={Math.max(0, posThrY - PAD)}
|
||||
fill="var(--down)" opacity={0.07} />
|
||||
<rect x={PAD} y={negThrY} width={W - 2 * PAD} height={Math.max(0, H - PAD - negThrY)}
|
||||
fill="var(--up)" opacity={0.07} />
|
||||
|
||||
{/* zero line */}
|
||||
<line x1={PAD} x2={W - PAD} y1={zeroY} y2={zeroY}
|
||||
stroke="var(--line-2, var(--line))" strokeWidth={1} />
|
||||
{/* positive / negative threshold lines */}
|
||||
<line x1={PAD} x2={W - PAD} y1={posThrY} y2={posThrY}
|
||||
stroke="var(--down)" strokeWidth={1} strokeDasharray="3 3" opacity={0.6} />
|
||||
<line x1={PAD} x2={W - PAD} y1={negThrY} y2={negThrY}
|
||||
stroke="var(--up)" strokeWidth={1} strokeDasharray="3 3" opacity={0.6} />
|
||||
|
||||
{/* funding curve */}
|
||||
<path d={path} fill="none" stroke="var(--amber, #f59e0b)" strokeWidth={1.5} />
|
||||
{/* current value dot */}
|
||||
<circle cx={x(history.length - 1)} cy={y(last.rate_pct)} r={3.5} fill={dotColor} />
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function BtcSkeleton() {
|
||||
return (
|
||||
<div className="post-stream" style={{ marginTop: 8 }}>
|
||||
|
||||
Reference in New Issue
Block a user