feat(chat,notifications): first-run chat intro card; clickable toast history + "+N" badge
- Chat: a dismissible first-run intro card (how chat works — encrypted, sent as shielded txs with a small fee, tied to the seed) with a "Copy my chat address" button, shown in the empty thread pane; dismissal persisted. The copy logic is shared with the existing sidebar button (moved to a helper, unchanged). - Toasts: clicking a toast now opens the existing notification-history panel, and a "+N more" badge appears when several live toasts are queued (render only ever showed the newest). Badge opacity is a ui.toml token. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -100,6 +100,15 @@ void Notifications::render()
|
||||
float iconGap = 4.0f * dp;
|
||||
float msgW = textFont ? textFont->CalcTextSizeA(textFont->LegacySize, FLT_MAX, 0.0f, notif.message.c_str()).x : 100.0f;
|
||||
float pillWidth = pillPadX + iconW + iconGap + msgW + pillPadX;
|
||||
// "+N more" badge when several live toasts are queued (render shows only the newest).
|
||||
const size_t moreCount = hiddenLiveCount();
|
||||
std::string badge = moreCount ? ("+" + std::to_string(moreCount)) : std::string();
|
||||
float badgeW = 0.0f, badgeGap = 0.0f;
|
||||
if (!badge.empty() && textFont) {
|
||||
badgeW = textFont->CalcTextSizeA(textFont->LegacySize, FLT_MAX, 0.0f, badge.c_str()).x + 10.0f * dp;
|
||||
badgeGap = 6.0f * dp;
|
||||
pillWidth += badgeW + badgeGap;
|
||||
}
|
||||
// Clamp to reasonable bounds
|
||||
float maxPillW = viewport->WorkSize.x * 0.5f;
|
||||
if (pillWidth > maxPillW) pillWidth = maxPillW;
|
||||
@@ -163,7 +172,7 @@ void Notifications::render()
|
||||
bool clipped = false;
|
||||
if (textFont) {
|
||||
ImU32 textCol = ImGui::ColorConvertFloat4ToU32(text_color);
|
||||
const float availTextW = (pMax.x - pillPadX) - cursorX;
|
||||
const float availTextW = (pMax.x - pillPadX) - cursorX - (badge.empty() ? 0.0f : (badgeW + badgeGap));
|
||||
std::string shown = notif.message;
|
||||
if (availTextW > 0.0f &&
|
||||
textFont->CalcTextSizeA(textFont->LegacySize, FLT_MAX, 0.0f, shown.c_str()).x > availTextW) {
|
||||
@@ -183,8 +192,23 @@ void Notifications::render()
|
||||
dl->PopClipRect();
|
||||
}
|
||||
|
||||
// Hover: pause the auto-dismiss (handled next frame) and reveal the full message if it was clipped.
|
||||
// "+N more" badge, right-aligned inside the pill.
|
||||
if (!badge.empty() && textFont) {
|
||||
float badgeX = pMax.x - pillPadX - badgeW;
|
||||
ImVec4 bf = accent_color; bf.w *= nde("badge-fill-alpha", 0.35f);
|
||||
dl->AddRectFilled(ImVec2(badgeX, pillY + 3.0f * dp), ImVec2(badgeX + badgeW, pMax.y - 3.0f * dp),
|
||||
ImGui::ColorConvertFloat4ToU32(bf), (pillHeight - 6.0f * dp) * 0.5f);
|
||||
dl->AddText(textFont, textFont->LegacySize, ImVec2(badgeX + 5.0f * dp, contentY),
|
||||
ImGui::ColorConvertFloat4ToU32(text_color), badge.c_str());
|
||||
}
|
||||
|
||||
// Hover: pause the auto-dismiss (next frame), reveal the full message if clipped, and allow a click to
|
||||
// open the notification history (the status bar consumes the request).
|
||||
toast_hovered_ = ImGui::IsMouseHoveringRect(pMin, pMax);
|
||||
if (toast_hovered_) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) requestHistory();
|
||||
}
|
||||
if (toast_hovered_ && clipped)
|
||||
ImGui::SetTooltip("%s", notif.message.c_str());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user