feat(console): zebra contrast, edge outline, blinking caret, external-daemon status

- Lower the zebra-stripe contrast (scanline-line-alpha 4 -> 2; the derived dark
  band softens with it) so the alternating rows are subtler.
- Give the input's terminal bar a 1px outline along its own edges (theme-aware),
  matching the output panel's glass rim, and a near-white surface on light skins.
- Add a blinking terminal caret at the end of the input when it isn't focused.
- Report a daemon started before the wallet ("no wallet-managed EmbeddedDaemon"
  but RPC connected) as "Running" instead of the misleading "no daemon".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 12:53:46 -05:00
parent 7249d11899
commit d3dcb5a015
3 changed files with 38 additions and 6 deletions

View File

@@ -190,7 +190,12 @@ ConsoleStatusLine FullNodeConsoleExecutor::toolbarStatus() const
{
ConsoleStatusLine s;
daemon::EmbeddedDaemon* d = app_->consoleDaemon();
if (!d) return s; // empty text -> toolbar shows the generic "no daemon" label
if (!d) {
// No wallet-managed daemon, but a daemon started externally (before the wallet) is still
// reachable over RPC and accepts commands — report it as running rather than "no daemon".
if (app_->isConnected()) { s.text = TR("console_status_running"); s.color = Success(); }
return s; // otherwise empty text -> toolbar shows the generic "no daemon" label
}
using DState = daemon::EmbeddedDaemon::State;
switch (d->getState()) {
case DState::Stopped: s.text = TR("console_status_stopped"); s.color = IM_COL32(150,150,150,255); break;

View File

@@ -1156,7 +1156,13 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
// the darkened output panel above.
{
int darkA = static_cast<int>(schema::UI().drawElement("tabs.console", "bg-darken-alpha").sizeOr(110.0f));
dlIn->AddRectFilled(inMin, inMax, IM_COL32(0, 0, 0, darkA), Layout::glassRounding());
const bool barLight = IsLightTheme();
// Match the output panel: near-white terminal surface on light skins, dark on dark, with a
// 1px glass-rim outline along the bar's own edges (so the outline hugs the input, not inset).
dlIn->AddRectFilled(inMin, inMax, barLight ? IM_COL32(255, 255, 255, 205) : IM_COL32(0, 0, 0, darkA),
Layout::glassRounding());
dlIn->AddRect(inMin, inMax, barLight ? IM_COL32(0, 0, 0, 45) : IM_COL32(255, 255, 255, 35),
Layout::glassRounding(), 0, 1.0f);
}
// Center content vertically within glass panel
@@ -1223,10 +1229,12 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
return 0;
};
// Blend the field into the dark terminal bar: transparent frame, subtle hover/active.
// Transparent frame with a subtle hover/active tint (the outline lives on the terminal bar above,
// hugging the input's edges). Colors are theme-aware so they read on the light-skin console too.
const bool inputLight = material::IsLightTheme();
ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(255, 255, 255, 12));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, IM_COL32(255, 255, 255, 18));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, inputLight ? IM_COL32(0, 0, 0, 10) : IM_COL32(255, 255, 255, 12));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, inputLight ? IM_COL32(0, 0, 0, 16) : IM_COL32(255, 255, 255, 18));
const bool busy = exec.busy();
if (busy) ImGui::BeginDisabled();
@@ -1243,6 +1251,25 @@ void ConsoleTab::renderInput(ConsoleCommandExecutor& exec)
}
}
if (busy) ImGui::EndDisabled();
// Blinking terminal caret at the end of the current input. Shown when the field isn't actively
// being edited (ImGui draws its own caret while focused), so the console always reads as a live
// prompt. Monospace font => caret X = frame-padding + charWidth * length.
if (!busy && !ImGui::IsItemActive()) {
if (std::fmod(ImGui::GetTime(), 1.06) < 0.53) {
ImFont* mf = Type().mono();
float charW = mf->CalcTextSizeA(mf->LegacySize, FLT_MAX, 0, "M").x;
ImVec2 itMin = ImGui::GetItemRectMin();
ImVec2 itMax = ImGui::GetItemRectMax();
float caretW = std::max(2.0f, 2.0f * Layout::dpiScale());
float caretX = itMin.x + ImGui::GetStyle().FramePadding.x + charW * (float)strlen(input_buffer_);
caretX = std::min(caretX, itMax.x - ImGui::GetStyle().FramePadding.x - caretW);
float pad = (itMax.y - itMin.y) * 0.18f;
ImU32 caretCol = inputLight ? IM_COL32(0, 0, 0, 210) : IM_COL32(255, 255, 255, 210);
dlIn->AddRectFilled(ImVec2(caretX, itMin.y + pad), ImVec2(caretX + caretW, itMax.y - pad), caretCol);
}
}
ImGui::PopStyleColor(3);
ImGui::PopItemWidth();