CSS updates (flexbox and theming) and emoji autocomplete

easrng 2022-02-14 15:58:59 -05:00
parent 6d57cbc4a1
commit 1e73e0df72
5 changed files with 119 additions and 67 deletions

View File

@ -53,7 +53,8 @@
<div id="viewer-list"></div> <div id="viewer-list"></div>
<div id="chatbox"></div> <div id="chatbox"></div>
<form id="chatbox-send"> <form id="chatbox-send">
<input type="text" placeholder="Message... (/help for commands)" /> <input type="text" placeholder="Message... (/help for commands)" list="emoji-autocomplete" />
<div id="emoji-autocomplete"></div> <!-- DO NOT ADD SPACING INSIDE THE TAG IT WILL BREAK THE CSS kthxbye -->
</form> </form>
</div> </div>

View File

@ -1,19 +1,40 @@
import { setDebounce, setVideoTime, setPlaying } from "./watch-session.mjs?v=9"; import { setDebounce, setVideoTime, setPlaying } from "./watch-session.mjs?v=9";
import { emojify } from "./emojis.mjs?v=9"; import { emojify, emojis } from "./emojis.mjs?v=9";
const setupChatboxEvents = (socket) => { const setupChatboxEvents = (socket) => {
// clear events by just reconstructing the form // clear events by just reconstructing the form
const oldChatForm = document.querySelector("#chatbox-send"); const oldChatForm = document.querySelector("#chatbox-send");
const chatForm = oldChatForm.cloneNode(true); const chatForm = oldChatForm.cloneNode(true);
const messageInput = chatForm.querySelector("input");
const emojiAutocomplete = chatForm.querySelector("#emoji-autocomplete");
oldChatForm.replaceWith(chatForm); oldChatForm.replaceWith(chatForm);
let autocompleting = false;
const replaceMessage = message => () => {
messageInput.value = message;
autocomplete();
}
async function autocomplete(){
if(autocompleting) return;
emojiAutocomplete.textContent = "";
autocompleting = true;
let text = messageInput.value.slice(0, messageInput.selectionStart);
const match = text.match(/(:[^\s:]+)?:[^\s:]*$/);
if(!match || match[1]) return autocompleting = false; // We don't need to autocomplete.
const prefix = text.slice(0, match.index);
const search = text.slice(match.index + 1);
const suffix = messageInput.value.slice(messageInput.selectionStart);
emojiAutocomplete.append(...(await emojis).filter(e => e.toLowerCase().startsWith(search.toLowerCase())).map(e => Object.assign(document.createElement("button"), {className: "emoji-option", textContent: e, onclick: replaceMessage(prefix + ":" + e + ":" + suffix)})))
autocompleting = false;
}
messageInput.addEventListener("input", autocomplete)
chatForm.addEventListener("submit", async (e) => { chatForm.addEventListener("submit", async (e) => {
e.preventDefault(); e.preventDefault();
const content = messageInput.value;
const input = chatForm.querySelector("input");
const content = input.value;
if (content.trim().length) { if (content.trim().length) {
input.value = ""; messageInput.value = "";
// handle commands // handle commands
if (content.startsWith("/")) { if (content.startsWith("/")) {
@ -82,39 +103,20 @@ const setupChatboxEvents = (socket) => {
}); });
}; };
const fixChatSize = () => {
const video = document.querySelector("video");
const chatbox = document.querySelector("#chatbox");
const chatboxContainer = document.querySelector("#chatbox-container");
if (video && chatbox && chatboxContainer) {
const delta = chatboxContainer.clientHeight - chatbox.clientHeight;
chatbox.style["height"] = `calc(${
window.innerHeight - video.clientHeight
}px - ${delta}px - 1em)`;
}
};
/** /**
* @param {WebSocket} socket * @param {WebSocket} socket
*/ */
export const setupChat = async (socket) => { export const setupChat = async (socket) => {
document.querySelector("#chatbox-container").style["display"] = "block"; document.querySelector("#chatbox-container").style["display"] = "flex";
setupChatboxEvents(socket); setupChatboxEvents(socket);
window.addEventListener("keydown", (event) => { window.addEventListener("keydown", (event) => {
try { try {
const isSelectionEmpty = window.getSelection().toString().length === 0; const isSelectionEmpty = window.getSelection().toString().length === 0;
if (event.code.match(/Key\w/) && isSelectionEmpty) if (event.code.match(/Key\w/) && isSelectionEmpty)
document.querySelector("#chatbox-send > input").focus(); messageInput.focus();
} catch (_err) {} } catch (_err) {}
}); });
fixChatSize();
window.addEventListener("resize", () => {
fixChatSize();
});
}; };
const addToChat = (node) => { const addToChat = (node) => {
@ -185,7 +187,7 @@ const printChatMessage = (eventType, user, colour, content) => {
if (user != null) { if (user != null) {
const userName = document.createElement("strong"); const userName = document.createElement("strong");
userName.style = `color: #${colour}`; userName.style = `--user-color: #${colour}`;
userName.textContent = user; userName.textContent = user;
chatMessage.appendChild(userName); chatMessage.appendChild(userName);
} }
@ -327,7 +329,7 @@ export const updateViewerList = (viewers) => {
const viewerElem = document.createElement("div"); const viewerElem = document.createElement("div");
const content = document.createElement("strong"); const content = document.createElement("strong");
content.textContent = viewer.nickname; content.textContent = viewer.nickname;
content.style = `color: #${viewer.colour}`; content.style = `--user-color: #${viewer.colour}`;
viewerElem.appendChild(content); viewerElem.appendChild(content);
listContainer.appendChild(viewerElem); listContainer.appendChild(viewerElem);
} }

View File

@ -8,4 +8,5 @@ export function emojify(text) {
}) })
if(last < text.length) nodes.push(document.createTextNode(text.slice(last))) if(last < text.length) nodes.push(document.createTextNode(text.slice(last)))
return nodes return nodes
} }
export const emojis = Promise.resolve(["blobcat", "blobhaj"])

View File

@ -140,7 +140,9 @@ const createVideoElement = (videoUrl, subtitles) => {
export const setupVideo = async (videoUrl, subtitles, currentTime, playing) => { export const setupVideo = async (videoUrl, subtitles, currentTime, playing) => {
document.querySelector("#pre-join-controls").style["display"] = "none"; document.querySelector("#pre-join-controls").style["display"] = "none";
const video = createVideoElement(videoUrl, subtitles); const video = createVideoElement(videoUrl, subtitles);
document.querySelector("#video-container").appendChild(video); const videoContainer = document.querySelector("#video-container");
videoContainer.style.display = "block";
videoContainer.appendChild(video);
video.currentTime = currentTime / 1000.0; video.currentTime = currentTime / 1000.0;

View File

@ -1,7 +1,15 @@
:root { :root {
--bg: rgb(28, 23, 36); --bg-rgb: 28, 23, 36;
--fg: rgb(234, 234, 248); --fg-rgb: 234, 234, 248;
--accent: hsl(275, 57%, 68%); --accent-rgb: 181, 127, 220;
--fg: rgb(var(--fg-rgb));
--bg: rgb(var(--bg-rgb));
--default-user-color: rgb(126, 208, 255);
--accent: rgb(var(--accent-rgb));
--fg-transparent: rgba(var(--fg-rgb), 0.125);
--bg-transparent: rgba(var(--bg-rgb), 0.125);
--chat-bg: linear-gradient(var(--fg-transparent), var(--fg-transparent)), linear-gradient(var(--bg), var(--bg));
--autocomplete-bg: linear-gradient(var(--fg-transparent), var(--fg-transparent)), linear-gradient(var(--fg-transparent), var(--fg-transparent)), linear-gradient(var(--bg), var(--bg));
} }
html { html {
@ -9,30 +17,34 @@ html {
color: var(--fg); color: var(--fg);
font-size: 1.125rem; font-size: 1.125rem;
font-family: sans-serif; font-family: sans-serif;
overflow-y: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
}
::-webkit-scrollbar {
width: 0;
background: transparent;
} }
html, html,
body { body {
margin: 0; margin: 0;
padding: 0;
overflow: hidden;
overscroll-behavior: none;
width: 100%;
height: 100%;
}
body {
display: flex;
flex-direction: column;
} }
video { video {
display: block; display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
width: 100vw; #video-container {
height: auto; flex-grow: 1;
flex-shrink: 1;
max-width: auto; display: none;
max-height: 100vh;
} }
a { a {
@ -72,7 +84,7 @@ button {
background-color: var(--accent); background-color: var(--accent);
border: var(--accent); border: var(--accent);
border-radius: 6px; border-radius: 6px;
color: #fff; color: var(--fg);
padding: 0.5em 1em; padding: 0.5em 1em;
display: inline-block; display: inline-block;
font-weight: 400; font-weight: 400;
@ -88,6 +100,7 @@ button {
user-select: none; user-select: none;
border: 1px solid rgba(0, 0, 0, 0); border: 1px solid rgba(0, 0, 0, 0);
line-height: 1.5; line-height: 1.5;
cursor: pointer;
} }
button.small-button { button.small-button {
@ -133,8 +146,16 @@ button.small-button {
overflow-wrap: break-word; overflow-wrap: break-word;
} }
.chat-message > strong { .chat-message > strong, #viewer-list strong {
color: rgb(126, 208, 255); color: var(--user-color, var(--default-user-color));
}
@supports (-webkit-background-clip: text) {
.chat-message > strong, #viewer-list strong {
background: linear-gradient(var(--fg-transparent), var(--fg-transparent)), linear-gradient(var(--user-color, var(--default-user-color)), var(--user-color, var(--default-user-color)));
-webkit-background-clip: text;
color: transparent !important;
}
} }
.chat-message.user-join, .chat-message.user-join,
@ -168,27 +189,34 @@ button.small-button {
#chatbox { #chatbox {
padding: 0.5em 2em; padding: 0.5em 2em;
min-height: 8em;
overflow-y: scroll; overflow-y: scroll;
flex-shrink: 1;
flex-grow: 1;
} }
#viewer-list { #viewer-list {
padding: 0.5em 2em; padding: 0.5em 2em;
/* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */ /* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */
height: 4em;
overflow-y: scroll; overflow-y: scroll;
color: rgb(126, 208, 255);
border-bottom: var(--fg); border-bottom: var(--fg);
border-bottom-style: solid; border-bottom-style: solid;
max-height: 4rem;
flex-shrink: 0;
} }
#chatbox-container { #chatbox-container {
background-color: #222; background-image: var(--chat-bg);
flex-direction: column;
flex-grow: 0;
flex-shrink: 1;
flex-basis: 400px;
overflow: hidden;
} }
#chatbox-send { #chatbox-send {
padding: 0 2em; padding: 0 2em;
padding-bottom: 0.5em; padding-bottom: 0.5em;
position: relative;
} }
#chatbox-send > input { #chatbox-send > input {
@ -196,22 +224,40 @@ button.small-button {
width: 100%; width: 100%;
} }
@media (min-aspect-ratio: 4/3) { #emoji-autocomplete {
#video-container video { position: absolute;
width: calc(100vw - 400px); bottom: 3.25rem;
position: absolute; background-image: var(--autocomplete-bg);
height: 100vh; padding: 0.25rem;
background-color: black; border-radius: 6px;
} width: calc(100% - 4.5rem);
}
#video-container { #emoji-autocomplete:empty {
float: left; display: none;
height: 100vh; }
position: relative;
.emoji-option {
background: transparent;
font-size: 0.75rem;
text-align: left;
margin: 0 0 0.25rem;
border-radius: 4px;
width: 100%;
}
.emoji-option:hover, .emoji-option:focus {
background: var(--fg-transparent);
}
.emoji-option:last-child {
margin: 0;
}
@media (min-aspect-ratio: 4/3) {
body {
flex-direction: row;
} }
#chatbox-container { #chatbox-container {
float: right;
width: 400px; width: 400px;
height: 100vh !important; height: 100vh !important;
} }