forked from lavender/watch-party
		
	CSS updates (flexbox and theming) and emoji autocomplete
This commit is contained in:
		
							parent
							
								
									6d57cbc4a1
								
							
						
					
					
						commit
						1e73e0df72
					
				
					 5 changed files with 119 additions and 67 deletions
				
			
		|  | @ -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); | ||||
|   } | ||||
|  |  | |||
|  | @ -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"]) | ||||
|  | @ -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); | ||||
| #emoji-autocomplete { | ||||
|   position: absolute; | ||||
|     height: 100vh; | ||||
|     background-color: black; | ||||
|   } | ||||
|   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 a new issue