mirror of
https://github.com/hanzoskill/llm-council.git
synced 2026-10-30 21:14:09 +00:00
494 lines
11 KiB
HTML
494 lines
11 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>LLM Council</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Black+Ops+One&family=Kanita:wght@900&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
color-scheme: light;
|
|
--bg: #f7f4ea;
|
|
--ink: #141414;
|
|
--accent: #ff6b00;
|
|
--accent-2: #00d5ff;
|
|
--panel: #ffffff;
|
|
--shadow: #000000;
|
|
--soft: rgba(0, 0, 0, 0.1);
|
|
--radius: 0.75rem;
|
|
--display: 'Black Ops One', 'Impact', 'Haettenschweiler', 'Franklin Gothic Heavy', 'Arial Black', sans-serif;
|
|
--body: 'Franklin Gothic Medium', 'Trebuchet MS', 'Verdana', sans-serif;
|
|
--mono: 'Courier New', monospace;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: var(--body);
|
|
color: var(--ink);
|
|
background: radial-gradient(circle at 20% 20%, #fff4d6 0%, var(--bg) 60%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
body::before {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
background-image: repeating-linear-gradient(135deg, rgba(0,0,0,0.04) 0 2px, transparent 2px 10px);
|
|
pointer-events: none;
|
|
z-index: -1;
|
|
}
|
|
|
|
.app {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 1.5rem 1.25rem 2.5rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.hero {
|
|
display: grid;
|
|
gap: 1rem;
|
|
padding: 1.25rem 1.5rem;
|
|
background: #fff9e8;
|
|
border: 3px solid var(--ink);
|
|
box-shadow: 10px 10px 0 var(--shadow);
|
|
}
|
|
|
|
.brand-mark {
|
|
font-family: 'Black Ops One', system-ui, sans-serif;
|
|
font-size: clamp(2.5rem, 6vw, 4rem);
|
|
font-weight: 900;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
line-height: 1.1;
|
|
color: var(--ink);
|
|
text-shadow:
|
|
4px 4px 0 var(--accent),
|
|
8px 8px 0 rgba(0,0,0,0.2);
|
|
position: relative;
|
|
transform: rotate(-1deg);
|
|
margin-bottom: 0.35rem;
|
|
}
|
|
|
|
.brand-meta,
|
|
.status-meta {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.75rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.status {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.status-pill {
|
|
font-family: var(--mono);
|
|
border: 2px solid var(--ink);
|
|
padding: 0.35rem 0.75rem;
|
|
background: #fff;
|
|
box-shadow: 4px 4px 0 var(--shadow);
|
|
}
|
|
|
|
.status-controls {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
font-size: 0.85rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.toggle input {
|
|
position: absolute;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.toggle-track {
|
|
width: 2.4rem;
|
|
height: 1.3rem;
|
|
border: 2px solid var(--ink);
|
|
background: #fff;
|
|
position: relative;
|
|
}
|
|
|
|
.toggle-track::after {
|
|
content: '';
|
|
width: 0.9rem;
|
|
height: 0.9rem;
|
|
background: var(--accent);
|
|
position: absolute;
|
|
top: 0.1rem;
|
|
left: 0.1rem;
|
|
transition: transform 150ms ease;
|
|
}
|
|
|
|
.toggle input:checked + .toggle-track::after {
|
|
transform: translateX(1.1rem);
|
|
}
|
|
|
|
.task,
|
|
.panel {
|
|
background: var(--panel);
|
|
border: 3px solid var(--ink);
|
|
box-shadow: 8px 8px 0 var(--shadow);
|
|
padding: 1.25rem 1.5rem;
|
|
}
|
|
|
|
.section-title h2,
|
|
.panel-header h2 {
|
|
font-family: var(--display);
|
|
margin: 0;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.label-spaced {
|
|
display: block;
|
|
margin-bottom: 0.35rem;
|
|
}
|
|
|
|
.task-brief {
|
|
margin: 0;
|
|
font-size: 1.05rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 1.5rem;
|
|
}
|
|
|
|
.panel-header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.panel-header--judge {
|
|
margin-bottom: 0.35rem;
|
|
}
|
|
.panel-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.select-label,
|
|
.editor-pane label,
|
|
.preview-pane label,
|
|
.action-group label {
|
|
font-size: 0.85rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
|
|
.planner-select {
|
|
min-height: 44px;
|
|
padding: 0.5rem 2.4rem 0.5rem 0.75rem;
|
|
border: 3px solid var(--ink);
|
|
background: #fff;
|
|
font-family: var(--body);
|
|
appearance: none;
|
|
background-image:
|
|
linear-gradient(45deg, transparent 50%, var(--ink) 50%),
|
|
linear-gradient(135deg, var(--ink) 50%, transparent 50%);
|
|
background-position: right 0.9rem center, right 0.55rem center;
|
|
background-size: 8px 8px;
|
|
background-repeat: no-repeat;
|
|
}
|
|
|
|
.planner-detail {
|
|
background: #fffef6;
|
|
}
|
|
|
|
.planner-card {
|
|
border: 3px solid var(--ink);
|
|
padding: 0.9rem 1rem;
|
|
background: #fff;
|
|
}
|
|
|
|
.planner-meta {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
.status-chip {
|
|
border: 2px solid var(--ink);
|
|
padding: 0.1rem 0.45rem;
|
|
font-size: 0.75rem;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.content-block {
|
|
margin: 0;
|
|
font-family: var(--mono);
|
|
background: #fef3d6;
|
|
border: 2px solid var(--ink);
|
|
padding: 0.8rem;
|
|
white-space: pre-wrap;
|
|
word-break: break-word;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
#plannerSummaryText {
|
|
min-height: 360px;
|
|
max-height: 460px;
|
|
overflow: auto;
|
|
padding: 1rem;
|
|
}
|
|
|
|
#judgeSummary,
|
|
#finalPlanPreview {
|
|
min-height: 500px;
|
|
max-height: 660px;
|
|
overflow: auto;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.panel-body--judge {
|
|
padding-bottom: 0.5rem;
|
|
}
|
|
|
|
#judgeSummary {
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.error-list {
|
|
margin: 0;
|
|
padding-left: 1.2rem;
|
|
color: #b00020;
|
|
}
|
|
|
|
.editor-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
gap: 1rem;
|
|
}
|
|
|
|
textarea,
|
|
textarea#refineContext {
|
|
width: 100%;
|
|
min-height: 180px;
|
|
font-family: var(--mono);
|
|
font-size: 0.95rem;
|
|
border: 3px solid var(--ink);
|
|
padding: 0.8rem;
|
|
background: #fff;
|
|
resize: vertical;
|
|
}
|
|
|
|
textarea#refineContext {
|
|
min-height: 96px;
|
|
}
|
|
|
|
#finalPlanEditor {
|
|
min-height: 500px;
|
|
}
|
|
|
|
.action-row {
|
|
margin-top: 1.2rem;
|
|
display: grid;
|
|
gap: 1.2rem;
|
|
}
|
|
|
|
.btn {
|
|
min-height: 44px;
|
|
padding: 0.6rem 1.1rem;
|
|
border: 3px solid var(--ink);
|
|
background: #fff;
|
|
font-family: var(--display);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
cursor: pointer;
|
|
box-shadow: 5px 5px 0 var(--shadow);
|
|
transition: transform 120ms ease;
|
|
}
|
|
|
|
.btn:hover {
|
|
transform: translate(-2px, -2px);
|
|
}
|
|
|
|
.btn.primary {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
}
|
|
|
|
.btn.danger {
|
|
background: var(--accent-2);
|
|
color: #002633;
|
|
}
|
|
|
|
.rerun-row {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto;
|
|
gap: 0.75rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.action-group--actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.75rem;
|
|
align-items: center;
|
|
}
|
|
|
|
.rerun-row .btn.danger {
|
|
min-height: 44px;
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.panel-wide {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.hero {
|
|
grid-template-columns: 2fr 1.2fr 1fr;
|
|
align-items: center;
|
|
}
|
|
|
|
.editor-grid {
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.grid {
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="app">
|
|
<header class="hero">
|
|
<div class="brand">
|
|
<div class="brand-mark">LLM Council</div>
|
|
<div class="brand-meta">
|
|
<span id="runId">run: —</span>
|
|
<span id="phase">phase: —</span>
|
|
</div>
|
|
</div>
|
|
<div class="status">
|
|
<div id="connectionStatus" class="status-pill">connecting…</div>
|
|
<div class="status-meta">
|
|
<span id="lastUpdated">last update: —</span>
|
|
<span id="sessionCountdown">session: —</span>
|
|
</div>
|
|
</div>
|
|
<div class="status-controls">
|
|
<label class="toggle">
|
|
<input id="keepOpenToggle" type="checkbox">
|
|
<span class="toggle-track"></span>
|
|
<span class="toggle-label">Keep UI open (disable auto-close)</span>
|
|
</label>
|
|
<span id="keepOpenStatus" class="status-text"></span>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="task">
|
|
<div class="section-title">
|
|
<h2>Task Brief</h2>
|
|
</div>
|
|
<p id="taskBrief" class="task-brief">—</p>
|
|
</section>
|
|
|
|
<main class="grid">
|
|
<section class="panel">
|
|
<div class="panel-header">
|
|
<h2>Planner Output</h2>
|
|
<span id="plannerSummary" class="panel-sub">—</span>
|
|
</div>
|
|
<div class="panel-body">
|
|
<label class="select-label" for="plannerSelect">Planner</label>
|
|
<select id="plannerSelect" class="planner-select"></select>
|
|
<div class="planner-card planner-detail">
|
|
<div class="planner-meta">
|
|
<div id="plannerId" class="planner-id">—</div>
|
|
<span id="plannerStatus" class="status-chip">—</span>
|
|
</div>
|
|
<pre id="plannerSummaryText" class="content-block">—</pre>
|
|
<ul id="plannerErrors" class="error-list"></ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<div class="panel-header panel-header--judge">
|
|
<h2 class="label-spaced">Judge Output</h2>
|
|
<span id="judgeStatus" class="panel-sub">—</span>
|
|
</div>
|
|
<div class="panel-body panel-body--judge">
|
|
<pre id="judgeSummary" class="content-block">—</pre>
|
|
<ul id="judgeErrors" class="error-list"></ul>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="panel panel-wide">
|
|
<div class="panel-header">
|
|
<h2>Final Plan</h2>
|
|
<span id="finalPlanStatus" class="panel-sub">—</span>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="editor-grid">
|
|
<div class="editor-pane">
|
|
<label class="label-spaced" for="finalPlanEditor">Editor</label>
|
|
<textarea id="finalPlanEditor" spellcheck="false"></textarea>
|
|
</div>
|
|
<div class="preview-pane" id="previewPane">
|
|
<label class="label-spaced">Preview</label>
|
|
<pre id="finalPlanPreview" class="content-block">—</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-row">
|
|
<div class="action-group action-group--actions">
|
|
<button id="acceptBtn" class="btn primary" type="button">Accept</button>
|
|
<button id="saveBtn" class="btn primary" type="button">Save</button>
|
|
<span id="saveStatus" class="status-text"></span>
|
|
</div>
|
|
<div class="action-group">
|
|
<label class="label-spaced" for="refineContext">Refine Notes</label>
|
|
<div class="rerun-row">
|
|
<textarea id="refineContext" rows="3" placeholder="Describe what to refine in the plan"></textarea>
|
|
<button id="refineBtn" class="btn danger" type="button">Refine</button>
|
|
</div>
|
|
<span id="refineStatus" class="status-text"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|