UI: Context-aware layouts and Smart Invite links (Server-in-URL)

This commit is contained in:
Timo
2026-04-22 09:19:49 +02:00
parent d9e2d6aa77
commit 4db23fc685
2 changed files with 95 additions and 41 deletions
+51 -33
View File
@@ -205,41 +205,59 @@
<!-- Room Tab -->
<div id="tab-room" class="tab-content active">
<div class="form-group">
<label>Server</label>
<div style="display:flex; gap:4px; margin-bottom:8px;">
<button id="serverOfficial" class="tab-btn active" style="flex:1; padding:6px; font-size:11px;">Official</button>
<button id="serverCustom" class="tab-btn" style="flex:1; padding:6px; font-size:11px;">Custom</button>
<!-- JOIN SECTION: Visible when not in a room -->
<div id="section-join">
<div class="form-group">
<label>Server</label>
<div style="display:flex; gap:4px; margin-bottom:8px;">
<button id="serverOfficial" class="tab-btn active" style="flex:1; padding:6px; font-size:11px;">Official</button>
<button id="serverCustom" class="tab-btn" style="flex:1; padding:6px; font-size:11px;">Custom</button>
</div>
<input type="text" id="serverUrl" placeholder="wss://your-server:3000" style="display:none;">
</div>
<input type="text" id="serverUrl" placeholder="wss://your-server:3000" style="display:none;">
</div>
<div class="form-group">
<label>Room ID</label>
<input type="text" id="roomId" placeholder="Leave empty to create">
</div>
<div class="form-group">
<label>Password (Optional)</label>
<input type="password" id="password" placeholder="Room password">
</div>
<div id="roomError" style="display:none; color:var(--error); font-size:11px; margin-bottom:8px; text-align:center;"></div>
<button id="joinBtn" class="primary">Join Room</button>
<button id="createRoomBtn" class="secondary" style="border: 1px solid var(--accent); color: var(--accent);">Create Random Room</button>
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1.5rem; margin-bottom: 8px;">
<label style="margin:0;">Public Rooms</label>
<button id="refreshRooms" style="background:transparent; border:none; color:var(--accent); font-size:10px; cursor:pointer;">REFRESH</button>
</div>
<div id="publicRooms" class="info-card" style="max-height: 120px; overflow-y: auto; padding: 4px;">
<div style="text-align:center; color: var(--text-muted); font-size: 11px; padding: 10px;">Refreshing...</div>
</div>
<div id="roomInfo" style="display:none; margin-top: 20px;">
<label>Invite Link</label>
<div class="invite-box">
<input type="text" id="inviteLink" readonly>
<button id="copyInvite" class="secondary">📋</button>
<div class="form-group">
<label>Room ID</label>
<input type="text" id="roomId" placeholder="Leave empty to create">
</div>
<button id="leaveBtn" class="secondary" style="color: var(--error);">Leave Room</button>
<div class="form-group">
<label>Password (Optional)</label>
<input type="password" id="password" placeholder="Room password">
</div>
<div id="roomError" style="display:none; color:var(--error); font-size:11px; margin-bottom:8px; text-align:center;"></div>
<button id="joinBtn" class="primary">Join Room</button>
<button id="createRoomBtn" class="secondary" style="border: 1px solid var(--accent); color: var(--accent);">Create Random Room</button>
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 1.5rem; margin-bottom: 8px;">
<label style="margin:0;">Public Rooms</label>
<button id="refreshRooms" style="background:transparent; border:none; color:var(--accent); font-size:10px; cursor:pointer;">REFRESH</button>
</div>
<div id="publicRooms" class="info-card" style="max-height: 120px; overflow-y: auto; padding: 4px;">
<div style="text-align:center; color: var(--text-muted); font-size: 11px; padding: 10px;">Refreshing...</div>
</div>
</div>
<!-- ACTIVE SECTION: Visible when in a room -->
<div id="section-active" style="display:none;">
<div class="info-card" style="margin-bottom: 20px;">
<label>Invite Link</label>
<div class="invite-box">
<input type="text" id="inviteLink" readonly>
<button id="copyInvite" class="secondary">📋</button>
</div>
</div>
<div style="margin-bottom: 20px;">
<label>Peers in Room</label>
<div id="peerList" class="info-card">
<div style="text-align:center; color: var(--text-muted); font-size: 12px;">No peers connected</div>
</div>
</div>
<button id="forceSyncBtn" class="primary" style="background: linear-gradient(135deg, #6366f1, #a855f7); margin-bottom: 12px;">
⚡ Force Sync Everyone
</button>
<button id="leaveBtn" class="secondary" style="color: var(--error); border-color: var(--error);">Leave Room</button>
</div>
</div>
+44 -8
View File
@@ -36,7 +36,9 @@ const elements = {
publicRooms: document.getElementById('publicRooms'),
refreshRooms: document.getElementById('refreshRooms'),
roomError: document.getElementById('roomError'),
retryBtn: document.getElementById('retryBtn')
retryBtn: document.getElementById('retryBtn'),
sectionJoin: document.getElementById('section-join'),
sectionActive: document.getElementById('section-active')
};
let localPeerId = null;
@@ -60,7 +62,8 @@ async function init() {
// Populate Tabs
await populateTabs();
updateUI(data.roomId, data.password);
toggleUIState(!!data.roomId);
updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl);
refreshLogs();
refreshHistory();
@@ -81,11 +84,18 @@ async function init() {
}
// --- UI Logic ---
function updateUI(roomId, password) {
function toggleUIState(inRoom) {
if (elements.sectionJoin) elements.sectionJoin.style.display = inRoom ? 'none' : 'block';
if (elements.sectionActive) elements.sectionActive.style.display = inRoom ? 'block' : 'none';
}
function updateUI(roomId, password, useCustomServer = false, serverUrl = '') {
const inRoom = !!roomId;
elements.roomInfo.style.display = inRoom ? 'block' : 'none';
toggleUIState(inRoom);
if (inRoom) {
const invite = `${OFFICIAL_LANDING_PAGE_URL}/join.html#join:${roomId}:${password}`;
const serverFlag = useCustomServer ? '1' : '0';
const encodedUrl = encodeURIComponent(serverUrl || '');
const invite = `${OFFICIAL_LANDING_PAGE_URL}/join.html#join:${roomId}:${password}:${serverFlag}:${encodedUrl}`;
elements.inviteLink.value = invite;
}
}
@@ -250,8 +260,26 @@ function checkInviteLink() {
if (tab && tab.url && tab.url.includes(OFFICIAL_LANDING_PAGE_URL) && tab.url.includes('#join:')) {
const parts = tab.url.split('#join:')[1].split(':');
if (parts.length >= 2) {
elements.roomId.value = parts[0];
elements.password.value = parts[1];
const roomId = parts[0];
const password = parts[1];
let useCustomServer = false;
let serverUrl = '';
// Smart Link: Parse Server Config if present
if (parts.length >= 4) {
useCustomServer = parts[2] === '1';
serverUrl = decodeURIComponent(parts[3]);
}
elements.roomId.value = roomId;
elements.password.value = password;
if (parts.length >= 4) {
elements.serverUrl.value = serverUrl;
setServerMode(useCustomServer);
chrome.storage.sync.set({ serverUrl, useCustomServer });
}
// Visual feedback
elements.joinBtn.style.boxShadow = '0 0 15px var(--accent)';
setTimeout(() => elements.joinBtn.style.boxShadow = '', 2000);
@@ -332,7 +360,10 @@ elements.joinBtn.addEventListener('click', async () => {
// Tell background to connect
chrome.runtime.sendMessage({ type: 'CONNECT' });
updateUI(roomId, password);
// UI Feedback: Immediately switch state for better responsiveness
const data = await chrome.storage.sync.get(['useCustomServer']);
updateUI(roomId, password, data.useCustomServer, serverUrl);
});
elements.leaveBtn.addEventListener('click', async () => {
@@ -421,6 +452,11 @@ chrome.runtime.onMessage.addListener((msg) => {
updateRoomList(msg.rooms);
} else if (msg.type === 'LOG_UPDATE' && msg.log && msg.log.type === 'error') {
showError(msg.log.message);
} else if (msg.type === 'JOIN_STATUS' && msg.success) {
// Final confirmation of join from background
chrome.storage.sync.get(['roomId', 'password', 'useCustomServer', 'serverUrl'], (data) => {
updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl);
});
}
});