fix(brand/ux): real brand C on header, yellow read-tick, sign-in spinner, notif DP
- #5: use the ACTUAL brand C (extracted transparent white C + gold dot from the master app-icon) on the blue headers instead of a hand-drawn mark; login card keeps the app icon. - #3: read-receipt double tick on my own (blue) bubble is now brand yellow (was blue-on-blue, invisible). - #2: Sign-in button shows a spinner + 'Signing in…' on submit. - #1: web notification uses the sender/group DP URL directly as the icon (drawing an external DP to canvas tainted it → silently fell back to initials). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -76,7 +76,7 @@
|
||||
<script>if(new URLSearchParams(location.search).get('embed')==='1')document.documentElement.classList.add('embed');</script>
|
||||
<a href="/home" id="homeLink"><span data-ic="arrowLeft" data-sz="16"></span> Home</a>
|
||||
<div class="topbar" id="topbar">
|
||||
<div class="brandrow"><img src="/mark-light.svg" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span>Connect</span></div></div>
|
||||
<div class="brandrow"><img src="/mark-light.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span>Connect</span></div></div>
|
||||
<div class="agentchip" id="agentChip"></div>
|
||||
</div>
|
||||
<div class="topbar2" id="bar"><span id="barStatus"></span><button id="endBtn">End session</button></div>
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="brandrow"><img src="/mark-light.svg" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span class="y">Connect</span> <span class="tag">· Dashboard</span></div></div>
|
||||
<div class="brandrow"><img src="/mark-light.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span class="y">Connect</span> <span class="tag">· Dashboard</span></div></div>
|
||||
<div class="row" id="hdrRight"></div>
|
||||
</header>
|
||||
<main id="app"></main>
|
||||
|
||||
+20
-16
@@ -301,8 +301,9 @@
|
||||
.sys-msg{align-self:center;font-size:.76rem;color:var(--muted);background:rgba(0,0,0,.04);padding:.25rem .7rem;border-radius:99px;margin:.2rem 0;max-width:90%;text-align:center;}
|
||||
.bubble .t{display:flex;align-items:center;justify-content:flex-end;gap:.25rem;font-size:.64rem;opacity:.65;margin-top:.15rem;}
|
||||
.bubble .rcpt{display:inline-flex;}
|
||||
.bubble.mine .rcpt{opacity:.8;}
|
||||
.bubble.mine .rcpt.seen{color:#8fd3ff;opacity:1;}
|
||||
.bubble.mine .rcpt{opacity:.85;}
|
||||
/* Read receipt on my own (blue) bubble: brand yellow so the double tick actually stands out. */
|
||||
.bubble.mine .rcpt.seen{color:var(--brand);opacity:1;}
|
||||
.att-img{cursor:zoom-in;}
|
||||
.fmt-bar{display:flex;align-items:center;gap:.05rem;padding:.3rem .4rem .1rem;flex-wrap:wrap;border-bottom:1px dashed var(--line);}
|
||||
.fmt-bar button{border:none;background:transparent;color:var(--muted);cursor:pointer;width:30px;height:30px;border-radius:7px;display:grid;place-items:center;}
|
||||
@@ -662,6 +663,9 @@
|
||||
.authcard .sub{color:var(--muted);font-size:.9rem;text-align:center;margin-bottom:1.2rem;}
|
||||
/* Blue card + gold CTA so the sign-in screen carries BOTH brand colours (never mono-blue). */
|
||||
.authcard .gobtn{background:var(--brand);color:var(--blue-d);}
|
||||
.gobtn:disabled{opacity:.9;cursor:default;}
|
||||
.btn-spin{display:inline-block;width:15px;height:15px;border:2px solid rgba(22,41,79,.3);border-top-color:var(--blue-d);border-radius:50%;animation:btnspin .6s linear infinite;vertical-align:-3px;margin-right:7px;}
|
||||
@keyframes btnspin{to{transform:rotate(360deg);}}
|
||||
.authcard .gobtn:hover{filter:brightness(.95);}
|
||||
.authtabs{display:flex;gap:.5rem;margin-bottom:1.1rem;}
|
||||
.authtabs button{flex:1;background:#eef1f6;color:var(--muted);font-weight:600;border:none;border-radius:9px;padding:.5rem;cursor:pointer;font-size:.9rem;}
|
||||
@@ -760,7 +764,7 @@
|
||||
<body>
|
||||
<script src="/icons.js?v=4"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script>
|
||||
<script>window.__BUILD='2026-07-02-batch35';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
<script>window.__BUILD='2026-07-02-batch36';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
|
||||
// Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load
|
||||
// (emojis stay as plain Unicode). (#5)
|
||||
function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script>
|
||||
@@ -769,7 +773,7 @@ function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, {
|
||||
<header>
|
||||
<div class="brandrow">
|
||||
<button class="navtoggle" id="navToggle" title="Toggle menu" aria-label="Toggle menu"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button>
|
||||
<img src="/mark-light.svg" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))">
|
||||
<img src="/mark-light.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))">
|
||||
<div class="brand">Biz <span class="y">Connect</span></div>
|
||||
</div>
|
||||
<div id="hdrRight"></div>
|
||||
@@ -2015,16 +2019,14 @@ function notify(title, body, kind, id){
|
||||
}).catch(()=>{});
|
||||
return;
|
||||
}
|
||||
// Web / PWA: standard Notification. Icon = the sender's/group's DP (falling back to their
|
||||
// initials, then the brand app icon) — never the old wordmark. badge = brand mark.
|
||||
// Web / PWA: standard Notification. Use the sender's/group's DP URL DIRECTLY as the icon —
|
||||
// the browser fetches notification icons cross-origin fine, whereas drawing an external DP to a
|
||||
// canvas taints it and silently fell back to initials (the bug). Brand icon only if no DP.
|
||||
if(!('Notification' in window) || Notification.permission!=='granted') return;
|
||||
notifAvatarDataUrl(kind, id, String(title||'').replace(/^[^\p{L}\p{N}]+/u,'')).then(avatar=>{
|
||||
const n=new Notification(title, { body, icon: avatar || '/icon-192.png', badge:'/icon-192.png' });
|
||||
n.onclick=()=>{ n.close(); openFromNotif(kind, id); };
|
||||
setTimeout(()=>{ try{ n.close(); }catch(_){} }, 8000);
|
||||
}).catch(()=>{
|
||||
try{ const n=new Notification(title, { body, icon:'/icon-192.png' }); n.onclick=()=>{ n.close(); openFromNotif(kind, id); }; }catch(_){}
|
||||
});
|
||||
const _row=rowFor(kind,id)||{};
|
||||
const n=new Notification(title, { body, icon: _row.avatar || '/icon-192.png', badge:'/icon-192.png' });
|
||||
n.onclick=()=>{ n.close(); openFromNotif(kind, id); };
|
||||
setTimeout(()=>{ try{ n.close(); }catch(_){} }, 8000);
|
||||
}catch(_){}
|
||||
}
|
||||
let _audioCtx=null;
|
||||
@@ -2845,7 +2847,7 @@ async function renderLogin(){
|
||||
const aw=document.getElementById('authwrap'); aw.style.display='flex';
|
||||
let regOpen=false; try{ regOpen=(await (await fetch('/api/setup-state')).json()).registrationOpen; }catch(_){}
|
||||
aw.innerHTML=`<div class="authcard">
|
||||
<div class="auth-brand"><img src="/mark-light.svg" alt="Biz Connect"><div class="wm">Biz <b>Connect</b></div></div>
|
||||
<div class="auth-brand"><img src="/icon-192.png" alt="Biz Connect"><div class="wm">Biz <b>Connect</b></div></div>
|
||||
<h1>Welcome back</h1>
|
||||
<div class="sub">Sign in to access chats, screen share and connect.</div>
|
||||
${regOpen?`<div class="authtabs">
|
||||
@@ -2880,10 +2882,12 @@ async function renderLogin(){
|
||||
}
|
||||
async function doLogin(){
|
||||
clearErr('li_err');
|
||||
const btn=document.getElementById('li_btn'); const orig=btn?btn.innerHTML:'';
|
||||
if(btn){ btn.disabled=true; btn.innerHTML='<span class="btn-spin"></span>Signing in…'; } // show progress on Enter/click
|
||||
try{
|
||||
await postJSON('/api/login',{email:document.getElementById('li_email').value,password:document.getElementById('li_pw').value,remember:document.getElementById('li_remember').checked});
|
||||
location.reload();
|
||||
}catch(e){ showErr('li_err', /invalid credentials/i.test(e.message)?'Incorrect email or password. Please try again.':e.message); }
|
||||
location.reload(); // the branded splash takes over from here
|
||||
}catch(e){ if(btn){ btn.disabled=false; btn.innerHTML=orig; } showErr('li_err', /invalid credentials/i.test(e.message)?'Incorrect email or password. Please try again.':e.message); }
|
||||
}
|
||||
async function doRegister(){
|
||||
clearErr('rg_err');
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<body>
|
||||
<header>
|
||||
<div class="brandrow">
|
||||
<img src="/mark-light.svg" alt="" style="height:40px;width:auto;max-width:170px;border-radius:8px;object-fit:contain" onerror="this.style.display='none'">
|
||||
<img src="/mark-light.png" alt="" style="height:40px;width:auto;max-width:170px;border-radius:8px;object-fit:contain" onerror="this.style.display='none'">
|
||||
<div class="brand">Biz <span>Connect</span></div>
|
||||
</div>
|
||||
<div class="hdr-right">
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Biz Connect">
|
||||
<!-- White C + gold dot on a transparent background — for placing directly on the blue header -->
|
||||
<path d="M40 10 A22 22 0 1 0 40 54" fill="none" stroke="#ffffff" stroke-width="9" stroke-linecap="round"/>
|
||||
<circle cx="40" cy="32" r="6.5" fill="#FFC708"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 366 B |
Reference in New Issue
Block a user