diff --git a/server/public/home.html b/server/public/home.html index f85572f..6131bbe 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -139,11 +139,13 @@ /* Modern thin scrollbars for every scroll area (chat, modals, lists, …). Without this, Electron on Windows falls back to the classic scrollbar with up/down stepper arrows. */ - ::-webkit-scrollbar{width:6px;height:6px;} + ::-webkit-scrollbar{width:11px;height:11px;} ::-webkit-scrollbar-button,::-webkit-scrollbar-button:start:decrement,::-webkit-scrollbar-button:end:increment,::-webkit-scrollbar-button:vertical:start,::-webkit-scrollbar-button:vertical:end,::-webkit-scrollbar-button:horizontal:start,::-webkit-scrollbar-button:horizontal:end{display:none!important;width:0!important;height:0!important;} ::-webkit-scrollbar-track{background:transparent;} - ::-webkit-scrollbar-thumb{background:#c7d0dd;border-radius:9px;border:1px solid transparent;background-clip:content-box;} - ::-webkit-scrollbar-thumb:hover{background:#aab6c8;} + /* Was 6px with a 1px inset border (~4px grabbable) and no min height → the thumb was tiny and felt + "stuck" when dragged. Wider, solid, with a min length so it's easy to grab and drags smoothly. */ + ::-webkit-scrollbar-thumb{background:#b9c4d4;border-radius:8px;min-height:44px;} + ::-webkit-scrollbar-thumb:hover{background:#9fadc2;} ::-webkit-scrollbar-corner{background:transparent;} *{scrollbar-width:thin;scrollbar-color:#c7d0dd transparent;} @@ -151,7 +153,8 @@ .chatlist:hover{scrollbar-color:#c7d0dd transparent;} .chatlist::-webkit-scrollbar{width:6px;} .chatlist::-webkit-scrollbar-button,.chatlist::-webkit-scrollbar-button:start:decrement,.chatlist::-webkit-scrollbar-button:end:increment{display:none!important;height:0!important;width:0!important;} - .convo-msgs::-webkit-scrollbar{width:6px;} .convo-msgs::-webkit-scrollbar-button{display:none!important;height:0!important;width:0!important;} + .convo-msgs::-webkit-scrollbar{width:10px;} .convo-msgs::-webkit-scrollbar-button{display:none!important;height:0!important;width:0!important;} + .convo-msgs::-webkit-scrollbar-thumb{min-height:44px;} .chatlist::-webkit-scrollbar-thumb{background:transparent;border-radius:8px;} .chatlist:hover::-webkit-scrollbar-thumb{background:#c7d0dd;} /* Pull-to-refresh indicator (mobile) */ @@ -553,10 +556,13 @@ .modal input#grpName:focus,.modal input#giName:focus{outline:none;border-color:var(--brand);} /* Branded confirm dialog (replaces the OS/Electron window.confirm). */ .bz-confirm .bzc-msg{margin:.2rem 0 1.1rem;color:var(--ink);font-size:.92rem;line-height:1.5;} - .seen-modal{max-width:360px;display:flex;flex-direction:column;max-height:80vh;} + /* overflow:hidden on the CARD so it never becomes a 2nd scroll container — .modal defaults to + overflow-y:auto, which nested against .seen-scroll and made the wheel/drag feel "stuck". */ + .seen-modal{max-width:360px;display:flex;flex-direction:column;max-height:80vh;overflow:hidden;} .seen-modal>h3{flex:0 0 auto;} - /* ONE scroll region for the whole list; the two section headers stick to the top as you scroll */ - .seen-modal .seen-scroll{flex:1 1 auto;overflow-y:auto;margin:.2rem -.4rem 0;padding:0 .4rem;min-height:0;} + /* THE single scroll region for the whole list; the two section headers stick as you scroll */ + .seen-modal .seen-scroll{flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain;margin:.2rem -.4rem 0;padding:0 .4rem;min-height:0;} + .seen-modal .seen-div{height:1px;background:var(--line,#e3e8f2);margin:.5rem .2rem;} .seen-modal .seen-row{display:flex;align-items:center;gap:.6rem;padding:.34rem .2rem;} /* dark lettering on the pastel avatar (white was invisible on the light background), unless a real DP covers it */ .seen-modal .seen-row .mini-av{width:34px;height:34px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;color:#334155;font-weight:700;font-size:.76rem;overflow:hidden;position:relative;} @@ -850,7 +856,7 @@
- @@ -941,6 +947,51 @@ function firstName(name){return String(name||'').trim().split(/\s+/)[0]||'there' const AV_COLORS=['#dbeafe','#e0e7ff','#dcfce7','#cffafe','#fae8ff','#fce7f3','#fee2e2','#fef3c7','#ecfccb','#fde4cf']; function avColor(name){let h=0;for(const c of String(name))h=(h*31+c.charCodeAt(0))>>>0;return AV_COLORS[h%AV_COLORS.length];} +// Auto-correct: curated high-confidence common-typo → fix map. Applied as you type (on a word +// boundary), so corrections happen automatically — no right-click menu. Works on web/desktop/mobile. +// Kept conservative (only unambiguous typos) to avoid "fighting" the user. Ctrl+Z reverts a fix. +const AUTOCORRECT={ + teh:'the',hte:'the',thier:'their',recieve:'receive',recieved:'received',beleive:'believe',beleived:'believed', + seperate:'separate',definately:'definitely',occured:'occurred',occuring:'occurring',untill:'until',wich:'which', + becuase:'because',becasue:'because',accross:'across',adress:'address',adressed:'addressed',alot:'a lot', + arguement:'argument',calender:'calendar',cemetary:'cemetery',changable:'changeable',collegue:'colleague', + comming:'coming',commited:'committed',concious:'conscious',definetly:'definitely',dissapoint:'disappoint', + embarass:'embarrass',enviroment:'environment',existance:'existence',familier:'familiar',finaly:'finally', + foriegn:'foreign',fourty:'forty',freind:'friend',gaurd:'guard',goverment:'government',grammer:'grammar', + happend:'happened',harrass:'harass',immediatly:'immediately',independant:'independent',infomation:'information', + knowlege:'knowledge',liason:'liaison',libary:'library',lisence:'license',maintainance:'maintenance', + mispell:'misspell',neccessary:'necessary',necesary:'necessary',noticable:'noticeable',occassion:'occasion', + occurance:'occurrence',ocurrence:'occurrence',paralell:'parallel',parliment:'parliament',particurly:'particularly', + perhasp:'perhaps',persistant:'persistent',posession:'possession',prefered:'preferred',privelege:'privilege', + probaly:'probably',probelm:'problem',proffesional:'professional',promiss:'promise',pronounciation:'pronunciation', + publically:'publicly',realy:'really',reccomend:'recommend',recomend:'recommend',refered:'referred', + relevent:'relevant',religous:'religious',rember:'remember',remeber:'remember',resturant:'restaurant', + rythm:'rhythm',secratary:'secretary',sieze:'seize',similiar:'similar',succesful:'successful',succesfully:'successfully', + suprise:'surprise',suprised:'surprised',tommorow:'tomorrow',tommorrow:'tomorrow',tounge:'tongue',truely:'truly', + unfortunatly:'unfortunately',usualy:'usually',vaccum:'vacuum',wierd:'weird',writen:'written',yeild:'yield', + yuo:'you',youre:"you're",cant:"can't",dont:"don't",doesnt:"doesn't",didnt:"didn't",wasnt:"wasn't",werent:"weren't", + isnt:"isn't",wouldnt:"wouldn't",couldnt:"couldn't",shouldnt:"shouldn't",hasnt:"hasn't",havent:"haven't", + ive:"I've",thats:"that's",whats:"what's",lets:"let's", + aer:'are',adn:'and',nad:'and',wnat:'want',waht:'what',knwo:'know', + woudl:'would',shoudl:'should',coudl:'could',funtion:'function',retrun:'return', +}; +// Apply an auto-correction if the caret just crossed a word boundary onto a known typo. +function maybeAutocorrect(el){ + try{ + if(!el||el.selectionStart==null||el.selectionStart!==el.selectionEnd) return; + const pos=el.selectionStart, val=el.value, ch=val[pos-1]; + if(!ch || !/[\s.,!?;:]/.test(ch)) return; // only right after a boundary char + const before=val.slice(0,pos-1); const m=before.match(/([A-Za-z']+)$/); if(!m) return; + const word=m[1], lower=word.toLowerCase(); const rep=AUTOCORRECT[lower]; + if(!rep) return; // not a known typo (native squiggles still flag others) + const fixed=/^[A-Z]/.test(word)?(rep.charAt(0).toUpperCase()+rep.slice(1)):rep; + if(fixed===word) return; + const start=pos-1-word.length; + el.value=val.slice(0,start)+fixed+val.slice(pos-1); + const np=start+fixed.length+1; el.setSelectionRange(np,np); + }catch(_){} +} + // All in-app toasts route through the branded BZToast (bizconnect-toast.js). We keep the single // toast(msg) entry point so every existing call site is unchanged, and classify by wording so // errors/successes get the right colour+icon; everything else shows as a neutral message. @@ -1732,7 +1783,7 @@ function showSeenByModal(msg){ let inner=''; if(seenNames.length) inner+='