feat(mobile): native-feel sticky top bar + bottom tab nav
Build & Push Docker Images / test-backend (push) Successful in 22s
Build & Push Docker Images / test-frontend (push) Failing after 23s
Build & Push Docker Images / build-backend (push) Has been skipped
Build & Push Docker Images / build-frontend (push) Has been skipped
Build & Push Docker Images / test-backend (push) Successful in 22s
Build & Push Docker Images / test-frontend (push) Failing after 23s
Build & Push Docker Images / build-backend (push) Has been skipped
Build & Push Docker Images / build-frontend (push) Has been skipped
Replaces the floating pill nav with persistent mobile chrome that
frames scrolling content the way iOS/Android native apps do.
New components:
- TopBar: brand left, contextual action right (Admin pill for admins,
bell for saved, Login button when logged out)
- BottomNav: 4-tab fixed nav (Search, Scan [elevated center FAB],
Saved, Profile). Saved/Profile disabled when logged out, tapping
opens LoginModal
- icons.jsx: 5 stroke-based SVG icons (Search, Scan, Bell, User, Cog)
plus Logo; replaces emoji in nav chrome
Behavior changes:
- App.jsx: tracks publicScreen ('home'|'scan'|'search') so BottomNav
can drive both top-level view + inner screen
- PublicView: screen state lifted to App via props (back-compat
defaults preserved so existing call sites don't break)
- App.css: old mobile .view-switcher block hidden (replaced by
BottomNav); .app padding bumped to clear the fixed bottom bar
Desktop (>768px) unchanged — existing centered pill nav still works,
new components hidden via display:none.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { IconBell, IconCog, IconUser, IconLogo } from './icons';
|
||||
import './TopBar.css';
|
||||
|
||||
function TopBar({
|
||||
currentUser,
|
||||
isAdmin,
|
||||
onShowSaved,
|
||||
onLoginRequest,
|
||||
onAdminClick,
|
||||
authChecked,
|
||||
}) {
|
||||
// ponytail: action slot priority — admin pill > bell (logged-in) > login button (logged-out).
|
||||
// ponytail: hidden on desktop via .top-bar { display: none } above 768px.
|
||||
function renderAction() {
|
||||
if (isAdmin) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="topbar-action topbar-action--admin"
|
||||
onClick={onAdminClick}
|
||||
aria-label="Admin panel"
|
||||
>
|
||||
<IconCog size={18} />
|
||||
<span>Admin</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
if (currentUser) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="topbar-action"
|
||||
onClick={onShowSaved}
|
||||
aria-label="Saved notifications"
|
||||
>
|
||||
<IconBell size={22} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
if (authChecked) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="topbar-action topbar-action--login"
|
||||
onClick={onLoginRequest}
|
||||
>
|
||||
<IconUser size={18} />
|
||||
<span>Login</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
return <span className="topbar-action topbar-action--placeholder" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="top-bar">
|
||||
<div className="topbar-brand">
|
||||
<IconLogo size={22} className="topbar-brand-icon" />
|
||||
<span className="topbar-brand-text">FarmaFinder</span>
|
||||
</div>
|
||||
<div className="topbar-actions">{renderAction()}</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export default TopBar;
|
||||
Reference in New Issue
Block a user