diff --git a/package-lock.json b/package-lock.json index 715fd0e..4d4796b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "eslint": "^9.39.4", "eslint-config-next": "^16.2.6", "husky": "^9.1.7", + "kill-port": "^2.0.1", "lint-staged": "^15.2.10", "postcss": "^8.5.15", "prettier": "^3.3.3", @@ -117,7 +118,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -2081,7 +2081,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.6.tgz", "integrity": "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^5.0.0", "@octokit/graphql": "^8.2.2", @@ -2310,7 +2309,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -2423,7 +2421,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -4616,7 +4613,6 @@ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.105.4.tgz", "integrity": "sha512-cEnx+k49knU+qdIP7rXwR6fqEXPHZs+74xFK1R0S8MgQ7v9tbePVdGxvO03n3bPympMdJWVLadARBfU4TgNHCQ==", "license": "MIT", - "peer": true, "dependencies": { "@supabase/auth-js": "2.105.4", "@supabase/functions-js": "2.105.4", @@ -4970,7 +4966,6 @@ "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.6.tgz", "integrity": "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -4999,7 +4994,6 @@ "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -5011,7 +5005,6 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -5096,7 +5089,6 @@ "integrity": "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.60.0", "@typescript-eslint/types": "8.60.0", @@ -5608,7 +5600,6 @@ "resolved": "https://registry.npmjs.org/@upstash/redis/-/redis-1.38.0.tgz", "integrity": "sha512-wu+dZBptlLy0+MCUEoHmzrY/TnmgDey3+c7EbIGwrLqAvkP8yi5MWZHYGIFtAygmL4Bkz2TdFu+eU0vFPncIcg==", "license": "MIT", - "peer": true, "dependencies": { "uncrypto": "^0.1.3" } @@ -5859,7 +5850,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6397,7 +6387,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -7736,7 +7725,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -7922,7 +7910,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8821,6 +8808,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==", + "dev": true, + "license": "MIT" + }, "node_modules/get-tsconfig": { "version": "4.14.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", @@ -9912,7 +9906,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -10024,6 +10017,20 @@ "json-buffer": "3.0.1" } }, + "node_modules/kill-port": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-2.0.1.tgz", + "integrity": "sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-them-args": "1.3.2", + "shell-exec": "1.0.2" + }, + "bin": { + "kill-port": "cli.js" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -10691,7 +10698,6 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", "license": "MIT", - "peer": true, "dependencies": { "@next/env": "16.2.6", "@swc/helpers": "0.5.15", @@ -11263,7 +11269,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", @@ -11434,7 +11439,6 @@ "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.9.tgz", "integrity": "sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==", "license": "Unlicense", - "peer": true, "engines": { "node": ">=12" }, @@ -11498,7 +11502,6 @@ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -11667,7 +11670,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -11680,7 +11682,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -12324,6 +12325,13 @@ "node": ">=8" } }, + "node_modules/shell-exec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz", + "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==", + "dev": true, + "license": "MIT" + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -13140,7 +13148,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13794,7 +13801,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14043,7 +14049,6 @@ "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -14593,7 +14598,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14607,7 +14611,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -15070,7 +15073,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/app/(app)/app-navbar.tsx b/src/app/(app)/app-navbar.tsx new file mode 100644 index 0000000..fdc0db5 --- /dev/null +++ b/src/app/(app)/app-navbar.tsx @@ -0,0 +1,39 @@ +import Link from 'next/link'; +import { Anchor } from 'lucide-react'; +import { CommandPalette } from '@/components/command-palette'; +import { LogoutButton } from './logout-button'; + +const NAV_LINKS = [ + { label: 'Dashboard', href: '/dashboard' }, + { label: 'Issues', href: '/issues' }, + { label: 'My PRs', href: '/my-prs' }, + { label: 'Leaderboard', href: '/leaderboard' }, +]; + +export function AppNavbar({ handle }: { handle: string | null }) { + return ( +
+
+ + + MergeShip + + +
+ +
+
+ +
+ {handle && {handle}} + +
+
+ ); +} diff --git a/src/app/(app)/app-shell.css b/src/app/(app)/app-shell.css new file mode 100644 index 0000000..0bec694 --- /dev/null +++ b/src/app/(app)/app-shell.css @@ -0,0 +1,376 @@ +/* Authenticated app — split-panel shell matching landing hero */ + +.app-shell { + --ms-cream: #f2f0eb; + --ms-ink: #111110; + --ms-muted: #b8b3aa; + --ms-muted-dark: #8a877e; + --ms-green: #16a34a; + --ms-border: #2a2a28; + --ms-border-subtle: rgba(242, 240, 235, 0.08); + --ms-card: #1a1a18; + --ms-card-hover: #222220; + + min-height: 100%; + background: var(--ms-ink); + color: var(--ms-cream); + font-family: var(--font-dm-sans), 'DM Sans', sans-serif; + font-weight: 300; + font-size: 16px; + line-height: 1.55; + -webkit-font-smoothing: antialiased; +} + +.app-shell ::selection { + background: rgba(22, 163, 74, 0.35); + color: var(--ms-cream); +} + +.app-shell::-webkit-scrollbar { + width: 6px; +} +.app-shell::-webkit-scrollbar-track { + background: var(--ms-ink); +} +.app-shell::-webkit-scrollbar-thumb { + background: #3a3a36; + border-radius: 0; +} +.app-shell::-webkit-scrollbar-thumb:hover { + background: #4a4a46; +} + +/* Page layout */ +.app-page { + padding: 48px 56px 64px; + max-width: 1280px; +} + +@media (max-width: 768px) { + .app-page { + padding: 32px 24px 48px; + } +} + +.app-page-header { + display: flex; + flex-direction: column; + gap: 24px; + margin-bottom: 48px; + padding-bottom: 24px; + border-bottom: 1px solid var(--ms-border); +} + +@media (min-width: 768px) { + .app-page-header { + flex-direction: row; + align-items: flex-end; + justify-content: space-between; + } +} + +.app-eyebrow { + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 11px; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.12em; + color: var(--ms-muted-dark); + margin-bottom: 16px; +} + +.app-title { + font-family: var(--font-dm-serif), 'DM Serif Display', serif; + font-size: clamp(2.25rem, 4vw, 4.5rem); + font-weight: 400; + line-height: 0.95; + letter-spacing: -0.04em; + color: var(--ms-cream); +} + +.app-title-sm { + font-family: var(--font-dm-serif), 'DM Serif Display', serif; + font-size: clamp(1.75rem, 3vw, 2.5rem); + font-weight: 400; + line-height: 1; + letter-spacing: -0.03em; + color: var(--ms-cream); +} + +.app-lead { + font-size: 1.05rem; + line-height: 1.55; + color: var(--ms-muted); + max-width: 560px; +} + +.app-body { + color: var(--ms-muted); + font-size: 0.95rem; + line-height: 1.55; +} + +.app-section-label { + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 10px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.14em; + color: var(--ms-muted-dark); + margin-bottom: 12px; +} + +.app-card { + background: var(--ms-card); + border: 1px solid var(--ms-border); + transition: + border-color 0.2s ease, + background 0.2s ease; +} + +.app-card:hover { + border-color: #3a3a36; + background: var(--ms-card-hover); +} + +.app-divider { + border-color: var(--ms-border); +} + +.app-footer { + margin-top: 96px; + padding-top: 24px; + border-top: 1px solid var(--ms-border); + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 16px; + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--ms-muted-dark); +} + +.app-footer a { + color: var(--ms-muted-dark); + text-decoration: none; + transition: color 0.15s ease; +} + +.app-footer a:hover { + color: var(--ms-cream); +} + +/* Split navbar — cream left / black right, aligned with sidebar + main */ +.app-navbar { + display: flex; + height: 64px; + z-index: 50; +} + +.app-navbar-left { + display: flex; + width: 16rem; + shrink: 0; + align-items: center; + gap: 28px; + background: var(--ms-cream); + color: var(--ms-ink); + padding: 0 20px 0 24px; + border-bottom: 1px solid #ddd9d0; +} + +.app-navbar-right { + display: flex; + flex: 1; + align-items: center; + justify-content: flex-end; + gap: 20px; + background: var(--ms-ink); + color: var(--ms-cream); + padding: 0 24px 0 32px; + border-bottom: 1px solid var(--ms-border); +} + +.app-navbar-logo { + display: flex; + align-items: center; + gap: 10px; + text-decoration: none; + color: var(--ms-ink); + flex-shrink: 0; +} + +.app-navbar-wordmark { + font-family: var(--font-dm-serif), 'DM Serif Display', serif; + font-size: 1.25rem; + letter-spacing: -0.01em; + line-height: 1; +} + +.app-navbar-links { + align-items: center; + gap: 28px; + min-width: 0; +} + +.app-navbar-link { + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 0.7rem; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--ms-ink); + text-decoration: none; + position: relative; + padding: 4px 0; + white-space: nowrap; + transition: color 0.15s ease; +} + +.app-navbar-link::after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + height: 1px; + width: 0; + background: var(--ms-ink); + transition: width 220ms ease; +} + +.app-navbar-link:hover::after { + width: 100%; +} + +.app-navbar-user { + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 0.72rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--ms-muted); + max-width: 140px; +} + +.app-navbar-btn { + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 0.72rem; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.1em; + padding: 11px 18px; + border: 1px solid var(--ms-cream); + background: transparent; + color: var(--ms-cream); + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 8px; + transition: + background 0.2s ease, + color 0.2s ease; + white-space: nowrap; +} + +.app-navbar-btn:hover { + background: var(--ms-cream); + color: var(--ms-ink); +} + +/* Sidebar */ +.app-sidebar { + background: var(--ms-cream); + color: var(--ms-ink); + border-right: 1px solid #ddd9d0; +} + +.app-sidebar-divider { + height: 1px; + background: #ddd9d0; +} + +.app-nav-section { + padding: 0 12px 10px; + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 9px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.14em; + color: var(--ms-green); +} + +.app-nav-item { + display: flex; + align-items: center; + gap: 9px; + padding: 7px 10px 7px 8px; + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 11px; + font-weight: 400; + letter-spacing: 0.07em; + text-transform: uppercase; + text-decoration: none; + color: var(--ms-ink); + border-left: 2px solid transparent; + transition: + background 0.15s ease, + color 0.15s ease, + border-color 0.15s ease; +} + +.app-nav-item svg { + width: 14px; + height: 14px; + flex-shrink: 0; + color: #9b9790; + transition: color 0.15s ease; +} + +.app-nav-item:hover:not(.app-nav-item--active) { + background: rgba(17, 17, 16, 0.05); + color: var(--ms-ink); +} + +.app-nav-item:hover:not(.app-nav-item--active) svg { + color: #6b6860; +} + +.app-nav-item--active { + background: var(--ms-ink); + color: var(--ms-cream); + border-left-color: var(--ms-green); +} + +.app-nav-item--active svg { + color: var(--ms-green); +} + +.app-sidebar-action { + display: flex; + width: 100%; + align-items: center; + gap: 8px; + padding: 7px 10px; + font-family: var(--font-dm-mono), 'DM Mono', monospace; + font-size: 11px; + font-weight: 400; + letter-spacing: 0.07em; + text-transform: uppercase; + color: #6b6860; + background: none; + border: none; + cursor: pointer; + text-align: left; + transition: color 0.15s ease; +} + +.app-sidebar-action:hover { + color: var(--ms-ink); +} + +.app-sidebar-action svg { + width: 13px; + height: 13px; + flex-shrink: 0; +} diff --git a/src/app/(app)/dashboard/loading.tsx b/src/app/(app)/dashboard/loading.tsx index a0ee2b6..9067afd 100644 --- a/src/app/(app)/dashboard/loading.tsx +++ b/src/app/(app)/dashboard/loading.tsx @@ -1,6 +1,6 @@ export default function DashboardLoading() { return ( -
+
diff --git a/src/app/(app)/dashboard/page.tsx b/src/app/(app)/dashboard/page.tsx index 85645bf..c8fde3a 100644 --- a/src/app/(app)/dashboard/page.tsx +++ b/src/app/(app)/dashboard/page.tsx @@ -60,56 +60,53 @@ export default async function DashboardPage() { - {/* Main Columns */} -
- {/* Left Column */} -
- }> - - + {/* Stats Row */} + }> + + - }> - - -
+ {/* Main Columns */} +
+ {/* Left Column */} +
+ }> + + - {/* Right Column */} -
- }> - - - }> - - -
+ }> + +
- {/* Footer */} -
- ©{new Date().getFullYear()} ARCH_06 / SYSTEM_v1.0 -
- - TERMS - - - PRIVACY - - - SECURITY - -
-
+ {/* Right Column */} +
+ }> + + + }> + + +
+ +
+ © {new Date().getFullYear()} MergeShip +
+ Terms + Privacy + Security +
+
); } function NotConfigured() { return ( -
+
-

Dashboard not configured

-

Auth isn't wired on this deployment yet.

+

Dashboard not configured

+

Auth isn't wired on this deployment yet.

); diff --git a/src/app/(app)/dashboard/sync-button.tsx b/src/app/(app)/dashboard/sync-button.tsx index d885789..16cb2de 100644 --- a/src/app/(app)/dashboard/sync-button.tsx +++ b/src/app/(app)/dashboard/sync-button.tsx @@ -87,14 +87,18 @@ export function SyncButton({ lastSyncedAt }: Props) { - + {formatSyncedAt(localSyncedAt)} diff --git a/src/app/(app)/error.tsx b/src/app/(app)/error.tsx index dafd0ad..77fc30e 100644 --- a/src/app/(app)/error.tsx +++ b/src/app/(app)/error.tsx @@ -2,21 +2,16 @@ export default function Error({ reset }: { reset: () => void }) { return ( -
-
-
- System Error -
- -

Something went wrong.

- -

- An unexpected error occurred while loading this page. -

- +
+
+

System Error

+

Something went wrong.

+

An unexpected error occurred while loading this page.

diff --git a/src/app/(app)/help-inbox/loading.tsx b/src/app/(app)/help-inbox/loading.tsx index e6ab74d..bb8f164 100644 --- a/src/app/(app)/help-inbox/loading.tsx +++ b/src/app/(app)/help-inbox/loading.tsx @@ -1,6 +1,6 @@ export default function HelpInboxPageLoading() { return ( -
+
diff --git a/src/app/(app)/help-inbox/page.tsx b/src/app/(app)/help-inbox/page.tsx index 73cbdd3..76eabaf 100644 --- a/src/app/(app)/help-inbox/page.tsx +++ b/src/app/(app)/help-inbox/page.tsx @@ -56,7 +56,7 @@ export default async function HelpInboxPage() { const sb = await getServerSupabase(); if (!sb) { return ( -
+

Service not configured.

); @@ -70,7 +70,7 @@ export default async function HelpInboxPage() { const service = getServiceSupabase(); if (!service) { return ( -
+

Service role not configured.

); @@ -159,7 +159,7 @@ export default async function HelpInboxPage() { } return ( -
+

Help inbox

diff --git a/src/app/(app)/issues/loading.tsx b/src/app/(app)/issues/loading.tsx index 4e37d73..b6fffc3 100644 --- a/src/app/(app)/issues/loading.tsx +++ b/src/app/(app)/issues/loading.tsx @@ -1,6 +1,6 @@ export default function IssuesPageLoading() { return ( -

+
diff --git a/src/app/(app)/issues/page.tsx b/src/app/(app)/issues/page.tsx index eda5d2c..bb40ce8 100644 --- a/src/app/(app)/issues/page.tsx +++ b/src/app/(app)/issues/page.tsx @@ -20,7 +20,9 @@ export default async function IssuesPage({ searchParams }: { searchParams: Searc const sb = await getServerSupabase(); if (!sb) return ( -
Not configured
+
+

Not configured

+
); const { @@ -111,24 +113,22 @@ export default async function IssuesPage({ searchParams }: { searchParams: Searc const repoOptions: RepoOption[] = repoResult.ok ? repoResult.data : []; return ( -
-
-
-
- 02 / ISSUES -
-

Browse Issues

-
- - {linkedRecs.length > 0 && ( - - )} - - -
+
+
+
+

02 / Issues

+

Browse Issues

+
+
+ + {linkedRecs.length > 0 && ( + + )} + +
); } diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx index 6fcfa9e..4839021 100644 --- a/src/app/(app)/layout.tsx +++ b/src/app/(app)/layout.tsx @@ -1,4 +1,3 @@ -import Link from 'next/link'; import { redirect } from 'next/navigation'; import { getServerSupabase } from '@/lib/supabase/server'; import { getServiceSupabase } from '@/lib/supabase/service'; @@ -7,6 +6,8 @@ import { LogoutButton } from './logout-button'; import { CommandPalette } from '@/components/command-palette'; import { isUserMaintainer } from '@/lib/maintainer/detect'; import { ThemeToggle } from './theme-toggle'; +import { AppNavbar } from './app-navbar'; +import './app-shell.css'; export default async function AppLayout({ children }: { children: React.ReactNode }) { const sb = await getServerSupabase(); @@ -39,48 +40,58 @@ export default async function AppLayout({ children }: { children: React.ReactNod } return ( -
- {/* Sidebar */} - - {/* Main Content Area */} -
{children}
+
{children}
+
); } diff --git a/src/app/(app)/leaderboard/loading.tsx b/src/app/(app)/leaderboard/loading.tsx index 1615f5b..6d51401 100644 --- a/src/app/(app)/leaderboard/loading.tsx +++ b/src/app/(app)/leaderboard/loading.tsx @@ -1,6 +1,6 @@ export default function LeaderboardPageLoading() { return ( -
+
diff --git a/src/app/(app)/leaderboard/page.tsx b/src/app/(app)/leaderboard/page.tsx index 2fa5a43..7bfbd9d 100644 --- a/src/app/(app)/leaderboard/page.tsx +++ b/src/app/(app)/leaderboard/page.tsx @@ -14,7 +14,7 @@ export default async function LeaderboardPage({ const result = await getLeaderboard(scope, scopeId, 50); return ( -
+

Leaderboard