@@ -31,6 +31,7 @@ function App() {
3131 const [ lastImportAt , setLastImportAt ] = useState < string | null > ( null )
3232 const [ profilerEnabled , setProfilerEnabled ] = useState ( false )
3333 const [ profilerReport , setProfilerReport ] = useState < ProfilerReport | null > ( null )
34+ const [ profilerPanelOpen , setProfilerPanelOpen ] = useState ( false )
3435 const workerRef = useRef < Worker | null > ( null )
3536 const generationRef = useRef ( 0 ) as MutableRefObject < number >
3637 const profilerEnabledRef = useRef ( false )
@@ -169,11 +170,73 @@ function App() {
169170 existingFlightsRef . current = [ ]
170171 } , [ createWorker ] )
171172
172- const profilerOverlay = (
173+ const topNav = (
174+ < div className = "fixed top-5 right-5 z-[9999] flex items-center gap-1" >
175+ { /* Profiler toggle */ }
176+ < button
177+ onClick = { ( ) => {
178+ if ( ! profilerEnabled ) {
179+ handleProfilerToggle ( )
180+ } else {
181+ setProfilerPanelOpen ( ! profilerPanelOpen )
182+ }
183+ } }
184+ className = { `relative p-2 transition-colors duration-200 ${
185+ profilerEnabled
186+ ? 'text-green-400 hover:text-green-300'
187+ : 'text-gray-500 hover:text-white'
188+ } `}
189+ title = { profilerEnabled
190+ ? profilerReport
191+ ? `Pipeline profiler — click to ${ profilerPanelOpen ? 'close' : 'open' } details`
192+ : 'Profiler on — process a file to see timings'
193+ : 'Enable pipeline profiler — measures timing for each processing step'
194+ }
195+ >
196+ < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" aria-hidden = "true" >
197+ < circle cx = "12" cy = "13" r = "8" />
198+ < path d = "M12 9v4l2 2" />
199+ < path d = "M10 2h4" />
200+ < path d = "M12 2v2" />
201+ </ svg >
202+ { profilerEnabled && (
203+ < span className = "absolute top-1 right-1 w-2 h-2 bg-green-400 rounded-full" />
204+ ) }
205+ </ button >
206+ { /* Blog post */ }
207+ < a
208+ href = "https://samselvanathan.com/posts/flightwrapped-on-device-ai-flight-visualizer"
209+ target = "_blank"
210+ rel = "noopener noreferrer"
211+ className = "p-2 text-gray-500 hover:text-white transition-colors duration-200"
212+ aria-label = "Read the blog post"
213+ >
214+ < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" strokeWidth = "2" strokeLinecap = "round" strokeLinejoin = "round" aria-hidden = "true" >
215+ < path d = "M4 19.5v-15A2.5 2.5 0 016.5 2H20v20H6.5a2.5 2.5 0 010-5H20" />
216+ </ svg >
217+ </ a >
218+ { /* GitHub */ }
219+ < a
220+ href = "https://github.com/samsel/FlightWrapped"
221+ target = "_blank"
222+ rel = "noopener noreferrer"
223+ className = "p-2 text-gray-500 hover:text-white transition-colors duration-200"
224+ aria-label = "View source on GitHub"
225+ >
226+ < svg width = "20" height = "20" viewBox = "0 0 24 24" fill = "currentColor" aria-hidden = "true" >
227+ < path d = "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z" />
228+ </ svg >
229+ </ a >
230+ </ div >
231+ )
232+
233+ const profilerPanel = (
173234 < ProfilerOverlay
174235 enabled = { profilerEnabled }
175236 onToggle = { handleProfilerToggle }
176237 report = { profilerReport }
238+ panelOpen = { profilerPanelOpen }
239+ onPanelToggle = { ( ) => setProfilerPanelOpen ( false ) }
177240 />
178241 )
179242
@@ -195,7 +258,8 @@ function App() {
195258 </ button >
196259 </ div >
197260 ) }
198- { profilerOverlay }
261+ { topNav }
262+ { profilerPanel }
199263 </ div >
200264 )
201265 }
@@ -205,7 +269,8 @@ function App() {
205269 < div className = "min-h-screen glass-bg text-white flex flex-col items-center justify-center px-4 animate-fade-in" >
206270 < h1 className = "text-3xl font-bold mb-8" > FlightWrapped</ h1 >
207271 < ParsingProgress progress = { progress } onReset = { resetToLanding } />
208- { profilerOverlay }
272+ { topNav }
273+ { profilerPanel }
209274 </ div >
210275 )
211276 }
@@ -219,7 +284,8 @@ function App() {
219284 archetype = { archetype }
220285 onComplete = { ( ) => setAppState ( 'results' ) }
221286 />
222- { profilerOverlay }
287+ { topNav }
288+ { profilerPanel }
223289 </ >
224290 )
225291 }
@@ -238,7 +304,8 @@ function App() {
238304 onFileUpload = { handleFileUpload }
239305 />
240306 </ div >
241- { profilerOverlay }
307+ { topNav }
308+ { profilerPanel }
242309 </ ErrorBoundary >
243310 )
244311}
0 commit comments