diff options
| author | RblSb <msrblsb@gmail.com> | 2023-01-07 08:20:41 +0300 |
|---|---|---|
| committer | RblSb <msrblsb@gmail.com> | 2023-01-07 08:20:41 +0300 |
| commit | b3d825acb9d12208cf44f2d4b385163a86c38695 (patch) | |
| tree | 09fdb4c54753c30f46f0c2824b550bbfb1217572 /res | |
| parent | c677e281d3d74d5925e19eb0479c27f46a3c7857 (diff) | |
Hints, Open in App button, ui animations
Diffstat (limited to 'res')
| -rw-r--r-- | res/client.js | 262 | ||||
| -rw-r--r-- | res/css/des.css | 99 | ||||
| -rw-r--r-- | res/index.html | 114 | ||||
| -rw-r--r-- | res/langs/en.json | 11 | ||||
| -rw-r--r-- | res/langs/ru.json | 11 |
5 files changed, 348 insertions, 149 deletions
diff --git a/res/client.js b/res/client.js index b5be1ad..92ad1c7 100644 --- a/res/client.js +++ b/res/client.js @@ -547,20 +547,26 @@ client_Buttons.init = function(main) { }; var smilesBtn = window.document.querySelector("#smilesbtn"); smilesBtn.onclick = function(e) { - var smilesWrap = window.document.querySelector("#smileswrap"); - if(smilesWrap.children.length == 0) { + var wrap = window.document.querySelector("#smiles-wrap"); + var list = window.document.querySelector("#smiles-list"); + if(list.children.length == 0) { return; } if(smilesBtn.classList.toggle("active")) { - smilesWrap.style.display = "grid"; + wrap.style.display = "block"; + var tmp = client_Buttons.outerHeight(list); + wrap.style.height = tmp + "px"; } else { - smilesWrap.style.display = "none"; + wrap.style.height = "0"; + wrap.addEventListener("transitionend",function(e) { + return wrap.style.display = "none"; + },{ once : true}); } - if(smilesWrap.firstElementChild.dataset.src == null) { + if(list.firstElementChild.dataset.src == null) { return; } var _g = 0; - var _g1 = smilesWrap.children; + var _g1 = list.children; while(_g < _g1.length) { var child = _g1[_g]; ++_g; @@ -595,13 +601,19 @@ client_Buttons.init = function(main) { userlistToggle.onclick = function(e) { var icon = userlistToggle.firstElementChild; var isHidden = icon.getAttribute("name") == "chevron-forward"; + var wrap = window.document.querySelector("#userlist-wrap"); var style = window.document.querySelector("#userlist").style; if(isHidden) { - style.display = "block"; icon.setAttribute("name","chevron-down"); + style.display = "block"; + var tmp = client_Buttons.outerHeight(wrap.firstElementChild); + wrap.style.height = tmp + "px"; + wrap.style.marginBottom = "1rem"; } else { - style.display = "none"; icon.setAttribute("name","chevron-forward"); + style.display = "none"; + wrap.style.height = "0"; + wrap.style.marginBottom = "0rem"; } client_Buttons.settings.isUserListHidden = !isHidden; client_Settings.write(client_Buttons.settings); @@ -609,7 +621,14 @@ client_Buttons.init = function(main) { window.document.querySelector("#usercount").onclick = userlistToggle.onclick; if(client_Buttons.settings.isUserListHidden) { userlistToggle.onclick(); + } else { + var wrap = window.document.querySelector("#userlist-wrap"); + var tmp = client_Buttons.outerHeight(wrap.firstElementChild); + wrap.style.height = tmp + "px"; } + haxe_Timer.delay(function() { + window.document.querySelector("#userlist-wrap").style.transition = "200ms"; + },0); var toggleSynch = window.document.querySelector("#togglesynch"); toggleSynch.onclick = function(e) { var icon = toggleSynch.firstElementChild; @@ -672,11 +691,21 @@ client_Buttons.init = function(main) { }; var showMediaUrl = window.document.querySelector("#showmediaurl"); showMediaUrl.onclick = function(e) { - client_Buttons.showPlayerGroup(showMediaUrl); + if(client_Buttons.showPlayerGroup(showMediaUrl)) { + haxe_Timer.delay(function() { + window.document.querySelector("#addfromurl").scrollIntoView(); + window.document.querySelector("#mediaurl").focus(); + },100); + } }; var showCustomEmbed = window.document.querySelector("#showcustomembed"); showCustomEmbed.onclick = function(e) { - client_Buttons.showPlayerGroup(showCustomEmbed); + if(client_Buttons.showPlayerGroup(showCustomEmbed)) { + haxe_Timer.delay(function() { + window.document.querySelector("#customembed").scrollIntoView(); + window.document.querySelector("#customembed-title").focus(); + },100); + } }; var mediaUrl = window.document.querySelector("#mediaurl"); mediaUrl.oninput = function() { @@ -692,7 +721,15 @@ client_Buttons.init = function(main) { }; var showOptions = window.document.querySelector("#showoptions"); showOptions.onclick = function(e) { - return client_Buttons.toggleGroup(showOptions); + var isActive = client_Buttons.toggleGroup(showOptions); + var tmp = isActive ? "1" : "0"; + window.document.querySelector("#optionsPanel").style.opacity = tmp; + return haxe_Timer.delay(function() { + if(showOptions.classList.contains("active") != isActive) { + return; + } + window.document.querySelector("#optionsPanel").classList.toggle("collapse",!isActive); + },isActive ? 0 : 200); }; window.document.querySelector("#exitBtn").onclick = function(e) { if((main.personal.group & 2) != 0) { @@ -721,14 +758,27 @@ client_Buttons.showPlayerGroup = function(el) { } client_Buttons.toggleGroup(group); } - client_Buttons.toggleGroup(el); + return client_Buttons.toggleGroup(el); }; client_Buttons.toggleGroup = function(el) { el.classList.toggle("collapsed"); var id = el.dataset.target; - window.document.querySelector(id).classList.toggle("collapse"); + var target = window.document.querySelector(id); + if(target.classList.toggle("collapse")) { + target.style.height = "0"; + } else { + if(target.style.height == "") { + target.style.height = "0"; + } + var tmp = client_Buttons.outerHeight(target.firstElementChild); + target.style.height = tmp + "px"; + } return el.classList.toggle("active"); }; +client_Buttons.outerHeight = function(el) { + var style = window.getComputedStyle(el); + return el.getBoundingClientRect().height + parseFloat(style.marginTop) + parseFloat(style.marginBottom); +}; client_Buttons.swapPlayerAndChat = function() { client_Buttons.settings.isSwapped = window.document.querySelector("body").classList.toggle("swap"); var sizes = window.document.body.style.gridTemplateColumns.split(" "); @@ -1157,7 +1207,7 @@ var client_Main = function() { if(this.host == "") { this.host = "localhost"; } - client_Settings.init({ version : 3, name : "", hash : "", isExtendedPlayer : false, playerSize : 1, chatSize : 300, synchThreshold : 2, isSwapped : false, isUserListHidden : true, latestLinks : [], latestSubs : [], hotkeysEnabled : true},$bind(this,this.settingsPatcher)); + client_Settings.init({ version : 4, name : "", hash : "", isExtendedPlayer : false, playerSize : 1, chatSize : 300, synchThreshold : 2, isSwapped : false, isUserListHidden : true, latestLinks : [], latestSubs : [], hotkeysEnabled : true, showHintList : true},$bind(this,this.settingsPatcher)); this.settings = client_Settings.read(); this.initListeners(); this.onTimeGet = new haxe_Timer(this.settings.synchThreshold * 1000); @@ -1180,38 +1230,40 @@ client_Main.__name__ = true; client_Main.main = function() { new client_Main(); }; -client_Main.serverMessage = function(type,text,isText) { +client_Main.chatMessageConnected = function() { + var div = window.document.createElement("div"); + div.className = "server-msg-reconnect"; + div.textContent = Lang.get("msgConnected"); + var msgBuf = window.document.querySelector("#messagebuffer"); + msgBuf.appendChild(div); + msgBuf.scrollTop = msgBuf.scrollHeight; +}; +client_Main.chatMessageDisconnected = function() { + var div = window.document.createElement("div"); + div.className = "server-msg-disconnect"; + div.textContent = Lang.get("msgDisconnected"); + var msgBuf = window.document.querySelector("#messagebuffer"); + msgBuf.appendChild(div); + msgBuf.scrollTop = msgBuf.scrollHeight; +}; +client_Main.serverMessage = function(text,isText,withTimestamp) { + if(withTimestamp == null) { + withTimestamp = true; + } if(isText == null) { isText = true; } - var msgBuf = window.document.querySelector("#messagebuffer"); var div = window.document.createElement("div"); var time = HxOverrides.dateStr(new Date()).split(" ")[1]; - switch(type) { - case 1: - div.className = "server-msg-reconnect"; - div.textContent = Lang.get("msgConnected"); - break; - case 2: - div.className = "server-msg-disconnect"; - div.textContent = Lang.get("msgDisconnected"); - break; - case 3: - div.className = "server-whisper"; - div.textContent = time + text + " " + Lang.get("entered"); - break; - case 4: - div.className = "server-whisper"; - div.innerHTML = "<div class=\"head\">\n\t\t\t\t\t<div class=\"server-whisper\"></div>\n\t\t\t\t\t<span class=\"timestamp\">" + time + "</span>\n\t\t\t\t</div>"; - var textDiv = div.querySelector(".server-whisper"); - if(isText) { - textDiv.textContent = text; - } else { - textDiv.innerHTML = text; - } - break; - default: + div.className = "server-whisper"; + div.innerHTML = "<div class=\"head\">\n\t\t\t<div class=\"server-whisper\"></div>\n\t\t\t<span class=\"timestamp\">" + (withTimestamp ? time : "") + "</span>\n\t\t</div>"; + var textDiv = div.querySelector(".server-whisper"); + if(isText) { + textDiv.textContent = text; + } else { + textDiv.innerHTML = text; } + var msgBuf = window.document.querySelector("#messagebuffer"); msgBuf.appendChild(div); msgBuf.scrollTop = msgBuf.scrollHeight; }; @@ -1225,6 +1277,9 @@ client_Main.prototype = { data.latestSubs = []; break; case 3: + data.showHintList = true; + break; + case 4: throw haxe_Exception.thrown("skipped version " + version); default: throw haxe_Exception.thrown("skipped version " + version); @@ -1252,12 +1307,12 @@ client_Main.prototype = { this.ws = new WebSocket("" + protocol + "//" + this.host + colonPort + path); this.ws.onmessage = $bind(this,this.onMessage); this.ws.onopen = function() { - client_Main.serverMessage(1); + client_Main.chatMessageConnected(); return _gthis.isConnected = true; }; this.ws.onclose = function() { if(_gthis.isConnected) { - client_Main.serverMessage(2); + client_Main.chatMessageDisconnected(); } _gthis.isConnected = false; _gthis.player.pause(); @@ -1414,7 +1469,7 @@ client_Main.prototype = { } this.player.getVideoData({ url : url, atEnd : atEnd},function(data) { if(data.duration == 0) { - client_Main.serverMessage(4,Lang.get("addVideoError")); + client_Main.serverMessage(Lang.get("addVideoError")); return; } if(data.title == null) { @@ -1443,7 +1498,7 @@ client_Main.prototype = { var isTemp = window.document.querySelector("#customembed").querySelector(".add-temp").checked; this.player.getIframeData({ url : iframe, atEnd : atEnd},function(data) { if(data.duration == 0) { - client_Main.serverMessage(4,Lang.get("addVideoError")); + client_Main.serverMessage(Lang.get("addVideoError")); return; } if(title.length > 0) { @@ -1492,7 +1547,7 @@ client_Main.prototype = { var data = JSON.parse(e.data); if(this.config != null && this.config.isVerbose) { var t = data.type; - haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 390, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]}); + haxe_Log.trace("Event: " + data.type,{ fileName : "src/client/Main.hx", lineNumber : 394, className : "client.Main", methodName : "onMessage", customParams : [Reflect.field(data,t.charAt(0).toLowerCase() + HxOverrides.substr(t,1,null))]}); } client_JsApi.fireOnceEvent(data); switch(data.type) { @@ -1627,7 +1682,7 @@ client_Main.prototype = { break; case "ServerMessage": var id = data.serverMessage.textId; - client_Main.serverMessage(4,id == "usernameError" ? StringTools.replace(Lang.get(id),"$MAX","" + this.config.maxLoginLength) : Lang.get(id)); + client_Main.serverMessage(id == "usernameError" ? StringTools.replace(Lang.get(id),"$MAX","" + this.config.maxLoginLength) : Lang.get(id)); break; case "SetLeader": ClientTools.setLeader(this.clients,data.setLeader.clientName); @@ -1713,7 +1768,7 @@ client_Main.prototype = { this.setLeaderButton((this.personal.group & 4) != 0); this.setPlaylistLock(connected.isPlaylistOpen); this.clearChat(); - client_Main.serverMessage(1); + client_Main.chatMessageConnected(); var _g = 0; var _g1 = connected.history; while(_g < _g1.length) { @@ -1723,6 +1778,80 @@ client_Main.prototype = { } this.player.setItems(connected.videoList,connected.itemPos); this.onUserGroupChanged(); + if(this.settings.showHintList) { + this.showChatHintList(); + } + } + ,showChatHintList: function() { + var _gthis = this; + var text = Lang.get("hintListStart"); + var addVideos = "<button id=\"addVideosHintButton\">" + Lang.get("addVideos") + "</button>"; + text += "</br>" + StringTools.replace(Lang.get("hintListAddVideo"),"$addVideos",addVideos); + var requestLeader = "<button id=\"requestLeaderHintButton\">" + Lang.get("requestLeader") + "</button>"; + text += "</br>" + StringTools.replace(Lang.get("hintListRequestLeader"),"$requestLeader",requestLeader); + if(client_Utils.isTouch()) { + text += " " + Lang.get("hintListRequestLeaderTouch"); + } else { + text += " " + Lang.get("hintListRequestLeaderMouse"); + } + if(client_Utils.isAndroid()) { + var openInAppLink = "<button id=\"openInApp\">" + Lang.get("openInApp") + "</button>"; + text += "</br>" + StringTools.replace(Lang.get("hintListOpenInApp"),"$openInApp",openInAppLink); + } + var hideThisMessage = "<button id=\"hideHintList\">" + Lang.get("hideThisMessage") + "</button>"; + text += "</br>" + StringTools.replace(Lang.get("hintListHide"),"$hideThisMessage",hideThisMessage); + client_Main.serverMessage(text,false,false); + window.document.querySelector("#addVideosHintButton").onclick = function(e) { + var addBtn = window.document.querySelector("#showmediaurl"); + addBtn.scrollIntoView(); + return haxe_Timer.delay(function() { + if(!window.document.querySelector("#addfromurl").classList.contains("collapse")) { + window.document.querySelector("#mediaurl").focus(); + return; + } + addBtn.onclick(); + },300); + }; + window.document.querySelector("#requestLeaderHintButton").onclick = function(e) { + window.scrollTo(0,0); + if(client_Utils.isTouch()) { + window.document.querySelector("#leader_btn").classList.add("hint"); + haxe_Timer.delay(function() { + window.document.querySelector("#leader_btn").classList.remove("hint"); + },1000); + } + }; + window.document.querySelector("#requestLeaderHintButton").onpointerenter = function(e) { + if(client_Utils.isTouch()) { + return; + } + window.document.querySelector("#leader_btn").classList.add("hint"); + }; + window.document.querySelector("#requestLeaderHintButton").onpointerleave = function(e) { + window.document.querySelector("#leader_btn").classList.remove("hint"); + }; + if(client_Utils.isAndroid()) { + window.document.querySelector("#openInApp").onclick = function(e) { + var isRedirected = false; + window.addEventListener("blur",function(e) { + isRedirected = true; + return isRedirected; + },{ once : true}); + window.setTimeout(function() { + if(isRedirected || window.document.hidden) { + return; + } + window.location.href = "https://github.com/RblSb/SyncTubeApp#readme"; + },500); + window.location.href = "synctube://" + $global.location.href; + return false; + }; + } + window.document.querySelector("#hideHintList").onclick = function(e) { + window.document.querySelector("#hideHintList").parentElement.remove(); + _gthis.settings.showHintList = false; + client_Settings.write(_gthis.settings); + }; } ,onUserGroupChanged: function() { var button = window.document.querySelector("#queue_next"); @@ -1789,18 +1918,18 @@ client_Main.prototype = { this.filters.push({ regex : new EReg("(^| )" + this.escapeRegExp(emote.name) + "(?!\\S)","g"), replace : "$1<" + tag + " class=\"channel-emote\" src=\"" + emote.image + "\" title=\"" + emote.name + "\"/>"}); } window.document.querySelector("#smilesbtn").classList.remove("active"); - var smilesWrap = window.document.querySelector("#smileswrap"); - smilesWrap.style.display = "none"; - smilesWrap.onclick = function(e) { + window.document.querySelector("#smiles-wrap").style.display = "none"; + var smilesList = window.document.querySelector("#smiles-list"); + smilesList.onclick = function(e) { var el = e.target; - if(el == smilesWrap) { + if(el == smilesList) { return; } var form = window.document.querySelector("#chatline"); form.value += " " + el.title; form.focus(); }; - smilesWrap.textContent = ""; + smilesList.textContent = ""; var _g = 0; var _g1 = config.emotes; while(_g < _g1.length) { @@ -1811,7 +1940,7 @@ client_Main.prototype = { el.className = "smile-preview"; el.dataset.src = emote.image; el.title = emote.name; - smilesWrap.appendChild(el); + smilesList.appendChild(el); } } ,onLogin: function(data,clientName) { @@ -1992,6 +2121,9 @@ client_Main.prototype = { case "fb":case "flashback": this.send({ type : "Flashback"}); return false; + case "help": + this.showChatHintList(); + return true; case "kick": this.mergeRedundantArgs(args,0,1); this.send({ type : "KickClient", kickClient : { name : args[0]}}); @@ -2071,12 +2203,7 @@ client_Main.prototype = { this.onBlinkTab.run(); } ,setLeaderButton: function(flag) { - var leaderBtn = window.document.querySelector("#leader_btn"); - if(flag) { - leaderBtn.classList.add("success-bg"); - } else { - leaderBtn.classList.remove("success-bg"); - } + window.document.querySelector("#leader_btn").classList.toggle("success-bg",flag); } ,setPlaylistLock: function(isOpen) { this.isPlaylistOpen = isOpen; @@ -2084,13 +2211,11 @@ client_Main.prototype = { var icon = lockPlaylist.firstElementChild; if(isOpen) { lockPlaylist.title = Lang.get("playlistOpen"); - lockPlaylist.classList.add("btn-success"); lockPlaylist.classList.add("success"); lockPlaylist.classList.remove("danger"); icon.setAttribute("name","lock-open"); } else { lockPlaylist.title = Lang.get("playlistLocked"); - lockPlaylist.classList.add("btn-danger"); lockPlaylist.classList.add("danger"); lockPlaylist.classList.remove("success"); icon.setAttribute("name","lock-closed"); @@ -2339,11 +2464,7 @@ client_Player.prototype = { var btn = item.querySelector(".qbtn-tmp"); btn.title = isTemp ? Lang.get("makePermanent") : Lang.get("makeTemporary"); btn.firstElementChild.setAttribute("name",isTemp ? "lock-open" : "lock-closed"); - if(isTemp) { - item.classList.add("queue_temp"); - } else { - item.classList.remove("queue_temp"); - } + item.classList.toggle("queue_temp",isTemp); } ,removeItem: function(url) { this.removeElementItem(url); @@ -2615,7 +2736,7 @@ client_Player.prototype = { } }; http.onError = function(msg) { - haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 477, className : "client.Player", methodName : "skipAd"}); + haxe_Log.trace(msg,{ fileName : "src/client/Player.hx", lineNumber : 476, className : "client.Player", methodName : "skipAd"}); }; http.request(); } @@ -2679,6 +2800,9 @@ client_Utils.isIOS = function() { return true; } }; +client_Utils.isAndroid = function() { + return $global.navigator.userAgent.toLowerCase().indexOf("android") > -1; +}; client_Utils.nodeFromString = function(div) { var wrapper = window.document.createElement("div"); wrapper.innerHTML = div; @@ -3208,7 +3332,7 @@ client_players_RawSubs.convertAssTime = function(time) { }; client_players_RawSubs.isProxyError = function(text) { if(StringTools.startsWith(text,"Proxy error:")) { - client_Main.serverMessage(4,"Failed to add subs: proxy error"); + client_Main.serverMessage("Failed to add subs: proxy error"); haxe_Log.trace("Failed to add subs: " + text,{ fileName : "src/client/players/RawSubs.hx", lineNumber : 191, className : "client.players.RawSubs", methodName : "isProxyError"}); return true; } @@ -3378,7 +3502,7 @@ client_players_Youtube.prototype = { loadJson(dataUrl); } ,youtubeApiError: function(error) { - client_Main.serverMessage(4,"Error " + error.code + ": " + error.message,false); + client_Main.serverMessage("Error " + error.code + ": " + error.message,false); } ,getRemoteDataFallback: function(url,callback) { var _gthis = this; diff --git a/res/css/des.css b/res/css/des.css index aa02177..968ad39 100644 --- a/res/css/des.css +++ b/res/css/des.css @@ -11,6 +11,7 @@ --foreground: #bbb; --accent: #0055ff; --success: #009632; + --leader-hint: #00963288; --warning: #ffb800; --error: #ff0800; --border: #333; @@ -19,6 +20,8 @@ html { box-sizing: border-box; + scroll-behavior: smooth; + -webkit-tap-highlight-color: transparent; } *, @@ -122,6 +125,10 @@ button { button:not(:first-child) { margin-left: .5rem; } +.server-whisper button { + margin-left: 0; + font-style: italic; +} button:hover, button.active { @@ -129,6 +136,16 @@ button.active { color: var(--foreground); } +/* Disable hover on touch devices */ +@media (hover: none) { + button:hover:not(.active) { + background-color: var(--background-chat); + } + .info header button:hover:not(.active) { + background-color: transparent; + } +} + button:hover ion-icon, button.active ion-icon, button:focus, @@ -159,6 +176,18 @@ button span { pointer-events: none; } +#leader_btn { + border: .125rem solid; + border-color: transparent; + transition: border-color ease-in-out 800ms; +} +#leader_btn.hint { + border-radius: .5rem; + border: .125rem solid; + color: var(--foreground); + border-color: var(--leader-hint); +} + /* Input */ label { @@ -227,14 +256,19 @@ button.danger-bg:focus { text-align: center; } -.collapse { - display: none; - visibility: hidden; +.collapsible { + overflow: hidden; + transition: height 200ms; } -.collapse.in { - display: block; - visibility: visible; +.collapse-list { + padding: 1rem; + margin: 0 auto; + max-width: 32rem; +} + +.collapse { + height: 0; } .display-flex { @@ -374,15 +408,8 @@ header h4 { flex-grow: 1; } -#addfromurl, -#customembed { - padding: 1rem; - margin: 0 auto; - max-width: 32rem; -} - -#addfromurl>*, -#customembed>* { +#addfromurl>*>*, +#customembed>*>* { margin-bottom: 1rem; } @@ -396,8 +423,8 @@ header h4 { flex-grow: 2; } -#customembed>input, -#customembed>textarea { +#customembed>*>input, +#customembed>*>textarea { display: block; width: 100%; } @@ -481,16 +508,23 @@ footer#footer { /* Users online */ -#userlist { +#userlist-wrap { overflow-y: auto; background-color: var(--background-video); border-right: 0; - padding: 1rem; border-radius: 1rem; - height: 12rem; + flex-shrink: 0; + + transition: 0ms; + height: 0; margin-bottom: 1rem; } +#userlist { + padding: 1rem; + height: 11rem; +} + .userlist_item { display: flex; align-items: center; @@ -544,19 +578,21 @@ footer#footer { left: 1rem; bottom: 1rem; right: 1rem; + transition: opacity 200ms; + opacity: 0; } -#optionsPanel div { +#optionsList div { margin-bottom: .5rem; } -#optionsPanel div:not(:first-child) { +#optionsList div:not(:first-child) { border-top: .063rem solid; border-color: var(--border); padding-top: 1rem; } -#optionsPanel li button { +#optionsList li button { padding: 1rem 0; display: flex; align-items: stretch; @@ -565,7 +601,7 @@ footer#footer { text-align: left; } -#optionsPanel li button:hover { +#optionsList li button:hover { background-color: var(--background-chat); } @@ -631,15 +667,20 @@ footer#footer { /* Emotes */ -#smileswrap { +#smiles-wrap { display: none; - background: rgba(0, 0, 0, 0.7); + height: 0; width: 100%; - height: 12rem; - padding: 1rem; + background: rgba(0, 0, 0, 0.7); border-radius: 1rem; overflow-y: scroll; text-align: center; +} + +#smiles-list { + display: grid; + height: 12rem; + padding: 1rem; grid-template-columns: repeat(auto-fit, minmax(4rem, 1fr)); grid-gap: .5rem; gap: .5rem; @@ -807,6 +848,6 @@ html { } .mobile-view #optionsPanel { - top: 2rem; + top: 2.2rem; bottom: 0; } diff --git a/res/index.html b/res/index.html index 3892a41..20df11c 100644 --- a/res/index.html +++ b/res/index.html @@ -82,37 +82,41 @@ </span> </div> <!-- Add video --> - <div class="collapse" id="addfromurl" aria-expanded="false"> - <div class="display-flex"> - <button id="insert_template" title="${addTemplateUrl}"> - <div>></div> - </button> - <input id="mediaurl" type="text" placeholder="${addVideoFromUrl}"> - </div> - <div id="mediatitleblock" class="display-flex" style="display: none;"> - <input id="mediatitle" type="text" placeholder="${optionalTitle}"> - </div> - <div id="subsurlblock" class="display-flex" style="display: none;"> - <input id="subsurl" type="text" placeholder="${subtitlesUrlOptional}"> - </div> - <div> - <label> - <input class="add-temp" type="checkbox" checked="checked">${addAsTemporary} - </label> - <button id="queue_next">${queueNext}</button> - <button id="queue_end">${queueLast}</button> + <div id="addfromurl" class="collapsible collapse" aria-expanded="false"> + <div class="collapse-list"> + <div class="display-flex"> + <button id="insert_template" title="${addTemplateUrl}"> + <div>></div> + </button> + <input id="mediaurl" type="text" placeholder="${addVideoFromUrl}"> + </div> + <div id="mediatitleblock" class="display-flex" style="display: none;"> + <input id="mediatitle" type="text" placeholder="${optionalTitle}"> + </div> + <div id="subsurlblock" class="display-flex" style="display: none;"> + <input id="subsurl" type="text" placeholder="${subtitlesUrlOptional}"> + </div> + <div> + <label> + <input class="add-temp" type="checkbox" checked="checked">${addAsTemporary} + </label> + <button id="queue_next">${queueNext}</button> + <button id="queue_end">${queueLast}</button> + </div> </div> </div> - <div class="collapse" id="customembed" aria-expanded="false"> - <input id="customembed-title" type="text" placeholder="${optionalTitle}"> - <textarea id="customembed-content" rows="5" - placeholder="${pasteEmbedCodeAndClick} '${queueNext}' ${or} '${queueLast}'. ${acceptableEmbedCodesAre} <iframe> ${or} <object>. ${customEmbedsCannotBeSynchronized}."></textarea> - <div> - <label> - <input class="add-temp" type="checkbox" checked="checked">${addAsTemporary} - </label> - <button id="ce_queue_next">${queueNext}</button> - <button id="ce_queue_end">${queueLast}</button> + <div class="collapsible collapse" id="customembed" aria-expanded="false"> + <div class="collapse-list"> + <input id="customembed-title" type="text" placeholder="${optionalTitle}"> + <textarea id="customembed-content" rows="5" + placeholder="${pasteEmbedCodeAndClick} '${queueNext}' ${or} '${queueLast}'. ${acceptableEmbedCodesAre} <iframe> ${or} <object>. ${customEmbedsCannotBeSynchronized}."></textarea> + <div> + <label> + <input class="add-temp" type="checkbox" checked="checked">${addAsTemporary} + </label> + <button id="ce_queue_next">${queueNext}</button> + <button id="ce_queue_end">${queueLast}</button> + </div> </div> </div> <!-- Queue --> @@ -142,35 +146,41 @@ <span> <button id="leader_btn" class="unselectable" title="${leaderDesc}">${leader}</button> <!-- Settings button --> - <button id="showoptions" class="collapsed" data-toggle="collapse" data-target="#optionsPanel" + <button id="showoptions" class="collapsed" data-toggle="collapse" data-target="#optionsList" aria-expanded="false"> <ion-icon name="settings-sharp"></ion-icon> </button> </span> </div> <!-- User list --> - <div id="userlist"></div> + <div id="userlist-wrap" class="collapsible"> + <div id="userlist"></div> + </div> <!-- Settings list --> <ul id="optionsPanel" class="collapse" aria-expanded="false"> - <div> - <h4>${account}</h4> - <li><button id="exitBtn">${login}</button></li> - </div> - <div> - <h4>${general}</h4> - <li><button id="hotkeysBtn"><span>${hotkeys}</span></button></li> - <li><button id="swapLayoutBtn" title="${swapLayout}"><span>${swapLayout}</span></button></li> - </div> - <div> - <h4>${video}</h4> - <li><button id="synchThresholdBtn"><span>${synchThreshold}</span></button></li> - <li><button id="setVideoUrlBtn"><span>${setVideoUrl}</span></button></li> - <li><button id="selectLocalVideoBtn"><span>${selectLocalVideo}</span></button></li> - <li><button id="removeVideoBtn"><span>${removeVideo}</span></button></li> - </div> - <div id="adminMenu" style="display: none;"> - <h4>${chat}</h4> - <li><button id="clearchatbtn"><span>${clearChat}</span></button></li> + <div id="optionsList" class="collapse"> + <div> + <div> + <h4>${account}</h4> + <li><button id="exitBtn">${login}</button></li> + </div> + <div> + <h4>${general}</h4> + <li><button id="hotkeysBtn"><span>${hotkeys}</span></button></li> + <li><button id="swapLayoutBtn" title="${swapLayout}"><span>${swapLayout}</span></button></li> + </div> + <div> + <h4>${video}</h4> + <li><button id="synchThresholdBtn"><span>${synchThreshold}</span></button></li> + <li><button id="setVideoUrlBtn"><span>${setVideoUrl}</span></button></li> + <li><button id="selectLocalVideoBtn"><span>${selectLocalVideo}</span></button></li> + <li><button id="removeVideoBtn"><span>${removeVideo}</span></button></li> + </div> + <div id="adminMenu" style="display: none;"> + <h4>${chat}</h4> + <li><button id="clearchatbtn"><span>${clearChat}</span></button></li> + </div> + </div> </div> </ul> <!-- Messages --> @@ -182,7 +192,9 @@ <ion-icon name="happy"></ion-icon> </button> </div> - <div id="smileswrap"></div> + <div id="smiles-wrap" class="collapsible"> + <div id="smiles-list"></div> + </div> <!-- Guest login --> <div id="guestlogin" style="display: none;"> <label>${enterAsGuest}</label> diff --git a/res/langs/en.json b/res/langs/en.json index e7ea8f4..90a77aa 100644 --- a/res/langs/en.json +++ b/res/langs/en.json @@ -5,6 +5,17 @@ "joined": "joined", "online": "online", "nothingPlaying": "Nothing Playing", + "hintListStart": "Welcome to SyncTube! Here you can:", + "hintListAddVideo": "$addVideos to watch together", + "hintListRequestLeader": "$requestLeader to pause and rewind videos for everyone", + "hintListRequestLeaderMouse": "(also use right mouse button for quick pause)", + "hintListRequestLeaderTouch": "(also use long tap for quick pause)", + "hintListOpenInApp": "$openInApp this server for better Android experience", + "hintListHide": "$hideThisMessage and send <b>/help</b> in chat to see it again", + "addVideos": "Add Videos", + "requestLeader": "Request Leader", + "openInApp": "Open in App", + "hideThisMessage": "Hide this message", "usernameError": "Username length must be from 1 to $MAX characters and don't repeat another's. Characters &^<>'\" are not allowed.", "passwordMatchError": "Wrong password.", "accessError": "Access Error.", diff --git a/res/langs/ru.json b/res/langs/ru.json index 637e883..7615efd 100644 --- a/res/langs/ru.json +++ b/res/langs/ru.json @@ -5,6 +5,17 @@ "joined": "вошел", "online": "онлайн", "nothingPlaying": "Ничего не играет", + "hintListStart": "Добро пожаловать на SyncTube! Здесь вы можете:", + "hintListAddVideo": "$addVideos для совместного просмотра", + "hintListRequestLeader": "$requestLeader для всеобщей паузы и перемотки видео", + "hintListRequestLeaderMouse": "(кстати, правая кнопка мыши сразу сделает паузу)", + "hintListRequestLeaderTouch": "(кстати, удерживайте кнопку для быстрой паузы)", + "hintListOpenInApp": "$openInApp этот сервер для лучшего опыта на Android", + "hintListHide": "$hideThisMessage и отправлять <b>`/help`</b> в чат чтобы прочесть его снова", + "addVideos": "Добавлять видео", + "requestLeader": "Запрашивать лидера", + "openInApp": "Открыть в приложении", + "hideThisMessage": "Скрыть это сообщение", "usernameError": "Ник должен быть от 1 до $MAX символов и не повторять чужие. Символы &^<>'\" запрещены.", "passwordMatchError": "Неправильный пароль.", "accessError": "Ошибка доступа.", |
