feat(market): 3-cell min groups, full accent outline, tighter chart, no scrollbar
- Portfolio groups now default to the 3-cell minimum height (was 4). The card design adapts: below ~112px it drops the redundant DRGX footer and uses the compact hero font so a 3-cell card stays legible. - Group accent color is now a colored outline around the whole card (and the editor's live preview) instead of a stripe on the left edge; the text no longer reserves the old left-stripe offset. - Price chart: trim the empty band between the 24H VOLUME stats and the chart (smaller hero-header bottom pad), and keep the Y-axis price labels inside the card on narrow windows (clamp to the card's left edge + bump min y-axis padding 40->54) so they no longer spill onto the tab background. - Market tab no longer draws a scrollbar (NoScrollbar); the portfolio grid still scrolls via the mouse wheel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -383,21 +383,18 @@ static void RenderPortfolioEditor(App* app)
|
||||
ImU32 accent = s_pf_color ? (ImU32)s_pf_color : 0;
|
||||
GlassPanelSpec g; g.rounding = 10.0f; g.fillAlpha = 22; g.borderAlpha = 40;
|
||||
DrawGlassPanel(pdl, pMin, pMax, g);
|
||||
if (accent) {
|
||||
float bx = pMin.x + 2.0f;
|
||||
pdl->AddRectFilled(ImVec2(bx, pMin.y + ppad * 0.6f),
|
||||
ImVec2(bx + 3.0f, pMax.y - ppad * 0.6f), accent, 2.0f);
|
||||
}
|
||||
// Colored outline around the whole preview card (matches the live group cards).
|
||||
if (accent) pdl->AddRect(pMin, pMax, accent, 10.0f, 0, 2.0f);
|
||||
if (s_pf_show_sparkline && (s_pf_price_basis == 0 || s_pf_price_basis == 1)) {
|
||||
std::vector<double> h = pfSparklineSeries(state.market, s_pf_spark_interval);
|
||||
if (h.size() >= 2) {
|
||||
ImU32 spCol = WithAlpha(h.back() >= h.front() ? Success() : Error(), 80);
|
||||
ImVec2 spMin(pMin.x + ppad + (accent ? 6.0f : 0.0f), pMin.y + ph * 0.46f);
|
||||
ImVec2 spMin(pMin.x + ppad, pMin.y + ph * 0.46f);
|
||||
ImVec2 spMax(pMax.x - ppad, pMax.y - ppad * 0.6f);
|
||||
pfDrawSparkline(pdl, spMin, spMax, h, spCol);
|
||||
}
|
||||
}
|
||||
float rowY = pMin.y + ppad, nameX = pMin.x + ppad + (accent ? 6.0f : 0.0f);
|
||||
float rowY = pMin.y + ppad, nameX = pMin.x + ppad;
|
||||
if (!s_pf_icon.empty()) {
|
||||
material::project_icons::drawByName(pdl, s_pf_icon,
|
||||
ImVec2(nameX + sub1f->LegacySize * 0.5f, rowY + sub1f->LegacySize * 0.5f),
|
||||
@@ -804,10 +801,11 @@ void RenderMarketTab(App* app)
|
||||
const auto& currentExchange = registry[s_exchange_idx];
|
||||
if (s_pair_idx >= (int)currentExchange.pairs.size()) s_pair_idx = 0;
|
||||
|
||||
// Non-scrolling container — content resizes to fit available height
|
||||
ImVec2 marketAvail = ImGui::GetContentRegionAvail();
|
||||
// Scrollable: the portfolio grid can extend past the window and scroll into view.
|
||||
ImGui::BeginChild("##MarketScroll", marketAvail, false, ImGuiWindowFlags_NoBackground);
|
||||
// Scrollable (the portfolio grid can extend past the window) but with no visible scrollbar —
|
||||
// scrolling still works via the mouse wheel.
|
||||
ImGui::BeginChild("##MarketScroll", marketAvail, false,
|
||||
ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar);
|
||||
|
||||
// Responsive: scale factors per frame
|
||||
float availWidth = ImGui::GetContentRegionAvail().x;
|
||||
@@ -842,7 +840,7 @@ void RenderMarketTab(App* app)
|
||||
+ mktH3->LegacySize + Layout::spacingMd() // price row -> separator
|
||||
+ Layout::spacingSm() // separator -> stats
|
||||
+ ovFont->LegacySize + Layout::spacingXs() + sub1->LegacySize // stats label + value
|
||||
+ Layout::spacingLg(); // bottom pad before the chart
|
||||
+ Layout::spacingSm(); // bottom pad before the chart (tight)
|
||||
|
||||
// -- Portfolio geometry. No parent card background: the summary floats under the header
|
||||
// and the custom-group cards float below it (each with its own glass background). --
|
||||
@@ -1096,8 +1094,11 @@ void RenderMarketTab(App* app)
|
||||
double labelVal = yMax - (yMax - yMin) * (double)g / 4.0;
|
||||
snprintf(buf, sizeof(buf), "$%.6f", labelVal);
|
||||
ImVec2 labelSz = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, buf);
|
||||
// Keep the axis label inside the card even on narrow windows (min-padding may be
|
||||
// smaller than the label width) so it never spills onto the tab background.
|
||||
float lblX = std::max(chartMin.x + 3.0f, plotLeft - labelSz.x - 6);
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(plotLeft - labelSz.x - 6, gy - labelSz.y * 0.5f),
|
||||
ImVec2(lblX, gy - labelSz.y * 0.5f),
|
||||
OnSurfaceDisabled(), buf);
|
||||
}
|
||||
|
||||
@@ -1468,12 +1469,11 @@ void RenderMarketTab(App* app)
|
||||
GlassPanelSpec gcGlass; gcGlass.rounding = 10.0f;
|
||||
gcGlass.fillAlpha = hov ? 34 : 22; gcGlass.borderAlpha = 40;
|
||||
DrawGlassPanel(dl, gcMin, gcMax, gcGlass);
|
||||
if (hov) dl->AddRect(gcMin, gcMax, WithAlpha(OnSurface(), 70), 10.0f, 0, 1.0f);
|
||||
if (accent)
|
||||
dl->AddRectFilled(ImVec2(gcMin.x + 2.0f, gcMin.y + pad * 0.6f),
|
||||
ImVec2(gcMin.x + 5.0f, gcMax.y - pad * 0.6f), accent, 2.0f);
|
||||
// Accented groups get a colored outline around the whole card; others a subtle hover ring.
|
||||
if (accent) dl->AddRect(gcMin, gcMax, accent, 10.0f, 0, hov ? 2.5f : 2.0f);
|
||||
else if (hov) dl->AddRect(gcMin, gcMax, WithAlpha(OnSurface(), 70), 10.0f, 0, 1.0f);
|
||||
|
||||
float left = gcMin.x + pad + (accent ? 6.0f : 0.0f);
|
||||
float left = gcMin.x + pad;
|
||||
float right = gcMax.x - pad;
|
||||
float availW = right - left;
|
||||
auto fit = [&](std::string s, ImFont* f, float maxW) {
|
||||
@@ -1513,6 +1513,11 @@ void RenderMarketTab(App* app)
|
||||
dl->AddText(body2, body2->LegacySize, ImVec2(nameX, hy), OnSurfaceMedium(),
|
||||
fit(e.label, body2, nameMaxW).c_str());
|
||||
|
||||
// Short cards (near the 3-cell minimum) drop the redundant DRGX footer and use the
|
||||
// compact hero font so the value keeps room; taller cards show the full layout.
|
||||
bool cardTall = (gcMax.y - gcMin.y) > 112.0f * mktDp;
|
||||
bool showFooter = !footStr.empty() && cardTall;
|
||||
|
||||
// Sparkline strip along the bottom.
|
||||
float sparkH = 0.0f;
|
||||
if (e.showSparkline && (e.priceBasis == 0 || e.priceBasis == 1)) {
|
||||
@@ -1527,7 +1532,7 @@ void RenderMarketTab(App* app)
|
||||
// Footer: DRGX amount just above the sparkline.
|
||||
float footBottom = gcMax.y - pad - (sparkH > 0 ? sparkH + Layout::spacingXs() : 0.0f);
|
||||
float footTop = footBottom;
|
||||
if (!footStr.empty()) {
|
||||
if (showFooter) {
|
||||
footTop = footBottom - capFont->LegacySize;
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(left, footTop),
|
||||
OnSurfaceDisabled(), fit(footStr, capFont, availW).c_str());
|
||||
@@ -1535,9 +1540,9 @@ void RenderMarketTab(App* app)
|
||||
|
||||
// Hero value: large, centered in the band between the header and footer.
|
||||
if (!heroStr.empty()) {
|
||||
ImFont* heroFont = ((gcMax.y - gcMin.y) > 120.0f * mktDp) ? h4 : sub1;
|
||||
ImFont* heroFont = cardTall ? h4 : sub1;
|
||||
float bandTop = hy + body2->LegacySize + Layout::spacingSm();
|
||||
float bandBot = (footStr.empty() ? footBottom : footTop) - Layout::spacingXs();
|
||||
float bandBot = (showFooter ? footTop : footBottom) - Layout::spacingXs();
|
||||
float heroY = std::max(bandTop, (bandTop + bandBot) * 0.5f - heroFont->LegacySize * 0.5f);
|
||||
dl->AddText(heroFont, heroFont->LegacySize, ImVec2(left, heroY),
|
||||
OnSurface(), fit(heroStr, heroFont, availW).c_str());
|
||||
|
||||
Reference in New Issue
Block a user