Refactor examples into per-app directories with separate HTML, CSS, and JS
- Give each example its own directory: chat/, whiteboard/, sdk-demo/, hrpc-demo/, data-demo/, screenshare/ - Split each into index.html, style.css, and app.js (no inline script/style; CSP-friendly) - Remove old flat files (e.g. chat.html, whiteboard.html, whiteboard.js) - Update README, examples/README, and docs/HRPC to use new paths
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
(function () {
|
||||
const statusEl = document.getElementById('status');
|
||||
const topicEl = document.getElementById('topic');
|
||||
const messageEl = document.getElementById('message');
|
||||
const btnJoin = document.getElementById('btnJoin');
|
||||
const btnLeave = document.getElementById('btnLeave');
|
||||
const btnSend = document.getElementById('btnSend');
|
||||
const peersEl = document.getElementById('peers');
|
||||
const logEl = document.getElementById('log');
|
||||
|
||||
function setStatus(msg, isError) {
|
||||
statusEl.textContent = msg;
|
||||
statusEl.className = 'status' + (isError ? ' error' : '');
|
||||
}
|
||||
|
||||
function log(msg, type) {
|
||||
const line = document.createElement('div');
|
||||
line.className = type || 'sys';
|
||||
line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
|
||||
logEl.appendChild(line);
|
||||
logEl.scrollTop = logEl.scrollHeight;
|
||||
}
|
||||
|
||||
(function initWhenReady(attempts) {
|
||||
if (attempts >= 50) {
|
||||
setStatus('BridgeSwarm extension not detected. Install the extension and reload, or wait a moment and refresh.', true);
|
||||
return;
|
||||
}
|
||||
if (typeof window.BridgeSwarm === 'undefined') {
|
||||
setStatus('Waiting for extension…');
|
||||
setTimeout(function () { initWhenReady(attempts + 1); }, 100);
|
||||
return;
|
||||
}
|
||||
window.BridgeSwarm.ready().then(function () {
|
||||
setStatus('Load the extension, then join a topic. Open this page in another tab or device to chat.');
|
||||
}).catch(function () {
|
||||
setStatus('BridgeSwarm extension not detected.', true);
|
||||
});
|
||||
})(0);
|
||||
|
||||
let swarm = null;
|
||||
const connections = [];
|
||||
|
||||
function updatePeers() {
|
||||
peersEl.textContent = 'Peers: ' + connections.length;
|
||||
}
|
||||
|
||||
btnJoin.addEventListener('click', async () => {
|
||||
if (typeof window.BridgeSwarm === 'undefined') {
|
||||
setStatus('Extension not ready yet. Wait a moment and try again.', true);
|
||||
return;
|
||||
}
|
||||
const topic = topicEl.value.trim() || 'default-topic';
|
||||
if (swarm) return;
|
||||
try {
|
||||
setStatus('Joining topic "' + topic + '"...');
|
||||
swarm = new window.BridgeSwarm({ appName: 'bridge-swarm-chat' });
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
connections.push({ conn, peerInfo });
|
||||
updatePeers();
|
||||
log('Peer connected: ' + (peerInfo.publicKey || '').slice(0, 16) + '…', 'peer');
|
||||
conn.on('data', (data) => {
|
||||
const text = new TextDecoder().decode(data);
|
||||
log('Received: ' + text, 'msg');
|
||||
});
|
||||
conn.on('end', () => {
|
||||
const i = connections.findIndex(c => c.conn === conn);
|
||||
if (i !== -1) connections.splice(i, 1);
|
||||
updatePeers();
|
||||
log('Peer left', 'sys');
|
||||
});
|
||||
conn.on('error', (err) => log('Peer error: ' + err.message, 'err'));
|
||||
});
|
||||
await swarm.join(topic);
|
||||
setStatus('Joined "' + topic + '". Send a message or open this page in another tab.');
|
||||
btnJoin.disabled = true;
|
||||
btnLeave.disabled = false;
|
||||
messageEl.disabled = false;
|
||||
btnSend.disabled = false;
|
||||
log('Joined topic: ' + topic, 'sys');
|
||||
} catch (err) {
|
||||
setStatus('Error: ' + err.message, true);
|
||||
log('Error: ' + err.message, 'err');
|
||||
}
|
||||
});
|
||||
|
||||
btnLeave.addEventListener('click', async () => {
|
||||
if (!swarm) return;
|
||||
try {
|
||||
const topic = topicEl.value.trim() || 'default-topic';
|
||||
await swarm.leave(topic);
|
||||
await swarm.destroy();
|
||||
connections.length = 0;
|
||||
updatePeers();
|
||||
swarm = null;
|
||||
setStatus('Left topic. You can join again.');
|
||||
btnJoin.disabled = false;
|
||||
btnLeave.disabled = true;
|
||||
messageEl.disabled = true;
|
||||
btnSend.disabled = true;
|
||||
log('Left topic', 'sys');
|
||||
} catch (err) {
|
||||
log('Error: ' + err.message, 'err');
|
||||
}
|
||||
});
|
||||
|
||||
function sendMessage() {
|
||||
const text = messageEl.value.trim();
|
||||
if (!text || !swarm || connections.length === 0) return;
|
||||
const data = new TextEncoder().encode(text);
|
||||
connections.forEach(({ conn }) => {
|
||||
try { conn.write(data); } catch (e) {}
|
||||
});
|
||||
log('Sent: ' + text, 'msg');
|
||||
messageEl.value = '';
|
||||
}
|
||||
|
||||
btnSend.addEventListener('click', sendMessage);
|
||||
messageEl.addEventListener('keydown', (e) => { if (e.key === 'Enter') sendMessage(); });
|
||||
})();
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BridgeSwarm – Chat</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>BridgeSwarm – Chat</h1>
|
||||
<p class="status" id="status">Load the extension, then join a topic. Open this page in another tab or device to chat.</p>
|
||||
<div class="row">
|
||||
<input type="text" id="topic" placeholder="Topic (e.g. my-chat-room)" value="bridge-swarm-demo">
|
||||
<button class="primary" id="btnJoin">Join</button>
|
||||
<button class="danger" id="btnLeave" disabled>Leave</button>
|
||||
</div>
|
||||
<div class="peers" id="peers">Peers: 0</div>
|
||||
<div class="row">
|
||||
<input type="text" id="message" placeholder="Type a message..." disabled>
|
||||
<button class="primary" id="btnSend" disabled>Send</button>
|
||||
</div>
|
||||
<div class="log" id="log"></div>
|
||||
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
max-width: 560px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
background: #1a1b26;
|
||||
color: #c0caf5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
h1 { font-size: 1.25rem; margin: 0 0 1rem; color: #7aa2f7; }
|
||||
.row { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; align-items: center; }
|
||||
input[type="text"] {
|
||||
flex: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border: 1px solid #3b4261;
|
||||
border-radius: 6px;
|
||||
background: #24283b;
|
||||
color: #c0caf5;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
input::placeholder { color: #565f89; }
|
||||
button {
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
button.primary { background: #7aa2f7; color: #1a1b26; }
|
||||
button.primary:hover { background: #89b4fa; }
|
||||
button.primary:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
button.danger { background: #f7768e; color: #1a1b26; }
|
||||
button.danger:hover { background: #ff9db5; }
|
||||
.status {
|
||||
font-size: 0.85rem;
|
||||
color: #9ece6a;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.status.error { color: #f7768e; }
|
||||
.log {
|
||||
background: #24283b;
|
||||
border: 1px solid #3b4261;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
height: 220px;
|
||||
overflow-y: auto;
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.4;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.log .peer { color: #bb9af7; }
|
||||
.log .msg { color: #9ece6a; }
|
||||
.log .sys { color: #7aa2f7; }
|
||||
.log .err { color: #f7768e; }
|
||||
.peers { font-size: 0.85rem; color: #a9b1d6; margin-bottom: 0.5rem; }
|
||||
Reference in New Issue
Block a user