[object Object]

← back to Rentv Sheet Enrich

Live console: real SVG phone/website/LinkedIn icons + value-as-plaintext links; persist density; harden phone-vs-domain detection

15117d10cae50e75721f65e42b25a213edabcfac · 2026-08-13 15:19:54 -0700 · Steve Abrams

Files touched

Diff

commit 15117d10cae50e75721f65e42b25a213edabcfac
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 13 15:19:54 2026 -0700

    Live console: real SVG phone/website/LinkedIn icons + value-as-plaintext links; persist density; harden phone-vs-domain detection
---
 public_live/index.html | 42 ++++++++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/public_live/index.html b/public_live/index.html
index 91a27d5..7d2796a 100644
--- a/public_live/index.html
+++ b/public_live/index.html
@@ -75,7 +75,11 @@
   td.saved{background:var(--green);color:var(--greenink)}
   td.enriched{box-shadow:inset 3px 0 0 #7bc043;background:rgba(123,192,67,.09)}
   td a{color:var(--accent);text-decoration:none} .namecell{font-weight:600}
-  a.callbtn{margin-left:5px;text-decoration:none;cursor:pointer;font-size:.95em;opacity:.75} a.callbtn:hover{opacity:1}
+  a.iconbtn,a.callbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:5px;text-decoration:none;cursor:pointer;opacity:.72;vertical-align:middle}
+  a.iconbtn:hover,a.callbtn:hover{opacity:1}
+  a.iconbtn svg,a.callbtn svg{width:1.05em;height:1.05em;display:block}
+  a.callbtn{color:#16a34a} a.iconbtn.web{color:var(--accent)} a.iconbtn.li{color:#0a66c2}
+  .linkval{color:inherit}
   .rowbtn{background:var(--accent);color:#04121f;border:0;border-radius:6px;padding:3px 8px;font-size:11px;font-weight:700;cursor:pointer;white-space:nowrap}
   .grouphdr td{background:#12161c;color:var(--accent);font-weight:700;font-size:12px;padding:6px 9px;position:sticky;top:26px}
   /* cards */
@@ -163,7 +167,7 @@ const g=(r,i)=> (i>=0&&i<r.length)?String(r[i]||'').trim():'';
 function hrefOf(v){ v=String(v||'').trim();
   const m=v.match(/https?:\/\/[^\s"')]+/i); if(m) return m[0].replace(/[),.]+$/,'');
   // bare domain or linkedin/site path (no spaces) -> add https:// so it's clickable
-  if(/^(www\.)?[a-z0-9-]+(\.[a-z0-9-]+)+(\/\S*)?$/i.test(v)) return 'https://'+v;
+  if(/^(www\.)?([a-z0-9-]+\.)+[a-z]{2,}(\/\S*)?$/i.test(v)) return 'https://'+v;  // TLD must be alphabetic — a dotted phone (310.555.9876) is NOT a domain
   return '';
 }
 
@@ -203,9 +207,12 @@ async function loadData(){
       o.splice(o.indexOf(nc)+1,0,fn,ln); ORDER=o;
     }
   }
-  // default sort = Last Name ascending on load (if the tab has one)
-  const lnIdx=DATA.headers.findIndex(h=>/^last name$/i.test(String(h).trim()));
-  SORT = lnIdx>=0 ? {col:lnIdx, dir:1} : null;
+  // restore saved sort for THIS view; else default to Last Name ascending
+  const savedSort=LS.get('sort.'+K, undefined);
+  if(savedSort!==undefined){ SORT=savedSort; }
+  else { const lnIdx=DATA.headers.findIndex(h=>/^last name$/i.test(String(h).trim())); SORT = lnIdx>=0 ? {col:lnIdx, dir:1} : null; }
+  // restore saved density
+  const dens=LS.get('dens',null); if(dens) document.documentElement.style.setProperty('--fs',dens+'px');
   buildRail(); render(); setSync('ok');
 }
 function setSync(state){
@@ -278,10 +285,10 @@ function renderChips(){ const c=$('#chips'); let h='';
 }
 function wireRail(){
   $('#search').oninput=e=>{SEARCH=e.target.value;clearTimeout(window._st);window._st=setTimeout(()=>{buildFacets();render()},180)};
-  $('#sortsel').onchange=e=>{SORT=e.target.value===''?null:{col:+e.target.value,dir:SORT?SORT.dir:1};LS.set('sort',SORT);render()};
-  $('#sortdir').onclick=()=>{if(SORT){SORT.dir*=-1;LS.set('sort',SORT);$('#sortdir').textContent=SORT.dir<0?'▼':'▲';render()}};
+  $('#sortsel').onchange=e=>{SORT=e.target.value===''?null:{col:+e.target.value,dir:SORT?SORT.dir:1};LS.set('sort.'+curKey(),SORT);render()};
+  $('#sortdir').onclick=()=>{if(SORT){SORT.dir*=-1;LS.set('sort.'+curKey(),SORT);$('#sortdir').textContent=SORT.dir<0?'▼':'▲';render()}};
   $('#groupsel').onchange=e=>{GROUP=e.target.value;LS.set('group',GROUP);render()};
-  $('#dens').oninput=e=>{document.documentElement.style.setProperty('--fs',e.target.value+'px')};
+  $('#dens').oninput=e=>{document.documentElement.style.setProperty('--fs',e.target.value+'px');LS.set('dens',e.target.value)};
   $('#fitcols').onclick=fitAllCols; $('#resetcols').onclick=resetLayout;
   $('#alls').onclick=()=>{SELECTED=new Set(META.tabs.map(t=>t.gid));loadData()};
   $('#nones').onclick=()=>{SELECTED=new Set([GID]);loadData()};
@@ -377,15 +384,26 @@ function cardsHTML(rows,mode){
   return h+'</div>';
 }
 function badge(ic,v){return `<span class="badge${v?' ok':''}">${ic}${v?' ✓':''}</span>`}
+// real inline-SVG icons (inherit currentColor, scale to text) — not emoji glyphs
+const ICON={
+  phone:'<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M6.6 10.8c1.4 2.8 3.8 5.2 6.6 6.6l2.2-2.2c.28-.28.68-.36 1.02-.24 1.12.4 2.33.62 3.58.62.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.4 21 3 13.6 3 4.4c0-.55.45-1 1-1h3.4c.55 0 1 .45 1 1 0 1.25.22 2.46.62 3.58.12.34.04.74-.24 1.02l-2.18 2.18z"/></svg>',
+  web:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.6 2.8 2.6 15.2 0 18M12 3c-2.6 2.8-2.6 15.2 0 18"/></svg>',
+  li:'<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M4.98 3.5A2.5 2.5 0 1 0 5 8.5 2.5 2.5 0 0 0 4.98 3.5zM3 9h4v12H3zM9 9h3.8v1.64h.05c.53-1 1.83-2.06 3.77-2.06 4.03 0 4.78 2.65 4.78 6.1V21h-4v-5.4c0-1.29-.02-2.95-1.8-2.95-1.8 0-2.07 1.4-2.07 2.85V21H9z"/></svg>'};
+function iconLink(url,kind){
+  const svg=kind==='li'?ICON.li:ICON.web, label=kind==='li'?'Open LinkedIn profile':'Open website';
+  return `<a class="iconbtn ${kind}" href="${esc(url)}" target="_blank" rel="noopener" title="${label}">${svg}</a>`;
+}
 function cellRender(v){v=String(v==null?'':v);const u=hrefOf(v);
-  if(u)return `<a href="${esc(u)}" target="_blank" rel="noopener">${esc(v.length>44?u.replace(/^https?:\/\/(www\.)?/,''):v)}</a>`;
-  if(/\d{3}[-.\s]?\d{3}[-.\s]?\d{4}/.test(v))return phoneLinkify(v);   // phone numbers -> tap-to-call
+  if(u){ const li=/linkedin\.com/i.test(u);                            // value stays plain text; icon opens the link
+    const disp=v.replace(/^https?:\/\/(www\.)?/i,'').replace(/\/+$/,'');
+    return `<span class="linkval">${esc(disp)}</span>${iconLink(u, li?'li':'web')}`; }
+  if(/\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/.test(v))return phoneLinkify(v);   // phone numbers (incl. "(310) 555-1234") -> tap-to-call
   return esc(v)}
 function phoneLinkify(v){
   const re=/(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g; let out='',last=0,m;
   while((m=re.exec(v))){ out+=esc(v.slice(last,m.index));
     let d=m[0].replace(/\D/g,''); if(d.length===10)d='1'+d;
-    out+=esc(m[0])+`<a class="callbtn" href="tel:+${esc(d)}" title="Call ${esc(m[0])}">📞</a>`; last=m.index+m[0].length; }
+    out+=esc(m[0])+`<a class="callbtn" href="tel:+${esc(d)}" title="Call ${esc(m[0])}">${ICON.phone}</a>`; last=m.index+m[0].length; }
   out+=esc(v.slice(last)); return out||esc(v);
 }
 function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[m]))}
@@ -404,7 +422,7 @@ function wireGrid(){
     const up=ev=>{ document.removeEventListener('mousemove',mv);document.removeEventListener('mouseup',up);
       th.classList.remove('dragging');ths.forEach(t=>t.classList.remove('droptarget'));
       if(moved){const tg=at(ev.clientX);if(tg&&+tg.dataset.c!==col)moveCol(col,+tg.dataset.c);}
-      else{SORT=(SORT&&SORT.col===col)?{col,dir:-SORT.dir}:{col,dir:1};LS.set('sort',SORT);render();$('#sortsel')&&($('#sortsel').value=col);} };
+      else{SORT=(SORT&&SORT.col===col)?{col,dir:-SORT.dir}:{col,dir:1};LS.set('sort.'+curKey(),SORT);render();$('#sortsel')&&($('#sortsel').value=col);} };
     document.addEventListener('mousemove',mv);document.addEventListener('mouseup',up);
   }));
   // resizable columns — drag a column's right edge; width persists per tab

← 58c6056 Server: send no-store/no-cache headers so the browser always  ·  back to Rentv Sheet Enrich  ·  Live console: icons open Website/LinkedIn in a popup window 44d2687 →