Ingen beskrivning
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

home-mockup.html 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>BizGaze Connect — Home</title>
  7. <style>
  8. :root{ --brand:#FFC708; --brand-d:#E0AC00; --blue:#1F3B73; --blue-d:#16294f; --blue-soft:#EAF0FB; --ink:#1f2430; --muted:#6b7280; --bg:#f6f8fb; --card:#fff; --line:#e6e9ef; --green:#16a34a; --red:#b91c1c; }
  9. *{box-sizing:border-box;}
  10. html,body{height:100%;}
  11. body{font-family:'Segoe UI',system-ui,sans-serif;background:var(--bg);color:var(--ink);margin:0;display:flex;flex-direction:column;height:100vh;overflow:hidden;}
  12. /* ---- Top bar (matches console.html) ---- */
  13. header{background:var(--blue);padding:.75rem 1.5rem;display:flex;justify-content:space-between;align-items:center;flex:0 0 auto;}
  14. .brandrow{display:flex;align-items:center;gap:.6rem;cursor:pointer;}
  15. .logo{width:30px;height:30px;border-radius:8px;background:var(--brand);display:grid;place-items:center;font-weight:800;color:var(--blue);}
  16. .brand{font-weight:700;color:#fff;font-size:1.05rem;} .brand span.y{color:var(--brand);font-weight:700;}
  17. .brand span.tag{color:#8ea3cf;font-weight:500;font-size:.85rem;}
  18. /* ---- Profile dropdown (from console.html) ---- */
  19. .profile{position:relative}
  20. .profile .pbtn{display:flex;align-items:center;gap:.5rem;background:rgba(255,255,255,.14);color:#fff;border:1px solid #46598c;border-radius:10px;padding:.4rem .85rem .4rem .5rem;font-weight:600;font-size:.88rem;cursor:pointer}
  21. .profile .pbtn:hover{background:rgba(255,255,255,.24)}
  22. .profile .pbtn .pav{width:28px;height:28px;border-radius:50%;background:var(--brand);color:var(--blue);display:grid;place-items:center;font-weight:800;font-size:.78rem}
  23. .profile .pmenu{position:absolute;right:0;top:calc(100% + 6px);background:#fff;border:1px solid #e6e9ef;border-radius:10px;box-shadow:0 10px 28px rgba(0,0,0,.18);min-width:210px;overflow:hidden;z-index:5000;display:none}
  24. .profile .pmenu.open{display:block}
  25. .profile .pmenu .phead{padding:.7rem .9rem;border-bottom:1px solid #eef1f6}
  26. .profile .pmenu .phead .n{font-weight:700;font-size:.9rem}
  27. .profile .pmenu .phead .e{color:var(--muted);font-size:.78rem}
  28. .profile .pmenu a{display:block;padding:.6rem .9rem;color:#1f2430;text-decoration:none;font-size:.9rem;cursor:pointer}
  29. .profile .pmenu a:hover{background:#f1f5f9}
  30. .profile .pmenu a.danger{color:#b91c1c;border-top:1px solid #eef1f6}
  31. /* ---- Shell ---- */
  32. .shell{flex:1 1 auto;display:flex;min-height:0;}
  33. /* ---- Sidebar ---- */
  34. .sidebar{width:320px;flex:0 0 320px;background:var(--card);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0;}
  35. .side-head{padding:1rem 1rem .75rem;border-bottom:1px solid var(--line);}
  36. .side-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:.7rem;}
  37. .side-title h2{font-size:.95rem;margin:0;color:var(--blue);}
  38. .newchat{width:30px;height:30px;border-radius:9px;border:none;background:var(--blue-soft);color:var(--blue);font-size:1.2rem;line-height:1;cursor:pointer;font-weight:700;display:grid;place-items:center;padding:0;}
  39. .newchat:hover{background:#dbe6fb;}
  40. .search{position:relative;}
  41. .search svg{position:absolute;left:.65rem;top:50%;transform:translateY(-50%);color:var(--muted);}
  42. .search input{width:100%;padding:.55rem .7rem .55rem 2.1rem;border-radius:10px;border:2px solid var(--line);background:#fbfcfe;color:var(--ink);font-size:.9rem;}
  43. .search input:focus{outline:none;border-color:var(--brand);}
  44. .chatlist{overflow-y:auto;flex:1 1 auto;padding:.4rem;}
  45. .chat-row{display:flex;gap:.7rem;align-items:center;padding:.6rem .65rem;border-radius:12px;cursor:pointer;position:relative;}
  46. .chat-row:hover{background:#f3f6fb;}
  47. .chat-row.active{background:var(--blue-soft);}
  48. .chat-row.active::before{content:"";position:absolute;left:0;top:.7rem;bottom:.7rem;width:3px;border-radius:3px;background:var(--blue);}
  49. .avatar{width:42px;height:42px;flex:0 0 42px;border-radius:50%;display:grid;place-items:center;color:#fff;font-weight:700;font-size:.92rem;position:relative;}
  50. .avatar .dot{position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;border:2px solid #fff;background:#cbd2dd;}
  51. .avatar .dot.on{background:var(--green);}
  52. .chat-main{flex:1 1 auto;min-width:0;}
  53. .chat-top{display:flex;justify-content:space-between;align-items:baseline;gap:.5rem;}
  54. .chat-name{font-weight:600;font-size:.92rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  55. .chat-time{color:var(--muted);font-size:.72rem;flex:0 0 auto;}
  56. .chat-bottom{display:flex;justify-content:space-between;align-items:center;gap:.5rem;margin-top:.15rem;}
  57. .chat-prev{color:var(--muted);font-size:.82rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto;}
  58. .chat-row.unread .chat-prev{color:var(--ink);font-weight:500;}
  59. .chat-row.unread .chat-name{font-weight:700;}
  60. .badge{flex:0 0 auto;background:var(--blue);color:#fff;font-size:.7rem;font-weight:700;min-width:19px;height:19px;border-radius:99px;padding:0 .35rem;display:grid;place-items:center;}
  61. .no-results{padding:2rem 1rem;text-align:center;color:var(--muted);font-size:.85rem;}
  62. /* ---- Main content ---- */
  63. .content{flex:1 1 auto;display:flex;flex-direction:column;min-width:0;min-height:0;}
  64. .tabs{display:flex;gap:.4rem;padding:1rem 1.5rem 0;border-bottom:1px solid var(--line);background:var(--card);}
  65. .tabs button{background:transparent;color:var(--muted);font-weight:600;font-size:.92rem;border:none;border-bottom:3px solid transparent;padding:.6rem .9rem .8rem;cursor:pointer;display:flex;align-items:center;gap:.45rem;border-radius:8px 8px 0 0;}
  66. .tabs button:hover{color:var(--blue);background:#f6f8fb;}
  67. .tabs button.active{color:var(--blue);border-bottom-color:var(--brand);}
  68. .panel-wrap{flex:1 1 auto;overflow-y:auto;padding:2rem 1.5rem;display:flex;}
  69. .panel{display:none;margin:auto;width:100%;max-width:560px;}
  70. .panel.active{display:block;}
  71. .card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:2.2rem;box-shadow:0 6px 18px rgba(20,30,60,.05);text-align:center;}
  72. .feat-icon{width:72px;height:72px;border-radius:20px;display:grid;place-items:center;margin:0 auto 1.2rem;}
  73. .feat-icon.blue{background:var(--blue-soft);color:var(--blue);}
  74. .feat-icon.yellow{background:#fff6d8;color:var(--brand-d);}
  75. .card h1{font-size:1.45rem;margin:0 0 .5rem;color:var(--blue);}
  76. .card p{color:var(--muted);font-size:.95rem;line-height:1.55;margin:0 auto 1.6rem;max-width:400px;}
  77. .btn{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;padding:.8rem 1.6rem;background:var(--brand);color:var(--ink);border:none;border-radius:11px;font-weight:700;font-size:.95rem;cursor:pointer;}
  78. .btn:hover{background:var(--brand-d);}
  79. .pill-soon{display:inline-block;background:#fff6d8;color:var(--brand-d);font-size:.74rem;font-weight:700;padding:.25rem .7rem;border-radius:99px;letter-spacing:.03em;margin-bottom:1.2rem;}
  80. .hint{margin-top:1.4rem;font-size:.8rem;color:var(--muted);}
  81. @media (max-width:760px){
  82. .sidebar{width:108px;flex:0 0 108px;}
  83. .side-title h2,.search,.chat-main{display:none;}
  84. .chat-row{justify-content:center;}
  85. .side-head{padding:.8rem .5rem;}
  86. }
  87. </style>
  88. </head>
  89. <body>
  90. <header>
  91. <div class="brandrow" id="brandrow">
  92. <img src="/logo.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))">
  93. <div class="brand">BizGaze <span class="y">Connect</span> <span class="tag">· Home</span></div>
  94. </div>
  95. <div id="hdrRight"></div>
  96. </header>
  97. <div class="shell">
  98. <!-- ---------- Sidebar ---------- -->
  99. <aside class="sidebar">
  100. <div class="side-head">
  101. <div class="side-title">
  102. <h2>Chats</h2>
  103. <button class="newchat" title="New chat" aria-label="New chat">+</button>
  104. </div>
  105. <div class="search">
  106. <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
  107. <input id="chatSearch" placeholder="Search chats" autocomplete="off">
  108. </div>
  109. </div>
  110. <div class="chatlist" id="chatlist"></div>
  111. </aside>
  112. <!-- ---------- Main ---------- -->
  113. <section class="content">
  114. <div class="tabs">
  115. <button data-tab="meeting" class="active">
  116. <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
  117. Meeting
  118. </button>
  119. <button data-tab="share">
  120. <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
  121. Share Screen
  122. </button>
  123. <button data-tab="connect">
  124. <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/></svg>
  125. Connect Screen
  126. </button>
  127. </div>
  128. <div class="panel-wrap">
  129. <!-- Meeting -->
  130. <div class="panel active" data-panel="meeting">
  131. <div class="card">
  132. <div class="feat-icon yellow">
  133. <svg viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/></svg>
  134. </div>
  135. <span class="pill-soon">COMING SOON</span>
  136. <h1>Meetings are on the way</h1>
  137. <p>Soon you'll be able to host multi-party video meetings with your BizGaze team and customers — right here, no install needed. We're putting on the finishing touches.</p>
  138. <button class="btn" id="notifyBtn">🔔 Notify me when it's ready</button>
  139. <div class="hint">In the meantime, use <b>Share Screen</b> or <b>Connect Screen</b> to start a session.</div>
  140. </div>
  141. </div>
  142. <!-- Share Screen -->
  143. <div class="panel" data-panel="share">
  144. <div class="card">
  145. <div class="feat-icon blue">
  146. <svg viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
  147. </div>
  148. <h1>Share your screen</h1>
  149. <p>Let a teammate or customer see your screen instantly. You'll get a 6-digit code to share — they enter it to connect. No download, works right in the browser.</p>
  150. <a class="btn" href="/share">Start sharing →</a>
  151. <div class="hint">Desktop browsers only — phones can't share their screen yet.</div>
  152. </div>
  153. </div>
  154. <!-- Connect Screen -->
  155. <div class="panel" data-panel="connect">
  156. <div class="card">
  157. <div class="feat-icon blue">
  158. <svg viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/></svg>
  159. </div>
  160. <h1>Connect to a screen</h1>
  161. <p>Helping someone out? Enter the 6-digit code they give you to view their screen and provide live support — with two-way voice and chat built in.</p>
  162. <a class="btn" href="/connect">Open connect page →</a>
  163. <div class="hint">The other person taps <b>Allow</b> before you can see anything.</div>
  164. </div>
  165. </div>
  166. </div>
  167. </section>
  168. </div>
  169. <script>
  170. // ---------- Helpers (reused patterns from console.html) ----------
  171. function pEsc(s){return String(s==null?'':s).replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));}
  172. function initials(name){return name.trim().split(/\s+/).slice(0,2).map(w=>w[0]).join('').toUpperCase();}
  173. // Stable avatar color from a name
  174. const AV_COLORS=['#1F3B73','#2563eb','#0e7490','#7c3aed','#be185d','#b45309','#15803d','#9d174d'];
  175. function avColor(name){let h=0;for(const c of name)h=(h*31+c.charCodeAt(0))>>>0;return AV_COLORS[h%AV_COLORS.length];}
  176. // Profile dropdown (mirrors profileHTML()/wireProfile() from console.html)
  177. const SAMPLE_USER={name:'Sravan Mareddy',email:'sravanm@bizgaze.com',role:'admin'};
  178. function profileHTML(u){
  179. return '<div class="profile"><button class="pbtn" id="pbtn">'
  180. + '<span class="pav">'+pEsc(initials(u.name))+'</span>'
  181. + pEsc(u.name)+' <span style="font-size:.65rem">&#9662;</span></button>'
  182. + '<div class="pmenu" id="pmenu">'
  183. + '<div class="phead"><div class="n">'+pEsc(u.name)+'</div><div class="e">'+pEsc(u.email)+' · '+pEsc(u.role)+'</div></div>'
  184. + '<a href="/console">Console / Dashboard</a>'
  185. + '<a href="#">Settings</a>'
  186. + '<a class="danger" id="plogout">Logout</a>'
  187. + '</div></div>';
  188. }
  189. function wireProfile(){
  190. const btn=document.getElementById('pbtn'),menu=document.getElementById('pmenu');
  191. if(!btn)return;
  192. btn.onclick=(e)=>{e.stopPropagation();menu.classList.toggle('open');};
  193. document.addEventListener('click',()=>menu.classList.remove('open'));
  194. const lo=document.getElementById('plogout');
  195. if(lo)lo.onclick=(e)=>{e.preventDefault();alert('Mockup — logout would sign you out and return to /.');};
  196. }
  197. document.getElementById('hdrRight').innerHTML=profileHTML(SAMPLE_USER);
  198. wireProfile();
  199. document.getElementById('brandrow').onclick=()=>{location.href='/';};
  200. // ---------- Mock chat data ----------
  201. const CHATS=[
  202. {name:'Anwi Systems', msg:"Perfect, the screen share worked great. Thanks!", time:'9:42 AM', unread:0, online:true, active:true},
  203. {name:'Priya Sharma', msg:"Can you connect to my screen at 3pm?", time:'9:15 AM', unread:2, online:true},
  204. {name:'GAPL Group', msg:"You: I've shared the 6-digit code with you", time:'Yesterday', unread:0, online:false},
  205. {name:'Battery Doctors', msg:"The invoice module is throwing an error again", time:'Yesterday', unread:5, online:true},
  206. {name:'Ramesh Marketing', msg:"You: Let me know once you're at your desk", time:'Mon', unread:0, online:false},
  207. {name:'STC Support', msg:"Typing…", time:'Mon', unread:1, online:true},
  208. {name:'Samruddhi Traders',msg:"Thanks for the help earlier 👍", time:'Sun', unread:0, online:false},
  209. {name:'DMS 3.0 Team', msg:"You: Closing the ticket, all resolved", time:'Fri', unread:0, online:false},
  210. ];
  211. const listEl=document.getElementById('chatlist');
  212. function chatRowHTML(c,i){
  213. const cls=['chat-row'];
  214. if(c.active)cls.push('active');
  215. if(c.unread>0)cls.push('unread');
  216. return '<div class="'+cls.join(' ')+'" data-i="'+i+'">'
  217. + '<div class="avatar" style="background:'+avColor(c.name)+'">'+pEsc(initials(c.name))
  218. + '<span class="dot'+(c.online?' on':'')+'"></span></div>'
  219. + '<div class="chat-main">'
  220. + '<div class="chat-top"><span class="chat-name">'+pEsc(c.name)+'</span><span class="chat-time">'+pEsc(c.time)+'</span></div>'
  221. + '<div class="chat-bottom"><span class="chat-prev">'+pEsc(c.msg)+'</span>'
  222. + (c.unread>0?'<span class="badge">'+c.unread+'</span>':'')+'</div>'
  223. + '</div></div>';
  224. }
  225. function renderChats(filter){
  226. const q=(filter||'').trim().toLowerCase();
  227. const rows=CHATS.map((c,i)=>({c,i})).filter(({c})=>!q||c.name.toLowerCase().includes(q)||c.msg.toLowerCase().includes(q));
  228. listEl.innerHTML = rows.length
  229. ? rows.map(({c,i})=>chatRowHTML(c,i)).join('')
  230. : '<div class="no-results">No chats match “'+pEsc(filter)+'”.</div>';
  231. listEl.querySelectorAll('.chat-row').forEach(row=>{
  232. row.onclick=()=>{
  233. CHATS.forEach(c=>c.active=false);
  234. CHATS[+row.dataset.i].active=true;
  235. CHATS[+row.dataset.i].unread=0;
  236. renderChats(document.getElementById('chatSearch').value);
  237. };
  238. });
  239. }
  240. renderChats('');
  241. document.getElementById('chatSearch').addEventListener('input',e=>renderChats(e.target.value));
  242. // ---------- Tab switching ----------
  243. const tabBtns=document.querySelectorAll('.tabs button');
  244. const panels=document.querySelectorAll('.panel');
  245. tabBtns.forEach(btn=>{
  246. btn.onclick=()=>{
  247. const tab=btn.dataset.tab;
  248. tabBtns.forEach(b=>b.classList.toggle('active',b===btn));
  249. panels.forEach(p=>p.classList.toggle('active',p.dataset.panel===tab));
  250. };
  251. });
  252. // Mockup-only stubs
  253. document.querySelector('.newchat').onclick=()=>alert('Mockup — “New chat” would open the contact picker.');
  254. document.getElementById('notifyBtn').onclick=()=>alert("Thanks! We'll let you know when Meetings launches.");
  255. </script>
  256. </body>
  257. </html>