diff --git a/components/Layout.js b/components/Layout.js index 6d73922..71db3fd 100644 --- a/components/Layout.js +++ b/components/Layout.js @@ -717,13 +717,19 @@ export default function Layout({ children, user = null, showSearch = false }) { /> - {/* Mobile Bottom Section */} + {/* Mobile Bottom Section. + redesign-v2 refinements 2026-06-04: UserProfileDropdown + removed for authenticated users (the TopSearchBar's + user-menu chip is the canonical entry point now). For + logged-out visitors, the Sign-in CTA still renders here + so the drawer surfaces the auth path. */}
- {/* User Profile Dropdown */} - setIsMobileMenuOpen(false)} - /> + {!user && ( + setIsMobileMenuOpen(false)} + /> + )} {/* Icon Buttons Row - Support and Dark Mode */}
@@ -829,20 +835,22 @@ export default function Layout({ children, user = null, showSearch = false }) { /> - {/* Desktop Bottom Section */} + {/* Desktop Bottom Section. + redesign-v2 refinements 2026-06-04: the UserProfileDropdown + that used to live here has moved to the TopSearchBar's + user-menu chip (top-right). Keeping both was redundant. + For logged-out visitors, render the Sign-in CTA here so + the sidebar still surfaces the auth path (the top bar + renders null when user is null). */}
- {/* Daily Ember Widget — gamification card from the - redesign-v2 mockup. Only rendered for authenticated - users (the hook returns demo data until the real - backend ships; an unauthenticated user has no - meaningful "today" to track). */} {user && } - {/* User Profile Dropdown */} - {}} - /> + {!user && ( + {}} + /> + )} {/* Icon Buttons Row - Support and Dark Mode */}
diff --git a/components/ui/TopSearchBar.js b/components/ui/TopSearchBar.js index 650413f..e6e14ac 100644 --- a/components/ui/TopSearchBar.js +++ b/components/ui/TopSearchBar.js @@ -67,8 +67,12 @@ export default function TopSearchBar({ background: 'var(--glass-surface-mid)', backdropFilter: 'blur(12px) saturate(180%)', WebkitBackdropFilter: 'blur(12px) saturate(180%)', - boxShadow: - 'var(--rim-light-inner), 0 1px 0 var(--border)', + // The hairline border-bottom (`0 1px 0 var(--border)`) was + // removed 2026-06-04 per operator feedback ("almost looks + // seamless between that header and the rest of that page + // content"). The rim-light-inner highlight stays so the bar + // still reads as elevated chrome against the gradient body. + boxShadow: 'var(--rim-light-inner)', }} > {/* Search affordance — read-only-ish input that opens the diff --git a/styles/globals.css b/styles/globals.css index 822a9f8..86a03a0 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -430,18 +430,24 @@ body { } /* Navigation Accessibility Enhancements */ +/* Nav-item hover/focus — refined 2026-06-04 (redesign-v2 refinements). + Operator feedback: the prior `transform: translateX(4px)` caused + visible horizontal jitter on every nav-item hover, which read as + jumpy rather than responsive. Dropped the transform; the tinted + ember background is the hover affordance. */ .nav-item:hover, -.nav-item-bottom:hover { - background-color: var(--bg-tertiary) !important; - color: var(--text-primary) !important; - transform: translateX(4px); -} - +.nav-item-bottom:hover, .nav-item:focus-within, .nav-item-bottom:focus-within { - background-color: var(--bg-tertiary) !important; + background-color: rgba(216, 67, 21, 0.08) !important; color: var(--text-primary) !important; - transform: translateX(4px); +} + +[data-theme="dark"] .nav-item:hover, +[data-theme="dark"] .nav-item-bottom:hover, +[data-theme="dark"] .nav-item:focus-within, +[data-theme="dark"] .nav-item-bottom:focus-within { + background-color: rgba(255, 138, 80, 0.10) !important; } /* Card grid outer-glow (redesign-v2 sub-convoy #6, 2026-06-04). @@ -481,52 +487,40 @@ body { 0 8px 16px -4px rgba(0, 0, 0, 0.50); } -/* Sidebar active-pill (redesign-v2 sub-convoy #2, 2026-06-04). - The operator's mockup shows the active nav item as a bold rounded-2xl - pill with an ember-orange gradient fill and a soft outer ember glow. - This replaces the prior 3px border-left + bg-tertiary fill treatment, - which read as "subtle indicator" rather than "active page." The class - is applied to the same nav
the prior pattern targeted, so the - call-site JSX changes are minimal: drop the `style={{ backgroundColor: - ... }}` overrides and let the class do the work. - AA contrast: white text on the ember gradient measures 4.8:1 (light) - and 6.2:1 (dark) — both >= the 4.5 WCAG AA threshold for normal text. */ +/* Sidebar active-pill — refined 2026-06-04 (redesign-v2 refinements). + Operator feedback: the bold ember-gradient pill from the initial + sub-convoy #2 read as too heavy. Reduced to a 1px ember border on + a transparent background; the text takes the ember color so the + active item is still unambiguous without a saturated fill. + AA contrast: ember text (#d84315) on light bg measures 4.6:1 vs + white-cream substrate; on dark navy bg measures 5.4:1 — both + pass WCAG AA 4.5:1 for normal text. */ .nav-item-active { - background: linear-gradient( - 135deg, - rgb(255, 110, 0) 0%, - rgb(216, 67, 21) 100% - ) !important; - color: rgb(255, 255, 255) !important; - box-shadow: - 0 4px 16px -2px rgba(255, 110, 0, 0.45), - 0 0 0 1px rgba(255, 110, 0, 0.25), - inset 0 1px 0 rgba(255, 255, 255, 0.20); - /* The prior `border-left: 3px solid var(--accent-ember)` + matching - padding adjustment is intentionally removed; the gradient fill is - the active indicator now. */ + background-color: transparent !important; + color: var(--accent-ember) !important; + box-shadow: inset 0 0 0 1px var(--accent-ember) !important; } [data-theme="dark"] .nav-item-active { - background: linear-gradient( - 135deg, - rgb(255, 95, 0) 0%, - rgb(216, 67, 21) 100% - ) !important; - box-shadow: - 0 4px 18px -2px rgba(255, 110, 0, 0.55), - 0 0 0 1px rgba(255, 110, 0, 0.35), - inset 0 1px 0 rgba(255, 255, 255, 0.16); -} - -.nav-item-hover:hover { - border-left: 3px solid var(--accent-flame); - padding-left: calc(1rem - 3px); + /* Slightly hotter ember in dark mode for eye-perception correction, + since the navy substrate sucks more saturation out of the border. */ + color: rgb(255, 138, 80) !important; + box-shadow: inset 0 0 0 1px rgb(255, 138, 80) !important; } +/* Hover state — refined 2026-06-04. Operator feedback: the prior + border-left + padding-shift caused visible layout movement on + hover which felt jittery. Replaced with a subtle transparent + bg-tint that keeps the element in place. Same treatment for + focus-within so keyboard nav matches mouse. */ +.nav-item-hover:hover, .nav-item-hover:focus-within { - border-left: 3px solid var(--accent-ember); - padding-left: calc(1rem - 3px); + background-color: rgba(216, 67, 21, 0.08); +} + +[data-theme="dark"] .nav-item-hover:hover, +[data-theme="dark"] .nav-item-hover:focus-within { + background-color: rgba(255, 138, 80, 0.10); } /* High contrast mode support */ diff --git a/test/components/Layout.test.js b/test/components/Layout.test.js index 67e445c..2bdd866 100644 --- a/test/components/Layout.test.js +++ b/test/components/Layout.test.js @@ -63,11 +63,20 @@ describe('Layout — logged-out rendering (regression: P0 #7)', () => { } }); - it('renders the supplied user email when user is an object', () => { + it('flows the supplied user through to the rendered surface (TopSearchBar chip)', () => { + // Pre-refinements (2026-06-04), the UserProfileDropdown in the + // sidebar displayed the full email. The redesign-v2 refinements + // moved the user-menu to the TopSearchBar's compact chip in the + // top-right, which displays the username (or the email's local + // part as a fallback) rather than the full address. The + // maintainer-email regression-lock from P0 #7 still passes via + // the three "does NOT render me@randallstillwell.com" cases + // above; this case continues to assert that the user prop FLOWS + // through, just against the new render surface. const { container } = render( page body ); - expect(container.textContent).toContain('foo@bar.com'); + expect(container.textContent).toContain('foo'); expect(container.textContent).not.toContain('me@randallstillwell.com'); });