CSS updates (flexbox and theming) and emoji autocomplete

This commit is contained in:
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="chatbox"></div>
<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>
</div>

View file

@ -1,19 +1,40 @@
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) => {
// clear events by just reconstructing the form
const oldChatForm = document.querySelector("#chatbox-send");
const chatForm = oldChatForm.cloneNode(true);
const messageInput = chatForm.querySelector("input");
const emojiAutocomplete = chatForm.querySelector("#emoji-autocomplete");
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) => {
e.preventDefault();
const input = chatForm.querySelector("input");
const content = input.value;
const content = messageInput.value;
if (content.trim().length) {
input.value = "";
messageInput.value = "";
// handle commands
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
*/
export const setupChat = async (socket) => {
document.querySelector("#chatbox-container").style["display"] = "block";
document.querySelector("#chatbox-container").style["display"] = "flex";
setupChatboxEvents(socket);
window.addEventListener("keydown", (event) => {
try {
const isSelectionEmpty = window.getSelection().toString().length === 0;
if (event.code.match(/Key\w/) && isSelectionEmpty)
document.querySelector("#chatbox-send > input").focus();
messageInput.focus();
} catch (_err) {}
});
fixChatSize();
window.addEventListener("resize", () => {
fixChatSize();
});
};
const addToChat = (node) => {
@ -185,7 +187,7 @@ const printChatMessage = (eventType, user, colour, content) => {
if (user != null) {
const userName = document.createElement("strong");
userName.style = `color: #${colour}`;
userName.style = `--user-color: #${colour}`;
userName.textContent = user;
chatMessage.appendChild(userName);
}
@ -327,7 +329,7 @@ export const updateViewerList = (viewers) => {
const viewerElem = document.createElement("div");
const content = document.createElement("strong");
content.textContent = viewer.nickname;
content.style = `color: #${viewer.colour}`;
content.style = `--user-color: #${viewer.colour}`;
viewerElem.appendChild(content);
listContainer.appendChild(viewerElem);
}

View file

@ -9,3 +9,4 @@ export function emojify(text) {
if(last < text.length) nodes.push(document.createTextNode(text.slice(last)))
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) => {
document.querySelector("#pre-join-controls").style["display"] = "none";
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;

View file

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