- Implemented.

Rebuilt embed-example.html with inline, full-screen, and popup examples.
Fixed host-page/frame scrolling and contained reply navigation.
New logins now transactionally replace prior sessions; displaced clients 
return to login.
Added per-user session/IP locking with automatic SQLite migration.
Added modular Spam Control dashboard for locks, honeypot, and CAPTCHA 
settings.
Moved CAPTCHA controls out of Plans & Platform.
This commit is contained in:
Ty Clifford
2026-06-09 18:54:25 -04:00
parent 5ca55bf7c1
commit 36c488ca1e
12 changed files with 599 additions and 169 deletions
+219 -66
View File
@@ -3,112 +3,265 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CyberChat Embed Example</title>
<title>CyberChat - Embed Examples</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Orbitron:wght@700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/cyberchat.css?v=20260609.4">
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Rajdhani:wght@400;600;700&family=Orbitron:wght@700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/cyberchat.css?v=20260609.5">
<style>
html, body {
height: auto;
min-height: 100vh;
overflow: auto;
min-height: 100%;
background: var(--bg0);
padding: 32px 20px 48px;
font-family: var(--mono);
}
.demo-page { max-width: 860px; margin: 0 auto; }
body {
padding: 32px 20px 56px;
color: var(--t0);
font-family: var(--mono);
overflow-x: hidden;
overflow-y: auto;
}
.demo-page {
width: min(100%, 960px);
margin: 0 auto;
}
.demo-header {
margin-bottom: 30px;
text-align: center;
margin-bottom: 32px;
}
.demo-header h1 {
font-family: var(--disp);
font-size: clamp(18px, 4vw, 32px);
background: linear-gradient(90deg, var(--g), var(--b), var(--p));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 5px;
margin-bottom: 6px;
background: linear-gradient(90deg, var(--g), var(--b), var(--p));
background-clip: text;
color: transparent;
font: 700 clamp(18px, 4vw, 32px) var(--disp);
letter-spacing: 5px;
}
.demo-header p {
font-size: 10px;
.demo-header p,
.demo-note {
color: var(--t1);
letter-spacing: 2px;
font-size: 10px;
letter-spacing: 1px;
line-height: 1.6;
}
.demo-section {
margin-top: 26px;
}
.demo-label {
font-size: 10px;
color: var(--g);
letter-spacing: 2px;
margin-bottom: 8px;
color: var(--g);
font-size: 10px;
letter-spacing: 2px;
}
.demo-frame {
width: 100%;
height: min(680px, 78vh);
min-height: 420px;
overflow: hidden;
border: 1px solid var(--bd);
border-radius: 6px;
background: var(--bg1);
box-shadow: 0 18px 60px rgba(0, 0, 0, .35);
}
/* ── THE EMBED CONTAINER — set any size you want ── */
#chat-here {
width: 100%;
height: 580px;
height: 100%;
}
.demo-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 10px 0 12px;
}
.demo-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 36px;
padding: 0 14px;
border: 1px solid var(--b);
border-radius: 3px;
background: transparent;
color: var(--b);
font: 10px var(--mono);
letter-spacing: 1px;
text-decoration: none;
}
.demo-button:hover {
background: var(--b);
color: #000;
}
.demo-button.alt {
border-color: var(--v);
color: var(--v);
}
.demo-button.alt:hover {
background: var(--v);
color: #000;
}
.demo-code {
background: var(--bg1);
margin-top: 12px;
padding: 18px 20px;
overflow-x: auto;
border: 1px solid var(--bd);
border-radius: 6px;
padding: 18px 20px;
margin-top: 24px;
font-size: 12px;
background: var(--bg1);
color: var(--t1);
line-height: 1.9;
overflow-x: auto;
font-size: 12px;
line-height: 1.75;
white-space: pre;
}
.demo-code .kw { color: var(--p); }
.demo-code .str { color: var(--g); }
.demo-code .cm { color: var(--t2); font-style: italic; }
.demo-code .cm { color: var(--t1); font-style: italic; }
.fullscreen-chat {
position: fixed;
inset: 0;
z-index: 10000;
display: grid;
grid-template-rows: 42px minmax(0, 1fr);
background: var(--bg0);
}
.fullscreen-chat[hidden] {
display: none;
}
.fullscreen-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 12px;
border-bottom: 1px solid var(--bd);
background: var(--bg1);
color: var(--g);
font-size: 10px;
letter-spacing: 1px;
}
.fullscreen-chat iframe {
width: 100%;
height: 100%;
border: 0;
background: var(--bg0);
}
@media (max-width: 520px) {
body { padding: 18px 10px 36px; }
.demo-frame { height: 72vh; min-height: 380px; }
.demo-code { padding: 14px; font-size: 10px; }
}
</style>
</head>
<body>
<div class="demo-page">
<div class="demo-header">
<h1>CYBERCHAT</h1>
<p>// EMBED EXAMPLE — DROP INTO ANY PAGE</p>
<main class="demo-page">
<header class="demo-header">
<h1>CYBERCHAT</h1>
<p>// INLINE, FULL-SCREEN, AND POPOUT EMBED EXAMPLES</p>
</header>
<section class="demo-section">
<div class="demo-label">INLINE EMBED</div>
<p class="demo-note">The chat owns the scrolling inside this fixed-height box. The surrounding page remains independent.</p>
<div class="demo-frame">
<div id="chat-here"></div>
</div>
<div class="demo-code"><span class="cm">&lt;!-- Include once in the host page --&gt;</span>
<span class="kw">&lt;link</span> rel=<span class="str">"stylesheet"</span> href=<span class="str">"/chat/assets/css/cyberchat.css?v=20260609.5"</span><span class="kw">&gt;</span>
<span class="kw">&lt;div</span> id=<span class="str">"my-chat"</span> style=<span class="str">"width:100%; height:680px; overflow:hidden"</span><span class="kw">&gt;&lt;/div&gt;</span>
<span class="kw">&lt;script&gt;</span>window.CYBERCHAT_BASE = <span class="str">'/chat'</span>;<span class="kw">&lt;/script&gt;</span>
<span class="kw">&lt;script</span> src=<span class="str">"/chat/assets/js/cyberchat-app.js?v=20260609.10"</span><span class="kw">&gt;&lt;/script&gt;</span>
<span class="kw">&lt;script&gt;</span>CyberChat.init(<span class="str">'#my-chat'</span>);<span class="kw">&lt;/script&gt;</span></div>
</section>
<section class="demo-section">
<div class="demo-label">FULL-SCREEN EMBED</div>
<p class="demo-note">Open the standalone chat inside a full-viewport overlay. An iframe keeps the chat isolated from the host page CSS.</p>
<div class="demo-actions">
<button class="demo-button" id="open-fullscreen" type="button">OPEN FULL SCREEN</button>
</div>
<div class="demo-code"><span class="kw">&lt;div</span> id=<span class="str">"chat-overlay"</span> style=<span class="str">"position:fixed; inset:0; z-index:10000"</span><span class="kw">&gt;</span>
<span class="kw">&lt;iframe</span> src=<span class="str">"/chat/index.html?embed=fullscreen"</span>
title=<span class="str">"CyberChat"</span> style=<span class="str">"width:100%; height:100%; border:0"</span><span class="kw">&gt;&lt;/iframe&gt;</span>
<span class="kw">&lt;/div&gt;</span></div>
</section>
<section class="demo-section">
<div class="demo-label">POPOUT / POPUP EMBED</div>
<p class="demo-note">Launch the standalone chat in a resizable window. The login cookie is shared when it is opened on the same origin.</p>
<div class="demo-actions">
<a class="demo-button alt" id="open-popout" href="index.html?embed=popout"
target="cyberchat-popout" rel="noopener">OPEN POPOUT</a>
</div>
<div class="demo-code"><span class="kw">&lt;button</span> type=<span class="str">"button"</span> onclick=<span class="str">"openCyberChat()"</span><span class="kw">&gt;</span>Open chat<span class="kw">&lt;/button&gt;</span>
<span class="kw">&lt;script&gt;</span>
function openCyberChat() {
window.open(
<span class="str">'/chat/index.html?embed=popout'</span>,
<span class="str">'cyberchat-popout'</span>,
<span class="str">'popup=yes,width=480,height=720,resizable=yes,scrollbars=no'</span>
);
}
<span class="kw">&lt;/script&gt;</span></div>
</section>
</main>
<div class="fullscreen-chat" id="fullscreen-chat" hidden>
<div class="fullscreen-toolbar">
<span>CYBERCHAT // FULL SCREEN</span>
<button class="demo-button" id="close-fullscreen" type="button">CLOSE</button>
</div>
<iframe id="fullscreen-frame" title="CyberChat full-screen example"></iframe>
</div>
<div class="demo-label">▸ LIVE EMBED (580px height, full width)</div>
<script>
window.CYBERCHAT_BASE = '';
</script>
<script src="assets/js/cyberchat-app.js?v=20260609.10"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
CyberChat.init('#chat-here');
<!-- ── This is all you need in your page ── -->
<div id="chat-here"></div>
<div class="demo-code"><span class="cm">&lt;!-- 1. Google Fonts (optional but recommended) --&gt;</span>
<span class="kw">&lt;link</span> href=<span class="str">"https://fonts.googleapis.com/css2?family=Share+Tech+Mono&amp;family=Rajdhani:wght@400;600;700&amp;family=Orbitron:wght@700;900&amp;display=swap"</span> rel=<span class="str">"stylesheet"</span><span class="kw">&gt;</span>
<span class="cm">&lt;!-- 2. CyberChat stylesheet --&gt;</span>
<span class="kw">&lt;link</span> rel=<span class="str">"stylesheet"</span> href=<span class="str">"assets/css/cyberchat.css?v=20260609.4"</span><span class="kw">&gt;</span>
<span class="cm">&lt;!-- 3. Container with any dimensions --&gt;</span>
<span class="kw">&lt;div</span> id=<span class="str">"my-chat"</span> style=<span class="str">"width:100%; height:600px"</span><span class="kw">&gt;&lt;/div&gt;</span>
<span class="cm">&lt;!-- 4. Script + init --&gt;</span>
<span class="kw">&lt;script</span> src=<span class="str">"assets/js/cyberchat-app.js?v=20260609.8"</span><span class="kw">&gt;&lt;/script&gt;</span>
<span class="kw">&lt;script&gt;</span>
window.CYBERCHAT_BASE = <span class="str">'/path/to/cyberchat'</span>; <span class="cm">// adjust to your install path</span>
CyberChat.init(<span class="str">'#my-chat'</span>);
<span class="kw">&lt;/script&gt;</span></div>
</div>
<script>
window.CYBERCHAT_BASE = '';
</script>
<script src="assets/js/cyberchat-app.js?v=20260609.8"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
CyberChat.init('#chat-here');
});
</script>
const overlay = document.getElementById('fullscreen-chat');
const frame = document.getElementById('fullscreen-frame');
document.getElementById('open-fullscreen').addEventListener('click', function() {
if (!frame.src) frame.src = 'index.html?embed=fullscreen';
overlay.hidden = false;
document.body.style.overflow = 'hidden';
});
document.getElementById('close-fullscreen').addEventListener('click', function() {
overlay.hidden = true;
document.body.style.overflow = '';
});
document.getElementById('open-popout').addEventListener('click', function(event) {
const popup = window.open(
'index.html?embed=popout',
'cyberchat-popout',
'popup=yes,width=480,height=720,resizable=yes,scrollbars=no'
);
if (popup) {
event.preventDefault();
popup.focus();
}
});
});
</script>
</body>
</html>