|
2 | 2 | import React, { useEffect, useMemo, useState, Suspense, lazy } from "react"; |
3 | 3 | import { Routes, Route, Navigate } from "react-router-dom"; |
4 | 4 | import { Card, CardHeader, CardContent, CardTitle } from "./components/ui/card"; |
5 | | -import { Button } from "./components/ui/button"; |
6 | | -import { Input } from "./components/ui/input"; |
7 | | -import { Loader2, Github, RefreshCcw, ShieldQuestion, Sun, Moon, Monitor, Maximize2, Minimize2, ExternalLink } from "lucide-react"; |
| 5 | +import { Loader2, ShieldQuestion } from "lucide-react"; |
8 | 6 | import { githubGraphQL, ORG_REPOS_ISSUES, fetchProjectsWithStatus, fetchIssueTypes } from "./api/github"; |
9 | 7 | import useAppStore from "./store"; |
| 8 | +import AppHeader from "./components/AppHeader"; |
10 | 9 |
|
11 | 10 | // Import components |
12 | | -const Navigation = lazy(() => import("./components/Navigation")); |
13 | 11 | const Dashboard = lazy(() => import("./components/Dashboard")); |
14 | 12 | const ByAssignee = lazy(() => import("./components/ByAssignee")); |
15 | 13 | const ByTags = lazy(() => import("./components/ByTags")); |
@@ -269,42 +267,20 @@ export default function App() { |
269 | 267 | }, [issueTypes]); |
270 | 268 |
|
271 | 269 | return ( |
272 | | - <div className="min-h-screen bg-gray-50"> |
273 | | - <header className="sticky top-0 z-10 bg-white/80 backdrop-blur shadow-sm"> |
274 | | - <div className="max-w-7xl mx-auto px-4 py-4"> |
275 | | - <div className="flex items-center gap-3 mb-4"> |
276 | | - <Github className="w-6 h-6" /> |
277 | | - <h1 className="text-xl font-semibold">GitHub Issues Manager</h1> |
278 | | - <a |
279 | | - href="https://github.com/evolvus/github-issue-manager" |
280 | | - target="_blank" |
281 | | - rel="noopener noreferrer" |
282 | | - className="text-sm text-blue-600 hover:underline flex items-center gap-1" |
283 | | - title="View Source Code" |
284 | | - > |
285 | | - <Github className="w-4 h-4" /> |
286 | | - </a> |
287 | | - <div className="ml-auto flex items-center gap-2 w-full sm:w-auto"> |
288 | | - <Input placeholder="Organization (e.g. vercel)" value={org} onChange={e=>setOrg(e.target.value)} className="w-44" /> |
289 | | - <Input placeholder="Personal Access Token" type="password" autoComplete="off" value={token} onChange={e=>setToken(e.target.value)} className="w-64" /> |
290 | | - <Button className="bg-black text-white" onClick={loadData} disabled={loading || !org || !token}> |
291 | | - {loading ? (<><Loader2 className="w-4 h-4 animate-spin"/><span>Loading</span></>) : (<><RefreshCcw className="w-4 h-4"/><span>Load</span></>)} |
292 | | - </Button> |
293 | | - <button onClick={cycleTheme} title={`Theme: ${theme}`} className="p-2 border rounded"> |
294 | | - {theme === "dark" ? <Moon className="w-4 h-4"/> : theme === "light" ? <Sun className="w-4 h-4"/> : <Monitor className="w-4 h-4"/>} |
295 | | - </button> |
296 | | - <button onClick={toggleDensity} title={`Density: ${density}`} className="p-2 border rounded"> |
297 | | - {density === "compact" ? <Minimize2 className="w-4 h-4"/> : <Maximize2 className="w-4 h-4"/>} |
298 | | - </button> |
299 | | - </div> |
300 | | - </div> |
301 | | - {sidebarOpen && ( |
302 | | - <Suspense fallback={<Loader2 className="w-4 h-4 animate-spin" />}> |
303 | | - <Navigation /> |
304 | | - </Suspense> |
305 | | - )} |
306 | | - </div> |
307 | | - </header> |
| 270 | + <div className="min-h-screen bg-gray-50"> |
| 271 | + <AppHeader |
| 272 | + org={org} |
| 273 | + setOrg={setOrg} |
| 274 | + token={token} |
| 275 | + setToken={setToken} |
| 276 | + loadData={loadData} |
| 277 | + loading={loading} |
| 278 | + cycleTheme={cycleTheme} |
| 279 | + toggleDensity={toggleDensity} |
| 280 | + theme={theme} |
| 281 | + density={density} |
| 282 | + sidebarOpen={sidebarOpen} |
| 283 | + /> |
308 | 284 |
|
309 | 285 | <main className="max-w-7xl mx-auto px-4 py-6"> |
310 | 286 | {error && ( |
|
0 commit comments