From bcd36e2269cd7f505860e62f83ab0b74567336e4 Mon Sep 17 00:00:00 2001 From: Kay Date: Sat, 28 Jan 2023 15:04:05 +0100 Subject: [PATCH] add options pane, add ping volume and hide player controls settings --- frontend/index.html | 57 ++- frontend/lib/options-pane.mjs | 43 ++ frontend/lib/pling.mjs | 162 ++++--- frontend/lib/watch-session.mjs | 1 - frontend/main.mjs | 8 + frontend/styles.css | 862 ++++++++++++++++++--------------- 6 files changed, 644 insertions(+), 489 deletions(-) create mode 100644 frontend/lib/options-pane.mjs diff --git a/frontend/index.html b/frontend/index.html index 8ff978d..be3741f 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -53,17 +53,52 @@
-
-
-
- -
- -
+
+
+
+
+ +
+ +
+
+
+

settings

+
+
+ + +
+
+
+ +
diff --git a/frontend/lib/options-pane.mjs b/frontend/lib/options-pane.mjs new file mode 100644 index 0000000..1efb066 --- /dev/null +++ b/frontend/lib/options-pane.mjs @@ -0,0 +1,43 @@ +export const toggleOptionPane = (event, element) => { + event.preventDefault(); + // show options + if ( + !document.querySelector("#options").style.display || + document.querySelector("#options").style.display === "none" + ) { + // using this to do any potential init logic for the fields too + loadPlayerControlsShown(document.querySelector("#playerControlsShown")) + loadPlingVolume(document.querySelector("#plingVolume")) + + element.innerText = "❌"; + document.querySelector("#options").style.display = "block"; + return (document.querySelector("#viewing").style.display = "none"); + } + // hide options + element.innerText = "⚙️"; + document.querySelector("#options").style.display = "none"; + document.querySelector("#viewing").style.display = "block"; +}; + +const getPlayerControlsShown = () => localStorage.getItem("watch-party-default-allow-controls") || false +// delete from storage on false to prevent weird js boolean parsing (Boolean('false') === True) +const setPlayerControlShown = (boolean) => !boolean +? localStorage.removeItem("watch-party-default-allow-controls") +: localStorage.setItem("watch-party-default-allow-controls", boolean) +export const togglePlayerControlsShown = (element) => { + const isShown = element.checked + setPlayerControlShown(!isShown) +} +const loadPlayerControlsShown = (element) => { + const isShown = getPlayerControlsShown() + element.checked = !isShown +} + +const getPlingVolume = () => localStorage.getItem("watch-party-pling-volume") || 100 +const setPlingVolume = (value) => localStorage.setItem("watch-party-pling-volume", value) +export const handlePlingVolume = (element) => { + setPlingVolume(element.value) +} +const loadPlingVolume = (element) => { + element.value = getPlingVolume() +} diff --git a/frontend/lib/pling.mjs b/frontend/lib/pling.mjs index 9305dfb..d332613 100644 --- a/frontend/lib/pling.mjs +++ b/frontend/lib/pling.mjs @@ -1,80 +1,82 @@ -export const pling = () => { - const maxGain = 0.3; - const duration = 0.22; - const fadeDuration = 0.1; - const secondBeepOffset = 0.05; - const thirdBeepOffset = 2 * secondBeepOffset; - - const ctx = new AudioContext(); - - const firstBeepGain = ctx.createGain(); - firstBeepGain.connect(ctx.destination); - firstBeepGain.gain.setValueAtTime(0.01, ctx.currentTime); - firstBeepGain.gain.exponentialRampToValueAtTime( - maxGain, - ctx.currentTime + fadeDuration - ); - firstBeepGain.gain.setValueAtTime( - maxGain, - ctx.currentTime + (duration - fadeDuration) - ); - firstBeepGain.gain.exponentialRampToValueAtTime( - 0.01, - ctx.currentTime + duration - ); - - const firstBeep = ctx.createOscillator(); - firstBeep.connect(firstBeepGain); - firstBeep.frequency.value = 400; - firstBeep.type = "sine"; - - const secondBeepGain = ctx.createGain(); - secondBeepGain.connect(ctx.destination); - secondBeepGain.gain.setValueAtTime(0.01, ctx.currentTime + secondBeepOffset); - secondBeepGain.gain.exponentialRampToValueAtTime( - maxGain, - ctx.currentTime + secondBeepOffset + fadeDuration - ); - secondBeepGain.gain.setValueAtTime( - maxGain, - ctx.currentTime + secondBeepOffset + (duration - fadeDuration) - ); - secondBeepGain.gain.exponentialRampToValueAtTime( - 0.01, - ctx.currentTime + secondBeepOffset + duration - ); - - const secondBeep = ctx.createOscillator(); - secondBeep.connect(secondBeepGain); - secondBeep.frequency.value = 600; - secondBeep.type = "sine"; - - const thirdBeepGain = ctx.createGain(); - thirdBeepGain.connect(ctx.destination); - thirdBeepGain.gain.setValueAtTime(0.01, ctx.currentTime + thirdBeepOffset); - thirdBeepGain.gain.exponentialRampToValueAtTime( - maxGain, - ctx.currentTime + thirdBeepOffset + fadeDuration - ); - thirdBeepGain.gain.setValueAtTime( - maxGain, - ctx.currentTime + thirdBeepOffset + (duration - fadeDuration) - ); - thirdBeepGain.gain.exponentialRampToValueAtTime( - 0.01, - ctx.currentTime + thirdBeepOffset + duration - ); - - const thirdBeep = ctx.createOscillator(); - thirdBeep.connect(thirdBeepGain); - thirdBeep.frequency.value = 900; - thirdBeep.type = "sine"; - - firstBeep.start(ctx.currentTime); - firstBeep.stop(ctx.currentTime + duration); - secondBeep.start(ctx.currentTime + secondBeepOffset); - secondBeep.stop(ctx.currentTime + (secondBeepOffset + duration)); - thirdBeep.start(ctx.currentTime + thirdBeepOffset); - thirdBeep.stop(ctx.currentTime + (thirdBeepOffset + duration)); -}; - +export const pling = () => { + // technically volume 0 breaks it but its the wanted outcome i guess? + const maxGain = + (Number(localStorage.getItem("watch-party-pling-volume")) / 100 ?? 1) * 0.3; + + const duration = 0.22; + const fadeDuration = 0.1; + const secondBeepOffset = 0.05; + const thirdBeepOffset = 2 * secondBeepOffset; + + const ctx = new AudioContext(); + + const firstBeepGain = ctx.createGain(); + firstBeepGain.connect(ctx.destination); + firstBeepGain.gain.setValueAtTime(0.01, ctx.currentTime); + firstBeepGain.gain.exponentialRampToValueAtTime( + maxGain, + ctx.currentTime + fadeDuration + ); + firstBeepGain.gain.setValueAtTime( + maxGain, + ctx.currentTime + (duration - fadeDuration) + ); + firstBeepGain.gain.exponentialRampToValueAtTime( + 0.01, + ctx.currentTime + duration + ); + + const firstBeep = ctx.createOscillator(); + firstBeep.connect(firstBeepGain); + firstBeep.frequency.value = 400; + firstBeep.type = "sine"; + + const secondBeepGain = ctx.createGain(); + secondBeepGain.connect(ctx.destination); + secondBeepGain.gain.setValueAtTime(0.01, ctx.currentTime + secondBeepOffset); + secondBeepGain.gain.exponentialRampToValueAtTime( + maxGain, + ctx.currentTime + secondBeepOffset + fadeDuration + ); + secondBeepGain.gain.setValueAtTime( + maxGain, + ctx.currentTime + secondBeepOffset + (duration - fadeDuration) + ); + secondBeepGain.gain.exponentialRampToValueAtTime( + 0.01, + ctx.currentTime + secondBeepOffset + duration + ); + + const secondBeep = ctx.createOscillator(); + secondBeep.connect(secondBeepGain); + secondBeep.frequency.value = 600; + secondBeep.type = "sine"; + + const thirdBeepGain = ctx.createGain(); + thirdBeepGain.connect(ctx.destination); + thirdBeepGain.gain.setValueAtTime(0.01, ctx.currentTime + thirdBeepOffset); + thirdBeepGain.gain.exponentialRampToValueAtTime( + maxGain, + ctx.currentTime + thirdBeepOffset + fadeDuration + ); + thirdBeepGain.gain.setValueAtTime( + maxGain, + ctx.currentTime + thirdBeepOffset + (duration - fadeDuration) + ); + thirdBeepGain.gain.exponentialRampToValueAtTime( + 0.01, + ctx.currentTime + thirdBeepOffset + duration + ); + + const thirdBeep = ctx.createOscillator(); + thirdBeep.connect(thirdBeepGain); + thirdBeep.frequency.value = 900; + thirdBeep.type = "sine"; + + firstBeep.start(ctx.currentTime); + firstBeep.stop(ctx.currentTime + duration); + secondBeep.start(ctx.currentTime + secondBeepOffset); + secondBeep.stop(ctx.currentTime + (secondBeepOffset + duration)); + thirdBeep.start(ctx.currentTime + thirdBeepOffset); + thirdBeep.stop(ctx.currentTime + (thirdBeepOffset + duration)); +}; diff --git a/frontend/lib/watch-session.mjs b/frontend/lib/watch-session.mjs index 4cdeb04..f2c6820 100644 --- a/frontend/lib/watch-session.mjs +++ b/frontend/lib/watch-session.mjs @@ -228,7 +228,6 @@ export const joinSession = async () => { is_playing ); - // TODO: Allow the user to set this somewhere let defaultAllowControls = false; try { defaultAllowControls = localStorage.getItem( diff --git a/frontend/main.mjs b/frontend/main.mjs index 04b0b44..bef1c87 100644 --- a/frontend/main.mjs +++ b/frontend/main.mjs @@ -1,7 +1,15 @@ import { setupJoinSessionForm } from "./lib/join-session.mjs?v=bfdcf2"; +import { + toggleOptionPane, + togglePlayerControlsShown, + handlePlingVolume +} from "./lib/options-pane.mjs?v=bfdcf2"; const main = () => { setupJoinSessionForm(); + window.toggleOptionPane = toggleOptionPane; + window.togglePlayerControlsShown = togglePlayerControlsShown; + window.handlePlingVolume = handlePlingVolume }; if (document.readyState === "complete") { diff --git a/frontend/styles.css b/frontend/styles.css index 0c08cc9..61e44b9 100644 --- a/frontend/styles.css +++ b/frontend/styles.css @@ -1,397 +1,465 @@ -*, -*:before, -*:after { - box-sizing: border-box; -} - -:root { - --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.25); - --bg-transparent: rgba(var(--bg-rgb), 0.25); - --autocomplete-bg: linear-gradient( - var(--fg-transparent), - var(--fg-transparent) - ), - linear-gradient(var(--bg), var(--bg)); - --chip-bg: linear-gradient( - var(--accent-transparent), - var(--accent-transparent) - ), - linear-gradient(var(--bg), var(--bg)); - --accent-transparent: rgba(var(--accent-rgb), 0.25); -} - -html { - background-color: var(--bg); - color: var(--fg); - font-size: 1.125rem; - font-family: sans-serif; -} - -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; -} - -#video-container { - flex-grow: 0; - flex-shrink: 1; - display: none; -} - -a { - color: var(--accent); -} - -.chip { - color: var(--fg); - background: var(--chip-bg); - text-decoration: none; - padding: 0 0.5rem 0 1.45rem; - display: inline-flex; - position: relative; - font-size: 0.9rem; - height: 1.125rem; - align-items: center; - border-radius: 2rem; - overflow: hidden; -} - -.chip::before { - content: ""; - position: absolute; - left: 0; - top: 0; - width: 1.125rem; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - text-align: center; - background: var(--accent-transparent); - background-repeat: no-repeat; - background-size: 18px; - background-position: center; -} - -.join-chip::before { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTggNXYxNGwxMS03eiIvPjwvc3ZnPg=="); -} - -.time-chip::before { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTExLjk5IDJDNi40NyAyIDIgNi40OCAyIDEyczQuNDcgMTAgOS45OSAxMEMxNy41MiAyMiAyMiAxNy41MiAyMiAxMlMxNy41MiAyIDExLjk5IDJ6TTEyIDIwYy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz48cGF0aCBkPSJNMTIuNSA3SDExdjZsNS4yNSAzLjE1Ljc1LTEuMjMtNC41LTIuNjd6Ii8+PC9zdmc+"); -} - -label { - display: block; -} - -input[type="url"], -input[type="text"] { - background: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 6px; - color: rgba(0, 0, 0, 0.8); - display: block; - - margin: 0.5em 0; - padding: 0.5em 1em; - line-height: 1.5; - - font-family: sans-serif; - font-size: 1em; - width: 100%; - - resize: none; - overflow-x: wrap; - overflow-y: scroll; -} - -button { - background-color: var(--accent); - border: var(--accent); - border-radius: 6px; - color: #fff; - padding: 0.5em 1em; - display: inline-block; - font-weight: 400; - text-align: center; - white-space: nowrap; - vertical-align: middle; - - font-family: sans-serif; - font-size: 1em; - width: 100%; - - user-select: none; - border: 1px solid rgba(0, 0, 0, 0); - line-height: 1.5; - cursor: pointer; - margin: 0.5em 0; -} - -button:disabled { - filter: saturate(0.75); - opacity: 0.75; - cursor: default; -} - -button.small-button { - font-size: 0.75em; - padding-top: 0; - padding-bottom: 0; -} - -.subtitle-track-group { - display: flex; -} - -.subtitle-track-group > * { - margin-top: 0 !important; - margin-bottom: 0 !important; - margin-right: 1ch !important; -} - -#pre-join-controls, -#create-controls { - margin: 0; - flex-grow: 1; - overflow-y: auto; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -#join-session-form, -#create-session-form { - width: 500px; - max-width: 100%; - padding: 1rem; -} - -#join-session-form > *:first-child, -#create-session-form > *:first-child { - margin-top: 0; -} - -#post-create-message { - display: none; - width: 100%; - font-size: 0.85em; -} - -#chatbox-container { - display: none; -} - -.chat-message { - overflow-wrap: break-word; - margin-bottom: 0.125rem; -} - -.chat-message > strong, -#viewer-list strong { - color: var(--user-color, var(--default-user-color)); -} - -.chat-message.user-join, -.chat-message.user-leave, -.chat-message.ping { - font-style: italic; -} - -.chat-message.set-time, -.chat-message.set-playing, -.chat-message.join-session { - font-style: italic; - text-align: right; - font-size: 0.85em; -} - -.chat-message.command-message { - font-size: 0.85em; -} - -.chat-message.set-time > strong, -.chat-message.set-playing > strong, -.chat-message.join-session > strong { - color: unset !important; -} - -.emoji { - width: 2ch; - height: 2ch; - object-fit: contain; - margin-bottom: -0.35ch; -} - -#chatbox { - padding: 0.5em 1em; - overflow-y: scroll; - flex-shrink: 1; - flex-grow: 1; -} - -#viewer-list { - padding: 0.5em 1em; - /* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */ - overflow-y: scroll; - border-bottom: var(--fg-transparent); - border-bottom-style: solid; - max-height: 4rem; - flex-shrink: 0; -} - -#chatbox-container { - background-color: var(--bg); - flex-direction: column; - flex-grow: 1; - flex-shrink: 1; - flex-basis: 36ch; - min-width: 36ch; - overflow: hidden; -} - -#chatbox-send { - padding: 0 1em; - padding-bottom: 0.5em; - position: relative; -} - -#chatbox-send > input { - font-size: 0.75em; - width: 100%; -} - -#emoji-autocomplete { - position: absolute; - bottom: 3.25rem; - background-image: var(--autocomplete-bg); - border-radius: 6px; - width: calc(100% - 2rem); - max-height: 8.5rem; - overflow-y: auto; - clip-path: inset(0 0 0 0 round 8px); -} - -#emoji-autocomplete:empty { - display: none; -} - -.emoji-option { - background: transparent; - font-size: 0.75rem; - text-align: left; - margin: 0 0.25rem; - border-radius: 4px; - width: calc(100% - 0.5rem); - display: flex; - align-items: center; - padding: 0.25rem 0.5rem; - scroll-margin: 0.25rem; -} - -.emoji-option:first-child { - margin-top: 0.25rem; -} - -.emoji-option:last-child { - margin-bottom: 0.25rem; -} - -.emoji-option .emoji { - width: 1.25rem; - height: 1.25rem; - margin: 0 0.5rem 0 0; - font-size: 2.25ch; - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - flex-shrink: 0; -} - -.emoji-name { - overflow: hidden; - text-overflow: ellipsis; -} - -.emoji-option.selected { - background: var(--fg-transparent); -} - -#join-session-colour { - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; - border: none; - padding: 0; - border-radius: 6px; - overflow: hidden; - margin: 0.5em 0; - height: 2rem; - width: 2.5rem; - cursor: pointer; -} - -input[type="color"]::-moz-color-swatch { - border: none; - margin: 0; - padding: 0; -} - -input[type="color"]::-webkit-color-swatch { - border: none; - margin: 0; - padding: 0; -} - -input[type="color"]::-webkit-color-swatch-wrapper { - border: none; - margin: 0; - padding: 0; -} - -@media (min-aspect-ratio: 4/3) { - body { - flex-direction: row; - } - - #chatbox-container { - height: 100vh !important; - flex-grow: 0; - } - - #video-container { - flex-grow: 1; - } - - #chatbox { - height: calc(100vh - 5em - 4em) !important; - } -} +*, +*:before, +*:after { + box-sizing: border-box; +} + +:root { + --bg-rgb: 28, 23, 36; + --fg-rgb: 234, 234, 248; + --accent-rgb: 181, 127, 220; + --accent-darker: rgb(95, 37, 136); /*50% darker*/ + --accent-darkest: rgb(47, 19, 68); /*75% darker*/ + --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.25); + --bg-transparent: rgba(var(--bg-rgb), 0.25); + --autocomplete-bg: linear-gradient( + var(--fg-transparent), + var(--fg-transparent) + ), + linear-gradient(var(--bg), var(--bg)); + --chip-bg: linear-gradient( + var(--accent-transparent), + var(--accent-transparent) + ), + linear-gradient(var(--bg), var(--bg)); + --accent-transparent: rgba(var(--accent-rgb), 0.25); +} + +html { + background-color: var(--bg); + color: var(--fg); + font-size: 1.125rem; + font-family: sans-serif; +} + +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; +} + +#video-container { + flex-grow: 0; + flex-shrink: 1; + display: none; +} + +a { + color: var(--accent); +} + +.chip { + color: var(--fg); + background: var(--chip-bg); + text-decoration: none; + padding: 0 0.5rem 0 1.45rem; + display: inline-flex; + position: relative; + font-size: 0.9rem; + height: 1.125rem; + align-items: center; + border-radius: 2rem; + overflow: hidden; +} + +.chip::before { + content: ""; + position: absolute; + left: 0; + top: 0; + width: 1.125rem; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + background: var(--accent-transparent); + background-repeat: no-repeat; + background-size: 18px; + background-position: center; +} + +.join-chip::before { + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTggNXYxNGwxMS03eiIvPjwvc3ZnPg=="); +} + +.time-chip::before { + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTExLjk5IDJDNi40NyAyIDIgNi40OCAyIDEyczQuNDcgMTAgOS45OSAxMEMxNy41MiAyMiAyMiAxNy41MiAyMiAxMlMxNy41MiAyIDExLjk5IDJ6TTEyIDIwYy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz48cGF0aCBkPSJNMTIuNSA3SDExdjZsNS4yNSAzLjE1Ljc1LTEuMjMtNC41LTIuNjd6Ii8+PC9zdmc+"); +} + +label { + display: block; +} + +input[type="url"], +input[type="text"] { + background: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + color: rgba(0, 0, 0, 0.8); + display: block; + + margin: 0.5em 0; + padding: 0.5em 1em; + line-height: 1.5; + + font-family: sans-serif; + font-size: 1em; + width: 100%; + + resize: none; + overflow-x: wrap; + overflow-y: scroll; +} + +button { + background-color: var(--accent); + border: var(--accent); + border-radius: 6px; + color: #fff; + padding: 0.5em 1em; + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + + font-family: sans-serif; + font-size: 1em; + width: 100%; + + user-select: none; + border: 1px solid rgba(0, 0, 0, 0); + line-height: 1.5; + cursor: pointer; + margin: 0.5em 0; +} + +button:disabled { + filter: saturate(0.75); + opacity: 0.75; + cursor: default; +} + +button.small-button { + font-size: 0.75em; + padding-top: 0; + padding-bottom: 0; +} + +.subtitle-track-group { + display: flex; +} + +.subtitle-track-group > * { + margin-top: 0 !important; + margin-bottom: 0 !important; + margin-right: 1ch !important; +} + +#pre-join-controls, +#create-controls { + margin: 0; + flex-grow: 1; + overflow-y: auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +#join-session-form, +#create-session-form { + width: 500px; + max-width: 100%; + padding: 1rem; +} + +#join-session-form > *:first-child, +#create-session-form > *:first-child { + margin-top: 0; +} + +#post-create-message { + display: none; + width: 100%; + font-size: 0.85em; +} + +#chatbox-container { + display: none; +} + +.chat-message { + overflow-wrap: break-word; + margin-bottom: 0.125rem; +} + +.chat-message > strong, +#viewer-list strong { + color: var(--user-color, var(--default-user-color)); +} + +.chat-message.user-join, +.chat-message.user-leave, +.chat-message.ping { + font-style: italic; +} + +.chat-message.set-time, +.chat-message.set-playing, +.chat-message.join-session { + font-style: italic; + text-align: right; + font-size: 0.85em; +} + +.chat-message.command-message { + font-size: 0.85em; +} + +.chat-message.set-time > strong, +.chat-message.set-playing > strong, +.chat-message.join-session > strong { + color: unset !important; +} + +.emoji { + width: 2ch; + height: 2ch; + object-fit: contain; + margin-bottom: -0.35ch; +} + +#chatbox { + padding: 0.5em 1em; + overflow-y: scroll; + flex-shrink: 1; + flex-grow: 1; +} + +#viewer-list { + padding: 0.5em 1em; + /* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */ + overflow-y: scroll; + border-bottom: var(--fg-transparent); + border-bottom-style: solid; + max-height: 4rem; + flex-shrink: 0; +} + +#chatbox-container { + background-color: var(--bg); + flex-direction: column; + flex-grow: 1; + flex-shrink: 1; + flex-basis: 36ch; + min-width: 36ch; + overflow: hidden; +} + +#chatbox-send { + padding: 0 1em; + position: relative; +} + +#chatbox-send > input { + font-size: 0.75em; + width: 100%; +} + +#emoji-autocomplete { + position: absolute; + bottom: 3.25rem; + background-image: var(--autocomplete-bg); + border-radius: 6px; + width: calc(100% - 2rem); + max-height: 8.5rem; + overflow-y: auto; + clip-path: inset(0 0 0 0 round 8px); +} + +#emoji-autocomplete:empty { + display: none; +} + +.emoji-option { + background: transparent; + font-size: 0.75rem; + text-align: left; + margin: 0 0.25rem; + border-radius: 4px; + width: calc(100% - 0.5rem); + display: flex; + align-items: center; + padding: 0.25rem 0.5rem; + scroll-margin: 0.25rem; +} + +.emoji-option:first-child { + margin-top: 0.25rem; +} + +.emoji-option:last-child { + margin-bottom: 0.25rem; +} + +.emoji-option .emoji { + width: 1.25rem; + height: 1.25rem; + margin: 0 0.5rem 0 0; + font-size: 2.25ch; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + flex-shrink: 0; +} + +.emoji-name { + overflow: hidden; + text-overflow: ellipsis; +} + +.emoji-option.selected { + background: var(--fg-transparent); +} + +#join-session-colour { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + border: none; + padding: 0; + border-radius: 6px; + overflow: hidden; + margin: 0.5em 0; + height: 2rem; + width: 2.5rem; + cursor: pointer; +} + +#options-toggle { + padding: 0 1em 1em; + position: relative; + text-align: right; + margin-top: auto; +} + +#options-toggle #options-icon { + padding: 3px 10px; + font-size: 1em; + max-width: 3em; + + color: transparent; + text-shadow: 0 0 0 white; + border: none; + box-shadow:0px 0px 0px 2px var(--accent-darkest) inset; + + transform-style: preserve-3d; + transition: cubic-bezier(0, 0, 0.58, 1), cubic-bezier(0, 0, 0.58, 1); + transition-duration: 150ms; +} + +#options-toggle #options-icon::before { + content: ""; + + position: absolute; + + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + + background-color: var(--accent-darker); + border-radius: inherit; + border: none; + box-shadow:0px 0px 0px 2px var(--accent-darkest) inset; + + transform: translate3d(0, 0.5em, -1em); + transition: cubic-bezier(0, 0, 0.58, 1), cubic-bezier(0, 0, 0.58, 1); + transition-duration: 150ms; +} + +#options-toggle #options-icon:hover { + transform: translate(0, 0.15em); + background-color: rgb(173, 113, 216); /*5% darker accent*/ +} + +#options-toggle #options-icon:hover::before { + transform: translate3d(0, 0.35em, -1em); +} + +#options-toggle #options-icon:active { + transform: translate(0em, 0.5em); + background-color: rgb(165, 100, 213); /*10% darker accent*/ +} + +#options-toggle #options-icon:active::before { + transform: translate3d(0, 0, -1em); +} + +#options { + display: none; /* default for sections is block */ + padding: 01em; +} + +input[type="color"]::-moz-color-swatch { + border: none; + margin: 0; + padding: 0; +} + +input[type="color"]::-webkit-color-swatch { + border: none; + margin: 0; + padding: 0; +} + +input[type="color"]::-webkit-color-swatch-wrapper { + border: none; + margin: 0; + padding: 0; +} + +@media (min-aspect-ratio: 4/3) { + body { + flex-direction: row; + } + + #chatbox-container { + height: 100vh !important; + flex-grow: 0; + } + + #video-container { + flex-grow: 1; + } + + #chatbox { + height: calc(100vh - 5em - 4em) !important; + } +}