Skip to content

Commit aa64cf7

Browse files
authored
Initialize Collab Pad HTML structure and scripts
This HTML file sets up the Collab Pad interface, including a dual-layer hit counter, connection status, and a collaborative text editor.
1 parent 0440b68 commit aa64cf7

1 file changed

Lines changed: 135 additions & 0 deletions

File tree

collab/index.html

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<script>
5+
// Dual-Layer Hit Counter
6+
(async () => {
7+
const key = 'collab';
8+
const ns = 'rmkr-dev-suite';
9+
const current = parseInt(localStorage.getItem(`stat-${key}`) || "0");
10+
localStorage.setItem(`stat-${key}`, current + 1);
11+
try { await fetch(`https://countapi.it/hit/${ns}/${key}`, { mode: 'no-cors' }); } catch (e) {}
12+
})();
13+
</script>
14+
<meta charset="UTF-8">
15+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
16+
<title>Collab Pad | RMKR Dev</title>
17+
18+
<script src="https://cdn.tailwindcss.com"></script>
19+
<script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
20+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Fira+Code:wght@300..700&display=swap" rel="stylesheet">
21+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" />
22+
23+
<style>
24+
:root {
25+
--color-bg: #0C1524; --color-card: #18233C;
26+
--color-accent: #FFC300; --color-text: #F0F4F8;
27+
--color-line: #2D3748;
28+
}
29+
body { font-family: 'Inter', sans-serif; background-color: var(--color-bg); color: var(--color-text); height: 100vh; overflow: hidden; }
30+
.wrap { max-width: 1200px; margin: 0 auto; padding: 2rem; height: 100%; display: flex; flex-direction: column; }
31+
32+
textarea {
33+
font-family: 'Fira Code', monospace;
34+
background: #080E1A !important;
35+
color: #4ade80 !important;
36+
border: 1px solid var(--color-line);
37+
flex-grow: 1; resize: none; outline: none; padding: 2rem;
38+
border-radius: 12px; font-size: 0.9rem; line-height: 1.6;
39+
}
40+
.status-pill { padding: 4px 12px; border-radius: 20px; font-size: 0.7rem; font-weight: 800; text-transform: uppercase; }
41+
.status-off { background: rgba(239, 68, 68, 0.1); color: #ef4444; }
42+
.status-on { background: rgba(34, 197, 94, 0.1); color: #22c55e; }
43+
</style>
44+
</head>
45+
<body>
46+
47+
<div class="wrap">
48+
<header class="flex justify-between items-center mb-6">
49+
<div>
50+
<h1 class="text-2xl font-bold italic tracking-tighter">COLLAB<span class="text-[--color-accent] not-italic">PAD</span></h1>
51+
<div class="flex items-center gap-2 mt-1">
52+
<span id="connection-status" class="status-pill status-off">Disconnected</span>
53+
<span class="text-[10px] text-gray-500 font-mono">ID: <span id="my-id" class="text-white">loading...</span></span>
54+
</div>
55+
</div>
56+
<div class="flex gap-3">
57+
<input type="text" id="peer-id-input" placeholder="Paste Peer ID to Connect" class="bg-[#080E1A] border border-[--color-line] px-3 py-2 rounded-lg text-xs text-white outline-none focus:border-[--color-accent]">
58+
<button onclick="connectToPeer()" class="bg-[--color-accent] text-[--color-bg] px-4 py-2 rounded-lg font-bold text-xs uppercase">Connect</button>
59+
<a href="../" class="bg-[--color-card] p-2 rounded-lg border border-[--color-line] text-[--color-accent]"><i class="fa-solid fa-house"></i></a>
60+
</div>
61+
</header>
62+
63+
<textarea id="editor" placeholder="Start typing... Everything here is synced with your peer."></textarea>
64+
65+
<footer class="mt-4 flex justify-between items-center text-[10px] text-gray-500 font-bold uppercase tracking-widest">
66+
<span>P2P Encrypted Session</span>
67+
<span id="peer-info">No Peer Connected</span>
68+
</footer>
69+
</div>
70+
71+
<script>
72+
const editor = document.getElementById('editor');
73+
const myIdDisplay = document.getElementById('my-id');
74+
const statusPill = document.getElementById('connection-status');
75+
const peerInfo = document.getElementById('peer-info');
76+
77+
let peer = new Peer(); // Create a new PeerJS instance
78+
let conn = null;
79+
80+
// 1. Initialize My ID
81+
peer.on('open', (id) => {
82+
myIdDisplay.innerText = id;
83+
});
84+
85+
// 2. Handle Incoming Connections
86+
peer.on('connection', (connection) => {
87+
setupConnection(connection);
88+
});
89+
90+
// 3. Connect to a Peer
91+
function connectToPeer() {
92+
const remoteId = document.getElementById('peer-id-input').value;
93+
if (!remoteId) return;
94+
const connection = peer.connect(remoteId);
95+
setupConnection(connection);
96+
}
97+
98+
function setupConnection(connection) {
99+
conn = connection;
100+
101+
conn.on('open', () => {
102+
statusPill.innerText = "Connected";
103+
statusPill.className = "status-pill status-on";
104+
peerInfo.innerText = "Connected to: " + conn.peer;
105+
106+
// Sync current editor state immediately
107+
conn.send(editor.value);
108+
});
109+
110+
conn.on('data', (data) => {
111+
// Update editor when data is received from peer
112+
if (editor.value !== data) {
113+
const selectionStart = editor.selectionStart;
114+
const selectionEnd = editor.selectionEnd;
115+
editor.value = data;
116+
editor.setSelectionRange(selectionStart, selectionEnd);
117+
}
118+
});
119+
}
120+
121+
// 4. Send Data on Input
122+
editor.addEventListener('input', () => {
123+
if (conn && conn.open) {
124+
conn.send(editor.value);
125+
}
126+
});
127+
128+
// Error handling
129+
peer.on('error', (err) => {
130+
console.error(err);
131+
alert("Peer Error: " + err.type);
132+
});
133+
</script>
134+
</body>
135+
</html>

0 commit comments

Comments
 (0)