Skip to content

Instantly share code, notes, and snippets.

@simsong
Created July 8, 2026 01:23
Show Gist options
  • Select an option

  • Save simsong/f9f87c1fcaf5a398fec69a6dcabcfc74 to your computer and use it in GitHub Desktop.

Select an option

Save simsong/f9f87c1fcaf5a398fec69a6dcabcfc74 to your computer and use it in GitHub Desktop.
Codex-created Plant Tracer admin UI wireframe for Plant-Tracer/webapp#1106
<!doctype html>
<html lang="en" data-theme="winter">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Plant Tracer Admin UI Wireframe</title>
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.12.24/dist/full.min.css" rel="stylesheet" type="text/css">
<script src="https://cdn.tailwindcss.com"></script>
<style>
html {
scroll-behavior: smooth;
}
section {
scroll-margin-top: 1rem;
}
.course-chip-primary {
box-shadow: 0 0 0 2px #111827 inset;
}
.course-chip-admin {
box-shadow: 0 0 0 2px #111827 inset, 0 0 0 4px #ef4444 inset;
}
</style>
</head>
<body class="bg-slate-50 text-slate-900">
<div class="min-h-screen">
<header class="sticky top-0 z-40 border-b border-slate-200 bg-white/95 backdrop-blur">
<div class="flex items-center justify-between px-6 py-3">
<div>
<div class="text-xl font-semibold tracking-normal">Plant Tracer Admin</div>
<div class="text-sm text-slate-500">Review prototype for /admin</div>
</div>
<div class="flex items-center gap-3">
<span class="badge badge-error font-semibold text-white">super_admin</span>
<button class="btn btn-sm btn-ghost">Sign out</button>
</div>
</div>
</header>
<div class="grid grid-cols-[15rem_minmax(0,1fr)] gap-6 px-6 py-6">
<aside class="sticky top-20 h-[calc(100vh-6rem)]">
<nav class="menu rounded-box border border-slate-200 bg-white p-3 shadow-sm">
<li class="menu-title">Admin</li>
<li><a href="#courses" class="active">Courses</a></li>
<li><a href="#users">Users</a></li>
<li><a href="#movies">Movies</a></li>
<li><a href="#storage">Storage</a></li>
</nav>
<div class="mt-4 rounded-box border border-slate-200 bg-white p-4 text-sm shadow-sm">
<div class="font-semibold">Current Scan</div>
<div class="mt-2 text-slate-600">Not running</div>
<progress class="progress progress-info mt-3 w-full" value="0" max="100"></progress>
</div>
</aside>
<main class="space-y-8">
<div class="grid grid-cols-4 gap-4">
<div class="stat rounded-box border border-slate-200 bg-white shadow-sm">
<div class="stat-title">Courses</div>
<div class="stat-value text-3xl">18</div>
</div>
<div class="stat rounded-box border border-slate-200 bg-white shadow-sm">
<div class="stat-title">Users</div>
<div class="stat-value text-3xl">412</div>
</div>
<div class="stat rounded-box border border-slate-200 bg-white shadow-sm">
<div class="stat-title">Movies</div>
<div class="stat-value text-3xl">9,244</div>
</div>
<div class="stat rounded-box border border-slate-200 bg-white shadow-sm">
<div class="stat-title">Storage</div>
<div class="stat-value text-2xl">Scan not run</div>
</div>
</div>
<section id="courses" class="rounded-box border border-slate-200 bg-white shadow-sm">
<div class="flex items-start justify-between border-b border-slate-200 p-5">
<div>
<h1 class="text-2xl font-semibold">Courses</h1>
<p class="mt-1 text-sm text-slate-500">Create, rename, delete, and manage course membership.</p>
</div>
<button class="btn btn-primary btn-sm">Create course</button>
</div>
<div class="p-5">
<div class="mb-4 flex items-center gap-3">
<input class="input input-bordered input-sm w-72" placeholder="Search courses">
<button class="btn btn-sm">Show empty</button>
<button class="btn btn-sm">Show with movies</button>
</div>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th>Course number</th>
<th>Name</th>
<th>Users</th>
<th>Movies</th>
<th>Admins</th>
<th class="w-72">Inline editor</th>
</tr>
</thead>
<tbody>
<tr>
<td class="font-mono">BIO101</td>
<td>Biology 101</td>
<td>42</td>
<td>612</td>
<td>Ada Lovelace, Kim Park</td>
<td>
<div class="join">
<button class="btn join-item btn-xs">Rename number/name</button>
<button class="btn join-item btn-xs">Members</button>
<button class="btn join-item btn-xs btn-error text-white" disabled>Delete course</button>
</div>
</td>
</tr>
<tr class="bg-blue-50">
<td colspan="6">
<div class="rounded-box border border-blue-200 bg-white p-4">
<div class="mb-3 flex items-center justify-between">
<div class="font-semibold">BIO101 membership editor</div>
<button class="btn btn-xs btn-ghost">Close</button>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<div class="mb-2 text-sm font-semibold">Admins</div>
<div class="flex flex-wrap gap-2">
<span class="badge badge-error gap-2 text-white">Ada Lovelace ×</span>
<span class="badge badge-error gap-2 text-white">Kim Park ×</span>
<button class="btn btn-xs">Add admin</button>
</div>
</div>
<div>
<div class="mb-2 text-sm font-semibold">Course number/name</div>
<div class="grid grid-cols-[10rem_minmax(0,1fr)_auto] gap-2">
<input class="input input-bordered input-sm" value="BIO101" aria-label="Course number">
<input class="input input-bordered input-sm" value="Biology 101" aria-label="Course name">
<button class="btn btn-sm btn-primary">Save</button>
</div>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td class="font-mono">CHEM10</td>
<td>Chemistry Lab</td>
<td>18</td>
<td>0</td>
<td>Sam Rivera</td>
<td>
<div class="join">
<button class="btn join-item btn-xs">Rename number/name</button>
<button class="btn join-item btn-xs">Members</button>
<button class="btn join-item btn-xs btn-error text-white" data-confirm-target="delete-course-chemlist">Delete course</button>
</div>
</td>
</tr>
<tr id="delete-course-chemlist" class="hidden bg-red-50">
<td colspan="6">
<div class="flex items-center justify-between rounded-box border border-red-200 bg-white p-4">
<div>
<div class="font-semibold text-red-700">Delete course CHEM10?</div>
<div class="text-sm text-slate-600">This course has no movies. Users whose last course is CHEM10 will be deleted.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete course</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="users" class="rounded-box border border-slate-200 bg-white shadow-sm">
<div class="flex items-start justify-between border-b border-slate-200 p-5">
<div>
<h1 class="text-2xl font-semibold">Users</h1>
<p class="mt-1 text-sm text-slate-500">Edit course membership, primary course, admin status, and super role.</p>
</div>
<button class="btn btn-primary btn-sm">Add user</button>
</div>
<div class="p-5">
<div class="mb-4 flex flex-wrap items-center gap-3">
<input class="input input-bordered input-sm w-72" placeholder="Search users">
<select class="select select-bordered select-sm">
<option>All courses</option>
<option>BIO101</option>
<option>CHEM10</option>
</select>
<select class="select select-bordered select-sm">
<option>All super roles</option>
<option>no</option>
<option>auditor</option>
<option>admin</option>
</select>
<button class="btn btn-sm">Add selected to course</button>
<button class="btn btn-sm btn-error text-white" data-confirm-target="delete-selected-users">Delete selected users</button>
</div>
<div id="delete-selected-users" class="mb-4 hidden rounded-box border border-red-200 bg-red-50 p-4">
<div class="flex items-center justify-between gap-4">
<div>
<div class="font-semibold text-red-700">Delete selected users?</div>
<div class="text-sm text-slate-600">This deletes user accounts, not just course memberships.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete users</button>
</div>
</div>
</div>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th><input type="checkbox" class="checkbox checkbox-sm"></th>
<th>Name</th>
<th>Email</th>
<th>Super</th>
<th>Courses</th>
<th class="w-64">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td>Ada Lovelace</td>
<td>ada@example.edu</td>
<td>
<details class="dropdown">
<summary class="btn btn-xs btn-error font-bold text-white">admin</summary>
<ul class="menu dropdown-content z-10 mt-1 w-36 rounded-box bg-white p-2 shadow">
<li><a>no</a></li>
<li><a class="font-bold text-blue-700">auditor</a></li>
<li><a class="font-bold text-red-700">admin</a></li>
</ul>
</details>
</td>
<td>
<div class="flex flex-wrap gap-2">
<span class="badge course-chip-admin">BIO101 admin primary</span>
<span class="badge">PHY200</span>
</div>
</td>
<td>
<div class="join">
<button class="btn join-item btn-xs">Edit courses</button>
<button class="btn join-item btn-xs btn-error text-white" data-confirm-target="delete-user-ada">Delete user</button>
</div>
</td>
</tr>
<tr id="delete-user-ada" class="hidden bg-red-50">
<td colspan="6">
<div class="flex items-center justify-between rounded-box border border-red-200 bg-white p-4">
<div>
<div class="font-semibold text-red-700">Delete user Ada Lovelace?</div>
<div class="text-sm text-slate-600">Five-second delay prevents accidental account deletion.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete user</button>
</div>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td>Grace Hopper</td>
<td>grace@example.edu</td>
<td><span class="badge badge-info font-bold text-white">auditor</span></td>
<td>
<div class="flex flex-wrap gap-2">
<span class="badge course-chip-primary">BIO101 primary</span>
<span class="badge">CHEM10</span>
</div>
</td>
<td>
<div class="join">
<button class="btn join-item btn-xs">Edit courses</button>
<button class="btn join-item btn-xs btn-error text-white">Delete user</button>
</div>
</td>
</tr>
<tr class="bg-blue-50">
<td colspan="6">
<div class="rounded-box border border-blue-200 bg-white p-4">
<div class="mb-3 flex items-center justify-between">
<div class="font-semibold">Edit Grace Hopper courses</div>
<button class="btn btn-xs btn-ghost">Close</button>
</div>
<div class="flex flex-wrap items-center gap-2">
<span class="badge course-chip-primary">BIO101 primary</span>
<span class="badge">CHEM10</span>
<button class="btn btn-xs">Add course</button>
<button class="btn btn-xs">Set selected primary</button>
<button class="btn btn-xs btn-error text-white">Remove selected</button>
</div>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td>Pat Lee</td>
<td>pat@example.edu</td>
<td><span class="badge">no</span></td>
<td><span class="badge course-chip-primary">CHEM10 primary</span></td>
<td>
<div class="join">
<button class="btn join-item btn-xs">Edit courses</button>
<button class="btn join-item btn-xs btn-error text-white">Delete user</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section id="movies" class="rounded-box border border-slate-200 bg-white shadow-sm">
<div class="flex items-start justify-between border-b border-slate-200 p-5">
<div>
<h1 class="text-2xl font-semibold">Movies</h1>
<p class="mt-1 text-sm text-slate-500">Per-course subtables are collapsed by default and lazy-loaded on expand.</p>
</div>
<div class="flex gap-2">
<button id="expand-all-movies" class="btn btn-sm">Expand all</button>
<button class="btn btn-sm btn-error text-white">Purge deleted in all courses</button>
</div>
</div>
<div class="space-y-4 p-5">
<div class="collapse-arrow collapse border border-slate-200 bg-slate-50">
<input type="checkbox" class="movie-course-toggle">
<div class="collapse-title flex items-center justify-between text-lg font-semibold">
<span>BIO101 - Biology 101</span>
<span class="mr-8 flex gap-2 text-sm font-normal">
<span class="badge">612 movies</span>
<span class="badge badge-warning">3 stale</span>
</span>
</div>
<div class="collapse-content">
<div class="mb-3 flex flex-wrap items-center justify-between gap-3">
<div class="flex gap-2">
<input class="input input-bordered input-sm w-64" placeholder="Search BIO101 movies">
<button class="btn btn-sm">Publish</button>
<button class="btn btn-sm">Unpublish</button>
<button class="btn btn-sm">Move course</button>
<button class="btn btn-sm">Assign owner</button>
</div>
<button class="btn btn-sm btn-error text-white">Purge deleted in BIO101</button>
</div>
<div class="overflow-x-auto">
<table class="table table-sm">
<thead>
<tr>
<th><input type="checkbox" class="checkbox checkbox-sm"></th>
<th>State</th>
<th>Movie</th>
<th>Owner</th>
<th>MP4</th>
<th>ZIP</th>
<th>Research</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge badge-success text-white">published</span></td>
<td>stem-growth-042.mp4</td>
<td>Ada Lovelace</td>
<td>32.1 MB</td>
<td>4.2 MB</td>
<td>allowed; MIT</td>
<td><button class="btn btn-xs">Edit inline</button></td>
</tr>
<tr class="bg-red-50 text-red-900">
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge badge-error text-white">stale upload</span></td>
<td>pending-upload-118</td>
<td>Pat Lee</td>
<td>missing</td>
<td>-</td>
<td>-</td>
<td><button class="btn btn-xs btn-error text-white">Remove red movies</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="collapse-arrow collapse border border-slate-200 bg-slate-50">
<input type="checkbox" class="movie-course-toggle">
<div class="collapse-title flex items-center justify-between text-lg font-semibold">
<span>CHEM10 - Chemistry Lab</span>
<span class="mr-8 flex gap-2 text-sm font-normal">
<span class="badge">0 movies</span>
<span class="badge badge-success text-white">empty</span>
</span>
</div>
<div class="collapse-content">
<div class="alert justify-between">
<span>No movies in this course. The course can be deleted if no other constraints apply.</span>
<button class="btn btn-sm btn-error text-white" data-confirm-target="delete-course-chem10">Delete course</button>
</div>
<div id="delete-course-chem10" class="mt-3 hidden rounded-box border border-red-200 bg-white p-4">
<div class="flex items-center justify-between">
<div>
<div class="font-semibold text-red-700">Delete CHEM10?</div>
<div class="text-sm text-slate-600">This deletes the empty course; users with no other course are deleted.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete course</button>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section id="storage" class="rounded-box border border-slate-200 bg-white shadow-sm">
<div class="flex items-start justify-between border-b border-slate-200 p-5">
<div>
<h1 class="text-2xl font-semibold">Storage</h1>
<p class="mt-1 text-sm text-slate-500">Scan S3, recover orphaned movie data, and delete objects that cannot be recovered.</p>
</div>
<div class="flex gap-2">
<button class="btn btn-sm btn-primary">Start scan</button>
<button class="btn btn-sm">Continue scan</button>
<button class="btn btn-sm">Export all storage CSV</button>
</div>
</div>
<div class="space-y-5 p-5">
<div class="rounded-box border border-slate-200 bg-slate-50 p-4">
<div class="mb-2 flex items-center justify-between">
<span class="font-semibold">S3 scan</span>
<span class="text-sm text-slate-500">18,200 objects scanned; incomplete</span>
</div>
<progress class="progress progress-info w-full" value="45" max="100"></progress>
</div>
<div class="flex flex-wrap gap-2">
<button class="btn btn-sm">Recover selected</button>
<button class="btn btn-sm">Convert selected ZIPs</button>
<button class="btn btn-sm btn-error text-white" data-confirm-target="delete-selected-storage">Delete selected</button>
<button class="btn btn-sm btn-error text-white" data-confirm-target="delete-all-unrecognized">Delete all unrecognized</button>
</div>
<div id="delete-selected-storage" class="hidden rounded-box border border-red-200 bg-red-50 p-4">
<div class="flex items-center justify-between gap-4">
<div>
<div class="font-semibold text-red-700">Delete selected storage objects?</div>
<div class="text-sm text-slate-600">Deletion is final. Confirmation is disabled for five seconds.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete selected</button>
</div>
</div>
</div>
<div id="delete-all-unrecognized" class="hidden rounded-box border border-red-200 bg-red-50 p-4">
<div class="flex items-center justify-between gap-4">
<div>
<div class="font-semibold text-red-700">Delete all unrecognized objects?</div>
<div class="text-sm text-slate-600">This affects only objects classified as unrecognized by the current scan.</div>
</div>
<div class="flex items-center gap-3">
<span class="countdown-label text-sm text-slate-600">Confirm enabled in 5s</span>
<button class="btn btn-sm btn-error text-white confirm-button" disabled>Confirm delete all</button>
</div>
</div>
</div>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th><input type="checkbox" class="checkbox checkbox-sm"></th>
<th>Type</th>
<th>Object / prefix</th>
<th>Evidence</th>
<th>Default recovery</th>
<th class="w-80">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge badge-success text-white">MP4 orphan</span></td>
<td class="font-mono text-xs">lost/plant-growth-2026-07-01.mp4</td>
<td>embedded metadata found</td>
<td>BIO101, Ada Lovelace</td>
<td>
<div class="join">
<button class="btn join-item btn-xs btn-success text-white">Recover</button>
<button class="btn join-item btn-xs">Review</button>
<button class="btn join-item btn-xs btn-error text-white" data-confirm-target="delete-selected-storage">Delete</button>
</div>
</td>
</tr>
<tr class="bg-blue-50">
<td colspan="6">
<div class="rounded-box border border-blue-200 bg-white p-4">
<div class="mb-3 flex items-center justify-between">
<div class="font-semibold">One-click recovery preview</div>
<button class="btn btn-xs btn-ghost">Close</button>
</div>
<div class="grid grid-cols-4 gap-3 text-sm">
<label class="form-control">
<span class="label-text">Course</span>
<select class="select select-bordered select-sm"><option>BIO101</option></select>
</label>
<label class="form-control">
<span class="label-text">Owner</span>
<select class="select select-bordered select-sm"><option>Ada Lovelace</option><option>Course admin</option></select>
</label>
<label class="form-control">
<span class="label-text">State</span>
<select class="select select-bordered select-sm"><option>unpublished</option><option>published</option></select>
</label>
<label class="form-control">
<span class="label-text">Name</span>
<input class="input input-bordered input-sm" value="plant-growth-2026-07-01">
</label>
</div>
<button class="btn btn-sm btn-success mt-4 text-white">Create movie record</button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge badge-info text-white">ZIP-only</span></td>
<td class="font-mono text-xs">uploads/frame-set-889.zip</td>
<td>frame ZIP; no MP4</td>
<td>Convert to MP4, assign to course admin</td>
<td>
<div class="join">
<button class="btn join-item btn-xs btn-info text-white">Convert</button>
<button class="btn join-item btn-xs">Review</button>
<button class="btn join-item btn-xs btn-error text-white" data-confirm-target="delete-selected-storage">Delete</button>
</div>
</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge badge-warning">empty frame group</span></td>
<td class="font-mono text-xs">movies/old-999/frames/</td>
<td>no frames, no MP4, no ZIP</td>
<td>none</td>
<td><button class="btn btn-xs btn-error text-white" data-confirm-target="delete-selected-storage">Delete</button></td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox checkbox-sm"></td>
<td><span class="badge">unrecognized</span></td>
<td class="font-mono text-xs">tmp/debug-output.log</td>
<td>not movie-like</td>
<td>none</td>
<td><button class="btn btn-xs btn-error text-white" data-confirm-target="delete-selected-storage">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</main>
</div>
</div>
<script>
const expandAllMovies = document.getElementById('expand-all-movies');
if (expandAllMovies) {
expandAllMovies.addEventListener('click', () => {
document.querySelectorAll('.movie-course-toggle').forEach((toggle) => {
toggle.checked = true;
});
});
}
document.querySelectorAll('[data-confirm-target]').forEach((button) => {
button.addEventListener('click', () => {
const target = document.getElementById(button.dataset.confirmTarget);
if (!target) {
return;
}
target.classList.remove('hidden');
const label = target.querySelector('.countdown-label');
const confirm = target.querySelector('.confirm-button');
if (!label || !confirm) {
return;
}
confirm.disabled = true;
let remaining = 5;
label.textContent = `Confirm enabled in ${remaining}s`;
const timer = window.setInterval(() => {
remaining -= 1;
if (remaining > 0) {
label.textContent = `Confirm enabled in ${remaining}s`;
return;
}
window.clearInterval(timer);
label.textContent = 'Confirm is enabled';
confirm.disabled = false;
}, 1000);
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment