fix(theme): per-skin legibility polish from the sweep review
Address the high-severity, systemic legibility issues found in the per-skin screenshot review (verified across all 9 skins): - Status pills (history): "Confirmed" text was 55%-alpha (dim); make it full opacity, and give status/shield pills a visible tinted fill (a48) + 1px border (a90) so they stop vanishing on dark-red / near-white / gradient skins. - Console light theming: light skins now use a near-white terminal surface, and the log text/JsonBrace colors switch to the dark defaults in light themes (the schema colors are dark-terminal-authored — honor them only in dark themes) so text isn't pale-on-white. - Dark-skin muted text: bump --on-surface-medium 0.85 / --on-surface-disabled 0.58 on dragonx/dark/color-pop-dark/obsidian (obsidian addresses were ~1.1:1). - Disabled Send button: the disabled fill was hardcoded white (invisible on light skins) — use a dark overlay in light themes. - Light-skin inputs: stronger frame fill + border color and a 1px frame border for light themes so fields (and buttons) have defined boundaries on white/ pastel surfaces. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,8 +19,8 @@ images = { background_image = "backgrounds/texture/pop-dark_bg.png", logo = "log
|
||||
--on-secondary = "#FFFFFF"
|
||||
--on-background = "#E8E6F0"
|
||||
--on-surface = "#E8E6F0"
|
||||
--on-surface-medium = "rgba(232,230,240,0.72)"
|
||||
--on-surface-disabled = "rgba(232,230,240,0.40)"
|
||||
--on-surface-medium = "rgba(232,230,240,0.85)"
|
||||
--on-surface-disabled = "rgba(232,230,240,0.58)"
|
||||
--error = "#FF5C72"
|
||||
--on-error = "#000000"
|
||||
--success = "#3DE8A0"
|
||||
@@ -61,7 +61,7 @@ images = { background_image = "backgrounds/texture/pop-dark_bg.png", logo = "log
|
||||
--sidebar-badge = "rgba(232,230,240,1.0)"
|
||||
--sidebar-divider = "rgba(200,190,240,0.05)"
|
||||
--chart-line = "rgba(124,108,255,0.12)"
|
||||
--window-control = "rgba(232,230,240,0.72)"
|
||||
--window-control = "rgba(232,230,240,0.85)"
|
||||
--window-control-hover = "rgba(124,108,255,0.12)"
|
||||
--window-close-hover = "rgba(255,92,114,0.75)"
|
||||
--spinner-track = "rgba(200,190,240,0.08)"
|
||||
|
||||
@@ -19,8 +19,8 @@ images = { background_image = "backgrounds/texture/dark_bg.png", logo = "logos/l
|
||||
--on-secondary = "#000000"
|
||||
--on-background = "#D0D0D4"
|
||||
--on-surface = "#D0D0D4"
|
||||
--on-surface-medium = "rgba(208,208,212,0.75)"
|
||||
--on-surface-disabled = "rgba(208,208,212,0.45)"
|
||||
--on-surface-medium = "rgba(208,208,212,0.85)"
|
||||
--on-surface-disabled = "rgba(208,208,212,0.58)"
|
||||
--error = "#B07080"
|
||||
--on-error = "#000000"
|
||||
--success = "#7AAE7C"
|
||||
@@ -61,7 +61,7 @@ images = { background_image = "backgrounds/texture/dark_bg.png", logo = "logos/l
|
||||
--sidebar-badge = "rgba(208,208,212,1.0)"
|
||||
--sidebar-divider = "rgba(220,220,225,0.05)"
|
||||
--chart-line = "rgba(220,220,225,0.08)"
|
||||
--window-control = "rgba(208,208,212,0.75)"
|
||||
--window-control = "rgba(208,208,212,0.85)"
|
||||
--window-control-hover = "rgba(220,220,225,0.10)"
|
||||
--window-close-hover = "rgba(200,50,60,0.70)"
|
||||
--spinner-track = "rgba(220,220,225,0.08)"
|
||||
|
||||
@@ -19,8 +19,8 @@ images = { background_image = "backgrounds/texture/obsidian_bg.png", logo = "log
|
||||
--on-secondary = "#000000"
|
||||
--on-background = "#E8E0F0"
|
||||
--on-surface = "#E8E0F0"
|
||||
--on-surface-medium = "rgba(232,224,240,0.75)"
|
||||
--on-surface-disabled = "rgba(232,224,240,0.45)"
|
||||
--on-surface-medium = "rgba(232,224,240,0.85)"
|
||||
--on-surface-disabled = "rgba(232,224,240,0.58)"
|
||||
--error = "#CF6679"
|
||||
--on-error = "#000000"
|
||||
--success = "#81C784"
|
||||
|
||||
@@ -37,8 +37,8 @@ images = { background_image = "backgrounds/texture/drgx_bg.png", logo = "logos/l
|
||||
--on-secondary = "#000000"
|
||||
--on-background = "#F0E0D8"
|
||||
--on-surface = "#F0E0D8"
|
||||
--on-surface-medium = "rgba(240,224,216,0.7)"
|
||||
--on-surface-disabled = "rgba(240,224,216,0.44)"
|
||||
--on-surface-medium = "rgba(240,224,216,0.85)"
|
||||
--on-surface-disabled = "rgba(240,224,216,0.58)"
|
||||
--error = "#FF5252"
|
||||
--on-error = "#000000"
|
||||
--success = "#81C784"
|
||||
|
||||
@@ -372,7 +372,7 @@ void ApplyColorThemeToImGui(const ColorTheme& theme)
|
||||
colors[ImGuiCol_Border] = ImVec4(1.0f, 1.0f, 1.0f, 0.15f);
|
||||
colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0.08f);
|
||||
} else {
|
||||
colors[ImGuiCol_Border] = ImVec4(0, 0, 0, 0.12f);
|
||||
colors[ImGuiCol_Border] = ImVec4(0, 0, 0, 0.22f);
|
||||
colors[ImGuiCol_BorderShadow] = ImVec4(0, 0, 0, 0.04f);
|
||||
}
|
||||
|
||||
@@ -383,10 +383,11 @@ void ApplyColorThemeToImGui(const ColorTheme& theme)
|
||||
colors[ImGuiCol_FrameBgActive] = ImVec4(1.0f, 1.0f, 1.0f, 0.15f);
|
||||
} else {
|
||||
// Light themes: the old 4/7/10% black fills were nearly invisible on a white surface (input
|
||||
// fields blended in). Darker fills so inputs/dropdowns read as defined boxes.
|
||||
colors[ImGuiCol_FrameBg] = ImVec4(0, 0, 0, 0.09f);
|
||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0, 0, 0, 0.14f);
|
||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0, 0, 0, 0.18f);
|
||||
// fields blended in). Darker fills + a 1px frame border (below) so inputs/dropdowns read as
|
||||
// defined boxes even on the pastel/gradient light skins (iridescent, color-pop-light).
|
||||
colors[ImGuiCol_FrameBg] = ImVec4(0, 0, 0, 0.11f);
|
||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0, 0, 0, 0.16f);
|
||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0, 0, 0, 0.20f);
|
||||
}
|
||||
|
||||
// Title bar
|
||||
@@ -508,7 +509,10 @@ void ApplyColorThemeToImGui(const ColorTheme& theme)
|
||||
style.WindowBorderSize = bwElem.extraFloats.count("window") ? bwElem.extraFloats.at("window") : 1.0f;
|
||||
style.ChildBorderSize = bwElem.extraFloats.count("child") ? bwElem.extraFloats.at("child") : 1.0f;
|
||||
style.PopupBorderSize = bwElem.extraFloats.count("popup") ? bwElem.extraFloats.at("popup") : 1.0f;
|
||||
style.FrameBorderSize = bwElem.extraFloats.count("frame") ? bwElem.extraFloats.at("frame") : 0.0f;
|
||||
// Light themes get a 1px frame border so inputs have a defined boundary on white/pastel surfaces;
|
||||
// dark themes stay borderless (their translucent glass FrameBg is enough). Schema can override.
|
||||
style.FrameBorderSize = bwElem.extraFloats.count("frame") ? bwElem.extraFloats.at("frame")
|
||||
: (s_isDarkTheme ? 0.0f : 1.0f);
|
||||
style.TabBorderSize = 0.0f;
|
||||
|
||||
style.AntiAliasedLines = true;
|
||||
|
||||
@@ -111,12 +111,15 @@ void ConsoleTab::refreshColors()
|
||||
ImU32 defInf = dark ? IM_COL32(191, 209, 229, 255) : IM_COL32(21, 101, 192, 255);
|
||||
ImU32 defRpc = dark ? IM_COL32(120, 180, 255, 210) : IM_COL32(25, 118, 210, 220);
|
||||
|
||||
COLOR_COMMAND = !cmd.color.empty() ? S.resolveColor(cmd.color, defCmd) : defCmd;
|
||||
COLOR_RESULT = !res.color.empty() ? S.resolveColor(res.color, defRes) : defRes;
|
||||
COLOR_ERROR = !err.color.empty() ? S.resolveColor(err.color, defErr) : defErr;
|
||||
COLOR_DAEMON = !dmn.color.empty() ? S.resolveColor(dmn.color, defDmn) : defDmn;
|
||||
COLOR_INFO = !inf.color.empty() ? S.resolveColor(inf.color, defInf) : defInf;
|
||||
COLOR_RPC = !rpc.color.empty() ? S.resolveColor(rpc.color, defRpc) : defRpc;
|
||||
// The schema console colors are authored for the dark terminal (light-on-dark); honor them only
|
||||
// in dark themes. Light themes always use the dark-text defaults so log text stays legible on the
|
||||
// now near-white console surface (otherwise the schema's light-blue text sat pale-on-white ~1.2:1).
|
||||
COLOR_COMMAND = (dark && !cmd.color.empty()) ? S.resolveColor(cmd.color, defCmd) : defCmd;
|
||||
COLOR_RESULT = (dark && !res.color.empty()) ? S.resolveColor(res.color, defRes) : defRes;
|
||||
COLOR_ERROR = (dark && !err.color.empty()) ? S.resolveColor(err.color, defErr) : defErr;
|
||||
COLOR_DAEMON = (dark && !dmn.color.empty()) ? S.resolveColor(dmn.color, defDmn) : defDmn;
|
||||
COLOR_INFO = (dark && !inf.color.empty()) ? S.resolveColor(inf.color, defInf) : defInf;
|
||||
COLOR_RPC = (dark && !rpc.color.empty()) ? S.resolveColor(rpc.color, defRpc) : defRpc;
|
||||
} else {
|
||||
// No schema — use hardcoded defaults per theme
|
||||
COLOR_COMMAND = dark ? IM_COL32(191, 209, 229, 255) : IM_COL32(21, 101, 192, 255);
|
||||
@@ -145,7 +148,7 @@ ImU32 ConsoleTab::channelTextColor(ConsoleChannel channel) const
|
||||
case ConsoleChannel::JsonKey: return WithAlpha(Secondary(), 255);
|
||||
case ConsoleChannel::JsonString: return WithAlpha(Success(), 255);
|
||||
case ConsoleChannel::JsonNumber: return WithAlpha(Warning(), 255);
|
||||
case ConsoleChannel::JsonBrace: return IM_COL32(200, 200, 200, 150);
|
||||
case ConsoleChannel::JsonBrace: return IsLightTheme() ? IM_COL32(90, 90, 90, 180) : IM_COL32(200, 200, 200, 150);
|
||||
case ConsoleChannel::None:
|
||||
default: return COLOR_RESULT;
|
||||
}
|
||||
@@ -266,7 +269,10 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
// Terminal-dark overlay: dim the glass so console text reads like a real terminal.
|
||||
{
|
||||
int darkA = static_cast<int>(schema::UI().drawElement("tabs.console", "bg-darken-alpha").sizeOr(110.0f));
|
||||
dlOut->AddRectFilled(outPanelMin, outPanelMax, IM_COL32(0, 0, 0, darkA), outGlass.rounding);
|
||||
// Light skins get a near-white terminal surface (not a black darken) so the dark, theme-aware
|
||||
// log text stays legible instead of sitting dark-on-dark-grey.
|
||||
ImU32 termOverlay = IsLightTheme() ? IM_COL32(255, 255, 255, 205) : IM_COL32(0, 0, 0, darkA);
|
||||
dlOut->AddRectFilled(outPanelMin, outPanelMax, termOverlay, outGlass.rounding);
|
||||
}
|
||||
|
||||
int consoleParentVtx = dlOut->VtxBuffer.Size;
|
||||
|
||||
@@ -904,8 +904,12 @@ static void RenderActionButtons(App* app, float width, float vScale,
|
||||
|
||||
// ---- Send button ----
|
||||
if (!can_send) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::ColorConvertU32ToFloat4(IM_COL32(255, 255, 255, (int)S.drawElement("tabs.send", "disabled-btn-bg-alpha").size)));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(IM_COL32(255, 255, 255, (int)S.drawElement("tabs.send", "disabled-btn-bg-alpha").size)));
|
||||
// The disabled fill must contrast the surface: a white overlay reads on dark skins but vanished
|
||||
// on the light/pastel skins (white-on-white). Use a dark overlay for light themes.
|
||||
int dAlpha = (int)S.drawElement("tabs.send", "disabled-btn-bg-alpha").size;
|
||||
ImU32 disFill = IsLightTheme() ? IM_COL32(0, 0, 0, dAlpha) : IM_COL32(255, 255, 255, dAlpha);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::ColorConvertU32ToFloat4(disFill));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertU32ToFloat4(disFill));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(OnSurfaceDisabled()));
|
||||
}
|
||||
|
||||
|
||||
@@ -748,7 +748,7 @@ void RenderTransactionsTab(App* app)
|
||||
} else if (tx.confirmations >= 100 && (tx.display_type == "generate" || tx.display_type == "mined")) {
|
||||
statusStr = TR("mature"); statusCol = greenCol;
|
||||
} else {
|
||||
statusStr = TR("confirmed"); statusCol = WithAlpha(Success(), 140);
|
||||
statusStr = TR("confirmed"); statusCol = Success();
|
||||
}
|
||||
// Position status badge in the middle-right area
|
||||
ImVec2 sSz = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, statusStr);
|
||||
@@ -762,23 +762,30 @@ void RenderTransactionsTab(App* app)
|
||||
float minStatusX = cx + innerW * 0.25f; // don't overlap address
|
||||
if (statusX < minStatusX) statusX = minStatusX;
|
||||
float statusTextX = statusX + (stackW - sSz.x) * 0.5f;
|
||||
// Pills use a visible tinted fill + a 1px border so each state separates from the
|
||||
// row background on every skin (faint alpha-30 fills used to vanish on dark-red /
|
||||
// near-white / gradient skins). Fill 48, border 90 of the state color's RGB.
|
||||
const float pillRound = schema::UI().drawElement("tabs.transactions", "status-pill-rounding").size;
|
||||
if (shieldedDisplay) {
|
||||
float shieldX = statusX + (stackW - shieldSz.x) * 0.5f;
|
||||
ImU32 shieldCol = Primary();
|
||||
ImU32 shieldBg = (shieldCol & 0x00FFFFFFu) | (static_cast<ImU32>(30) << 24);
|
||||
ImVec2 shieldPillMin(shieldX - Layout::spacingSm(), cy - 1.0f);
|
||||
ImVec2 shieldPillMax(shieldX + shieldSz.x + Layout::spacingSm(),
|
||||
shieldPillMin.y + capFont->LegacySize + Layout::spacingXs());
|
||||
dl->AddRectFilled(shieldPillMin, shieldPillMax, shieldBg,
|
||||
schema::UI().drawElement("tabs.transactions", "status-pill-rounding").size);
|
||||
dl->AddRectFilled(shieldPillMin, shieldPillMax,
|
||||
(shieldCol & 0x00FFFFFFu) | (static_cast<ImU32>(48) << 24), pillRound);
|
||||
dl->AddRect(shieldPillMin, shieldPillMax,
|
||||
(shieldCol & 0x00FFFFFFu) | (static_cast<ImU32>(90) << 24), pillRound, 0, 1.0f);
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(shieldX, cy), shieldCol, shieldedStr);
|
||||
}
|
||||
// Background pill
|
||||
ImU32 pillBg = (statusCol & 0x00FFFFFFu) | (static_cast<ImU32>(30) << 24);
|
||||
ImVec2 pillMin(statusTextX - Layout::spacingSm(), cy + body2->LegacySize + 1);
|
||||
ImVec2 pillMax(statusTextX + sSz.x + Layout::spacingSm(), pillMin.y + capFont->LegacySize + Layout::spacingXs());
|
||||
dl->AddRectFilled(pillMin, pillMax, pillBg, schema::UI().drawElement("tabs.transactions", "status-pill-rounding").size);
|
||||
dl->AddRectFilled(pillMin, pillMax,
|
||||
(statusCol & 0x00FFFFFFu) | (static_cast<ImU32>(48) << 24), pillRound);
|
||||
dl->AddRect(pillMin, pillMax,
|
||||
(statusCol & 0x00FFFFFFu) | (static_cast<ImU32>(90) << 24), pillRound, 0, 1.0f);
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(statusTextX, cy + body2->LegacySize + Layout::spacingXs()), statusCol, statusStr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user