Polish: professional layout, collapsible sections, tighter design
- Replaced amateur CSS with professional dark theme (Inter font, muted palette, proper spacing, consistent border radius, hover states, transitions) - Nav bar with Dashboard/Intelligence Console/Architecture tabs - Urgent pipeline: shows contracts directly, removed busy step indicators - In Progress + Ready to Go: collapsed by default with expand toggle (page went from 30+ visible contract cards to just the urgents) - Workers Available: limited to 5 instead of 8 - Proper section headers with labels and metadata - Search section always visible with better placeholder text - Professional footer with product branding - Responsive breakpoints for mobile (768px, 480px) - Page is now ~50% shorter with same information density Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2da8562c90
commit
8e3cac5812
@ -6,67 +6,141 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
body{font-family:-apple-system,system-ui,sans-serif;background:#0b0f19;color:#c9d1d9;font-size:14px;line-height:1.5}
|
||||
.bar{background:#161b22;padding:12px 20px;border-bottom:1px solid #21262d;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px}
|
||||
.bar h1{font-size:16px;font-weight:600;color:#f0f6fc}.bar .rt{font-size:11px;color:#8b949e}
|
||||
.content{max-width:900px;margin:0 auto;padding:20px 16px}
|
||||
body{font-family:'Inter',-apple-system,system-ui,'Segoe UI',sans-serif;background:#090c10;color:#b0b8c4;font-size:14px;line-height:1.6;-webkit-font-smoothing:antialiased}
|
||||
|
||||
/* Insight cards — the "how did it know that?" moments */
|
||||
.insight{background:#161b22;border:1px solid #21262d;border-radius:12px;padding:20px;margin-bottom:16px}
|
||||
.insight .label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:1.5px;margin-bottom:6px}
|
||||
.insight .headline{font-size:18px;font-weight:700;color:#f0f6fc;margin-bottom:4px}
|
||||
.insight .sub{font-size:13px;color:#8b949e;margin-bottom:14px}
|
||||
.insight.urgent{border-left:3px solid #f85149}
|
||||
.insight.opportunity{border-left:3px solid #3fb950}
|
||||
.insight.warning{border-left:3px solid #d29922}
|
||||
.insight.info{border-left:3px solid #58a6ff}
|
||||
/* Top bar */
|
||||
.bar{background:#0d1117;padding:0 24px;height:56px;border-bottom:1px solid #171d27;display:flex;justify-content:space-between;align-items:center}
|
||||
.bar h1{font-size:14px;font-weight:600;color:#e6edf3;letter-spacing:-0.2px}
|
||||
.bar .rt{font-size:11px;color:#545d68}
|
||||
.bar nav{display:flex;gap:2px}
|
||||
.bar nav a{font-size:12px;color:#545d68;text-decoration:none;padding:6px 14px;border-radius:6px;transition:all 0.15s}
|
||||
.bar nav a:hover{color:#e6edf3;background:#161b22}
|
||||
.bar nav a.active{color:#e6edf3;background:#1c2333}
|
||||
|
||||
/* Worker in insight — clean, scannable */
|
||||
.iworker{display:flex;align-items:center;gap:12px;padding:10px;background:#0d1117;border-radius:8px;margin-bottom:6px}
|
||||
.iworker .av{width:38px;height:38px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;color:#f0f6fc;flex-shrink:0}
|
||||
.iworker .info{flex:1}
|
||||
.iworker .nm{font-weight:600;color:#f0f6fc;font-size:14px}
|
||||
.iworker .detail{color:#8b949e;font-size:12px}
|
||||
.iworker .why{color:#58a6ff;font-size:11px;margin-top:2px;font-style:italic}
|
||||
/* Layout */
|
||||
.content{max-width:940px;margin:0 auto;padding:24px 20px 40px}
|
||||
.section{margin-bottom:32px}
|
||||
.section-header{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}
|
||||
.section-title{font-size:11px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.2px}
|
||||
.section-meta{font-size:10px;color:#3d444d}
|
||||
|
||||
/* Cards */
|
||||
.card{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:20px;margin-bottom:12px}
|
||||
.card.accent-red{border-left:3px solid #da3633}
|
||||
.card.accent-green{border-left:3px solid #2ea043}
|
||||
.card.accent-amber{border-left:3px solid #bf8700}
|
||||
.card.accent-blue{border-left:3px solid #388bfd}
|
||||
.card .card-label{font-size:9px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.4px;margin-bottom:6px}
|
||||
.card .card-title{font-size:17px;font-weight:600;color:#e6edf3;margin-bottom:3px;letter-spacing:-0.3px}
|
||||
.card .card-sub{font-size:12px;color:#545d68;margin-bottom:14px;line-height:1.5}
|
||||
|
||||
/* Keep old class names working */
|
||||
.insight{background:#0d1117;border:1px solid #171d27;border-radius:10px;padding:20px;margin-bottom:12px}
|
||||
.insight .label{font-size:9px;font-weight:600;color:#545d68;text-transform:uppercase;letter-spacing:1.4px;margin-bottom:6px}
|
||||
.insight .headline{font-size:17px;font-weight:600;color:#e6edf3;margin-bottom:3px;letter-spacing:-0.3px}
|
||||
.insight .sub{font-size:12px;color:#545d68;margin-bottom:14px}
|
||||
.insight.urgent{border-left:3px solid #da3633}
|
||||
.insight.opportunity{border-left:3px solid #2ea043}
|
||||
.insight.warning{border-left:3px solid #bf8700}
|
||||
.insight.info{border-left:3px solid #388bfd}
|
||||
|
||||
/* Workers */
|
||||
.iworker{display:flex;align-items:center;gap:12px;padding:10px 12px;background:#161b22;border-radius:8px;margin-bottom:4px;transition:background 0.15s}
|
||||
.iworker:hover{background:#1c2333}
|
||||
.iworker .av{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px;color:#e6edf3;flex-shrink:0}
|
||||
.iworker .info{flex:1;min-width:0}
|
||||
.iworker .nm{font-weight:600;color:#e6edf3;font-size:13px}
|
||||
.iworker .detail{color:#545d68;font-size:11px}
|
||||
.iworker .why{color:#388bfd;font-size:11px;margin-top:1px}
|
||||
.iworker .acts{display:flex;gap:4px}
|
||||
.ibtn{padding:6px 14px;border-radius:6px;font-size:11px;cursor:pointer;border:none;font-weight:600}
|
||||
.ibtn.call{background:#1f3d68;color:#58a6ff}
|
||||
.ibtn.sms{background:#0d261a;color:#3fb950}
|
||||
.ibtn{padding:5px 12px;border-radius:6px;font-size:10px;cursor:pointer;border:none;font-weight:600;transition:opacity 0.15s}
|
||||
.ibtn:hover{opacity:0.8}
|
||||
.ibtn.call{background:#1a2e4a;color:#58a6ff}
|
||||
.ibtn.sms{background:#122b1e;color:#3fb950}
|
||||
|
||||
/* Stats strip */
|
||||
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:20px}
|
||||
.stat{background:#161b22;border:1px solid #21262d;border-radius:10px;padding:16px;text-align:center}
|
||||
.stat .n{font-size:28px;font-weight:800;color:#f0f6fc}.stat .l{font-size:10px;color:#8b949e;text-transform:uppercase;margin-top:2px}
|
||||
/* Stats */
|
||||
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:24px}
|
||||
.stat{background:#0d1117;border:1px solid #171d27;border-radius:8px;padding:16px 12px;text-align:center}
|
||||
.stat .n{font-size:26px;font-weight:700;color:#e6edf3;letter-spacing:-1px}
|
||||
.stat .l{font-size:9px;color:#545d68;text-transform:uppercase;letter-spacing:0.8px;margin-top:4px}
|
||||
|
||||
/* Search */
|
||||
.sa{margin-top:20px;background:#161b22;border:1px solid #21262d;border-radius:10px;overflow:hidden}
|
||||
.sa summary{cursor:pointer;color:#8b949e;font-size:13px;list-style:none;padding:14px 16px}
|
||||
.sa{background:#0d1117;border:1px solid #171d27;border-radius:10px;overflow:hidden}
|
||||
.sa summary{cursor:pointer;color:#545d68;font-size:12px;list-style:none;padding:14px 20px;transition:color 0.15s}
|
||||
.sa summary:hover{color:#b0b8c4}
|
||||
.sa summary::-webkit-details-marker{display:none}
|
||||
.sa .inner{padding:0 16px 16px}
|
||||
.sa input[type=text]{width:100%;padding:12px;background:#0b0f19;border:1px solid #21262d;border-radius:8px;color:#f0f6fc;font-size:14px;outline:none;margin-bottom:8px}
|
||||
.sa input:focus{border-color:#58a6ff}
|
||||
.sa .inner{padding:0 20px 20px}
|
||||
.sa input[type=text]{width:100%;padding:12px 16px;background:#161b22;border:1px solid #21262d;border-radius:8px;color:#e6edf3;font-size:13px;outline:none;margin-bottom:8px;transition:border 0.15s}
|
||||
.sa input:focus{border-color:#388bfd}
|
||||
.srow{display:flex;gap:8px;margin-bottom:10px}
|
||||
.sa select{flex:1;padding:8px;background:#0b0f19;border:1px solid #21262d;border-radius:6px;color:#c9d1d9;font-size:12px}
|
||||
.sbtn{width:100%;padding:10px;background:#7c3aed;border:none;border-radius:8px;color:#fff;font-size:13px;font-weight:600;cursor:pointer}
|
||||
.sbtn:hover{background:#6d28d9}
|
||||
#sresults{margin-top:12px}
|
||||
.ft{text-align:center;padding:16px;color:#484f58;font-size:11px;margin-top:20px}.ft a{color:#58a6ff;text-decoration:none}
|
||||
.ld{color:#484f58;text-align:center;padding:20px}
|
||||
@media(max-width:768px){.stats{grid-template-columns:repeat(2,1fr)}.iworker{flex-direction:column;text-align:center}.iworker .acts{justify-content:center}}
|
||||
.sa select{flex:1;padding:8px 12px;background:#161b22;border:1px solid #21262d;border-radius:6px;color:#b0b8c4;font-size:12px}
|
||||
.sbtn{width:100%;padding:10px;background:#1f6feb;border:none;border-radius:8px;color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:background 0.15s}
|
||||
.sbtn:hover{background:#388bfd}
|
||||
#sresults{margin-top:14px}
|
||||
|
||||
/* Footer */
|
||||
.ft{text-align:center;padding:24px;color:#3d444d;font-size:11px;border-top:1px solid #171d27;margin-top:32px}
|
||||
.ft a{color:#545d68;text-decoration:none;transition:color 0.15s}
|
||||
.ft a:hover{color:#e6edf3}
|
||||
|
||||
.ld{color:#3d444d;text-align:center;padding:40px;font-size:13px}
|
||||
|
||||
/* Responsive */
|
||||
@media(max-width:768px){
|
||||
.stats{grid-template-columns:repeat(2,1fr)}
|
||||
.iworker{flex-direction:column;text-align:center}
|
||||
.iworker .acts{justify-content:center}
|
||||
.bar{padding:0 16px;height:48px}
|
||||
.bar nav{display:none}
|
||||
.content{padding:16px 12px 32px}
|
||||
}
|
||||
@media(max-width:480px){
|
||||
.stats{grid-template-columns:1fr 1fr}
|
||||
.stat .n{font-size:22px}
|
||||
}
|
||||
</style></head><body>
|
||||
<div class="bar"><h1>Staffing Co-Pilot</h1><div class="rt" id="status">Loading your day...</div></div>
|
||||
<div class="bar">
|
||||
<h1>Staffing Co-Pilot</h1>
|
||||
<nav>
|
||||
<a href="." class="active">Dashboard</a>
|
||||
<a href="console">Intelligence Console</a>
|
||||
<a href="proof">Architecture</a>
|
||||
</nav>
|
||||
<div class="rt" id="status">Loading...</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div id="main"><div class="ld">Analyzing your contracts and workers...</div></div>
|
||||
|
||||
<div id="market"></div>
|
||||
<div id="learning"></div>
|
||||
<div id="main"><div class="ld">Analyzing contracts and workers...</div></div>
|
||||
|
||||
<details class="sa"><summary>Search workers...</summary><div class="inner">
|
||||
<input type="text" id="sq" placeholder="Describe who you need — the AI understands plain English" onkeydown="if(event.key==='Enter')doSearch()">
|
||||
<div class="srow"><select id="sst"><option value="">Any State</option></select>
|
||||
<select id="srl"><option value="">Any Role</option></select></div>
|
||||
<button class="sbtn" onclick="doSearch()">Find Workers</button><div id="sresults"></div></div></details>
|
||||
<div class="ft"><a href="console">Intelligence Console</a> · <a href="proof">How this works</a></div>
|
||||
<div class="section" id="market-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">Market Intelligence</span>
|
||||
<span class="section-meta">Public permit data · Updated live</span>
|
||||
</div>
|
||||
<div id="market"></div>
|
||||
</div>
|
||||
|
||||
<div class="section" id="learning-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">System Activity</span>
|
||||
<span class="section-meta">Learning from every interaction</span>
|
||||
</div>
|
||||
<div id="learning"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">Worker Search</span>
|
||||
<span class="section-meta">Natural language · 500K profiles</span>
|
||||
</div>
|
||||
<details class="sa" open><summary>Search all workers</summary><div class="inner">
|
||||
<input type="text" id="sq" placeholder="Try: reliable forklift operator available in Nashville" onkeydown="if(event.key==='Enter')doSearch()">
|
||||
<div class="srow"><select id="sst"><option value="">Any State</option></select>
|
||||
<select id="srl"><option value="">Any Role</option></select></div>
|
||||
<button class="sbtn" onclick="doSearch()">Find Workers</button><div id="sresults"></div></div></details>
|
||||
</div>
|
||||
|
||||
<div class="ft">Staffing Co-Pilot · Hybrid SQL + Vector Search · 500K embedded profiles · <a href="console">Console</a> · <a href="proof">Architecture</a></div>
|
||||
</div>
|
||||
<script>
|
||||
var P=location.pathname.indexOf('/lakehouse')>=0?'/lakehouse':'';
|
||||
@ -171,52 +245,31 @@ function renderMain(today,sum,roles,topWorkers,coverage,needRoles,needStates){
|
||||
|
||||
if(urgent.length){
|
||||
var ins=makeInsight('urgent','Urgent Pipeline',
|
||||
urgent.length+' emergency contract'+(urgent.length>1?'s':'') +' — the system found workers, here\'s your action plan',
|
||||
null);
|
||||
// Pipeline steps explanation
|
||||
var steps=document.createElement('div');
|
||||
steps.style.cssText='display:flex;gap:4px;margin-bottom:16px;flex-wrap:wrap';
|
||||
var stepData=[
|
||||
['1','Review','Check the pre-matched workers below','#f85149'],
|
||||
['2','Call first choice','Highest-rated worker gets the first call','#d29922'],
|
||||
['3','Confirm or replace','If they can\'t make it, the backup is ready','#58a6ff'],
|
||||
['4','Send details','Client address, start time, dress code','#3fb950']
|
||||
];
|
||||
stepData.forEach(function(s){
|
||||
var sd=document.createElement('div');
|
||||
sd.style.cssText='flex:1;min-width:120px;background:#0d1117;border-radius:8px;padding:10px;border-top:2px solid '+s[3];
|
||||
var num=document.createElement('div');num.style.cssText='font-size:18px;font-weight:800;color:'+s[3];num.textContent='Step '+s[0];
|
||||
var title=document.createElement('div');title.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin-top:2px';title.textContent=s[1];
|
||||
var desc=document.createElement('div');desc.style.cssText='font-size:10px;color:#8b949e;margin-top:2px';desc.textContent=s[2];
|
||||
sd.appendChild(num);sd.appendChild(title);sd.appendChild(desc);steps.appendChild(sd);
|
||||
});
|
||||
ins.appendChild(steps);
|
||||
|
||||
urgent.forEach(function(c){
|
||||
addContractInsight(ins,c,true);
|
||||
});
|
||||
urgent.length+' emergency contract'+(urgent.length>1?'s':'')+ ' — workers pre-matched, ready for your call',null);
|
||||
urgent.forEach(function(c){addContractInsight(ins,c,true)});
|
||||
el.appendChild(ins);
|
||||
}
|
||||
|
||||
// Non-urgent that need work
|
||||
// Non-urgent that need work — collapsed by default
|
||||
if(needsWork.length){
|
||||
var ins1b=makeInsight('warning','In Progress',
|
||||
needsWork.length+' contract'+(needsWork.length>1?'s':'')+' still filling — workers matched, awaiting confirmation',
|
||||
'These are standard priority. Workers are ranked by fit — start from the top.');
|
||||
needsWork.forEach(function(c){
|
||||
addContractInsight(ins1b,c,false);
|
||||
});
|
||||
el.appendChild(ins1b);
|
||||
needsWork.length+' contract'+(needsWork.length>1?'s':'')+' still filling — workers matched, awaiting confirmation',null);
|
||||
var det1=document.createElement('details');
|
||||
var sum1=document.createElement('summary');sum1.style.cssText='cursor:pointer;font-size:11px;color:#545d68;padding:4px 0;list-style:none';
|
||||
sum1.textContent='Show '+needsWork.length+' contracts';det1.appendChild(sum1);
|
||||
needsWork.forEach(function(c){addContractInsight(det1,c,false)});
|
||||
ins1b.appendChild(det1);el.appendChild(ins1b);
|
||||
}
|
||||
|
||||
// Filled — collapsed by default
|
||||
if(filled.length){
|
||||
var ins2=makeInsight('opportunity','Ready to Go',
|
||||
filled.length+' contract'+(filled.length>1?'s':'')+' fully staffed — review and send shift details',
|
||||
'All positions matched. The workers listed below are the system\'s best picks based on role, location, reliability, and certifications. Tap Call or SMS to confirm.');
|
||||
filled.forEach(function(c){
|
||||
addContractInsight(ins2,c,false);
|
||||
});
|
||||
el.appendChild(ins2);
|
||||
filled.length+' contract'+(filled.length>1?'s':'')+' fully staffed — review and send shift details',null);
|
||||
var det2=document.createElement('details');
|
||||
var sum2=document.createElement('summary');sum2.style.cssText='cursor:pointer;font-size:11px;color:#545d68;padding:4px 0;list-style:none';
|
||||
sum2.textContent='Show '+filled.length+' contracts';det2.appendChild(sum2);
|
||||
filled.forEach(function(c){addContractInsight(det2,c,false)});
|
||||
ins2.appendChild(det2);el.appendChild(ins2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +286,7 @@ function renderMain(today,sum,roles,topWorkers,coverage,needRoles,needStates){
|
||||
}
|
||||
var ins3=makeInsight('info',headline,sub,
|
||||
'Filtered to roles and states with open positions today. Reliability 85%+.');
|
||||
topWorkers.rows.forEach(function(w,i){
|
||||
topWorkers.rows.slice(0,5).forEach(function(w,i){
|
||||
// Show which contract gap this worker could fill
|
||||
var gapNote='';
|
||||
if(needRoles&&needRoles[w.role]){gapNote='→ Could fill '+needRoles[w.role]+' open '+w.role+' spot'+(needRoles[w.role]>1?'s':'')}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user