1
0
forked from GRIN/grim

Build 73: chromeless Pay-screen navbar

On the Pay surface the 3-item bar drops its floating pill + shadow — Wallet,
the center ツ, and Activity sit dark directly on the yellow, Cash App-style.
Other surfaces keep the floating pill.
This commit is contained in:
2ro
2026-06-14 15:41:44 -04:00
parent 7e3f335e79
commit f5c449463b
+41 -30
View File
@@ -410,9 +410,12 @@ impl GoblinWalletView {
});
}
/// Floating 3-item pill bar: Wallet · Pay (center ツ puck) · Activity.
/// 3-item bar: Wallet · Pay (center ツ) · Activity. A floating pill on most
/// surfaces; chromeless (no pill/shadow, dark items on yellow) on the Pay tab.
fn tab_bar_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) {
let t = theme::tokens();
let pay = self.tab == Tab::Pay;
let yt = &theme::YELLOW;
let has_requests = wallet
.nostr_service()
.map(|s| !s.store.pending_requests().is_empty())
@@ -424,20 +427,22 @@ impl GoblinWalletView {
ui.horizontal(|ui| {
ui.add_space(margin);
let (bar_rect, _) = ui.allocate_exact_size(Vec2::new(bar_w, bar_h), Sense::hover());
// Soft shadow + floating pill.
let shadow = bar_rect.translate(Vec2::new(0.0, 3.0)).expand(2.0);
ui.painter().rect_filled(
shadow,
CornerRadius::same(34),
Color32::from_black_alpha(70),
);
ui.painter().rect(
bar_rect,
CornerRadius::same(32),
t.surface,
Stroke::new(1.0, t.line),
egui::StrokeKind::Inside,
);
// Soft shadow + floating pill — omitted on the Pay surface.
if !pay {
let shadow = bar_rect.translate(Vec2::new(0.0, 3.0)).expand(2.0);
ui.painter().rect_filled(
shadow,
CornerRadius::same(34),
Color32::from_black_alpha(70),
);
ui.painter().rect(
bar_rect,
CornerRadius::same(32),
t.surface,
Stroke::new(1.0, t.line),
egui::StrokeKind::Inside,
);
}
let cell = bar_w / 3.0;
let tabs = [
@@ -454,11 +459,14 @@ impl GoblinWalletView {
let active = self.tab == tab;
match icon {
Some(icon) => {
// Icon-only; the active tab gets a circular highlight.
if active {
// Icon-only; the active tab gets a circular highlight (only
// where there's a pill — not on the chromeless Pay surface).
if active && !pay {
ui.painter().circle_filled(rect.center(), 22.0, t.surface2);
}
let color = if active {
let color = if pay {
if active { yt.text } else { yt.text_dim }
} else if active {
t.surface_text
} else {
t.surface_text_mute
@@ -472,24 +480,27 @@ impl GoblinWalletView {
);
}
None => {
// Center Pay action: accent ツ puck.
let grow = if active || resp.hovered() { 1.0 } else { 0.0 };
ui.painter().circle_filled(
rect.center(),
24.0 + grow,
if resp.hovered() {
t.accent_dark
} else {
t.accent
},
);
// Center Pay action: accent ツ puck off the Pay surface; a
// chromeless dark ツ on it (Cash App style).
if !pay {
let grow = if active || resp.hovered() { 1.0 } else { 0.0 };
ui.painter().circle_filled(
rect.center(),
24.0 + grow,
if resp.hovered() {
t.accent_dark
} else {
t.accent
},
);
}
ui.painter().text(
rect.center(),
egui::Align2::CENTER_CENTER,
w::TSU,
// Noto Sans JP's clean ツ — the Pay puck mark, only here.
FontId::new(31.0, egui::FontFamily::Name("noto-tsu".into())),
t.accent_ink,
if pay { yt.text } else { t.accent_ink },
);
}
}