From faea6777a033a62afd9d1e1486f4ff1dfcbb4ae1 Mon Sep 17 00:00:00 2001 From: zwitschi Date: Sun, 9 Nov 2025 17:36:31 +0100 Subject: [PATCH] feat: add CSS styles and JavaScript functionality for projects and scenarios, including filtering and layout enhancements --- requirements.txt | 3 +- static/css/projects.css | 109 ++++++++++++++++++++++++++++++++ static/css/scenarios.css | 78 +++++++++++++++++++++++ static/js/projects.js | 19 ++++++ templates/projects/detail.html | 4 ++ templates/projects/form.html | 4 ++ templates/projects/list.html | 21 +++++- templates/scenarios/detail.html | 8 +++ templates/scenarios/form.html | 4 ++ 9 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 static/css/projects.css create mode 100644 static/css/scenarios.css create mode 100644 static/js/projects.js diff --git a/requirements.txt b/requirements.txt index e07bb5c..1ae5423 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ jinja2 pandas numpy passlib -python-jose \ No newline at end of file +python-jose +python-multipart \ No newline at end of file diff --git a/static/css/projects.css b/static/css/projects.css new file mode 100644 index 0000000..bc0daf2 --- /dev/null +++ b/static/css/projects.css @@ -0,0 +1,109 @@ +:root { + --card-bg: rgba(21, 27, 35, 0.8); + --card-border: rgba(255, 255, 255, 0.08); + --hover-highlight: rgba(241, 178, 26, 0.12); +} + +.projects-table { + width: 100%; + border-collapse: collapse; + border-radius: var(--table-radius); + overflow: hidden; + box-shadow: var(--shadow); +} + +.projects-table th, +.projects-table td { + padding: 0.875rem 1rem; + border-bottom: 1px solid var(--card-border); + background: var(--card-bg); +} + +.projects-table tbody tr:hover { + background: var(--hover-highlight); +} + +.definition-list { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 1.25rem 2rem; +} + +.definition-list dt { + font-weight: 600; + color: var(--muted); + margin-bottom: 0.2rem; + text-transform: uppercase; + font-size: 0.75rem; +} + +.definition-list dd { + margin: 0; + font-size: 1rem; +} + +.card { + background: var(--card-bg); + border: 1px solid var(--card-border); + box-shadow: var(--shadow); + border-radius: var(--radius); + padding: 1.5rem; + margin-bottom: 2rem; +} + +.card-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1rem; +} + +.card-header h2 { + margin: 0; +} + +.alert { + padding: 0.75rem 1rem; + border-radius: var(--radius-sm); + margin-bottom: 1rem; +} + +.alert-error { + background: rgba(209, 75, 75, 0.2); + border: 1px solid rgba(209, 75, 75, 0.4); + color: var(--color-text-invert); +} + +.form { + display: flex; + flex-direction: column; + gap: 1.25rem; +} + +.form-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1.25rem; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.form-group input, +.form-group select, +.form-group textarea { + padding: 0.75rem 0.85rem; + border-radius: var(--radius-sm); + border: 1px solid var(--card-border); + background: rgba(8, 12, 19, 0.75); + color: var(--text); +} + +.form-actions { + display: flex; + gap: 0.75rem; + justify-content: flex-end; +} diff --git a/static/css/scenarios.css b/static/css/scenarios.css new file mode 100644 index 0000000..27efe04 --- /dev/null +++ b/static/css/scenarios.css @@ -0,0 +1,78 @@ +.scenario-meta { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1.25rem; +} + +.table { + width: 100%; + border-collapse: collapse; + border-radius: var(--table-radius); + overflow: hidden; + box-shadow: var(--shadow); +} + +.table th, +.table td { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--color-border); + background: rgba(21, 27, 35, 0.85); +} + +.table tbody tr:hover { + background: rgba(43, 165, 143, 0.12); +} + +.breadcrumb { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.9rem; + color: var(--muted); + margin-bottom: 1.2rem; +} + +.breadcrumb a { + color: var(--brand-2); + text-decoration: none; +} + +.actions { + display: flex; + gap: 0.75rem; +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.6rem 1.1rem; + border-radius: var(--radius-sm); + text-decoration: none; + font-weight: 600; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.btn-primary { + background: linear-gradient(90deg, var(--brand) 0%, var(--brand-2) 100%); + color: var(--color-text-dark); + box-shadow: 0 8px 18px rgba(241, 178, 26, 0.25); +} + +.btn-secondary { + background: rgba(148, 197, 255, 0.2); + color: var(--color-text-invert); + border: 1px solid rgba(148, 197, 255, 0.35); +} + +.btn-link { + padding: 0.35rem 0.5rem; + color: var(--brand-3); + text-decoration: none; +} + +.btn:hover, +.btn:focus { + transform: translateY(-1px); + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.25); +} diff --git a/static/js/projects.js b/static/js/projects.js new file mode 100644 index 0000000..ebad17a --- /dev/null +++ b/static/js/projects.js @@ -0,0 +1,19 @@ +document.addEventListener("DOMContentLoaded", () => { + const table = document.querySelector("[data-project-table]"); + if (!table) { + return; + } + + const rows = Array.from(table.querySelectorAll("tbody tr")); + const filterInput = document.querySelector("[data-project-filter]"); + + if (filterInput) { + filterInput.addEventListener("input", () => { + const query = filterInput.value.trim().toLowerCase(); + rows.forEach((row) => { + const match = row.textContent.toLowerCase().includes(query); + row.style.display = match ? "" : "none"; + }); + }); + } +}); diff --git a/templates/projects/detail.html b/templates/projects/detail.html index e246a8e..001ec4c 100644 --- a/templates/projects/detail.html +++ b/templates/projects/detail.html @@ -1,6 +1,10 @@ {% extends "base.html" %} {% block title %}{{ project.name }} · Project · CalMiner{% endblock %} +{% block head_extra %} + +{% endblock %} + {% block content %}