diff --git a/src/app/styles/profile-inline-edit.css b/src/app/styles/profile-inline-edit.css index 5982c153..ad400cf0 100644 --- a/src/app/styles/profile-inline-edit.css +++ b/src/app/styles/profile-inline-edit.css @@ -186,6 +186,25 @@ outline-offset: -2px; } +/* Centered guidance line for the empty banner box — gives the blank + gradient rectangle a purpose ("this is your banner; 3:1") instead of + reading as a featureless placeholder. Padded clear of the floating + "Change banner" pill in the bottom-right corner. */ +.profile-banner-upload__hint { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 16px 16px 44px; + text-align: center; + font-family: var(--font-inter), system-ui, sans-serif; + font-size: 0.8125rem; + line-height: 1.4; + color: var(--fg-muted); + pointer-events: none; +} + .profile-banner-upload__img { width: 100%; height: 100%; diff --git a/src/components/layout/desktop-top-bar.tsx b/src/components/layout/desktop-top-bar.tsx index 3e2cc665..9fcc54a2 100644 --- a/src/components/layout/desktop-top-bar.tsx +++ b/src/components/layout/desktop-top-bar.tsx @@ -229,6 +229,12 @@ export default function DesktopTopBar() { // stays the primary "discard" action. const isOnCreatePage = pathname === "/create" || pathname === "/project/new"; const showBackRow = isOnCertDetail || isOnProjectDetail || isOnCreatePage; + // /explore renders its own contextual "Search Certified" field inside the + // page chrome (it doubles as the cross-kind filter), so the top-bar's + // global search field is a redundant second "Search Certified" input at + // every width ≥800px. Suppress the top-bar copy there — Explore owns the + // search affordance on its own surface. + const isOnExplore = pathname === "/explore"; // Settings is its own standalone surface now (reachable from the // site drawer); no tab strip there. The edit-profile page is the one // exception — it borrows the profile strip (locked to Overview, see @@ -344,6 +350,15 @@ export default function DesktopTopBar() { if (isLoading) return null; + // Marketing landing (/welcome), signed out: the page is self-contained — + // it owns its own hero "Sign in with Certified" CTA and the footer. The + // full app chrome here (global search + Explore/Apps/Help icon nav + a + // second top-right "Sign in") is redundant against that hero CTA, so the + // top bar drops out entirely. Signed-in viewers keep the bar so they can + // navigate back out of the marketing page. (The mobile already + // renders /welcome as a transparent overlay for signed-out viewers.) + if (pathname === "/welcome" && !isAuthenticated) return null; + const tabHref = (tab: ProfileTab) => { if (tab.href) return tab.href; if (!pathname) return "#"; @@ -414,9 +429,11 @@ export default function DesktopTopBar() {
-
- -
+ {isOnExplore ? null : ( +
+ +
+ )} {isAuthenticated ? (
= ({ className="profile-banner-upload__img" onError={() => setImgFailed(true)} /> - ) : null} + ) : ( + // Neutral guidance hint for the otherwise-featureless empty + // box. Sets reader expectations (what the banner is, the crop) + // instead of leaving a blank gradient rectangle. aria-hidden: + // the "Change banner" button already carries the accessible + // affordance, so the hint is decorative for screen readers. + + )}