demo: search.html UX polish — skeleton loader, card-in stagger, hero takeover, B&W faces
Search results no longer pop in as a single block. New behavior:
- Skeleton list pre-claims the vertical space results will occupy
with shimmering placeholder cards, so arriving results fade in
over the skeleton instead of pushing layout. Sweep is staggered
per row for a "rolling wave" not "everything blinking together".
- Domain-language stage caption ("matching against permits",
"ranking by reliability") rotates on a fixed schedule so users
read progress, not a stuck spinner.
- @keyframes card-in: real worker cards rise 4px and fade in over
350ms with nth-child stagger across the first ~12 rows. Honors
prefers-reduced-motion.
- Avatar imgs filter through grayscale + slight contrast/blur to
pull the SDXL Turbo color cast (which screams "AI generated" at
small sizes). Cert icons get the same treatment.
- Once-per-session hero takeover compresses the Section ⓪ strip
("Not a CRM — an index that learns from you") into a centered
hero on first paint, dismissed by clicking anywhere. Stats
hydrate from live endpoints.
console.html: mirrors the avatar B&W filter for visual consistency,
and removes the headshot insertion entirely — back to monogram
initials. The console (internal staffer view) doesn't need synthetic
faces; the public demo at /lakehouse/ does.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4b92d1da91
commit
f892230699
@ -56,7 +56,12 @@ details .body{padding-top:10px;font-size:12px;color:#8b949e}
|
||||
|
||||
.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;overflow:hidden;position:relative}
|
||||
.worker .av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
|
||||
.worker .av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
|
||||
/* Softening — mirror of search.html. Pulls saturation + contrast off
|
||||
the SDXL Turbo over-render so faces feel less "AI-generated".
|
||||
If you tweak one, tweak the other. */
|
||||
filter: saturate(0.86) contrast(0.93) brightness(1.02) blur(0.3px);
|
||||
}
|
||||
.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}
|
||||
@ -312,26 +317,8 @@ function workerRow(name, role, detail, opts){
|
||||
if(band.band) w.dataset.roleBand = band.band;
|
||||
var initials = (name||'?').split(' ').map(function(s){return (s[0]||'').toUpperCase()}).join('').substring(0,2);
|
||||
var av = el('div','av',initials);
|
||||
// Real synthetic headshot via /headshots/<key>; deterministic so
|
||||
// same worker always gets the same face. Falls back to monogram if
|
||||
// pool isn't fetched yet.
|
||||
var faceKey = (opts.face_key) || name || '';
|
||||
var nameParts = (name||'').trim().split(/\s+/);
|
||||
var firstName = nameParts[0]||'';
|
||||
var lastName = nameParts.length > 1 ? nameParts[nameParts.length-1] : '';
|
||||
var gHint = genderFor(firstName);
|
||||
var eHint = (typeof guessEthnicityFromName === 'function')
|
||||
? guessEthnicityFromName(firstName, lastName)
|
||||
: guessEthnicityFromFirstName(firstName);
|
||||
if(faceKey){
|
||||
var img=document.createElement('img');
|
||||
img.alt='';
|
||||
// Eager + cache-buster v=2: 11KB thumbs are cheap to load fresh
|
||||
// and the v= param invalidates browsers holding old photos.
|
||||
img.src = P + '/headshots/' + encodeURIComponent(faceKey) + '?g='+gHint+'&e='+eHint+'&v=2';
|
||||
img.onerror=function(){ this.remove(); };
|
||||
av.appendChild(img);
|
||||
}
|
||||
// Headshot insertion removed 2026-04-28. The .av element stays as
|
||||
// a monogram-initials avatar.
|
||||
w.appendChild(av);
|
||||
var info = el('div','info');
|
||||
var nm = el('div','nm', name||'?');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user