Parts inventory: catalog, search, and stock tracking
FastAPI + SQLite behind a single-page frontend, deployed as a container on mainserver behind Caddy. One flexible parts table plus key/value specs so components, filament, fasteners and tooling share a schema. Categories and locations are nestable trees whose filters and sidebar counts both roll up through descendants. Category spec templates pre-fill the properties worth recording for each kind of part, which is what makes manual entry tolerable. Every quantity change is logged. Search is FTS5 with prefix matching across names, MPNs, spec values, tags, category and location. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="color-scheme" content="dark">
|
||||
<title>Parts Inventory</title>
|
||||
<link rel="stylesheet" href="/static/app.css">
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><text y='13' font-size='13'>🧰</text></svg>">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section id="login" class="hidden">
|
||||
<form id="login-form">
|
||||
<h1>Parts Inventory</h1>
|
||||
<p>Enter the password to continue.</p>
|
||||
<input type="password" id="password" autocomplete="current-password" placeholder="Password" required>
|
||||
<p id="login-error" class="hidden" style="color:var(--bad);margin:10px 0 0"></p>
|
||||
<button class="primary" type="submit" style="width:100%;margin-top:14px">Unlock</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section id="app" class="hidden">
|
||||
<header>
|
||||
<span class="brand">🧰 Parts</span>
|
||||
<input class="search" id="search" type="search" placeholder="Search parts, values, MPN, tags…" autocomplete="off">
|
||||
<span class="stat" id="stats"></span>
|
||||
<button class="ghost small mobile-only" id="filters-btn">Filters</button>
|
||||
<button class="primary" id="add-btn">+ Add</button>
|
||||
<button class="ghost small" id="manage-btn" title="Categories & locations">⚙</button>
|
||||
<button class="ghost small hidden" id="logout-btn" title="Log out">⏻</button>
|
||||
</header>
|
||||
|
||||
<div class="layout">
|
||||
<aside id="sidebar">
|
||||
<h3>Filters</h3>
|
||||
<div class="filter" id="filter-all">All parts <span class="count" id="count-all"></span></div>
|
||||
<div class="filter" id="filter-low">Low stock <span class="count" id="count-low"></span></div>
|
||||
<h3>Categories</h3>
|
||||
<div id="category-list"></div>
|
||||
<h3>Locations</h3>
|
||||
<div id="location-list"></div>
|
||||
<h3>Tags</h3>
|
||||
<div id="tag-list"></div>
|
||||
</aside>
|
||||
|
||||
<main>
|
||||
<div class="toolbar">
|
||||
<span class="grow" id="result-summary"></span>
|
||||
<select id="sort">
|
||||
<option value="relevance">Best match</option>
|
||||
<option value="name">Name A–Z</option>
|
||||
<option value="quantity">Quantity, lowest</option>
|
||||
<option value="updated">Recently updated</option>
|
||||
<option value="created">Recently added</option>
|
||||
<option value="location">Location</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="results"></div>
|
||||
<div style="text-align:center;margin:14px 0">
|
||||
<button id="more-btn" class="hidden">Load more</button>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="modal-root"></div>
|
||||
<script src="/static/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user