Clarify current market opportunities

This commit is contained in:
2569718930@qq.com
2026-04-23 04:55:53 +08:00
parent 30f33bcf90
commit d8ca1ca24d
2 changed files with 63 additions and 58 deletions
@@ -2278,6 +2278,26 @@
grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-columns: repeat(5, minmax(0, 1fr));
} }
.root :global(.opportunity-empty-state) {
display: flex;
min-height: 132px;
align-items: center;
justify-content: center;
border: 1px dashed rgba(34, 211, 238, 0.2);
border-radius: 16px;
background:
radial-gradient(
circle at 50% 0%,
rgba(34, 211, 238, 0.08),
transparent 44%
),
rgba(7, 12, 22, 0.72);
color: rgba(148, 163, 184, 0.9);
font-size: 13px;
font-weight: 800;
letter-spacing: 0.04em;
}
.root :global(.opportunity-card) { .root :global(.opportunity-card) {
position: relative; position: relative;
min-width: 0; min-width: 0;
@@ -2421,22 +2441,6 @@
filter: drop-shadow(0 0 8px rgba(34, 211, 238, 0.22)); filter: drop-shadow(0 0 8px rgba(34, 211, 238, 0.22));
} }
/* Market-closed opportunity card — dimmed state */
.root :global(.opportunity-card.market-closed) {
opacity: 0.6;
border-style: dashed;
}
.root :global(.opportunity-card.market-closed:hover) {
opacity: 0.82;
}
.root :global(.opportunity-market-status) {
color: rgba(251, 191, 36, 0.8);
font-size: 10px;
font-weight: 700;
}
@keyframes home-panel-enter { @keyframes home-panel-enter {
from { from {
opacity: 0; opacity: 0;
@@ -282,7 +282,7 @@ function buildDashboardSummaryCards(
return [ return [
{ {
key: "opportunities", key: "opportunities",
title: locale === "en-US" ? "Today's Opportunities" : "今日机会分布", title: locale === "en-US" ? "Current Opportunities" : "当前机会分布",
items: [ items: [
{ {
label: locale === "en-US" ? "High risk" : "高风险", label: locale === "en-US" ? "High risk" : "高风险",
@@ -1147,8 +1147,13 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
[locale, snapshots], [locale, snapshots],
); );
// Always show top 5 cities by score, regardless of market tradability const items = useMemo(
const items = useMemo(() => snapshots.slice(0, 5), [snapshots]); () =>
snapshots
.filter((snapshot) => snapshot.tradableOpportunity)
.slice(0, 5),
[snapshots],
);
// Always render: summary cards should be visible even without tradable opportunities // Always render: summary cards should be visible even without tradable opportunities
if (!snapshots.length) return null; if (!snapshots.length) return null;
@@ -1186,28 +1191,26 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
))} ))}
</div> </div>
{items.length > 0 && ( <div className="opportunity-strip-heading">
<> <div>
<div className="opportunity-strip-heading"> <span>
<div> {locale === "en-US"
<span> ? "Current Best Markets"
{locale === "en-US" : "当前最佳机会市场"}
? "Today's Top Opportunities" </span>
: "今日最佳机会"} <strong>
</span> {locale === "en-US"
<strong> ? "Live market question · YES/NO · Edge · Trend"
{locale === "en-US" : "当前市场问题 · YES/NO 价格 · Edge · 小趋势线"}
? "Market question · YES/NO · Edge · Trend" </strong>
: "市场问题 · YES/NO 价格 · Edge · 小趋势线"} </div>
</strong> <Link href="/docs/intraday-signal" className="opportunity-view-all">
</div> {locale === "en-US" ? "View all" : "查看全部"}
<Link href="/docs/intraday-signal" className="opportunity-view-all"> </Link>
{locale === "en-US" ? "View all" : "查看全部"} </div>
</Link> {items.length > 0 ? (
</div> <div className="opportunity-card-grid top-opportunities">
<div className="opportunity-card-grid top-opportunities"> {items.map(({ city, detail, summary }, index) => {
{items.map(
({ city, detail, summary, tradableOpportunity }, index) => {
const symbol = getTempSymbol(city, summary, detail); const symbol = getTempSymbol(city, summary, detail);
const debPrediction = const debPrediction =
summary?.deb?.prediction ?? detail?.deb?.prediction; summary?.deb?.prediction ?? detail?.deb?.prediction;
@@ -1222,7 +1225,6 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
city.risk_level || city.risk_level ||
summary?.risk?.level || summary?.risk?.level ||
detail?.risk?.level; detail?.risk?.level;
const marketClosed = !tradableOpportunity;
const marketBucket = detail?.market_scan?.temperature_bucket; const marketBucket = detail?.market_scan?.temperature_bucket;
const marketQuestion = const marketQuestion =
detail?.market_scan?.primary_market?.question || detail?.market_scan?.primary_market?.question ||
@@ -1235,19 +1237,20 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
detail?.market_scan?.sparkline?.length detail?.market_scan?.sparkline?.length
? detail.market_scan.sparkline ? detail.market_scan.sparkline
: [ : [
Number(summary?.current?.temp ?? detail?.current?.temp ?? 0), Number(
summary?.current?.temp ?? detail?.current?.temp ?? 0,
),
Number(debPrediction ?? 0), Number(debPrediction ?? 0),
Number(detail?.forecast?.today_high ?? debPrediction ?? 0), Number(
detail?.forecast?.today_high ?? debPrediction ?? 0,
),
], ],
); );
return ( return (
<button <button
key={city.name} key={city.name}
type="button" type="button"
className={clsx( className="opportunity-card"
"opportunity-card",
marketClosed && "market-closed",
)}
onClick={() => void store.focusCity(city.name)} onClick={() => void store.focusCity(city.name)}
> >
<div className="opportunity-card-header"> <div className="opportunity-card-header">
@@ -1266,12 +1269,6 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
</div> </div>
<span className="opportunity-meta"> <span className="opportunity-meta">
{marketQuestion} {marketQuestion}
{marketClosed && (
<span className="opportunity-market-status">
{" · "}
{locale === "en-US" ? "Market closed" : "市场已关闭"}
</span>
)}
</span> </span>
<div className="opportunity-card-footer"> <div className="opportunity-card-footer">
<div className="opportunity-price-pair"> <div className="opportunity-price-pair">
@@ -1293,10 +1290,14 @@ function OpportunityStrip({ snapshots }: { snapshots: CitySnapshot[] }) {
</svg> </svg>
</button> </button>
); );
}, })}
)} </div>
</div> ) : (
</> <div className="opportunity-empty-state">
{locale === "en-US"
? "No active opportunity market right now."
: "当前暂无可交易机会市场"}
</div>
)} )}
</section> </section>
); );