From 39cb427e72e99de98d4ed510654800b8bc8c18f8 Mon Sep 17 00:00:00 2001 From: snax y-not Date: Tue, 29 Sep 2026 02:57:21 -0400 Subject: [PATCH 1/2] ui: move view switcher from header into content toolbar above events Adds a ViewToolbar row (result count left, view switcher right) directly above the events content, inside the collapsible filter wrapper so it hides/shows with the filter bar on mobile scroll. Removes the switcher from the site header. Buttons use aria-pressed in a labelled group, with tooltips; on mobile only the active option shows its text label. Styles use theme tokens. localStorage persistence unchanged. Co-Authored-By: Claude Opus 5.5 --- src/components/EventApp.tsx | 8 ++--- src/components/Header.tsx | 9 +----- src/components/ViewToggle.tsx | 58 ++++++++++++++++++++++------------ src/components/ViewToolbar.tsx | 27 ++++++++++++++++ 4 files changed, 68 insertions(+), 34 deletions(-) create mode 100644 src/components/ViewToolbar.tsx diff --git a/src/components/EventApp.tsx b/src/components/EventApp.tsx index 6148946e..a935fbf7 100644 --- a/src/components/EventApp.tsx +++ b/src/components/EventApp.tsx @@ -25,6 +25,7 @@ import type { ABTest, ETHDenverEvent } from '@/lib/types'; import { resolveItemVariants, getVisitorId } from '@/lib/ab-testing'; import { Header } from './Header'; import { FilterBar } from './FilterBar'; +import { ViewToolbar } from './ViewToolbar'; import { ListView } from './ListView'; import { GalleryView } from './GalleryView'; import { TableView } from './TableView'; @@ -488,8 +489,6 @@ export function EventApp({ initialConference, initialEvents }: { initialConferen return (
+
{/* Main content area */} diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 904305a7..af2efbe5 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -4,14 +4,11 @@ import { memo, useState } from 'react'; import Image from 'next/image'; import { User, MapPin, Loader2 } from 'lucide-react'; import { trackAuthPrompt } from '@/lib/analytics'; -import { ViewMode, ETHDenverEvent } from '@/lib/types'; -import { ViewToggle } from './ViewToggle'; +import { ETHDenverEvent } from '@/lib/types'; import { useAuth } from '@/contexts/AuthContext'; import { AuthModal, UserMenu } from './AuthModal'; interface HeaderProps { - viewMode: ViewMode; - onViewChange: (mode: ViewMode) => void; events: ETHDenverEvent[]; itinerary: Set; onOpenFriends: () => void; @@ -24,8 +21,6 @@ interface HeaderProps { } export const Header = memo(function Header({ - viewMode, - onViewChange, events, itinerary, onOpenFriends, @@ -50,8 +45,6 @@ export const Header = memo(function Header({ {/* Right: Controls */}
- - {/* Proximity check-in indicator */} {hasNearbyLiveEvents && user && ( - ))} +
+ {views.map(({ mode, icon: Icon, label }) => { + const active = viewMode === mode; + return ( + + ); + })}
); } diff --git a/src/components/ViewToolbar.tsx b/src/components/ViewToolbar.tsx new file mode 100644 index 00000000..31a7951d --- /dev/null +++ b/src/components/ViewToolbar.tsx @@ -0,0 +1,27 @@ +'use client'; + +import { memo } from 'react'; +import { ViewMode } from '@/lib/types'; +import { ViewToggle } from './ViewToggle'; + +interface ViewToolbarProps { + viewMode: ViewMode; + onViewChange: (mode: ViewMode) => void; + eventCount: number; +} + +/** + * Toolbar row directly above the events content: result count on the left, + * view mode switcher on the right. + */ +export const ViewToolbar = memo(function ViewToolbar({ viewMode, onViewChange, eventCount }: ViewToolbarProps) { + return ( +
+

+ {eventCount.toLocaleString()}{' '} + {eventCount === 1 ? 'event' : 'events'} +

+ +
+ ); +}); From 623f3d0231658e52f2271e57cfaadbf0c1caa515 Mon Sep 17 00:00:00 2001 From: snax y-not Date: Tue, 29 Sep 2026 10:00:22 -0400 Subject: [PATCH 2/2] =?UTF-8?q?ui:=20search=20placeholder=20'Search=20even?= =?UTF-8?q?ts=E2=80=A6'=20(count=20now=20shown=20in=20view=20toolbar)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- src/components/EventApp.tsx | 1 - src/components/FilterBar.tsx | 6 ++---- src/components/SearchBar.tsx | 5 ++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/components/EventApp.tsx b/src/components/EventApp.tsx index a935fbf7..850f40cc 100644 --- a/src/components/EventApp.tsx +++ b/src/components/EventApp.tsx @@ -566,7 +566,6 @@ export function EventApp({ initialConference, initialEvents }: { initialConferen onToggleFriend={toggleFriend} searchQuery={filters.searchQuery} onSearchChange={handleSearchChange} - eventCount={filteredEvents.length} onSubmitEvent={handleOpenSubmitEvent} onSignIn={handleOpenSignIn} orgNames={orgNames} diff --git a/src/components/FilterBar.tsx b/src/components/FilterBar.tsx index 4499a14c..fadae281 100644 --- a/src/components/FilterBar.tsx +++ b/src/components/FilterBar.tsx @@ -34,7 +34,6 @@ interface FilterBarProps { onToggleFriend: (friendId: string) => void; searchQuery: string; onSearchChange: (query: string) => void; - eventCount: number; onSubmitEvent?: () => void; onSignIn?: () => void; conferenceTabs?: TabConfig[]; @@ -68,7 +67,6 @@ export const FilterBar = memo(function FilterBar({ onToggleFriend, searchQuery, onSearchChange, - eventCount, onSubmitEvent, onSignIn, orgNames, @@ -202,7 +200,7 @@ export const FilterBar = memo(function FilterBar({ {/* Desktop: inline search bar between conference dropdown and Now */}
- + {onSubmitEvent && (