abersbail's picture
Deploy static HTML database
1ab72c5 verified
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simple 10 Database</title>
<style>
:root {
color-scheme: light;
--bg: #f5f7fb;
--panel: #ffffff;
--text: #172033;
--muted: #61708a;
--line: #d9e0ec;
--brand: #0f766e;
--brand-dark: #0b5f59;
--danger: #b42318;
--shadow: 0 10px 30px rgba(28, 39, 61, 0.09);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
background: var(--bg);
color: var(--text);
font-family: Arial, Helvetica, sans-serif;
}
main {
width: min(1120px, calc(100% - 32px));
margin: 0 auto;
padding: 28px 0;
}
header {
display: flex;
justify-content: space-between;
gap: 20px;
align-items: flex-end;
margin-bottom: 20px;
}
h1 {
margin: 0 0 6px;
font-size: 32px;
line-height: 1.1;
}
p {
margin: 0;
color: var(--muted);
line-height: 1.5;
}
.stats {
display: flex;
gap: 10px;
flex-wrap: wrap;
justify-content: flex-end;
}
.stat {
min-width: 92px;
padding: 10px 12px;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
box-shadow: var(--shadow);
}
.stat strong {
display: block;
font-size: 20px;
}
.stat span {
display: block;
margin-top: 2px;
color: var(--muted);
font-size: 12px;
text-transform: uppercase;
}
.panel {
background: var(--panel);
border: 1px solid var(--line);
border-radius: 8px;
box-shadow: var(--shadow);
overflow: hidden;
}
.toolbar {
display: grid;
grid-template-columns: 1fr auto auto;
gap: 12px;
padding: 16px;
border-bottom: 1px solid var(--line);
}
input,
select {
width: 100%;
height: 42px;
border: 1px solid var(--line);
border-radius: 6px;
padding: 0 12px;
color: var(--text);
background: #fff;
font: inherit;
}
button {
height: 42px;
border: 0;
border-radius: 6px;
padding: 0 14px;
color: #fff;
background: var(--brand);
cursor: pointer;
font: 700 14px Arial, Helvetica, sans-serif;
white-space: nowrap;
}
button:hover {
background: var(--brand-dark);
}
button.secondary {
color: var(--text);
background: #e8edf5;
}
button.secondary:hover {
background: #dce4ef;
}
button.danger {
background: var(--danger);
}
.form {
display: grid;
grid-template-columns: 90px 1fr 160px 2fr auto;
gap: 12px;
padding: 16px;
border-bottom: 1px solid var(--line);
}
.table-wrap {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
min-width: 760px;
}
th,
td {
padding: 13px 16px;
border-bottom: 1px solid var(--line);
text-align: left;
vertical-align: top;
}
th {
color: var(--muted);
background: #f8fafc;
font-size: 12px;
text-transform: uppercase;
}
tr:last-child td {
border-bottom: 0;
}
.badge {
display: inline-flex;
min-width: 82px;
justify-content: center;
padding: 5px 8px;
border-radius: 999px;
background: #eef6f4;
color: #0f5f59;
font-size: 12px;
font-weight: 700;
text-transform: capitalize;
}
.empty {
padding: 36px 16px;
color: var(--muted);
text-align: center;
}
@media (max-width: 800px) {
header,
.toolbar,
.form {
grid-template-columns: 1fr;
}
header {
display: block;
}
.stats {
justify-content: flex-start;
margin-top: 16px;
}
}
</style>
</head>
<body>
<main>
<header>
<div>
<h1>Simple 10 Database</h1>
<p>Browser database page using the 10 Hugging Face dataset records.</p>
</div>
<div class="stats">
<div class="stat">
<strong id="totalCount">0</strong>
<span>Total</span>
</div>
<div class="stat">
<strong id="visibleCount">0</strong>
<span>Visible</span>
</div>
</div>
</header>
<section class="panel" aria-label="Database records">
<div class="toolbar">
<input id="searchInput" type="search" placeholder="Search records">
<select id="categoryFilter" aria-label="Filter by category">
<option value="all">All categories</option>
<option value="starter">Starter</option>
<option value="standard">Standard</option>
<option value="advanced">Advanced</option>
</select>
<button class="secondary" id="resetButton" type="button">Reset Data</button>
</div>
<form class="form" id="recordForm">
<input id="recordId" type="number" min="1" placeholder="ID" required>
<input id="recordName" type="text" placeholder="Name" required>
<select id="recordCategory" required>
<option value="starter">Starter</option>
<option value="standard">Standard</option>
<option value="advanced">Advanced</option>
</select>
<input id="recordDescription" type="text" placeholder="Description" required>
<button type="submit">Add Record</button>
</form>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Category</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody id="recordTable"></tbody>
</table>
<div class="empty" id="emptyState" hidden>No records found.</div>
</div>
</section>
</main>
<script>
const seedRecords = [
{ id: 1, name: "Alpha", category: "starter", description: "First sample database record" },
{ id: 2, name: "Beta", category: "starter", description: "Second sample database record" },
{ id: 3, name: "Gamma", category: "starter", description: "Third sample database record" },
{ id: 4, name: "Delta", category: "standard", description: "Fourth sample database record" },
{ id: 5, name: "Epsilon", category: "standard", description: "Fifth sample database record" },
{ id: 6, name: "Zeta", category: "standard", description: "Sixth sample database record" },
{ id: 7, name: "Eta", category: "advanced", description: "Seventh sample database record" },
{ id: 8, name: "Theta", category: "advanced", description: "Eighth sample database record" },
{ id: 9, name: "Iota", category: "advanced", description: "Ninth sample database record" },
{ id: 10, name: "Kappa", category: "advanced", description: "Tenth sample database record" }
];
const storageKey = "simple-10-database-records";
const table = document.getElementById("recordTable");
const emptyState = document.getElementById("emptyState");
const totalCount = document.getElementById("totalCount");
const visibleCount = document.getElementById("visibleCount");
const searchInput = document.getElementById("searchInput");
const categoryFilter = document.getElementById("categoryFilter");
const form = document.getElementById("recordForm");
let records = loadRecords();
function loadRecords() {
const stored = localStorage.getItem(storageKey);
return stored ? JSON.parse(stored) : [...seedRecords];
}
function saveRecords() {
localStorage.setItem(storageKey, JSON.stringify(records));
}
function getFilteredRecords() {
const query = searchInput.value.trim().toLowerCase();
const category = categoryFilter.value;
return records
.filter((record) => category === "all" || record.category === category)
.filter((record) => {
const text = `${record.id} ${record.name} ${record.category} ${record.description}`.toLowerCase();
return text.includes(query);
})
.sort((a, b) => a.id - b.id);
}
function render() {
const filtered = getFilteredRecords();
table.innerHTML = "";
for (const record of filtered) {
const row = document.createElement("tr");
row.innerHTML = `
<td>${record.id}</td>
<td>${escapeHtml(record.name)}</td>
<td><span class="badge">${escapeHtml(record.category)}</span></td>
<td>${escapeHtml(record.description)}</td>
<td><button class="danger" type="button" data-id="${record.id}">Delete</button></td>
`;
table.appendChild(row);
}
totalCount.textContent = String(records.length);
visibleCount.textContent = String(filtered.length);
emptyState.hidden = filtered.length > 0;
}
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
form.addEventListener("submit", (event) => {
event.preventDefault();
const id = Number(document.getElementById("recordId").value);
if (records.some((record) => record.id === id)) {
alert("This ID already exists.");
return;
}
records.push({
id,
name: document.getElementById("recordName").value.trim(),
category: document.getElementById("recordCategory").value,
description: document.getElementById("recordDescription").value.trim()
});
saveRecords();
form.reset();
render();
});
table.addEventListener("click", (event) => {
const button = event.target.closest("button[data-id]");
if (!button) {
return;
}
const id = Number(button.dataset.id);
records = records.filter((record) => record.id !== id);
saveRecords();
render();
});
document.getElementById("resetButton").addEventListener("click", () => {
records = [...seedRecords];
saveRecords();
render();
});
searchInput.addEventListener("input", render);
categoryFilter.addEventListener("change", render);
render();
</script>
</body>
</html>