Post-PR-#11 polish: demo UI, staffer console, face pool, icons, contractor profile (24 commits) #12
@ -54,8 +54,19 @@ details .body{padding-top:10px;font-size:12px;color:#8b949e}
|
||||
.accent-g{border-left:3px solid #3fb950}
|
||||
.accent-r{border-left:3px solid #f85149}
|
||||
|
||||
.worker{display:flex;align-items:center;gap:10px;padding:8px 10px;background:#161b22;border-radius:6px;margin-bottom:4px;font-size:12px}
|
||||
.worker .av{width:28px;height:28px;border-radius:6px;background:#1a2744;display:flex;align-items:center;justify-content:center;font-weight:600;color:#e6edf3;font-size:10px;flex-shrink:0}
|
||||
.worker{display:flex;align-items:center;gap:10px;padding:8px 10px;background:#161b22;border-radius:6px;margin-bottom:4px;font-size:12px;border-left:3px solid #30363d}
|
||||
.worker .av{width:32px;height:32px;border-radius:50%;background:#0d1117;border:1px solid #21262d;display:flex;align-items:center;justify-content:center;font-weight:600;color:#c9d1d9;font-size:11px;flex-shrink:0;letter-spacing:0.5px}
|
||||
.worker[data-role-band="warehouse"]{border-left-color:#58a6ff}
|
||||
.worker[data-role-band="production"]{border-left-color:#d29922}
|
||||
.worker[data-role-band="trades"]{border-left-color:#bc8cff}
|
||||
.worker[data-role-band="driver"]{border-left-color:#3fb950}
|
||||
.worker[data-role-band="lead"]{border-left-color:#f0883e}
|
||||
.role-pill{display:inline-block;font-size:9px;padding:1px 7px;border-radius:3px;background:#0d1117;color:#8b949e;margin-right:6px;font-weight:600;letter-spacing:0.4px;text-transform:uppercase;border-left:2px solid #30363d;vertical-align:1px}
|
||||
.role-pill[data-rb="warehouse"]{border-left-color:#58a6ff;color:#79c0ff}
|
||||
.role-pill[data-rb="production"]{border-left-color:#d29922;color:#e3b341}
|
||||
.role-pill[data-rb="trades"]{border-left-color:#bc8cff;color:#d2a8ff}
|
||||
.role-pill[data-rb="driver"]{border-left-color:#3fb950;color:#56d364}
|
||||
.role-pill[data-rb="lead"]{border-left-color:#f0883e;color:#ffa657}
|
||||
.worker .info{flex:1;min-width:0}
|
||||
.worker .nm{color:#e6edf3;font-weight:500}
|
||||
.worker .why{color:#545d68;font-size:11px;margin-top:1px}
|
||||
@ -199,6 +210,57 @@ var A=location.origin+P;
|
||||
// DOM helpers — all dynamic content goes through these. No innerHTML
|
||||
// anywhere in the script; every API-derived string passes through
|
||||
// textContent so no injection path regardless of upstream data.
|
||||
// Role classification — mirrors search.html, no emojis. Maps role
|
||||
// strings to a band+label used by the worker-card border + role pill.
|
||||
var ROLE_BANDS = [
|
||||
{ match: /forklift|warehouse|associate|material\s*handler|loader|loading|packag|shipping|logistics|inventory|sanitation|janit/i, band: 'warehouse', label: 'Warehouse' },
|
||||
{ match: /production|assembl/i, band: 'production', label: 'Production' },
|
||||
{ match: /welder|weld|electric|maint(enance)?\s*tech|cnc|machine\s*op|hvac|plumb|carpenter|mason/i, band: 'trades', label: 'Skilled Trade' },
|
||||
{ match: /driver|truck|haul|cdl/i, band: 'driver', label: 'Driver' },
|
||||
{ match: /line\s*lead|supervisor|foreman|coordinator/i, band: 'lead', label: 'Lead' },
|
||||
{ match: /quality/i, band: 'production', label: 'Quality' },
|
||||
];
|
||||
function roleBand(role){
|
||||
if(!role) return { band: 'warehouse', label: '' };
|
||||
for (var i = 0; i < ROLE_BANDS.length; i++) {
|
||||
if (ROLE_BANDS[i].match.test(role)) return ROLE_BANDS[i];
|
||||
}
|
||||
return { band: 'warehouse', label: role.split(' ')[0].toUpperCase().slice(0, 12) };
|
||||
}
|
||||
|
||||
// Build a sober worker card: monogram avatar + colored role band on
|
||||
// the left edge + uppercase role pill in the detail line. Used by
|
||||
// every chapter that renders worker rows. `name` and `role` drive the
|
||||
// classification; `detail` is the full text after the pill.
|
||||
function workerRow(name, role, detail, opts){
|
||||
opts = opts || {};
|
||||
var band = roleBand(role||'');
|
||||
var w = el('div','worker');
|
||||
if(band.band) w.dataset.roleBand = band.band;
|
||||
var initials = (name||'?').split(' ').map(function(s){return (s[0]||'').toUpperCase()}).join('').substring(0,2);
|
||||
w.appendChild(el('div','av',initials));
|
||||
var info = el('div','info');
|
||||
var nm = el('div','nm', name||'?');
|
||||
if(opts.endorsed){
|
||||
nm.appendChild(el('span','boost-chip',opts.endorsed));
|
||||
}
|
||||
info.appendChild(nm);
|
||||
var why = el('div','why');
|
||||
if(band.label){
|
||||
var pill = document.createElement('span'); pill.className='role-pill';
|
||||
pill.dataset.rb = band.band;
|
||||
pill.textContent = band.label;
|
||||
why.appendChild(pill);
|
||||
}
|
||||
why.appendChild(document.createTextNode(detail||''));
|
||||
info.appendChild(why);
|
||||
w.appendChild(info);
|
||||
if(opts.score){
|
||||
w.appendChild(el('div','score', opts.score));
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
function el(tag, cls, text){
|
||||
var e=document.createElement(tag);
|
||||
if(cls) e.className=cls;
|
||||
@ -380,21 +442,13 @@ function loadChapter4(){
|
||||
|
||||
var list=document.createElement('div');list.style.marginTop='6px';
|
||||
(prop.candidates||[]).slice(0,5).forEach(function(cand,i){
|
||||
var w=el('div','worker');
|
||||
var initials=(cand.name||'?').split(' ').map(function(s){return (s[0]||'').toUpperCase()}).join('').substring(0,2);
|
||||
w.appendChild(el('div','av',initials));
|
||||
var info=el('div','info');
|
||||
var nm=el('div','nm',cand.name||cand.doc_id||'?');
|
||||
if((cand.playbook_boost||0)>0){
|
||||
var ncit=(cand.playbook_citations||[]).length;
|
||||
nm.appendChild(el('span','boost-chip','Endorsed · '+ncit+' past fill'+(ncit!==1?'s':'')));
|
||||
}
|
||||
info.appendChild(nm);
|
||||
var why=cand.doc_id+' · '+(cand.playbook_boost>0?'boosted +'+cand.playbook_boost.toFixed(3)+' by memory · ':'')+'semantic score '+(cand.score||0).toFixed(3);
|
||||
info.appendChild(el('div','why',why));
|
||||
w.appendChild(info);
|
||||
w.appendChild(el('div','score','#'+(i+1)));
|
||||
list.appendChild(w);
|
||||
var detail = cand.doc_id+' · '+(cand.playbook_boost>0?'boosted +'+cand.playbook_boost.toFixed(3)+' by memory · ':'')+'semantic score '+(cand.score||0).toFixed(3);
|
||||
var endorsed = (cand.playbook_boost||0) > 0
|
||||
? 'Endorsed · '+((cand.playbook_citations||[]).length)+' past fill'+((cand.playbook_citations||[]).length!==1?'s':'')
|
||||
: null;
|
||||
list.appendChild(workerRow(cand.name||cand.doc_id||'?', prop.role||'', detail, {
|
||||
endorsed: endorsed, score: '#'+(i+1)
|
||||
}));
|
||||
});
|
||||
card.appendChild(list);
|
||||
|
||||
@ -628,12 +682,8 @@ function loadChapter8(){
|
||||
bfHdr.textContent='✓ '+d.backfills.length+' local '+(d.worker.role||'workers')+' available — sorted by responsiveness';
|
||||
host.appendChild(bfHdr);
|
||||
d.backfills.slice(0,5).forEach(function(c){
|
||||
var row=el('div','row');
|
||||
var left=document.createElement('div');left.style.flex='1';left.style.minWidth='0';
|
||||
left.appendChild(el('div','title',c.name));
|
||||
left.appendChild(el('div','meta',(c.role||'?')+' · '+(c.city||'')+', '+(c.state||'')+' · rel '+Math.round((c.rel||0)*100)+'% · resp '+Math.round((c.resp||0)*100)+'%'));
|
||||
row.appendChild(left);
|
||||
host.appendChild(row);
|
||||
var detail=(c.role||'?')+' · '+(c.city||'')+', '+(c.state||'')+' · rel '+Math.round((c.rel||0)*100)+'% · resp '+Math.round((c.resp||0)*100)+'%';
|
||||
host.appendChild(workerRow(c.name||'?', c.role||'', detail));
|
||||
});
|
||||
}
|
||||
var narr=el('div','narr');
|
||||
@ -675,23 +725,16 @@ function runTry(){
|
||||
|
||||
var workers=d.sql_results||d.vector_results||d.results||[];
|
||||
workers.slice(0,5).forEach(function(w,i){
|
||||
var row=el('div','worker');
|
||||
var nm=w.name||(w.text||'').split('—')[0].trim()||w.doc_id||'?';
|
||||
var initials=nm.split(' ').map(function(s){return (s[0]||'').toUpperCase()}).join('').substring(0,2);
|
||||
row.appendChild(el('div','av',initials));
|
||||
var info=el('div','info');
|
||||
var n=el('div','nm',nm);
|
||||
if((w.playbook_boost||0)>0){
|
||||
n.appendChild(el('span','boost-chip','Endorsed · '+((w.playbook_citations||[]).length||'?')+' past fill(s)'));
|
||||
}
|
||||
info.appendChild(n);
|
||||
var bits=[];
|
||||
if(w.role) bits.push(w.role);
|
||||
if(w.city&&w.state) bits.push(w.city+', '+w.state);
|
||||
if(w.rel!==undefined) bits.push('reliability '+Math.round(w.rel*100)+'%');
|
||||
if(w.avail!==undefined) bits.push('availability '+Math.round(w.avail*100)+'%');
|
||||
info.appendChild(el('div','why',bits.join(' · ')||'AI semantic match'));
|
||||
row.appendChild(info);
|
||||
var endorsed = (w.playbook_boost||0) > 0
|
||||
? 'Endorsed · '+((w.playbook_citations||[]).length||'?')+' past fill(s)'
|
||||
: null;
|
||||
var row = workerRow(nm, w.role||'', bits.join(' · ')||'AI semantic match', { endorsed: endorsed });
|
||||
row.appendChild(el('div','score','#'+(i+1)));
|
||||
card.appendChild(row);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user