CVNSS commited on
Commit
9215025
·
verified ·
1 Parent(s): 1fef416

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +147 -198
index.html CHANGED
@@ -1,260 +1,209 @@
1
  <!DOCTYPE html>
2
  <html lang="vi">
3
  <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width,initial-scale=1" />
6
- <title>Chat CVNSS4.0</title>
7
- <style>
8
- :root{
9
- --primary:#1a73e8; --bg:#f5f6f8; --text:#202124;
10
- /* Che kín header + ô Join tlk.io (KHÔNG che ô tin nhắn ở đáy) */
11
- --ov-top: clamp(180px, 24vh, 280px); /* nếu còn hở ô Join => tăng giá trị này */
12
- --ov-right: 260px; /* cột phải thường ~240–300px */
13
- }
14
- *{ box-sizing:border-box }
15
- body{
16
- margin:0; font-family: "Google Sans", Arial, sans-serif;
17
- background:var(--bg); color:var(--text);
18
- display:flex; flex-direction:column; min-height:100vh;
19
- }
20
- header{
21
- background:var(--primary); color:#fff; padding:16px; text-align:center;
22
- font-size:20px; font-weight:600; box-shadow:0 2px 6px rgba(0,0,0,.1);
23
- }
24
- .card{
25
- width:min(960px,92vw); margin:24px auto; background:#fff; border-radius:12px;
26
- box-shadow:0 6px 18px rgba(0,0,0,.08); padding:22px;
27
- }
28
- h2{ margin:0 0 10px 0; font-weight:700 }
29
- .subtle{ color:#5f6368; font-size:14px; margin:6px 0 14px }
30
- .row{ display:flex; gap:10px; flex-wrap:wrap; align-items:center }
31
- input[type="text"]{
32
- flex:1 1 260px; padding:12px 14px; font-size:16px;
33
- border:1px solid #dadce0; border-radius:8px;
34
- }
35
- input[type="text"]:focus{ outline:none; border-color:var(--primary) }
36
- button{
37
- padding:12px 18px; border:none; border-radius:8px;
38
- background:var(--primary); color:#fff; font-weight:700; cursor:pointer;
39
- transition: transform .06s ease, filter .12s ease;
40
- }
41
- button:hover{ filter:brightness(0.96) }
42
- button:active{ transform: translateY(1px) }
43
- .btn-red{ background:#d93025; color:#ffeb3b; } /* Vào Chat: nền đỏ, chữ vàng */
44
- .ghost{ background:#e9eef6; color:#174ea6 }
45
- .secondary{ background:#5f6368 }
46
- .mono{ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace }
47
- .muted{ color:#6c727a }
48
- #chat-box{ display:none }
49
- .pill{ display:inline-block; background:#eef3fd; color:#174ea6;
50
- padding:6px 10px; border-radius:999px; font-size:14px; margin-bottom:10px; }
51
- .tag-danger{
52
- display:inline-block; background:#d93025; color:#ffeb3b; font-weight:800;
53
- padding:4px 10px; border-radius:999px; font-size:12px; letter-spacing:.3px;
54
- }
55
- .chat-wrap{ position:relative; border:1px solid #e3e6ea; border-radius:10px; overflow:hidden }
56
- iframe{ width:100%; height:72vh; min-height:520px; border:0; background:#fff }
57
- /* Overlays: che hẳn header + ô Join + cột phải của tlk.io, KHÔNG che đáy */
58
- .ov-top{
59
- position:absolute; left:0; right:0; top:0; height:var(--ov-top);
60
- background:#fff; z-index:3; pointer-events:none;
61
- box-shadow:0 8px 10px -10px rgba(0,0,0,.12);
62
- }
63
- .ov-right{
64
- position:absolute; top:0; right:0; bottom:0; width:var(--ov-right);
65
- background:#fff; z-index:2; pointer-events:none;
66
- box-shadow:-8px 0 10px -10px rgba(0,0,0,.12);
67
- }
68
- /* KHÔNG dùng overlay đáy để không che ô gõ tin nhắn */
69
- .links{ display:none; gap:8px; align-items:center; flex-wrap:wrap; margin-top:12px }
70
- .link-badge{ background:#f1f3f4; padding:6px 8px; border-radius:6px }
71
- .toast{
72
- position:fixed; left:50%; bottom:24px; transform:translateX(-50%);
73
- background:#323232; color:#fff; padding:10px 14px; border-radius:8px; font-size:14px;
74
- opacity:0; pointer-events:none; transition:opacity .2s ease;
75
- }
76
- .toast.show{ opacity:1 }
77
- footer{ margin-top:auto; text-align:center; color:#6c727a; font-size:13px; padding:16px }
78
- ol.guide{ margin:0; padding-left:20px }
79
- ol.guide li{ margin:6px 0 }
80
- @media (max-width:800px){ :root{ --ov-right: 0px } } /* mobile tlk.io thường không có cột phải */
81
- </style>
82
  </head>
83
  <body>
84
  <header>💬 Chat CVNSS4.0</header>
85
 
86
- <!-- Hướng dẫn + form ngoài: luôn dùng form này, không bao giờ dùng Join trong tlk.io -->
87
  <section id="login" class="card">
88
  <h2>Tham gia phòng chat</h2>
89
- <p class="subtle">Luồng 3 bước siêu gọn: nhập tên → <span class="muted">Vào Chat</span> → (tuỳ chọn) tạo phòng bí mật để mời người khác.</p>
90
-
91
  <ol class="guide">
92
- <li><b>Nhập tên</b> của bạn ở ô dưới đây (có thể sửa lại sau).</li>
93
  <li>Nhấn <b>Vào Chat</b> (nút đỏ). <span class="muted">Form Join gốc của tlk.io sẽ bị ẩn hoàn toàn.</span></li>
94
  <li>
95
- <b>✨ Tạo phòng bí mật</b> nếu cần mời người khác (ngẫu nhiên ID + Copy link tự ẩn).
96
- <div style="margin-top:6px">
97
- <span class="muted">Nếu bạn không cần “✨ Tạo phòng bí mật”, hãy <u>bỏ qua bước này</u>.</span>
98
- </div>
99
- <div style="margin-top:8px">
100
- <span class="tag-danger">Vào Chat</span>
101
- </div>
102
  </li>
103
  </ol>
104
 
105
- <div class="row" style="margin-top:12px;">
106
- <input type="text" id="nickname" placeholder="Nhập tên của bạn…" autocomplete="name" />
107
  <button id="joinBtn" class="btn-red">Vào Chat</button>
108
  </div>
109
 
110
- <div class="row" style="margin-top:10px;">
111
- <button class="ghost" id="newRoomBtn">✨ Tạo phòng bí mật</button>
112
- <span class="muted" id="roomHint"></span>
113
  </div>
114
 
115
  <div id="linkArea" class="links" aria-live="polite">
116
  <span>🔗 Link phòng:</span>
117
- <span id="roomUrl" class="link-badge mono"></span>
118
- <button class="secondary" id="copyBtn" title="Copy link để gửi cho mọi người">📋 Copy</button>
119
  </div>
120
  </section>
121
 
122
- <!-- Khối chat -->
123
- <section id="chat-box" class="card">
124
- <span id="roomPill" class="pill"></span>
125
- <div class="chat-wrap">
126
- <div class="ov-top"></div>
127
- <div class="ov-right"></div>
128
- <iframe id="chatFrame" title="tlk.io chat"></iframe>
129
  </div>
 
130
  </section>
131
 
132
- <div id="toast" class="toast" role="status" aria-live="polite">Đã copy link phòng!</div>
133
-
134
- <footer>
135
- Nguồn: Sản phẩm thử nghiệm của Team CVNSS4.0 • Đóng tab là xóa hết dữ liệu ✅
136
- </footer>
137
 
138
  <script>
139
- // ========== Trạng thái & URL ==========
140
- const qs = new URLSearchParams(location.search);
141
- let room = (qs.get("room") || "cvnss4-0").trim().toLowerCase();
142
- const base = `${location.origin}${location.pathname}`;
143
- const els = {
144
- pill: document.getElementById("roomPill"),
145
- login: document.getElementById("login"),
146
- chatBox: document.getElementById("chat-box"),
147
- frame: document.getElementById("chatFrame"),
148
- name: document.getElementById("nickname"),
149
- join: document.getElementById("joinBtn"),
150
- newRoom: document.getElementById("newRoomBtn"),
151
- linkArea: document.getElementById("linkArea"),
152
- roomUrl: document.getElementById("roomUrl"),
153
- copy: document.getElementById("copyBtn"),
154
- toast: document.getElementById("toast"),
155
- hint: document.getElementById("roomHint"),
 
 
 
 
 
156
  };
157
 
158
- // Prefill tên gần đây
159
- const lastName = localStorage.getItem("cvnss4_name") || "";
160
- if (lastName) els.name.value = lastName;
161
- els.name.focus({ preventScroll:true });
162
-
163
- // Gắn label phòng hiện tại
164
- function syncRoomUI(){
165
- els.pill.textContent = "Phòng: " + room;
166
- els.hint.textContent = "(đang ở phòng " + room + ")";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
- syncRoomUI();
169
 
170
- // Toast helper
171
- function toast(msg){
172
- els.toast.textContent = msg;
173
- els.toast.classList.add('show');
174
- setTimeout(()=> els.toast.classList.remove('show'), 1400);
 
 
 
 
175
  }
176
 
177
- // Build URL tlk.io (dựa vào nickname)
178
- function buildTlkUrl(name){
179
- // tlk.io hỗ trợ ?nickname= để auto-join, nhờ vậy không cần form Join gốc
180
- const nick = encodeURIComponent(name || "Guest");
181
- const r = encodeURIComponent(room);
182
- return `https://tlk.io/${r}?nickname=${nick}`;
 
 
183
  }
184
 
185
- // ====== Vào chat: luôn ẩn Join gốc bằng overlay, chỉ dùng form ngoài ======
186
  function enterChat(){
187
- const name = (els.name.value || "").trim() || "Guest";
188
- localStorage.setItem("cvnss4_name", name);
189
  els.login.style.display = "none";
190
  els.chatBox.style.display = "block";
191
- els.frame.src = buildTlkUrl(name);
192
-
193
- // Scroll xuống khối chat cho chắc (mobile)
194
- setTimeout(()=> els.chatBox.scrollIntoView({ behavior:"smooth", block:"start" }), 50);
195
  }
196
 
197
  els.join.addEventListener("click", enterChat);
198
- els.name.addEventListener("keydown", (e)=>{
199
- if (e.key === "Enter") enterChat();
200
- });
201
-
202
- // ====== Tạo phòng bí mật: random id + cập nhật URL + hiện link + copy & ẩn ngay ======
203
- els.newRoom.addEventListener("click", async ()=>{
204
- const rnd = Math.random().toString(36).slice(2, 8);
205
- room = `cvnss4-0-${rnd}`;
206
- const link= `${base}?room=${room}`;
207
 
208
- // Cập nhật UI & URL
 
 
209
  syncRoomUI();
210
  history.replaceState(null, "", `?room=${room}`);
211
 
212
- // Hiện block link
213
  els.roomUrl.textContent = link;
214
  els.linkArea.style.display = "flex";
215
 
216
- // Auto copy ngay khi tạo (nếu quyền cho phép)
217
- try{
218
- if (navigator.clipboard?.writeText) {
219
- await navigator.clipboard.writeText(link);
220
- toast("✅ Link đã copy! Gửi cho mọi người ngay.");
221
- }
222
- }catch(_){ /* bỏ qua */ }
223
 
224
- // Gắn handler Copy (nếu cần copy thủ công lại)
225
- els.copy.onclick = async ()=>{
226
  try{
227
- if (navigator.clipboard?.writeText) {
228
- await navigator.clipboard.writeText(link);
229
- } else {
230
- // Fallback: chọn nội dung để người dùng Ctrl+C
231
- const sel = window.getSelection();
232
- const range = document.createRange();
233
- range.selectNodeContents(els.roomUrl);
234
- sel.removeAllRanges(); sel.addRange(range);
235
- document.execCommand("copy");
236
- sel.removeAllRanges();
237
- }
238
- // Web Share API (không bắt buộc)
239
- if (navigator.share){
240
- try{ await navigator.share({ title:"Phòng chat CVNSS4.0", url:link }); }catch(_){}
241
- }
242
  toast("✅ Đã copy link phòng!");
243
- } catch(e){
244
- toast("⚠️ Sao chép không thành công—hãy copy thủ công");
245
- }
246
- // Ẩn ngay khối link cho gọn
247
  els.linkArea.style.display = "none";
248
  };
 
249
 
250
- // Tự ẩn khối link sau 12 giây nếu quên bấm Copy
251
- setTimeout(()=> {
252
- if (els.linkArea.style.display !== "none") els.linkArea.style.display = "none";
253
- }, 12000);
 
 
254
  });
255
 
256
- // Nếu mở trang bằng link phòng, giữ nguyên: khách nhập tên ở ngoài → Vào Chat
257
- // Không làm thêm để bảo đảm chỉ dùng form ngoài.
 
 
 
 
 
 
258
  </script>
259
  </body>
260
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="vi">
3
  <head>
4
+ <meta charset="utf-8"/>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
6
+ <title>Chat CVNSS4.0</title>
7
+ <style>
8
+ :root{ --bg:#f6f7fb; --text:#202124; --primary:#1a73e8; --danger:#d93025; --accent:#ffeb3b; }
9
+ *{box-sizing:border-box} body{margin:0;font-family:"Google Sans",Arial,sans-serif;background:var(--bg);color:var(--text);display:flex;flex-direction:column;min-height:100vh}
10
+ header{background:var(--primary);color:#fff;padding:14px 16px;text-align:center;font-weight:700;box-shadow:0 2px 6px rgba(0,0,0,.08)}
11
+ .card{width:min(960px,92vw);margin:22px auto;background:#fff;border-radius:12px;box-shadow:0 6px 18px rgba(0,0,0,.08);padding:20px}
12
+ h2{margin:0 0 8px;font-weight:800}
13
+ .muted{color:#5f6368}
14
+ .row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
15
+ input[type=text]{flex:1 1 260px;padding:12px 14px;font-size:16px;border:1px solid #dadce0;border-radius:8px}
16
+ input[type=text]:focus{outline:none;border-color:var(--primary)}
17
+ button{padding:12px 18px;border:0;border-radius:8px;font-weight:800;cursor:pointer}
18
+ .btn-red{background:var(--danger);color:var(--accent)}
19
+ .btn-ghost{background:#e9eef6;color:#174ea6}
20
+ .btn-secondary{background:#5f6368;color:#fff}
21
+ .tag-danger{display:inline-block;background:var(--danger);color:var(--accent);font-weight:900;padding:4px 10px;border-radius:999px;font-size:12px;letter-spacing:.3px}
22
+ .links{display:none;gap:8px;align-items:center;flex-wrap:wrap;margin-top:10px}
23
+ .mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
24
+ .status{display:none;align-items:center;gap:8px;padding:10px 12px;border:1px dashed #e0e3e7;border-radius:10px;margin-bottom:10px;background:#fbfcff}
25
+ .pill{display:inline-block;background:#eef3fd;color:#174ea6;padding:6px 10px;border-radius:999px;font-size:13px}
26
+ .chat-wrap{position:relative;border:1px solid #e3e6ea;border-radius:10px;overflow:hidden}
27
+ /* khung mount cho chat (embed/iframe) */
28
+ #chatMount{min-height:560px}
29
+ iframe{width:100%;height:72vh;min-height:560px;border:0;background:#fff}
30
+ .toast{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);background:#323232;color:#fff;padding:10px 14px;border-radius:8px;font-size:14px;opacity:0;pointer-events:none;transition:opacity .2s}
31
+ .toast.show{opacity:1}
32
+ footer{margin-top:auto;text-align:center;color:#6c727a;font-size:13px;padding:16px}
33
+ ol.guide{margin:0;padding-left:20px} ol.guide li{margin:6px 0}
34
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  </head>
36
  <body>
37
  <header>💬 Chat CVNSS4.0</header>
38
 
 
39
  <section id="login" class="card">
40
  <h2>Tham gia phòng chat</h2>
41
+ <p class="muted">Luồng 3 bước siêu gọn: nhập tên → <b>Vào Chat</b> → (tuỳ chọn) <b>✨ Tạo phòng bí mật</b> để mời người khác.</p>
 
42
  <ol class="guide">
43
+ <li><b>Nhập tên</b> của bạn ở ô dưới đây (có thể đổi sau).</li>
44
  <li>Nhấn <b>Vào Chat</b> (nút đỏ). <span class="muted">Form Join gốc của tlk.io sẽ bị ẩn hoàn toàn.</span></li>
45
  <li>
46
+ <b>✨ Tạo phòng bí mật</b> nếu cần (ID ngẫu nhiên + Copy link tự ẩn).
47
+ <div style="margin-top:6px"><span class="muted">Nếu bạn không cần “✨ Tạo phòng bí mật”, hãy <u>bỏ qua bước này</u>.</span></div>
48
+ <div style="margin-top:8px"><span class="tag-danger">Vào Chat</span></div>
 
 
 
 
49
  </li>
50
  </ol>
51
 
52
+ <div class="row" style="margin-top:12px">
53
+ <input id="nickname" type="text" placeholder="Nhập tên của bạn…" autocomplete="name">
54
  <button id="joinBtn" class="btn-red">Vào Chat</button>
55
  </div>
56
 
57
+ <div class="row" style="margin-top:10px">
58
+ <button id="newRoomBtn" class="btn-ghost">✨ Tạo phòng bí mật</button>
59
+ <span id="roomHint" class="muted"></span>
60
  </div>
61
 
62
  <div id="linkArea" class="links" aria-live="polite">
63
  <span>🔗 Link phòng:</span>
64
+ <span id="roomUrl" class="mono"></span>
65
+ <button id="copyBtn" class="btn-secondary">📋 Copy</button>
66
  </div>
67
  </section>
68
 
69
+ <section id="chatBox" class="card" style="display:none">
70
+ <div class="status" id="statusBar">
71
+ <span class="pill">👤 Bạn: <b id="meName">Guest</b></span>
72
+ <span class="pill">Phòng: <b id="roomPill"></b></span>
73
+ <button id="renameBtn" class="btn-ghost" title="Đổi tên">Đổi tên</button>
74
+ <button id="fallbackBtn" class="btn-secondary" title="Nếu không thấy chat">Dùng chế độ iframe</button>
 
75
  </div>
76
+ <div class="chat-wrap"><div id="chatMount"></div></div>
77
  </section>
78
 
79
+ <div id="toast" class="toast">Đã copy!</div>
80
+ <footer>Nguồn: Sản phẩm thử nghiệm của Team CVNSS4.0 • Đóng tab là xóa hết dữ liệu ✅</footer>
 
 
 
81
 
82
  <script>
83
+ (() => {
84
+ // --------- State & helpers ----------
85
+ const qs = new URLSearchParams(location.search);
86
+ let room = (qs.get("room") || "cvnss4-0").trim().toLowerCase();
87
+ let mode = "embed"; // "embed" (mặc định) -> gọn, không Join; "iframe" là phương án dự phòng
88
+ const els = {
89
+ login: document.getElementById("login"),
90
+ chatBox: document.getElementById("chatBox"),
91
+ chatMount: document.getElementById("chatMount"),
92
+ name: document.getElementById("nickname"),
93
+ join: document.getElementById("joinBtn"),
94
+ newRoom: document.getElementById("newRoomBtn"),
95
+ roomUrl: document.getElementById("roomUrl"),
96
+ linkArea: document.getElementById("linkArea"),
97
+ copy: document.getElementById("copyBtn"),
98
+ toast: document.getElementById("toast"),
99
+ roomHint: document.getElementById("roomHint"),
100
+ status: document.getElementById("statusBar"),
101
+ meName: document.getElementById("meName"),
102
+ roomPill: document.getElementById("roomPill"),
103
+ rename: document.getElementById("renameBtn"),
104
+ fallback: document.getElementById("fallbackBtn"),
105
  };
106
 
107
+ const baseUrl = `${location.origin}${location.pathname}`;
108
+
109
+ function toast(msg){ els.toast.textContent = msg; els.toast.classList.add("show"); setTimeout(()=>els.toast.classList.remove("show"), 1400); }
110
+ function syncRoomUI(){ els.roomHint.textContent = `(đang phòng ${room})`; els.roomPill.textContent = room; }
111
+ function getName(){ return (els.name.value || localStorage.getItem("cvnss4_name") || "Guest").trim() || "Guest"; }
112
+ function setName(n){ els.meName.textContent = n; localStorage.setItem("cvnss4_name", n); }
113
+
114
+ // --------- Chat renderers ----------
115
+ function clearMount(){ els.chatMount.replaceChildren(); }
116
+
117
+ // Prefer embed.js (gọn, không có Join/header)
118
+ function renderEmbed(name){
119
+ clearMount();
120
+ const holder = document.createElement("div");
121
+ holder.id = "tlkio";
122
+ holder.dataset.channel = room;
123
+ holder.dataset.nickname = name;
124
+ holder.dataset.theme = "theme--day";
125
+ holder.style.minHeight = "560px";
126
+ els.chatMount.appendChild(holder);
127
+
128
+ // load/reload embed.js mỗi lần mount (an toàn cho nhiều host)
129
+ const s = document.createElement("script");
130
+ s.async = true; s.src = "https://tlk.io/embed.js";
131
+ s.onerror = () => { mode = "iframe"; renderIframe(name); }; // nếu host chặn script → fallback
132
+ els.chatMount.appendChild(s);
133
  }
 
134
 
135
+ // Fallback: iframe (đi thẳng vào room bằng ?nickname=), không overlay rối rắm
136
+ function renderIframe(name){
137
+ clearMount();
138
+ const url = `https://tlk.io/${encodeURIComponent(room)}?nickname=${encodeURIComponent(name)}#embed`;
139
+ const ifr = document.createElement("iframe");
140
+ ifr.title = "tlk.io chat";
141
+ ifr.src = url;
142
+ ifr.referrerPolicy = "no-referrer";
143
+ els.chatMount.appendChild(ifr);
144
  }
145
 
146
+ function renderChat(){
147
+ const name = getName();
148
+ setName(name);
149
+ syncRoomUI();
150
+ els.status.style.display = "flex";
151
+ if(mode === "embed") renderEmbed(name); else renderIframe(name);
152
+ // cuộn tới chat
153
+ setTimeout(()=> els.chatBox.scrollIntoView({behavior:"smooth", block:"start"}), 50);
154
  }
155
 
156
+ // --------- Actions ----------
157
  function enterChat(){
 
 
158
  els.login.style.display = "none";
159
  els.chatBox.style.display = "block";
160
+ renderChat();
 
 
 
161
  }
162
 
163
  els.join.addEventListener("click", enterChat);
164
+ els.name.addEventListener("keydown", e => { if(e.key === "Enter") enterChat(); });
 
 
 
 
 
 
 
 
165
 
166
+ // Tạo phòng mật
167
+ els.newRoom.addEventListener("click", async () => {
168
+ room = `cvnss4-0-${Math.random().toString(36).slice(2,8)}`;
169
  syncRoomUI();
170
  history.replaceState(null, "", `?room=${room}`);
171
 
172
+ const link = `${baseUrl}?room=${room}`;
173
  els.roomUrl.textContent = link;
174
  els.linkArea.style.display = "flex";
175
 
176
+ // auto copy nếu được cấp quyền
177
+ try{ await navigator.clipboard?.writeText?.(link); toast("✅ Link đã copy!"); }catch(_){}
178
+ // ẩn tự động sau 10s để gọn
179
+ setTimeout(()=>{ if(els.linkArea.style.display!=="none") els.linkArea.style.display="none"; }, 10000);
 
 
 
180
 
181
+ els.copy.onclick = async () => {
 
182
  try{
183
+ await navigator.clipboard?.writeText?.(link);
184
+ if(navigator.share){ try{ await navigator.share({title:"Phòng chat CVNSS4.0", url:link}); }catch(_){} }
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  toast("✅ Đã copy link phòng!");
186
+ }catch(_){ toast("⚠️ Không copy được—hãy copy thủ công"); }
 
 
 
187
  els.linkArea.style.display = "none";
188
  };
189
+ });
190
 
191
+ // Đổi tên nhanh không cần reload
192
+ els.rename.addEventListener("click", () => {
193
+ const cur = getName();
194
+ const n = prompt("Nhập tên mới:", cur) || cur;
195
+ setName(n);
196
+ renderChat();
197
  });
198
 
199
+ // Buộc chuyển sang iframe nếu embed không hiện
200
+ els.fallback.addEventListener("click", () => { mode = "iframe"; renderChat(); });
201
+
202
+ // Prefill
203
+ const lastName = localStorage.getItem("cvnss4_name"); if(lastName) els.name.value = lastName;
204
+ syncRoomUI();
205
+ els.name.focus({preventScroll:true});
206
+ })();
207
  </script>
208
  </body>
209
  </html>