feat: nav chat right + double-wide, centered CTAs, live chat panel with history, webhook integration

This commit is contained in:
oliver
2026-04-24 12:26:37 -03:00
parent 15d85141ac
commit 8b618284ef
+441 -37
View File
@@ -100,9 +100,10 @@
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
display: flex; display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center; align-items: center;
justify-content: space-between; gap: 24px;
padding: 0 8vw; padding: 0 8vw;
} }
@@ -153,18 +154,21 @@
color: var(--gold); color: var(--gold);
} }
.nav-links li a.nav-cta { .nav-cta {
border: 1px solid var(--gold); border: 1px solid var(--gold);
color: var(--gold); color: var(--gold);
-webkit-text-fill-color: var(--gold); -webkit-text-fill-color: var(--gold);
padding: 7px 18px; padding: 7px 18px;
border-radius: 2px; border-radius: 2px;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.08em;
transition: transition:
background 0.2s, background 0.2s,
color 0.2s, color 0.2s,
-webkit-text-fill-color 0.2s; -webkit-text-fill-color 0.2s;
} }
.nav-links li a.nav-cta:hover { .nav-cta:hover {
background: var(--gold); background: var(--gold);
color: var(--bg); color: var(--bg);
-webkit-text-fill-color: var(--bg); -webkit-text-fill-color: var(--bg);
@@ -264,7 +268,7 @@
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 4px; border-radius: 4px;
height: 34px; height: 34px;
width: 220px; width: 440px;
transition: transition:
border-color 0.25s, border-color 0.25s,
box-shadow 0.25s; box-shadow 0.25s;
@@ -305,6 +309,38 @@
.nav-chat-send:hover { .nav-chat-send:hover {
color: var(--gold-hi); color: var(--gold-hi);
} }
.nav-chat-toggle {
flex-shrink: 0;
background: none;
border: none;
border-right: 1px solid var(--border);
padding: 0 10px;
color: var(--gold);
font-size: 0.9rem;
cursor: pointer;
height: 100%;
display: flex;
align-items: center;
transition: color 0.2s;
}
.nav-chat-toggle:hover {
color: var(--gold-hi);
}
.nav-center {
display: flex;
align-items: center;
gap: 12px;
justify-content: center;
}
.nav-right {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
.nav-cta-sm {
display: none;
}
.hero-actions { .hero-actions {
display: flex; display: flex;
@@ -363,23 +399,179 @@
} }
/* ── NAV BOOK MEETING CTA ── */ /* ── NAV BOOK MEETING CTA ── */
.nav-links li a.nav-cta-book { .nav-cta-book {
border: 1px solid rgba(190, 120, 45, 0.38); border: 1px solid rgba(210, 140, 60, 0.38);
color: var(--silver); color: var(--silver);
-webkit-text-fill-color: var(--silver); -webkit-text-fill-color: var(--silver);
padding: 7px 18px; padding: 7px 18px;
border-radius: 2px; border-radius: 2px;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.08em;
transition: transition:
border-color 0.2s, border-color 0.2s,
color 0.2s, color 0.2s,
-webkit-text-fill-color 0.2s; -webkit-text-fill-color 0.2s;
} }
.nav-links li a.nav-cta-book:hover { .nav-cta-book:hover {
border-color: var(--gold); border-color: var(--gold);
color: var(--gold); color: var(--gold);
-webkit-text-fill-color: var(--gold); -webkit-text-fill-color: var(--gold);
} }
/* ── CHAT PANEL ── */
.chat-panel {
position: fixed;
top: 62px;
right: 8vw;
width: 440px;
background: var(--card);
border: 1px solid var(--border);
border-top: 2px solid var(--gold);
border-radius: 0 0 8px 8px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
display: flex;
flex-direction: column;
z-index: 498;
visibility: hidden;
opacity: 0;
transform: translateY(-8px);
transition:
opacity 0.22s ease,
visibility 0.22s ease,
transform 0.22s ease;
overflow: hidden;
}
.chat-panel.open {
visibility: visible;
opacity: 1;
transform: translateY(0);
}
.chat-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
background: var(--lift);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.chat-panel-title {
font-size: 0.75rem;
font-weight: 700;
color: var(--gold);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.chat-panel-close {
background: none;
border: none;
color: var(--grey);
cursor: pointer;
font-size: 0.9rem;
line-height: 1;
padding: 2px 6px;
transition: color 0.2s;
}
.chat-panel-close:hover {
color: var(--gold);
}
.chat-history {
flex: 1;
height: 240px;
overflow-y: auto;
padding: 12px 14px;
display: flex;
flex-direction: column;
gap: 10px;
scroll-behavior: smooth;
}
.chat-history::-webkit-scrollbar {
width: 4px;
}
.chat-history::-webkit-scrollbar-track {
background: var(--bg);
}
.chat-history::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 2px;
}
.chat-msg {
display: flex;
flex-direction: column;
gap: 3px;
}
.chat-msg.user {
align-items: flex-end;
}
.chat-msg.agent {
align-items: flex-start;
}
.chat-label {
font-size: 0.6rem;
color: var(--grey);
text-transform: uppercase;
letter-spacing: 0.07em;
}
.chat-bubble {
max-width: 82%;
padding: 8px 12px;
font-size: 0.82rem;
line-height: 1.55;
font-family: "Segoe UI", system-ui, sans-serif;
}
.chat-msg.agent .chat-bubble {
background: var(--lift);
color: var(--light);
border-radius: 0 6px 6px 6px;
}
.chat-msg.user .chat-bubble {
background: var(--gold-lo);
color: var(--white);
border-radius: 6px 0 6px 6px;
}
.chat-thinking .chat-bubble {
color: var(--grey);
font-style: italic;
}
.chat-input-row {
display: flex;
align-items: center;
border-top: 1px solid var(--border);
background: var(--bg);
flex-shrink: 0;
}
.chat-input-field {
flex: 1;
background: transparent;
border: none;
outline: none;
padding: 12px 14px;
font-size: 0.85rem;
font-family: "Segoe UI", system-ui, sans-serif;
color: var(--white);
min-width: 0;
}
.chat-input-field::placeholder {
color: var(--grey);
}
.chat-input-send {
background: none;
border: none;
border-left: 1px solid var(--border);
padding: 0 14px;
color: var(--gold);
font-size: 0.9rem;
cursor: pointer;
height: 44px;
display: flex;
align-items: center;
transition: color 0.2s;
}
.chat-input-send:hover {
color: var(--gold-hi);
}
.hero-trust { .hero-trust {
font-size: 0.78rem; font-size: 0.78rem;
color: var(--grey); color: var(--grey);
@@ -1059,11 +1251,21 @@
.hero h1 { .hero h1 {
font-size: 1.9rem; font-size: 1.9rem;
} }
nav {
grid-template-columns: 1fr auto;
gap: 12px;
}
.nav-center {
display: none;
}
.nav-chat { .nav-chat {
display: none; display: none;
} }
.nav-links { .nav-cta-sm {
gap: 14px; display: inline-block;
}
.chat-panel {
display: none !important;
} }
.footer-top { .footer-top {
gap: 36px; gap: 36px;
@@ -1088,12 +1290,6 @@
footer { footer {
padding: 52px 5vw 32px; padding: 52px 5vw 32px;
} }
.nav-links {
gap: 10px;
}
.nav-links li:not(:last-child) {
display: none;
}
#modal-box { #modal-box {
padding: 36px 20px; padding: 36px 20px;
} }
@@ -1107,29 +1303,69 @@
<!-- NAV --> <!-- NAV -->
<nav> <nav>
<a class="nav-logo" href="#">my-biz<span>.app</span></a> <a class="nav-logo" href="#">my-biz<span>.app</span></a>
<ul class="nav-links"> <div class="nav-center">
<li> <a class="nav-cta-book" href="#">Book Meeting</a>
<div class="nav-chat"> <a class="nav-cta" id="open-modal" href="#">Free Trial</a>
<input </div>
type="text" <div class="nav-right">
class="nav-chat-input" <div class="nav-chat" id="nav-chat">
placeholder="Your Sales Agent" <button
aria-label="Ask your AI sales agent" class="nav-chat-toggle"
/> id="nav-chat-toggle"
<button class="nav-chat-send" aria-label="Send message"> aria-label="Toggle chat history"
&#10148; >
</button> &#128172;
</div> </button>
</li> <input
<li> type="text"
<a class="nav-cta-book" href="#">Book Meeting</a> class="nav-chat-input"
</li> id="nav-chat-input"
<li> placeholder="Your Sales Agent"
<a class="nav-cta" id="open-modal" href="#">Free Trial</a> aria-label="Ask your AI sales agent"
</li> />
</ul> <button
class="nav-chat-send"
id="nav-chat-send"
aria-label="Send message"
>
&#10148;
</button>
</div>
<a class="nav-cta open-modal nav-cta-sm" href="#">Free Trial</a>
</div>
</nav> </nav>
<!-- Sales Agent chat panel — drops below nav, right-aligned -->
<div class="chat-panel" id="chat-panel" aria-hidden="true">
<div class="chat-panel-header">
<span class="chat-panel-title">&#128172;&nbsp;Sales Agent</span>
<button
class="chat-panel-close"
id="chat-panel-close"
aria-label="Close chat"
>
&#10005;
</button>
</div>
<div class="chat-history" id="chat-history"></div>
<div class="chat-input-row">
<input
type="text"
class="chat-input-field"
id="chat-input-field"
placeholder="Type a message&#x2026;"
aria-label="Chat message"
/>
<button
class="chat-input-send"
id="chat-input-send"
aria-label="Send"
>
&#10148;
</button>
</div>
</div>
<!-- HERO --> <!-- HERO -->
<section class="hero" id="home"> <section class="hero" id="home">
<!-- Parallax background --> <!-- Parallax background -->
@@ -1692,6 +1928,174 @@
</div> </div>
</div> </div>
<!-- ── Sales Agent Chat ───────────────────────────────────────────── -->
<script>
(function () {
"use strict";
var CHAT_URL =
"https://002-001-5dd6e535-4d1c-46bc-9bd9-42ad4bc5f082.odoo4projects.com/webhook/702862fd-dd17-4a34-8efb-e9056d2c50df/chat";
var SESSION =
"mbs_" +
Math.random().toString(36).slice(2) +
Date.now().toString(36);
var panel = document.getElementById("chat-panel");
var chatLog = document.getElementById("chat-history");
var toggleBtn = document.getElementById("nav-chat-toggle");
var closeBtn = document.getElementById("chat-panel-close");
var navInput = document.getElementById("nav-chat-input");
var navSend = document.getElementById("nav-chat-send");
var panelInput = document.getElementById("chat-input-field");
var panelSend = document.getElementById("chat-input-send");
var busy = false;
var greeted = false;
/* ── visibility ─────────────────────────────────────────── */
function openPanel() {
panel.classList.add("open");
panel.setAttribute("aria-hidden", "false");
if (!greeted) {
greeted = true;
appendMsg(
"agent",
"Hi! I\u2019m your Sales Agent. Ask me anything about plans, onboarding, or pricing.",
);
}
scrollLog();
}
function closePanel() {
panel.classList.remove("open");
panel.setAttribute("aria-hidden", "true");
}
function togglePanel() {
panel.classList.contains("open")
? closePanel()
: openPanel();
}
/* ── DOM helpers ─────────────────────────────────────────── */
function scrollLog() {
chatLog.scrollTop = chatLog.scrollHeight;
}
function appendMsg(role, text) {
var wrap = document.createElement("div");
wrap.className = "chat-msg " + role;
var lbl = document.createElement("span");
lbl.className = "chat-label";
lbl.textContent = role === "user" ? "You" : "Sales Agent";
var bbl = document.createElement("div");
bbl.className = "chat-bubble";
bbl.textContent = text;
wrap.appendChild(lbl);
wrap.appendChild(bbl);
chatLog.appendChild(wrap);
scrollLog();
return wrap;
}
/* ── send ────────────────────────────────────────────────── */
function send(text) {
text = (text || "").trim();
if (!text || busy) return;
busy = true;
appendMsg("user", text);
openPanel();
navInput.value = "";
panelInput.value = "";
var thinkEl = appendMsg("agent", "\u2026");
thinkEl.classList.add("chat-thinking");
fetch(CHAT_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: text,
session_id: SESSION,
}),
})
.then(function (r) {
var ct = r.headers.get("content-type") || "";
if (ct.indexOf("json") !== -1) return r.json();
return r.text().then(function (t) {
return { reply: t };
});
})
.then(function (d) {
if (thinkEl.parentNode)
chatLog.removeChild(thinkEl);
var reply =
d.reply ||
d.message ||
d.response ||
d.output ||
d.text ||
(typeof d === "string" ? d : JSON.stringify(d));
appendMsg("agent", reply);
busy = false;
})
.catch(function () {
if (thinkEl.parentNode)
chatLog.removeChild(thinkEl);
appendMsg(
"agent",
"Sorry, I could not connect right now. Please try again.",
);
busy = false;
});
}
/* ── events ──────────────────────────────────────────────── */
toggleBtn.addEventListener("click", function (e) {
e.stopPropagation();
togglePanel();
});
closeBtn.addEventListener("click", closePanel);
navSend.addEventListener("click", function () {
send(navInput.value);
});
panelSend.addEventListener("click", function () {
send(panelInput.value);
});
navInput.addEventListener("keydown", function (e) {
if (e.key === "Enter") send(navInput.value);
});
panelInput.addEventListener("keydown", function (e) {
if (e.key === "Enter") send(panelInput.value);
});
/* close on outside click */
document.addEventListener("click", function (e) {
var nc = document.getElementById("nav-chat");
if (
panel.classList.contains("open") &&
!panel.contains(e.target) &&
nc &&
!nc.contains(e.target)
) {
closePanel();
}
});
/* close on Escape */
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && panel.classList.contains("open"))
closePanel();
});
})();
</script>
<script> <script>
(function () { (function () {
var WEBHOOK = var WEBHOOK =