Admin Panel
A customer table that survives 10,000 rows
The internal-tool half on its own — dashboard, list view, settings, billing and sign-in. Ships noindex, because an admin panel has no business in a search result.
A board, a search that works across it, settings and a sign-in — plus the two screens every internal tool needs and nobody builds: a real 500 boundary and a 404.
app/error.tsxapp/globals.cssapp/layout.tsxapp/login/page.tsxapp/not-found.tsxapp/page.tsxnpx hoverlab init project-tracker ./my-app
Or over MCP, from your editor's agent — no account needed.
Free to read, copy and install, for personal and non-commercial projects. Shipping it in client work or a paid product needs Pro ($79 once). The source lands in your repo and stops being ours — no attribution, nothing to upgrade.
/Everything between here and the August release, by stage.
Rate-limit the export endpoint
Empty-state illustrations for search
Migrate billing webhooks to v2
Checkout: support SEPA direct debit
Rotate staging TLS certificates
Blocked — Waiting on DNS delegation
New onboarding checklist
Upgrade CI runners to Node 22
Search relevance tuning
An empty search box is the most common state of a search box, and it is usually blank. Recent queries are the cheapest useful thing to put there, and the result count is what makes them worth re-running.
12 of 840 projects
Manage your account, your workspace and how you sign in.
4 of 10 seats used
Ada Lovelace
ada@acme.com
Marco Silva
marco@acme.com
Priya Raman
priya@acme.com
alex@contractor.devInvite pending
Keys carry full account access. Treat them like passwords.
Production server
sk_live_••••••••••••4f2a
Created 12 Mar 2026
Last used 2 hours ago
CI pipeline
sk_live_••••••••••••9c1e
Created 3 Jun 2026
Last used Yesterday
Local development
sk_test_••••••••••••b7d0
Created 28 Jul 2026
Never used
These actions affect everyone in the workspace.
Hand this workspace to another member. You keep admin access, but billing and deletion move to them.
Make everything read-only and stop billing at the end of the period. You can un-archive at any time.
Permanently removes all projects, members and history. This cannot be undone and support cannot recover it.
The request failed before it finished. Your data is safe — nothing was changed.
err_7f3a92c4b81eGET /api/v1/projects → 503 Service Unavailable upstream: projects-api duration: 30012ms (timeout)
You are offline. Keep working — edits are written locally and sent automatically the moment the connection is back. Nothing is lost by closing this tab, though it will not send until you open it again.
If this keeps happening, the status page has more than we can put on an error screen — including whether we already know.
The link may be out of date, or the page may have moved. Here are a few ways forward.
Live components in your current theme — switch routes, or the phone icon to check the mobile layout. Colours are this template’s Fern palette, which ships in app/globals.css. A true green rather than an emerald or an olive, on a barely-tinted white. Board columns carry status colour of their own, so the shell stays out of the argument.
then
cd project-tracker npm install npm run dev
The archive contains the whole project — routes, blocks, theme tokens, Tailwind and PostCSS config, tsconfig and a .gitignore. One runtime dependency, and no Hoverlab dependency at all: it is your code from the moment it unzips.
The component, its props, the design tokens it expects and the command that installs it — as one prompt. Paste it into Claude, Cursor, v0 or ChatGPT and what they build around it will match the rest of the catalog instead of inventing its own system.
| Path | Page | File |
|---|---|---|
| / | Project Board | app/page.tsx |
| /search | Search Results | app/search/page.tsx |
| /settings | Account Settings | app/settings/page.tsx |
| /login | Sign-In Screen | app/login/page.tsx |
| /server-error | Server Error | app/server-error/page.tsx |
| 404 | 404 Page | app/not-found.tsx |
Every file is listed. The 16 files in components/ are the blocks the pages import — each one has its own page if you want to read it on its own.
Everything except the blocks. Opens on app/globals.css — the file that makes the rest look right, since every block styles itself with bg-card and text-muted-foreground rather than literal colours.
@tailwind base;
@tailwind components;
@tailwind utilities;
/**
* Design tokens — the Fern palette.
*
* A true green rather than an emerald or an olive, on a barely-tinted white. Board columns carry status colour of their own, so the shell stays out of the argument.
*
* This file is the reason a pasted block looks right. Every block and page
* styles itself with semantic classes — `bg-card`, `text-muted-foreground`,
* `border-border` — rather than literal colours, so they inherit whatever
* you define here instead of fighting it. Change a value below and every
* section in the project moves with it. Change the hue on `--primary` and
* `--ring` together and you have rebranded the site.
*
* Values are bare HSL channels, not `hsl(...)` calls. That is what lets
* Tailwind compose them with an alpha suffix: `bg-primary/10` expands to
* `hsl(var(--primary) / 0.1)`, which is impossible if the variable already
* carries its own function wrapper.
*
* Every foreground/background pair below clears WCAG AA (4.5:1) in both
* themes. If you retune one, check the pair rather than trusting the eye —
* mid-lightness accents are the ones that fail.
*/
@layer base {
:root {
--background: 135 28% 98%;
--foreground: 135 30% 9%;
--card: 135 32% 99%;
--card-foreground: 135 30% 9%;
--popover: 135 32% 99%;
--popover-foreground: 135 30% 9%;
--primary: 135 55% 26%;
--primary-foreground: 135 32% 99%;
--secondary: 135 24% 93%;
--secondary-foreground: 135 30% 18%;
--muted: 135 20% 94%;
--muted-foreground: 135 12% 38%;
--accent: 160 40% 91%;
--accent-foreground: 162 50% 16%;
--destructive: 0 70% 45%;
--destructive-foreground: 0 0% 100%;
--border: 135 18% 88%;
--input: 135 18% 88%;
--ring: 135 55% 26%;
--radius: 0.5rem;
}
.dark {
--background: 135 26% 5%;
--foreground: 135 14% 96%;
--card: 135 20% 8%;
--card-foreground: 135 14% 96%;
--popover: 135 20% 8%;
--popover-foreground: 135 14% 96%;
--primary: 135 60% 50%;
--primary-foreground: 135 42% 7%;
--secondary: 135 16% 15%;
--secondary-foreground: 135 14% 96%;
--muted: 135 22% 15%;
--muted-foreground: 135 10% 66%;
--accent: 160 26% 18%;
--accent-foreground: 160 45% 85%;
--destructive: 0 62% 52%;
--destructive-foreground: 0 0% 100%;
--border: 135 14% 19%;
--input: 135 14% 19%;
--ring: 135 60% 50%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground antialiased;
}
/**
* Global motion opt-out.
*
* Blocks guard their own animations with Tailwind's `motion-safe:`, but
* third-party CSS and anything you add later will not. This is the
* backstop: it neutralises every animation and transition on the page
* for users who have asked the OS for reduced motion, rather than
* relying on each author to remember.
*/
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
}
A customer table that survives 10,000 rows
The internal-tool half on its own — dashboard, list view, settings, billing and sign-in. Ships noindex, because an admin panel has no business in a search result.