Files
Timmy-time-dashboard/src/dashboard/templates/briefing.html
2026-03-05 19:45:38 -05:00

213 lines
5.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Morning Briefing{% endblock %}
{% block extra_styles %}
<style>
/* ── Briefing-specific styles ── */
.briefing-container { max-width: 680px; }
.briefing-header {
border-left: 3px solid var(--amber);
padding-left: 1rem;
}
.briefing-greeting {
font-size: 1.6rem;
font-weight: 700;
color: var(--amber);
letter-spacing: 0.04em;
font-family: var(--font);
}
.briefing-timestamp {
font-size: 0.75rem;
color: var(--text-dim);
margin-top: 0.25rem;
}
.briefing-ts-val { color: var(--text); }
.briefing-prose {
font-size: 1rem;
line-height: 1.75;
color: var(--text-bright);
white-space: pre-wrap;
word-break: break-word;
}
/* Approval cards */
.approval-card {
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: 1rem;
margin-bottom: 0.75rem;
background: rgba(24, 10, 45, 0.5);
transition: border-color 0.2s;
}
.approval-card.approved {
border-color: var(--green);
opacity: 0.7;
}
.approval-card.rejected {
border-color: var(--red);
opacity: 0.7;
}
.approval-card-title {
font-weight: 600;
font-size: 0.95rem;
color: var(--text-bright);
margin-bottom: 0.25rem;
}
.approval-card-desc {
font-size: 0.85rem;
color: var(--text);
margin-bottom: 0.5rem;
}
.approval-card-action {
font-size: 0.8rem;
color: var(--text-dim);
font-family: var(--font);
margin-bottom: 0.75rem;
border-left: 2px solid var(--border);
padding-left: 0.5rem;
}
.impact-badge {
font-size: 0.7rem;
padding: 0.2em 0.5em;
border-radius: 4px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.impact-low { background: var(--green-dim); color: var(--green); }
.impact-medium { background: var(--amber-dim); color: var(--amber); }
.impact-high { background: var(--red-dim); color: var(--red); }
.approval-actions {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.btn-approve {
background: var(--green-dim);
color: var(--green);
border: 1px solid var(--green);
border-radius: var(--radius-sm);
padding: 0.4rem 0.9rem;
font-size: 0.82rem;
font-family: var(--font);
cursor: pointer;
min-height: 44px;
transition: background 0.15s;
touch-action: manipulation;
}
.btn-approve:hover { background: rgba(0, 232, 122, 0.2); }
.btn-reject {
background: transparent;
color: var(--red);
border: 1px solid var(--red);
border-radius: var(--radius-sm);
padding: 0.4rem 0.9rem;
font-size: 0.82rem;
font-family: var(--font);
cursor: pointer;
min-height: 44px;
transition: background 0.15s;
touch-action: manipulation;
}
.btn-reject:hover { background: rgba(255, 68, 85, 0.1); }
.no-approvals {
text-align: center;
color: var(--text-dim);
padding: 2rem 0;
font-size: 0.9rem;
}
.btn-refresh {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.3rem 0.7rem;
font-size: 0.75rem;
font-family: var(--font);
cursor: pointer;
text-decoration: none;
display: inline-block;
transition: border-color 0.15s;
}
.btn-refresh:hover { border-color: var(--purple); color: var(--text-bright); }
@media (max-width: 576px) {
.briefing-greeting { font-size: 1.3rem; }
.briefing-prose { font-size: 0.95rem; }
}
</style>
{% endblock %}
{% block content %}
<div class="container briefing-container py-4">
<div class="briefing-header mb-4">
<div style="display:flex; justify-content:space-between; align-items:flex-start;">
<div>
<div class="briefing-greeting">Good morning.</div>
<div class="briefing-timestamp">
Briefing generated
<span class="briefing-ts-val">{{ briefing.generated_at.strftime('%Y-%m-%d %H:%M UTC') }}</span>
&mdash; covering
<span class="briefing-ts-val">{{ briefing.period_start.strftime('%H:%M') }}</span>
to
<span class="briefing-ts-val">{{ briefing.period_end.strftime('%H:%M UTC') }}</span>
</div>
</div>
<button class="btn-refresh" id="btn-regenerate" onclick="regenerateBriefing()">REGENERATE</button>
</div>
</div>
<div class="card mc-panel briefing-summary mb-4">
<div class="card-header mc-panel-header">// TIMMY&rsquo;S REPORT</div>
<div class="card-body p-4">
<div class="briefing-prose">{{ briefing.summary | e }}</div>
</div>
</div>
<div class="card mc-panel">
<div class="card-header mc-panel-header d-flex justify-content-between align-items-center">
<span>// APPROVAL QUEUE</span>
<span class="badge badge-warning" id="approval-count">{{ briefing.approval_items | length }} pending</span>
</div>
<div class="card-body p-3"
id="approval-queue"
hx-get="/briefing/approvals"
hx-trigger="load"
hx-swap="innerHTML">
<div style="text-align:center; color:var(--text-dim); padding:16px; font-size:0.85rem;">Loading approval items&hellip;</div>
</div>
</div>
</div>
<script>
async function regenerateBriefing() {
var btn = document.getElementById('btn-regenerate');
btn.textContent = 'REGENERATING...';
btn.disabled = true;
try {
var resp = await fetch('/briefing/regenerate', { method: 'POST' });
if (resp.ok) {
window.location.reload();
} else {
btn.textContent = 'FAILED';
setTimeout(function() { btn.textContent = 'REGENERATE'; btn.disabled = false; }, 2000);
}
} catch (e) {
btn.textContent = 'ERROR';
setTimeout(function() { btn.textContent = 'REGENERATE'; btn.disabled = false; }, 2000);
}
}
</script>
{% endblock %}