forked from lavender/watch-party
CSS updates (flexbox and theming) and emoji autocomplete
parent
6d57cbc4a1
commit
1e73e0df72
|
@ -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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ export function emojify(text) {
|
|||
})
|
||||
if(last < text.length) nodes.push(document.createTextNode(text.slice(last)))
|
||||
return nodes
|
||||
}
|
||||
}
|
||||
export const emojis = Promise.resolve(["blobcat", "blobhaj"])
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue