Skip to content

Commit 37beaff

Browse files
authored
Merge pull request #4 from yashc73080:development
Compact mobile navbar and improved UI for panels
2 parents c2bd6f8 + 0c2e5c3 commit 37beaff

8 files changed

Lines changed: 158 additions & 104 deletions

File tree

frontend/app/components/ChatInterface.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,38 +136,41 @@ export default function ChatInterface({ selectedLocations, onNewChat, onShowHist
136136
return (
137137
<div
138138
onClick={handleOpenDetails}
139-
className="bg-white border border-gray-200 rounded-lg p-3 mb-2 shadow-sm hover:shadow-md transition-shadow cursor-pointer"
139+
className="bg-white border border-gray-200 rounded-lg p-2.5 md:p-3 mb-2 shadow-sm hover:shadow-md transition-shadow cursor-pointer"
140140
>
141-
<div className="flex justify-between items-start">
141+
<div className="flex justify-between items-start gap-2">
142142
<div className="flex-1 min-w-0">
143143
<h4 className="font-medium text-gray-900 text-sm truncate">{place.name}</h4>
144-
<p className="text-xs text-gray-500 truncate mt-0.5">{place.address}</p>
144+
<p className="text-xs text-gray-500 truncate">{place.address}</p>
145145
{place.rating && (
146-
<div className="flex items-center mt-1">
146+
<div className="flex items-center mt-0.5">
147147
<span className="text-yellow-500 text-xs"></span>
148-
<span className="text-xs text-gray-600 ml-1">{place.rating}</span>
148+
<span className="text-xs text-gray-600 ml-0.5">{place.rating}</span>
149149
</div>
150150
)}
151151
</div>
152-
<div className="flex flex-col gap-1.5 ml-2 shrink-0">
152+
{/* Mobile: icon-only buttons side-by-side, Desktop: stacked buttons with text */}
153+
<div className="flex flex-row md:flex-col gap-1.5 ml-2 shrink-0">
153154
<button
154155
onClick={(e) => { e.stopPropagation(); handleShowOnMap(); }}
155-
className="w-full px-4 py-2 md:px-3 md:py-1.5 bg-blue-600 text-white text-sm md:text-xs font-medium rounded-lg md:rounded-md hover:bg-blue-700 transition-colors flex items-center justify-center gap-1.5 md:gap-1"
156+
className="p-2 md:px-3 md:py-1.5 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors flex items-center justify-center gap-1"
157+
title="Show on map"
156158
>
157159
<svg className="w-4 h-4 md:w-3.5 md:h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
158160
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
159161
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
160162
</svg>
161-
Show
163+
<span className="hidden md:inline text-xs font-medium">Show</span>
162164
</button>
163165
<button
164166
onClick={(e) => { e.stopPropagation(); handleAddToItinerary(); }}
165-
className="w-full px-4 py-2 md:px-3 md:py-1.5 bg-green-600 text-white text-sm md:text-xs font-medium rounded-lg md:rounded-md hover:bg-green-700 transition-colors flex items-center justify-center gap-1.5 md:gap-1"
167+
className="p-2 md:px-3 md:py-1.5 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors flex items-center justify-center gap-1"
168+
title="Add to itinerary"
166169
>
167170
<svg className="w-4 h-4 md:w-3.5 md:h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
168171
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
169172
</svg>
170-
Add
173+
<span className="hidden md:inline text-xs font-medium">Add</span>
171174
</button>
172175
</div>
173176
</div>

frontend/app/components/ChatWidget.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,28 @@ export default function ChatWidget() {
6161
transition-all duration-300 ease-in-out
6262
${isMobileVisible ? 'translate-y-0 opacity-100' : 'translate-y-full opacity-0 pointer-events-none'}
6363
${getMobileHeightClass()}
64-
pb-20
64+
pb-12
6565
`}>
66-
{/* Drag Handle */}
66+
{/* Centered Drag Pill */}
6767
<div
68-
className="flex justify-center py-5 cursor-grab active:cursor-grabbing touch-none w-full"
68+
className="flex justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none"
6969
onMouseDown={handleDragStart}
7070
onTouchStart={handleDragStart}
7171
>
72-
<div className="w-12 h-1.5 bg-gray-300 rounded-full hover:bg-gray-400 transition-colors"></div>
72+
<div className="w-10 h-1 bg-gray-300 rounded-full"></div>
7373
</div>
7474

75-
<div className="px-4 pb-2 flex justify-between items-center border-b">
76-
<h2 className="font-semibold text-gray-900">Pathwise AI</h2>
75+
{/* Header Row - left side draggable, right side buttons */}
76+
<div className="px-4 pb-2 flex items-center border-b">
77+
{/* Draggable area - title */}
78+
<div
79+
className="flex-1 cursor-grab active:cursor-grabbing touch-none"
80+
onMouseDown={handleDragStart}
81+
onTouchStart={handleDragStart}
82+
>
83+
<h2 className="font-semibold text-gray-900">Pathwise AI</h2>
84+
</div>
85+
{/* Buttons - not draggable */}
7786
<div className="flex gap-1">
7887
{/* New Chat button */}
7988
<button

frontend/app/components/MobileNav.js

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@ import { useTrip } from '../context/TripContext';
44
import { useAuth } from '../context/authContext';
55

66
export default function MobileNav() {
7-
const { activePanel, setActivePanel, optimizedRoute, isSidebarOpen, setIsSidebarOpen, isChatOpen, setIsChatOpen } = useTrip();
7+
const {
8+
activePanel,
9+
setActivePanel,
10+
optimizedRoute,
11+
isSidebarOpen,
12+
setIsSidebarOpen,
13+
isChatOpen,
14+
setIsChatOpen,
15+
chatHeight,
16+
sidebarHeight,
17+
routeHeight
18+
} = useTrip();
819
const { userLoggedIn, openLoginModal, currentUser, openSavedTripsModal } = useAuth();
920

10-
const handleTabClick = (panel) => {
11-
21+
// Compact nav whenever any panel is open
22+
const isFullPanelOpen = activePanel !== 'none';
1223

24+
const handleTabClick = (panel) => {
1325
// Toggle panel off if already active, otherwise switch to it
1426
if (activePanel === panel) {
1527
setActivePanel('none');
@@ -54,40 +66,40 @@ export default function MobileNav() {
5466
};
5567

5668
return (
57-
<nav className="md:hidden fixed bottom-0 left-0 right-0 z-50 pb-4 pt-2 px-3 flex items-center gap-3 bg-gradient-to-t from-white via-white to-transparent">
69+
<nav className={`md:hidden fixed bottom-0 left-0 right-0 z-50 px-3 flex items-center gap-2 bg-gradient-to-t from-white via-white to-transparent transition-all duration-300 ${isFullPanelOpen ? 'pb-2 pt-1' : 'pb-4 pt-2 gap-3'}`}>
5870
{/* Floating Profile Button */}
5971
<button
6072
onClick={handleProfileClick}
61-
className={`w-12 h-12 rounded-full shadow-lg flex items-center justify-center text-white text-sm font-medium transition-all duration-200 hover:scale-105 shrink-0 ${userLoggedIn ? 'bg-gradient-to-br from-blue-500 to-blue-700' : 'bg-gray-400'}`}
73+
className={`rounded-full shadow-lg flex items-center justify-center text-white font-medium transition-all duration-300 hover:scale-105 shrink-0 ${userLoggedIn ? 'bg-gradient-to-br from-blue-500 to-blue-700' : 'bg-gray-400'} ${isFullPanelOpen ? 'w-9 h-9 text-xs' : 'w-12 h-12 text-sm'}`}
6274
aria-label="Profile"
6375
>
6476
{getInitials()}
6577
</button>
6678

6779
{/* Tab Group - fills remaining space */}
68-
<div className="flex flex-1 bg-white rounded-2xl shadow-lg overflow-hidden">
80+
<div className={`flex flex-1 bg-white shadow-lg overflow-hidden transition-all duration-300 ${isFullPanelOpen ? 'rounded-xl' : 'rounded-2xl'}`}>
6981
{/* Itinerary Tab */}
7082
<button
7183
onClick={() => handleTabClick('itinerary')}
72-
className={`flex-1 flex flex-col items-center justify-center py-3 transition-colors ${activePanel === 'itinerary'
84+
className={`flex-1 flex items-center justify-center gap-1.5 transition-all duration-300 ${isFullPanelOpen ? 'py-2' : 'py-3 flex-col gap-0'} ${activePanel === 'itinerary'
7385
? 'text-blue-600 bg-blue-50'
7486
: 'text-gray-500'
7587
}`}
7688
aria-label="View itinerary"
7789
>
78-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
90+
<svg className={`transition-all duration-300 ${isFullPanelOpen ? 'w-4 h-4' : 'w-5 h-5'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
7991
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" />
8092
</svg>
81-
<span className="text-[10px] mt-0.5 font-medium">Trip</span>
93+
<span className={`font-medium transition-all duration-300 ${isFullPanelOpen ? 'text-xs' : 'text-[10px] mt-0.5'}`}>Trip</span>
8294
</button>
8395

8496
{/* Divider */}
85-
<div className="w-px bg-gray-200 my-2"></div>
97+
<div className={`w-px bg-gray-200 transition-all duration-300 ${isFullPanelOpen ? 'my-2' : 'my-2'}`}></div>
8698

8799
{/* Route Tab */}
88100
<button
89101
onClick={() => handleTabClick('route')}
90-
className={`flex-1 flex flex-col items-center justify-center py-3 transition-colors ${activePanel === 'route'
102+
className={`flex-1 flex items-center justify-center gap-1.5 transition-all duration-300 ${isFullPanelOpen ? 'py-2' : 'py-3 flex-col gap-0'} ${activePanel === 'route'
91103
? 'text-blue-600 bg-blue-50'
92104
: optimizedRoute
93105
? 'text-gray-500'
@@ -96,28 +108,28 @@ export default function MobileNav() {
96108
aria-label="View optimized route"
97109
disabled={!optimizedRoute}
98110
>
99-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
111+
<svg className={`transition-all duration-300 ${isFullPanelOpen ? 'w-4 h-4' : 'w-5 h-5'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
100112
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
101113
</svg>
102-
<span className="text-[10px] mt-0.5 font-medium">Route</span>
114+
<span className={`font-medium transition-all duration-300 ${isFullPanelOpen ? 'text-xs' : 'text-[10px] mt-0.5'}`}>Route</span>
103115
</button>
104116

105117
{/* Divider */}
106-
<div className="w-px bg-gray-200 my-2"></div>
118+
<div className={`w-px bg-gray-200 transition-all duration-300 ${isFullPanelOpen ? 'my-2' : 'my-2'}`}></div>
107119

108120
{/* AI Chat Tab */}
109121
<button
110122
onClick={() => handleTabClick('chat')}
111-
className={`flex-1 flex flex-col items-center justify-center py-3 transition-colors ${activePanel === 'chat'
123+
className={`flex-1 flex items-center justify-center gap-1.5 transition-all duration-300 ${isFullPanelOpen ? 'py-2' : 'py-3 flex-col gap-0'} ${activePanel === 'chat'
112124
? 'text-blue-600 bg-blue-50'
113125
: 'text-gray-500'
114126
}`}
115127
aria-label="Open AI assistant"
116128
>
117-
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
129+
<svg className={`transition-all duration-300 ${isFullPanelOpen ? 'w-4 h-4' : 'w-5 h-5'}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
118130
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
119131
</svg>
120-
<span className="text-[10px] mt-0.5 font-medium">AI</span>
132+
<span className={`font-medium transition-all duration-300 ${isFullPanelOpen ? 'text-xs' : 'text-[10px] mt-0.5'}`}>AI</span>
121133
</button>
122134
</div>
123135
</nav>

frontend/app/components/RoutePanel.js

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,35 +132,44 @@ export default function RoutePanel() {
132132
transition-all duration-300 ease-in-out
133133
${isMobileVisible ? 'translate-y-0' : 'translate-y-full'}
134134
${routeHeight === 'full' ? 'h-[75vh]' : 'h-[40vh]'}
135-
pb-20
135+
pb-12
136136
`}
137137
>
138-
{/* Drag Handle */}
138+
{/* Centered Drag Pill */}
139139
<div
140-
className="flex justify-center py-6 cursor-grab active:cursor-grabbing touch-none w-full"
140+
className="flex justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none"
141141
onMouseDown={handleDragStart}
142142
onTouchStart={handleDragStart}
143143
>
144-
<div className="w-16 h-1.5 bg-gray-300 rounded-full active:bg-gray-400 transition-colors"></div>
144+
<div className="w-10 h-1 bg-gray-300 rounded-full"></div>
145145
</div>
146146

147-
<div className="p-4 border-b flex justify-between items-center">
148-
<h3 className="font-semibold text-gray-900">Optimized Route</h3>
149-
<div className="flex gap-2 items-center">
147+
{/* Header Row - left side draggable, right side buttons */}
148+
<div className="px-4 pb-2 flex items-center border-b">
149+
{/* Draggable area - title */}
150+
<div
151+
className="flex-1 cursor-grab active:cursor-grabbing touch-none"
152+
onMouseDown={handleDragStart}
153+
onTouchStart={handleDragStart}
154+
>
155+
<h3 className="font-semibold text-gray-900">Optimized Route</h3>
156+
</div>
157+
{/* Buttons - not draggable */}
158+
<div className="flex gap-1 items-center">
150159
{showSignInPrompt && !currentUser && (
151160
<button
152161
onClick={openLoginModal}
153-
className="mr-2 px-3 py-1.5 bg-blue-100 text-blue-700 text-xs font-semibold rounded-full animate-pulse hover:bg-blue-200"
162+
className="mr-1 px-2 py-1 bg-blue-100 text-blue-700 text-xs font-semibold rounded-full animate-pulse hover:bg-blue-200"
154163
>
155-
Sign In to Save
164+
Sign In
156165
</button>
157166
)}
158167
{optimizedRoute && (
159168
<>
160169
<button
161170
onClick={handleSaveTrip}
162171
disabled={isSaving}
163-
className={`p-2 text-green-600 hover:text-green-700 hover:bg-green-50 rounded-lg transition-all duration-200 ${isSaving ? 'opacity-75 cursor-not-allowed' : ''}`}
172+
className={`p-1.5 text-green-600 hover:text-green-700 hover:bg-green-50 rounded-lg transition-all duration-200 ${isSaving ? 'opacity-75 cursor-not-allowed' : ''}`}
164173
title="Save Trip"
165174
aria-label="Save trip"
166175
>
@@ -174,7 +183,7 @@ export default function RoutePanel() {
174183
</button>
175184
<button
176185
onClick={exportToGoogleMaps}
177-
className="p-2 text-blue-600 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition-all duration-200"
186+
className="p-1.5 text-blue-600 hover:text-blue-700 hover:bg-blue-50 rounded-lg transition-all duration-200"
178187
title="Export to Google Maps"
179188
aria-label="Export to Google Maps"
180189
>
@@ -186,7 +195,7 @@ export default function RoutePanel() {
186195
)}
187196
<button
188197
onClick={handleClose}
189-
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
198+
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors"
190199
aria-label="Close route panel"
191200
>
192201
<svg className="w-5 h-5 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">

frontend/app/components/Search.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export default function Search() {
180180
id="pac-input"
181181
className="flex-1 p-2.5 bg-transparent border-none focus:ring-0 focus:outline-none text-gray-900 placeholder-gray-400"
182182
type="text"
183-
placeholder="Search for a location or click on the map"
183+
placeholder="Search or click on the map"
184184
aria-label="Search for a location"
185185
/>
186186
</div>

0 commit comments

Comments
 (0)