feat: refresh Doris Schoolhouse casefile theme
This commit is contained in:
@@ -1,66 +1,228 @@
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--bg: #0f172a;
|
||||
--panel: #111827;
|
||||
--panel-2: #1f2937;
|
||||
--line: #334155;
|
||||
--text: #e5e7eb;
|
||||
--muted: #94a3b8;
|
||||
--accent: #38bdf8;
|
||||
--hf-night: #090b10;
|
||||
--hf-panel: rgba(17, 21, 29, 0.94);
|
||||
--hf-panel-raise: rgba(25, 31, 43, 0.96);
|
||||
--hf-paper: #f2efdd;
|
||||
--hf-muted: #cbbda7;
|
||||
--hf-line: rgba(242, 239, 221, 0.12);
|
||||
--hf-shadow: 0 20px 48px rgba(0, 0, 0, 0.34);
|
||||
--hf-red: #d53600;
|
||||
--hf-red-deep: #910f3f;
|
||||
--hf-amber: #f2c14e;
|
||||
--hf-blue: #7b8fb2;
|
||||
--bg: #090b10;
|
||||
--panel: var(--hf-panel);
|
||||
--panel-2: var(--hf-panel-raise);
|
||||
--line: var(--hf-line);
|
||||
--text: var(--hf-paper);
|
||||
--muted: var(--hf-muted);
|
||||
--accent: var(--hf-amber);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, system-ui, sans-serif;
|
||||
background: linear-gradient(180deg, #020617, var(--bg));
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(213, 54, 0, 0.22), transparent 22rem),
|
||||
radial-gradient(circle at top right, rgba(123, 143, 178, 0.16), transparent 20rem),
|
||||
linear-gradient(180deg, #07090d 0%, #0d1017 52%, #131824 100%);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.site-header, .page-shell { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
||||
.site-header { display: flex; justify-content: space-between; gap: 24px; align-items: end; }
|
||||
.site-header p { color: var(--muted); margin: 6px 0 0; }
|
||||
nav { display: flex; gap: 16px; flex-wrap: wrap; }
|
||||
nav a { color: var(--accent); text-decoration: none; }
|
||||
|
||||
.hero { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }
|
||||
.card {
|
||||
background: rgba(17, 24, 39, 0.92);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
.incident-tape {
|
||||
height: 14px;
|
||||
background: repeating-linear-gradient(135deg, var(--hf-amber) 0 18px, #111 18px 36px);
|
||||
box-shadow: 0 3px 14px rgba(0, 0, 0, 0.32);
|
||||
}
|
||||
|
||||
.site-header, .page-shell { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
||||
.casefile-header { display: grid; gap: 18px; padding-top: 18px; }
|
||||
.brand-row, .casefile-title-row { display: flex; justify-content: space-between; gap: 16px; align-items: center; flex-wrap: wrap; }
|
||||
.nav-brand { display: grid; gap: 3px; }
|
||||
.nav-kicker, .eyebrow { margin: 0; font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: var(--hf-amber); }
|
||||
.nav-links { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.nav-link {
|
||||
text-decoration: none;
|
||||
padding: 9px 13px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--text);
|
||||
font-size: .88rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.nav-link:hover { border-color: rgba(242, 193, 78, 0.58); background: rgba(242, 193, 78, 0.12); }
|
||||
.brand-badges { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.hot-fuzz-art {
|
||||
position: relative;
|
||||
flex: 0 1 320px;
|
||||
min-width: min(100%, 280px);
|
||||
}
|
||||
.poster-illustration {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
filter: drop-shadow(0 24px 30px rgba(0, 0, 0, 0.35));
|
||||
}
|
||||
.poster-frame { fill: rgba(10, 12, 18, 0.88); stroke: rgba(242, 239, 221, 0.2); stroke-width: 2; }
|
||||
.poster-halo { fill: url(#schoolhouse-sunset); opacity: 0.9; }
|
||||
.poster-tape { fill: rgba(242, 193, 78, 0.88); stroke: rgba(17, 17, 17, 0.8); stroke-width: 2; }
|
||||
.constable-silhouette { fill: rgba(8, 10, 15, 0.92); stroke: rgba(242, 239, 221, 0.12); stroke-width: 1.5; }
|
||||
.constable-silhouette.partner { fill: rgba(24, 30, 42, 0.94); }
|
||||
.swan-stamp { fill: rgba(123, 143, 178, 0.2); stroke: rgba(242, 239, 221, 0.42); stroke-width: 2; }
|
||||
.swan-mark { fill: rgba(242, 239, 221, 0.94); }
|
||||
.poster-callout { fill: rgba(242, 239, 221, 0.82); font-size: 18px; font-weight: 800; letter-spacing: 0.24em; text-anchor: middle; }
|
||||
.recipe-card,
|
||||
.folder-body,
|
||||
.folder-tab,
|
||||
.barbell-bar,
|
||||
.plate-outer,
|
||||
.plate-inner { fill: rgba(242, 239, 221, 0.9); }
|
||||
.plate-inner { fill: rgba(10, 12, 18, 0.72); }
|
||||
.film-grain,
|
||||
.cinematic-glow {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border-radius: 28px;
|
||||
}
|
||||
.film-grain {
|
||||
background: repeating-linear-gradient(0deg, rgba(255,255,255,0.025) 0 2px, transparent 2px 5px), repeating-linear-gradient(90deg, rgba(255,255,255,0.018) 0 1px, transparent 1px 4px);
|
||||
mix-blend-mode: soft-light;
|
||||
opacity: 0.35;
|
||||
}
|
||||
.cinematic-glow {
|
||||
background: radial-gradient(circle at 16% 18%, rgba(123, 143, 178, 0.22), transparent 24%), radial-gradient(circle at 84% 24%, rgba(213, 54, 0, 0.24), transparent 26%), linear-gradient(115deg, rgba(242, 193, 78, 0.05), transparent 40%, rgba(145, 15, 63, 0.1) 78%, transparent 100%);
|
||||
animation: emergencyPulse 8s ease-in-out infinite alternate;
|
||||
}
|
||||
.app-casefile { position: relative; overflow: hidden; isolation: isolate; }
|
||||
.casefile-stamp {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0 0 0.85rem;
|
||||
padding: 0.35rem 0.7rem;
|
||||
border: 1px solid rgba(242, 193, 78, 0.45);
|
||||
border-radius: 999px;
|
||||
color: #ffe5b0;
|
||||
background: rgba(242, 193, 78, 0.1);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.16em;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
.app-casefile-schoolhouse .casefile-stamp { box-shadow: 0 0 0 1px rgba(123, 143, 178, 0.12), 0 0 28px rgba(123, 143, 178, 0.18); }
|
||||
@keyframes emergencyPulse {
|
||||
0% { opacity: 0.72; transform: scale(1); }
|
||||
50% { opacity: 0.92; transform: scale(1.015); }
|
||||
100% { opacity: 0.78; transform: scale(1.03); }
|
||||
}
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--line);
|
||||
background: rgba(255,255,255,.05);
|
||||
font-size: .82rem;
|
||||
}
|
||||
.badge-hotfuzz { background: linear-gradient(135deg, var(--hf-red), var(--hf-red-deep)); color: #fff4ea; border-color: transparent; }
|
||||
.site-header p { color: var(--muted); margin: 6px 0 0; }
|
||||
|
||||
.hero, .three-up { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }
|
||||
.card {
|
||||
background: var(--panel);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: var(--hf-shadow);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0 auto auto 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, var(--hf-red), var(--hf-amber), var(--hf-blue));
|
||||
}
|
||||
.notice-card { margin-bottom: 20px; }
|
||||
.success-card {
|
||||
border-color: #14532d;
|
||||
background: linear-gradient(180deg, rgba(20, 83, 45, 0.28), rgba(17, 24, 39, 0.92));
|
||||
border-color: rgba(92, 127, 105, 0.45);
|
||||
background: linear-gradient(180deg, rgba(92, 127, 105, 0.24), rgba(17, 21, 29, 0.96));
|
||||
}
|
||||
|
||||
.form-card { max-width: 760px; }
|
||||
.stack { display: grid; gap: 14px; }
|
||||
label { display: grid; gap: 8px; color: var(--muted); }
|
||||
input, textarea, button {
|
||||
input, textarea, button, select {
|
||||
font: inherit;
|
||||
border-radius: 10px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--line);
|
||||
padding: 12px 14px;
|
||||
}
|
||||
input, textarea { background: var(--panel-2); color: var(--text); }
|
||||
input, textarea, select { background: var(--panel-2); color: var(--text); }
|
||||
button {
|
||||
background: var(--accent);
|
||||
color: #082f49;
|
||||
background: linear-gradient(135deg, var(--hf-red), var(--hf-red-deep));
|
||||
color: #fff4ea;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
button:hover { filter: brightness(1.06); }
|
||||
|
||||
.muted { color: var(--muted); }
|
||||
.stat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin: 12px 0 16px; }
|
||||
.stat-grid div { background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px; padding: 12px; display: grid; gap: 8px; }
|
||||
.stat-grid div { background: var(--panel-2); border: 1px solid var(--line); border-radius: 14px; padding: 12px; display: grid; gap: 8px; }
|
||||
.stat-grid span { font-size: 1.5rem; font-weight: 700; color: var(--text); }
|
||||
.three-up { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-top: 20px; }
|
||||
.list-block { display: grid; gap: 10px; }
|
||||
.list-item { padding: 10px 12px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px; }
|
||||
.list-item strong { display: block; margin-bottom: 6px; }
|
||||
.list-item small { color: var(--muted); display: block; }
|
||||
.evidence-board,
|
||||
.evidence-card,
|
||||
.evidence-slab,
|
||||
.intake-docket { position: relative; }
|
||||
.dossier-grid { align-items: stretch; }
|
||||
.case-legend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.case-legend::after {
|
||||
content: 'FOR THE GREATER GOOD';
|
||||
font-size: 0.67rem;
|
||||
letter-spacing: 0.16em;
|
||||
color: rgba(242, 193, 78, 0.7);
|
||||
}
|
||||
.evidence-board::after,
|
||||
.evidence-card::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 14px;
|
||||
border: 1px dashed rgba(242, 193, 78, 0.09);
|
||||
border-radius: 16px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.dossier-note { padding-left: 12px; border-left: 3px solid rgba(242, 193, 78, 0.4); }
|
||||
.case-list { list-style: none; padding: 0; margin: 0; }
|
||||
.case-list li { padding-left: 18px; position: relative; }
|
||||
.case-list li::before { content: '•'; position: absolute; left: 0; color: var(--hf-amber); }
|
||||
.intake-docket {
|
||||
background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.015));
|
||||
border: 1px solid rgba(242, 239, 221, 0.06);
|
||||
border-radius: 18px;
|
||||
padding: 14px;
|
||||
}
|
||||
.chain-of-custody { padding-bottom: 10px; border-bottom: 1px dashed rgba(242, 193, 78, 0.2); }
|
||||
.evidence-slab { background: var(--panel-2); border: 1px solid var(--line); border-radius: 14px; padding: 12px; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.site-header, .page-shell { padding: 18px; }
|
||||
.stat-grid { grid-template-columns: 1fr; }
|
||||
.hot-fuzz-art { flex-basis: 100%; min-width: 0; }
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% if request.query_params.get('submitted') %}
|
||||
<section class="card form-card notice-card success-card">
|
||||
<section class="card form-card notice-card success-card evidence-board">
|
||||
<div class="case-legend"><span class="section-label">Submission packet</span><span class="pill">Filed</span></div>
|
||||
<h2>Submission Created</h2>
|
||||
<p>Submission {{ request.query_params.get('submitted') }} was created successfully.</p>
|
||||
<p class="muted">Artifact: {{ request.query_params.get('artifact_kind', 'document') }} · Files: {{ request.query_params.get('file_count', '1') }}</p>
|
||||
<p class="muted">Paperless status: {{ request.query_params.get('paperless_status', 'uploaded-local') }}</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
<section class="card form-card">
|
||||
<section class="card form-card evidence-board">
|
||||
<div class="case-legend chain-of-custody"><span class="section-label">Submission packet</span><span class="pill">chain-of-custody</span></div>
|
||||
<h2>Assignment Upload</h2>
|
||||
<form class="stack" method="post" enctype="multipart/form-data" action="/api/assignments/intake" id="assignment-upload-form">
|
||||
<p class="muted">Package coursework like a proper intake docket so the archive, Paperless, and later review all stay in sync.</p>
|
||||
<form class="stack intake-docket" method="post" enctype="multipart/form-data" action="/api/assignments/intake" id="assignment-upload-form">
|
||||
<label>Class
|
||||
<select name="class_id" id="class-select" required>
|
||||
<option value="">Loading classes…</option>
|
||||
|
||||
@@ -4,19 +4,60 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ title or 'Doris Schoolhouse' }}</title>
|
||||
<link rel="stylesheet" href="/static/app.css">
|
||||
<link rel="stylesheet" href="/static/app.css?v=4">
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<div>
|
||||
<h1>Doris Schoolhouse</h1>
|
||||
<p>School intake, recordings, D2L sync, and Paperless linkage.</p>
|
||||
<body class="doris-hot-fuzz app-schoolhouse">
|
||||
<div class="incident-tape" aria-hidden="true"></div>
|
||||
<header class="site-header casefile-header app-casefile app-casefile-schoolhouse">
|
||||
<div class="film-grain" aria-hidden="true"></div>
|
||||
<div class="cinematic-glow" aria-hidden="true"></div>
|
||||
<div class="brand-row">
|
||||
<div class="nav-brand">
|
||||
<span class="nav-kicker">N.W.A. Case File</span>
|
||||
<strong>Doris Constabulary</strong>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="/">Dashboard</a>
|
||||
<a href="/assignments/upload">Assignment Upload</a>
|
||||
<a href="/recordings/upload">Recording Upload</a>
|
||||
<nav class="nav-links" aria-label="Doris Schoolhouse navigation">
|
||||
<a class="nav-link" href="http://10.5.1.16:8787/">Dashboard</a>
|
||||
<a class="nav-link" href="/">Dashboard</a>
|
||||
<a class="nav-link" href="/assignments/upload">Assignment Upload</a>
|
||||
<a class="nav-link" href="/recordings/upload">Recording Upload</a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="casefile-title-row">
|
||||
<div>
|
||||
<p class="eyebrow">Sandford records desk</p>
|
||||
<div class="casefile-stamp coursework-evidence-tag">Records Intake</div>
|
||||
<h1>Doris Schoolhouse</h1>
|
||||
<p class="lede">Assignment packets, recording intake, and D2L paperwork now framed like a proper evidence room instead of some sad upload form farm.</p>
|
||||
<div class="brand-badges" aria-label="Theme badges">
|
||||
<span class="pill badge-hotfuzz">For the Greater Good</span>
|
||||
<span class="pill">Evidence locker: coursework</span>
|
||||
<span class="pill">Case type: Records Intake</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hot-fuzz-art" aria-hidden="true">
|
||||
<svg viewBox="0 0 320 220" class="poster-illustration" role="presentation">
|
||||
<defs>
|
||||
<linearGradient id="schoolhouse-sunset" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#f2c14e"></stop>
|
||||
<stop offset="50%" stop-color="#d53600"></stop>
|
||||
<stop offset="100%" stop-color="#910f3f"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<rect x="8" y="8" width="304" height="204" rx="24" class="poster-frame"></rect>
|
||||
<circle cx="228" cy="72" r="58" class="poster-halo"></circle>
|
||||
<path d="M18 170 L112 100 L134 124 L40 198 Z" class="poster-tape tape-left"></path>
|
||||
<path d="M202 82 L302 32 L314 60 L214 112 Z" class="poster-tape tape-right"></path>
|
||||
<path d="M112 180 C110 150 116 126 132 110 C140 100 148 94 154 90 C160 94 168 100 176 110 C192 126 198 150 196 180 Z" class="constable-silhouette lead"></path>
|
||||
<path d="M174 184 C172 154 178 132 194 118 C202 110 210 104 218 100 C226 104 234 110 242 118 C258 132 264 154 262 184 Z" class="constable-silhouette partner"></path>
|
||||
<circle cx="84" cy="60" r="28" class="swan-stamp"></circle>
|
||||
<path d="M76 64 C80 54 91 48 101 53 C93 52 88 57 89 63 C90 69 101 68 103 76 C94 78 83 76 78 69 L71 76 L66 71 L74 64 Z" class="swan-mark"></path>
|
||||
<rect x="124" y="84" width="78" height="54" rx="6" class="folder-body"></rect>
|
||||
<rect x="134" y="74" width="36" height="14" rx="4" class="folder-tab"></rect>
|
||||
<text x="160" y="204" class="poster-callout">RECORDS INTAKE</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main class="page-shell">
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
<section class="hero">
|
||||
<div class="card">
|
||||
<section class="hero evidence-board dossier-grid">
|
||||
<div class="card evidence-card">
|
||||
<div class="case-legend">
|
||||
<span class="section-label">Course board</span>
|
||||
<span class="pill">Records Intake</span>
|
||||
</div>
|
||||
<h2>Overview</h2>
|
||||
<div class="stat-grid" id="summary-stats">
|
||||
<div><strong>Courses</strong><span id="stat-courses">—</span></div>
|
||||
@@ -9,13 +13,17 @@
|
||||
<div><strong>Submissions</strong><span id="stat-submissions">—</span></div>
|
||||
<div><strong>Recordings</strong><span id="stat-recordings">—</span></div>
|
||||
</div>
|
||||
<p class="muted" id="backend-note">Loading backend…</p>
|
||||
<p class="muted dossier-note" id="backend-note">Loading backend…</p>
|
||||
<button id="sync-button" type="button">Refresh from D2L</button>
|
||||
<p class="muted" id="sync-status">No sync run loaded yet.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card evidence-card">
|
||||
<div class="case-legend">
|
||||
<span class="section-label">Operator notes</span>
|
||||
<span class="pill">Course board</span>
|
||||
</div>
|
||||
<h2>What this app currently does</h2>
|
||||
<ul>
|
||||
<ul class="case-list">
|
||||
<li>Reads current D2L scrape data</li>
|
||||
<li>Caches course and assignment rows</li>
|
||||
<li>Stores assignment upload intake records</li>
|
||||
@@ -25,16 +33,19 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="three-up">
|
||||
<div class="card">
|
||||
<section class="three-up dossier-grid">
|
||||
<div class="card evidence-board">
|
||||
<div class="case-legend"><span class="section-label">Assignments</span><span class="pill">Open files</span></div>
|
||||
<h2>Recent assignments</h2>
|
||||
<div id="recent-assignments" class="list-block muted">Loading…</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card evidence-board">
|
||||
<div class="case-legend"><span class="section-label">Submissions</span><span class="pill">Chain status</span></div>
|
||||
<h2>Recent submissions</h2>
|
||||
<div id="recent-submissions" class="list-block muted">Loading…</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card evidence-board">
|
||||
<div class="case-legend"><span class="section-label">Recordings</span><span class="pill">Audio evidence</span></div>
|
||||
<h2>Recent recordings</h2>
|
||||
<div id="recent-recordings" class="list-block muted">Loading…</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
<section class="card form-card">
|
||||
<section class="card form-card evidence-board">
|
||||
<div class="case-legend chain-of-custody"><span class="section-label">Audio evidence</span><span class="pill">intake-docket</span></div>
|
||||
<h2>Recording Upload</h2>
|
||||
<form class="stack" method="post" enctype="multipart/form-data" action="/api/recordings/intake">
|
||||
<p class="muted">Treat lectures and review audio like evidence bags: clearly dated, tied to the right class, and ready for later transcription and filing.</p>
|
||||
<form class="stack intake-docket" method="post" enctype="multipart/form-data" action="/api/recordings/intake">
|
||||
<label>Class
|
||||
<select name="class_id" id="recording-class-select" required>
|
||||
<option value="">Loading classes…</option>
|
||||
|
||||
Reference in New Issue
Block a user