Add initial project files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 19:11:00 -07:00
parent bfab8f71fb
commit 72b23c18aa
32 changed files with 1870 additions and 0 deletions

162
frontend/log.html Normal file
View File

@@ -0,0 +1,162 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Log Entry — Bourbonacci</title>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<nav>
<a href="/index.html" class="nav-brand">🥃 Bourbonacci</a>
<div class="nav-links" id="nav-links"></div>
<div id="nav-user"></div>
</nav>
<main style="max-width:640px">
<h1 class="page-title">Log Entry</h1>
<div class="tabs">
<div class="tab active" id="tab-add" onclick="switchTab('add')">Add to Bottle</div>
<div class="tab" id="tab-remove" onclick="switchTab('remove')">Remove (Drink)</div>
</div>
<!-- ADD FORM -->
<div id="pane-add">
<div class="card">
<div id="alert-add"></div>
<form id="form-add">
<div class="form-group">
<label for="add-date">Date</label>
<input type="date" id="add-date" required />
</div>
<div class="form-group">
<label for="bourbon-name">Bourbon Name</label>
<input type="text" id="bourbon-name" required placeholder="e.g. Buffalo Trace" />
</div>
<div class="form-group">
<label for="proof">Proof</label>
<input type="number" id="proof" min="0" max="200" step="0.1" placeholder="e.g. 90" />
</div>
<div class="form-group">
<label for="add-shots">Amount (shots)</label>
<input type="number" id="add-shots" min="0.25" step="0.25" value="1" required />
</div>
<div class="form-group">
<label for="add-notes">Notes</label>
<textarea id="add-notes" placeholder="Tasting notes, batch info, anything worth remembering…"></textarea>
</div>
<div style="display:flex;gap:1rem;margin-top:.5rem">
<button type="submit" class="btn btn-primary" id="btn-add">Add to Bottle</button>
<a href="/dashboard.html" class="btn btn-ghost">Cancel</a>
</div>
</form>
</div>
</div>
<!-- REMOVE FORM -->
<div id="pane-remove" style="display:none">
<div class="card">
<p style="color:var(--cream-dim);margin-bottom:1rem;font-size:.9rem">
Log shots you've poured and consumed from the infinity bottle.
</p>
<div id="alert-remove"></div>
<form id="form-remove">
<div class="form-group">
<label for="remove-date">Date</label>
<input type="date" id="remove-date" required />
</div>
<div class="form-group">
<label for="remove-shots">Shots Consumed</label>
<input type="number" id="remove-shots" min="0.25" step="0.25" value="1" required />
</div>
<div class="form-group">
<label for="remove-notes">Notes</label>
<textarea id="remove-notes" placeholder="Occasion, tasting notes…"></textarea>
</div>
<div style="display:flex;gap:1rem;margin-top:.5rem">
<button type="submit" class="btn btn-danger" id="btn-remove">Log Removal</button>
<a href="/dashboard.html" class="btn btn-ghost">Cancel</a>
</div>
</form>
</div>
</div>
</main>
<script src="/js/api.js"></script>
<script src="/js/auth.js"></script>
<script>
function today() {
return new Date().toISOString().split('T')[0];
}
document.addEventListener('DOMContentLoaded', () => {
if (!Auth.requireAuth()) return;
Auth.renderNav('log');
document.getElementById('add-date').value = today();
document.getElementById('remove-date').value = today();
});
function switchTab(tab) {
document.getElementById('pane-add').style.display = tab === 'add' ? '' : 'none';
document.getElementById('pane-remove').style.display = tab === 'remove' ? '' : 'none';
document.getElementById('tab-add').className = 'tab' + (tab === 'add' ? ' active' : '');
document.getElementById('tab-remove').className = 'tab' + (tab === 'remove' ? ' active' : '');
}
document.getElementById('form-add').addEventListener('submit', async (e) => {
e.preventDefault();
const alert = document.getElementById('alert-add');
const btn = document.getElementById('btn-add');
alert.innerHTML = '';
btn.disabled = true;
try {
await API.entries.create({
entry_type: 'add',
date: document.getElementById('add-date').value,
bourbon_name: document.getElementById('bourbon-name').value.trim(),
proof: parseFloat(document.getElementById('proof').value) || null,
amount_shots: parseFloat(document.getElementById('add-shots').value),
notes: document.getElementById('add-notes').value.trim() || null,
});
alert.innerHTML = `<div class="alert alert-success">Added to the bottle!</div>`;
e.target.reset();
document.getElementById('add-date').value = today();
document.getElementById('add-shots').value = '1';
} catch (err) {
alert.innerHTML = `<div class="alert alert-error">${err.message}</div>`;
} finally {
btn.disabled = false;
}
});
document.getElementById('form-remove').addEventListener('submit', async (e) => {
e.preventDefault();
const alert = document.getElementById('alert-remove');
const btn = document.getElementById('btn-remove');
alert.innerHTML = '';
btn.disabled = true;
try {
await API.entries.create({
entry_type: 'remove',
date: document.getElementById('remove-date').value,
amount_shots: parseFloat(document.getElementById('remove-shots').value),
notes: document.getElementById('remove-notes').value.trim() || null,
});
alert.innerHTML = `<div class="alert alert-success">Removal logged. Cheers!</div>`;
e.target.reset();
document.getElementById('remove-date').value = today();
document.getElementById('remove-shots').value = '1';
} catch (err) {
alert.innerHTML = `<div class="alert alert-error">${err.message}</div>`;
} finally {
btn.disabled = false;
}
});
</script>
</body>
</html>