north-star / commit
added room controls
src/app.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/index.html | 7 ++++++ src/style.css | 47 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/src/app.js b/src/app.js index 14232c4..9abc076 100644 --- a/src/app.js +++ b/src/app.js @@ -11,6 +11,10 @@ const debugParagraph = document.getElementById('debug'); const nameForm = document.getElementById('name-form'); const selfNameInput = document.getElementById('self-name-input'); const selfColorInput = document.getElementById('self-color-input'); +const roomCurrent = document.getElementById('room-current'); +const inviteRoomLink = document.getElementById('invite-room-link'); +const inviteRoomStatus = document.getElementById('invite-room-status'); +const createRoomLink = document.getElementById('create-room-link'); const logDebug = (message) => { debugParagraph.innerText = message; } @@ -84,6 +88,71 @@ if (!roomId) { } console.debug('Room ID:', roomId); +if (roomCurrent) { + roomCurrent.textContent = `You are currently in room ${roomId}`; +} + +const BASE_ROOM_URL = `${window.location.origin}${window.location.pathname}`; +if (inviteRoomLink) { + inviteRoomLink.href = `${BASE_ROOM_URL}#room=${encodeURIComponent(roomId)}`; +} +if (createRoomLink) { + createRoomLink.href = BASE_ROOM_URL; +} + +let inviteStatusTimer = null; +const setInviteStatus = (message, isError = false) => { + if (!inviteRoomStatus) return; + + inviteRoomStatus.textContent = message; + inviteRoomStatus.classList.toggle('error', isError); + + if (inviteStatusTimer) { + clearTimeout(inviteStatusTimer); + } + + inviteStatusTimer = setTimeout(() => { + inviteRoomStatus.textContent = ''; + inviteRoomStatus.classList.remove('error'); + }, 1800); +}; + +const copyTextToClipboard = async (text) => { + if (navigator.clipboard && window.isSecureContext) { + await navigator.clipboard.writeText(text); + return; + } + + const tempTextArea = document.createElement('textarea'); + tempTextArea.value = text; + tempTextArea.setAttribute('readonly', ''); + tempTextArea.style.position = 'fixed'; + tempTextArea.style.left = '-9999px'; + document.body.appendChild(tempTextArea); + tempTextArea.select(); + + const copied = document.execCommand('copy'); + document.body.removeChild(tempTextArea); + + if (!copied) { + throw new Error('Copy command failed'); + } +}; + +if (inviteRoomLink) { + inviteRoomLink.addEventListener('click', async (event) => { + event.preventDefault(); + + try { + await copyTextToClipboard(inviteRoomLink.href); + setInviteStatus('Copied!'); + } catch (err) { + console.error('Failed to copy invite URL', err); + setInviteStatus('Copy failed', true); + } + }); +} + const NAME_STORAGE_KEY = 'north-star-self-name'; const COLOR_STORAGE_KEY = 'north-star-self-color'; const normalizeName = (value) => (value || '').trim().slice(0, 32); diff --git a/src/index.html b/src/index.html index 5551059..b5bee25 100644 --- a/src/index.html +++ b/src/index.html @@ -11,6 +11,13 @@ <body> <p class="app-title"><a href="https://pavelsafronov.gitlab.io/north-star/">North Star</a></p> + <p id="room-current" class="room-current"></p> + <p class="room-links"> + <a id="invite-room-link" href="#">Invite to Room</a> + <span id="invite-room-status" class="room-link-status" aria-live="polite"></span> + + <a id="create-room-link" href="https://pavelsafronov.gitlab.io/north-star/">Create New Room</a> + </p> <form id="name-form" class="name-form" autocomplete="off"> <label for="self-name-input">You</label> <input id="self-name-input" name="selfName" type="text" maxlength="32" enterkeyhint="done" /> diff --git a/src/style.css b/src/style.css index acd6ffa..6af8c78 100644 --- a/src/style.css +++ b/src/style.css @@ -35,6 +35,53 @@ a { text-decoration: none; } +.room-current { + position: fixed; + top: max(50px, calc(env(safe-area-inset-top) + 50px)); + left: 50%; + transform: translateX(-50%); + margin: 0; + z-index: 11; + font-size: clamp(12px, 1.8vmin, 16px); + font-weight: 600; + color: #f8fafc; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); +} + +.room-links { + position: fixed; + top: max(74px, calc(env(safe-area-inset-top) + 74px)); + left: 50%; + transform: translateX(-50%); + margin: 0; + z-index: 11; + display: flex; + align-items: center; + gap: 10px; + font-size: clamp(13px, 2vmin, 18px); + font-weight: 600; +} + +.room-links a { + text-decoration: underline; + text-underline-offset: 0.15em; +} + +.room-links span { + color: rgba(248, 250, 252, 0.8); +} + +.room-link-status { + min-width: 58px; + color: #86efac; + font-size: 0.9em; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); +} + +.room-link-status.error { + color: #fecaca; +} + .name-form { position: fixed; left: 50%;