diff options
| author | Austin Riddell <53499821+aus-tin@users.noreply.github.com> | 2020-05-19 10:37:35 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-19 18:37:35 +0300 |
| commit | d88e6d0f80211b2ace5595af9931b997eb4c6bc4 (patch) | |
| tree | 12d9a63b404c1af3e6cec9a6c19d91d55473c81f /src/client | |
| parent | 9168f9d5a8a6333e45309fdeabb2f71a368a5fce (diff) | |
Major frontend redesign (#5)
* Major frontend redesign
* Some improvements
Co-authored-by: RblSb <msrblsb@gmail.com>
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/Buttons.hx | 235 | ||||
| -rw-r--r-- | src/client/ClientSettings.hx | 4 | ||||
| -rw-r--r-- | src/client/Main.hx | 64 | ||||
| -rw-r--r-- | src/client/MobileView.hx | 29 | ||||
| -rw-r--r-- | src/client/Player.hx | 35 | ||||
| -rw-r--r-- | src/client/Split.hx | 7 |
6 files changed, 143 insertions, 231 deletions
diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index 769cb25..7d673b7 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -17,18 +17,23 @@ class Buttons { public static function init(main:Main):Void { settings = main.settings; - window.onresize = onVideoResize; + if (settings.isSwapped) document.body.classList.add("swap"); initSplit(); + setSplitSize(settings.playerSize, settings.chatSize); initChatInput(main); - initNavBar(main); final passIcon = ge("#guestpass_icon"); passIcon.onclick = e -> { - final isOpen = passIcon.classList.toggle("glyphicon-eye-open"); - passIcon.classList.toggle("glyphicon-eye-close"); + final icon = passIcon.firstElementChild; + final isOpen = icon.getAttribute("name") == "eye-off"; final pass:InputElement = cast ge("#guestpass"); - if (isOpen) pass.type = "password"; - else pass.type = "text"; + if (isOpen) { + pass.type = "password"; + icon.setAttribute("name", "eye"); + } else { + pass.type = "text"; + icon.setAttribute("name", "eye-off"); + } } final smilesBtn = ge("#smilesbtn"); @@ -36,7 +41,7 @@ class Buttons { final smilesWrap = ge("#smileswrap"); if (smilesWrap.children.length == 0) return; final isActive = smilesBtn.classList.toggle("active"); - if (isActive) smilesWrap.style.display = "block"; + if (isActive) smilesWrap.style.display = "grid"; else smilesWrap.style.display = "none"; if (smilesWrap.firstElementChild.dataset.src == null) return; for (child in smilesWrap.children) { @@ -69,31 +74,24 @@ class Buttons { final userlistToggle = ge("#userlisttoggle"); userlistToggle.onclick = e -> { - final isHidden = userlistToggle.classList.toggle("glyphicon-chevron-right"); - userlistToggle.classList.toggle("glyphicon-chevron-down"); + final icon = userlistToggle.firstElementChild; + final isHidden = userlistToggle.classList.toggle("chevron-right"); + userlistToggle.classList.toggle("chevron-down"); final style = ge("#userlist").style; - if (isHidden) style.display = "none"; - else style.display = "block"; + if (isHidden) { + style.display = "none"; + icon.setAttribute("name", "chevron-forward"); + } + else { + style.display = "block"; + icon.setAttribute("name", "chevron-down"); + } settings.isUserListHidden = isHidden; Settings.write(settings); } ge("#usercount").onclick = userlistToggle.onclick; if (settings.isUserListHidden) userlistToggle.onclick(); - final extendPlayer = ge("#extendplayer"); - extendPlayer.onclick = e -> { - final isExtended = extendPlayer.classList.toggle("active"); - final sizes = isExtended ? [20, 80] : [40, 60]; - ge("#userlist").style.width = isExtended ? "80px" : "90px"; - if (settings.isSwapped) sizes.reverse(); - split.setSizes(sizes); - settings.isExtendedPlayer = isExtended; - writeSplitSize(); - window.dispatchEvent(new Event("resize")); - main.scrollChatToEnd(); - } - if (settings.isExtendedPlayer) extendPlayer.onclick(); - final toggleSynch = ge("#togglesynch"); toggleSynch.onclick = e -> { final icon = toggleSynch.firstElementChild; @@ -101,13 +99,11 @@ class Buttons { if (!window.confirm(Lang.get("toggleSynchConfirm"))) return; main.isSyncActive = false; icon.style.color = "rgba(238, 72, 67, 0.75)"; - icon.classList.add("glyphicon-pause"); - icon.classList.remove("glyphicon-play"); + icon.setAttribute("name", "pause"); } else { main.isSyncActive = true; icon.style.color = ""; - icon.classList.add("glyphicon-play"); - icon.classList.remove("glyphicon-pause"); + icon.setAttribute("name", "play"); main.send({type: UpdatePlaylist}); } } @@ -125,11 +121,9 @@ class Buttons { final text = main.getPlaylistLinks().join(","); Utils.copyToClipboard(text); final icon = getPlaylist.firstElementChild; - icon.classList.remove("glyphicon-link"); - icon.classList.add("glyphicon-ok"); + icon.setAttribute("name", "checkmark"); Timer.delay(() -> { - icon.classList.add("glyphicon-link"); - icon.classList.remove("glyphicon-ok"); + icon.setAttribute("name", "link"); }, 2000); } final clearPlaylist = ge("#clearplaylist"); @@ -142,6 +136,7 @@ class Buttons { if (!window.confirm(Lang.get("shufflePlaylistConfirm"))) return; main.send({type: ShufflePlaylist}); } + final lockPlaylist = ge("#lockplaylist"); lockPlaylist.onclick = e -> { if (main.isAdmin()) main.send({type: TogglePlaylistLock}); @@ -158,131 +153,77 @@ class Buttons { input.value = main.getTemplateUrl(); input.focus(); } + + final showOptions = ge("#showoptions"); + showOptions.onclick = e -> { + final isActive = toggleGroup(showOptions); + ge("#messagebuffer").style.display = isActive ? "none" : "block"; + ge("#chatbox").style.display = isActive ? "none" : "flex"; + ge("#userlisttoggle").style.display = isActive ? "none" : "inline-flex"; + ge("#optionsTitle").style.display = isActive ? "inline-flex" : "none"; + } + + final exitBtn = ge("#exitBtn"); + exitBtn.onclick = e -> { + if (main.isUser()) main.send({type: Logout}); + else ge("#guestname").focus(); + toggleGroup(showOptions); + } + + final swapLayoutBtn = ge("#swapLayoutBtn"); + swapLayoutBtn.onclick = e -> { + settings.isSwapped = ge("body").classList.toggle("swap"); + final sizes = document.body.style.gridTemplateColumns.split(" "); + sizes.reverse(); + document.body.style.gridTemplateColumns = sizes.join(" "); + Settings.write(settings); + } } static function showPlayerGroup(el:Element):Void { final groups:Array<Element> = cast document.querySelectorAll('[data-target]'); for (group in groups) { if (el == group) continue; - group.classList.add("collapsed"); - group.classList.remove("active"); - ge(group.dataset.target).classList.add("collapse"); + if (group.classList.contains("collapsed")) continue; + toggleGroup(group); } + toggleGroup(el); + } + + static function toggleGroup(el:Element):Bool { el.classList.toggle("collapsed"); - el.classList.toggle("active"); ge(el.dataset.target).classList.toggle("collapse"); + return el.classList.toggle("active"); } static function initSplit():Void { if (split != null) split.destroy(); - final divs = ["#chatwrap", "#videowrap"]; - final sizes = [settings.chatSize, settings.playerSize]; - if (settings.isSwapped) { - divs.reverse(); - sizes.reverse(); - } - split = new Split(divs, { - sizes: sizes, - onDragEnd: () -> { - window.dispatchEvent(new Event("resize")); - writeSplitSize(); - }, - minSize: 185, - snapOffset: 0 + split = new Split({ + columnGutters: [{ + element: ge(".gutter"), + track: 1, + }], + minSize: 200, + snapOffset: 0, + onDragEnd: saveSplitSize }); - window.dispatchEvent(new Event("resize")); } - static function writeSplitSize():Void { - final sizes = split.getSizes(); - if (settings.isSwapped) sizes.reverse(); - settings.chatSize = sizes[0]; - settings.playerSize = sizes[1]; - Settings.write(settings); - } - - static function onVideoResize():Void { - final player = ge("#ytapiplayer"); - final height = player.offsetHeight - ge("#chatline").offsetHeight; - ge("#messagebuffer").style.height = '${height}px'; - ge("#userlist").style.height = '${height}px'; - } - - static function onClick(el:Element, func:Any->Void):Void { - if (!Utils.isTouch()) el.onclick = func; - else el.ontouchend = func; + static function setSplitSize(playerSize:Float, chatSize:Float):Void { + final sizes = document.body.style.gridTemplateColumns.split(" "); + final playerId = settings.isSwapped ? sizes.length - 1 : 0; + final chatId = settings.isSwapped ? 0 : sizes.length - 1; + sizes[playerId] = '${playerSize}fr'; + sizes[chatId] = '${chatSize}fr'; + document.body.style.gridTemplateColumns = sizes.join(" "); } - static function initNavBar(main:Main):Void { - final toggleMenu = ge("#toggleMenu"); - final onclick = e -> { - ge("#nav-collapsible").classList.toggle("in"); - } - onClick(toggleMenu, onclick); - - final classes:Array<Element> = cast document.querySelectorAll(".dropdown-toggle"); - for (klass in classes) { - klass.onclick = e -> { - final isActive = klass.classList.toggle("focus"); - hideMenus(); - final menu = klass.parentElement.querySelector(".dropdown-menu"); - if (isActive) menu.style.display = "block"; - else menu.style.display = "none"; - } - klass.onmouseover = klass.onclick; - } - final classes:Array<Element> = cast document.querySelectorAll(".dropdown"); - for (klass in classes) { - klass.onmouseleave = e -> { - final toggle:Element = cast klass.querySelector(".dropdown-toggle"); - toggle.classList.remove("focus"); - toggle.blur(); - final menu = klass.querySelector(".dropdown-menu"); - menu.style.display = ""; - } - } - - final exitBtn = ge("#exitBtn"); - exitBtn.onclick = e -> { - if (main.isUser()) main.send({type: Logout}); - else ge("#guestname").focus(); - exitBtn.blur(); - hideMenus(); - } - - final swapLayoutBtn = ge("#swapLayoutBtn"); - swapLayoutBtn.onclick = e -> { - final p = ge("#main"); - if (ge("#main").firstElementChild == ge("#chatwrap")) { - // do not remove videowrap with insertBefore - // because this will recreate iframe-based players - p.appendChild(p.removeChild(p.children[1])); // gutter - p.appendChild(p.removeChild(p.children[0])); // chat - p.appendChild(p.removeChild(p.children[1])); // clear - } else { - p.insertBefore(p.children[2], p.children[0]); - p.insertBefore(p.children[2], p.children[1]); - } - final p = ge("#controlsrow"); - p.insertBefore(p.children[1], p.children[0]); - final p = ge("#playlistrow"); - p.insertBefore(p.children[1], p.children[0]); - settings.isSwapped = ge("#main").firstElementChild == ge("#videowrap"); - Settings.write(settings); - initSplit(); - swapLayoutBtn.blur(); - hideMenus(); - main.scrollChatToEnd(); - } - if (settings.isSwapped) swapLayoutBtn.onclick(); - final removeBtn = ge("#removeVideoBtn"); - removeBtn.onclick = e -> { - final has = main.toggleVideoElement(); - if (has || main.isListEmpty()) removeBtn.innerText = Lang.get("removeVideo"); - else removeBtn.innerText = Lang.get("addVideo"); - removeBtn.blur(); - hideMenus(); - } + static function saveSplitSize():Void { + final sizes = document.body.style.gridTemplateColumns.split(" "); + if (settings.isSwapped) sizes.reverse(); + settings.playerSize = Std.parseFloat(sizes[0]); + settings.chatSize = Std.parseFloat(sizes[sizes.length - 1]); + Settings.write(settings); } public static function initTextButtons(main:Main):Void { @@ -292,7 +233,6 @@ class Buttons { if (secs > 5) secs = 1; main.setSynchThreshold(secs); updateSynchThresholdBtn(); - synchThresholdBtn.blur(); } updateSynchThresholdBtn(); @@ -301,9 +241,15 @@ class Buttons { settings.hotkeysEnabled = !settings.hotkeysEnabled; Settings.write(settings); updateHotkeysBtn(); - hotkeysBtn.blur(); } updateHotkeysBtn(); + + final removeBtn = ge("#removeVideoBtn"); + removeBtn.onclick = e -> { + final has = main.toggleVideoElement(); + if (has || main.isListEmpty()) removeBtn.innerText = Lang.get("removeVideo"); + else removeBtn.innerText = Lang.get("addVideo"); + } } public static function initHotkeys(main:Main, player:Player):Void { @@ -338,11 +284,6 @@ class Buttons { } } - static function hideMenus():Void { - final menus:Array<Element> = cast document.querySelectorAll(".dropdown-menu"); - for (menu in menus) menu.style.display = ""; - } - static function updateSynchThresholdBtn():Void { final text = Lang.get("synchThreshold"); final secs = settings.synchThreshold; diff --git a/src/client/ClientSettings.hx b/src/client/ClientSettings.hx index 213d463..03f1d23 100644 --- a/src/client/ClientSettings.hx +++ b/src/client/ClientSettings.hx @@ -5,8 +5,8 @@ typedef ClientSettings = { name:String, hash:String, isExtendedPlayer:Bool, - chatSize:Int, - playerSize:Int, + playerSize:Float, + chatSize:Float, synchThreshold:Int, isSwapped:Bool, isUserListHidden:Bool, diff --git a/src/client/Main.hx b/src/client/Main.hx index 0844636..730742f 100644 --- a/src/client/Main.hx +++ b/src/client/Main.hx @@ -54,11 +54,11 @@ class Main { name: "", hash: "", isExtendedPlayer: false, - chatSize: 40, - playerSize: 60, + playerSize: 70, + chatSize: 30, synchThreshold: 2, isSwapped: false, - isUserListHidden: false, + isUserListHidden: true, latestLinks: [], hotkeysEnabled: true } @@ -120,7 +120,6 @@ class Main { function initListeners():Void { Buttons.init(this); - MobileView.init(); ge("#leader_btn").onclick = e -> { // change button style before answer @@ -572,9 +571,9 @@ class Main { } function showGuestLoginPanel():Void { - ge("#guestlogin").style.display = "block"; + ge("#guestlogin").style.display = "flex"; ge("#guestpassword").style.display = "none"; - ge("#chatline").style.display = "none"; + ge("#chatbox").style.display = "none"; ge("#exitBtn").textContent = Lang.get("login"); window.dispatchEvent(new Event("resize")); } @@ -582,7 +581,7 @@ class Main { function hideGuestLoginPanel():Void { ge("#guestlogin").style.display = "none"; ge("#guestpassword").style.display = "none"; - ge("#chatline").style.display = "block"; + ge("#chatbox").style.display = "flex"; ge("#exitBtn").textContent = Lang.get("exit"); if (isAdmin()) ge("#clearchatbtn").style.display = "inline-block"; window.dispatchEvent(new Event("resize")); @@ -590,11 +589,10 @@ class Main { function showGuestPasswordPanel():Void { ge("#guestlogin").style.display = "none"; - ge("#chatline").style.display = "none"; - ge("#guestpassword").style.display = "block"; + ge("#chatbox").style.display = "none"; + ge("#guestpassword").style.display = "flex"; (cast ge("#guestpass") : InputElement).type = "password"; - ge("#guestpass_icon").classList.add("glyphicon-eye-open"); - ge("#guestpass_icon").classList.remove("glyphicon-eye-close"); + ge("#guestpass_icon").setAttribute("name", "eye"); } function updateClients(newClients:Array<ClientData>):Void { @@ -613,7 +611,7 @@ class Main { public function serverMessage(type:Int, ?text:String, isText = true):Void { final msgBuf = ge("#messagebuffer"); final div = document.createDivElement(); - final time = "[" + Date.now().toString().split(" ")[1] + "] "; + final time = Date.now().toString().split(" ")[1]; switch (type) { case 1: div.className = "server-msg-reconnect"; @@ -626,8 +624,13 @@ class Main { div.textContent = time + text + " " + Lang.get("entered"); case 4: div.className = "server-whisper"; - if (isText) div.textContent = time + text; - else div.innerHTML = time + text; + div.innerHTML = '<div class="head"> + <div class="server-whisper"></div> + <span class="timestamp">$time</span> + </div>'; + final textDiv = div.querySelector(".server-whisper"); + if (isText) textDiv.textContent = text; + else textDiv.innerHTML = text; default: } msgBuf.appendChild(div); @@ -642,7 +645,7 @@ class Main { final list = new StringBuf(); for (client in clients) { list.add('<div class="userlist_item">'); - if (client.isLeader) list.add('<span class="glyphicon glyphicon-star-empty"></span>'); + if (client.isLeader) list.add('<ion-icon name="play"></ion-icon>'); final klass = client.isAdmin ? "userlist_owner" : ""; list.add('<span class="$klass">${client.name}</span></div>'); } @@ -663,16 +666,20 @@ class Main { final userDiv = document.createDivElement(); userDiv.className = 'chat-msg-$name'; + final headDiv = document.createDivElement(); + headDiv.className = "head"; + final tstamp = document.createSpanElement(); tstamp.className = "timestamp"; - if (time == null) time = "[" + Date.now().toString().split(" ")[1] + "] "; + if (time == null) time = Date.now().toString().split(" ")[1]; tstamp.textContent = time; final nameDiv = document.createElement("strong"); nameDiv.className = "username"; - nameDiv.textContent = name + ": "; + nameDiv.textContent = name; - final textDiv = document.createSpanElement(); + final textDiv = document.createDivElement(); + textDiv.className = "text"; text = text.htmlEscape(); if (text.startsWith("/")) { @@ -694,8 +701,9 @@ class Main { } } - userDiv.appendChild(tstamp); - userDiv.appendChild(nameDiv); + userDiv.appendChild(headDiv); + headDiv.appendChild(nameDiv); + headDiv.appendChild(tstamp); userDiv.appendChild(textDiv); msgBuf.appendChild(userDiv); if (isInChatEnd) { @@ -763,8 +771,8 @@ class Main { function setLeaderButton(flag:Bool):Void { final leaderBtn = ge("#leader_btn"); - if (flag) leaderBtn.classList.add("label-success"); - else leaderBtn.classList.remove("label-success"); + if (flag) leaderBtn.classList.add("success-bg"); + else leaderBtn.classList.remove("success-bg"); } function setPlaylistLock(isOpen:Bool):Void { @@ -773,15 +781,15 @@ class Main { if (isOpen) { lockPlaylist.title = Lang.get("playlistOpen"); lockPlaylist.classList.add("btn-success"); - lockPlaylist.classList.remove("btn-danger"); - icon.classList.add("glyphicon-ok"); - icon.classList.remove("glyphicon-lock"); + 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.remove("btn-success"); - icon.classList.add("glyphicon-lock"); - icon.classList.remove("glyphicon-ok"); + lockPlaylist.classList.add("danger"); + lockPlaylist.classList.remove("success"); + icon.setAttribute("name", "lock-closed"); } } diff --git a/src/client/MobileView.hx b/src/client/MobileView.hx deleted file mode 100644 index 52d06f9..0000000 --- a/src/client/MobileView.hx +++ /dev/null @@ -1,29 +0,0 @@ -package client; - -import js.Browser.document; -import client.Main.ge; - -class MobileView { - - public static function init():Void { - final mvbtn = ge("#mv_btn"); - mvbtn.onclick = e -> { - final hasMobileView = Utils.toggleFullScreen(document.documentElement); - final vwrap = ge("#videowrap"); - if (hasMobileView) { - document.body.classList.add("mobile-view"); - mvbtn.classList.add("active"); - if (vwrap.children[0].id == "currenttitle") { - vwrap.appendChild(vwrap.children[0]); - } - } else { - document.body.classList.remove("mobile-view"); - mvbtn.classList.remove("active"); - if (vwrap.children[0].id != "currenttitle") { - vwrap.insertBefore(vwrap.children[1], vwrap.children[0]); - } - } - } - } - -} diff --git a/src/client/Player.hx b/src/client/Player.hx index cdbccfd..7572673 100644 --- a/src/client/Player.hx +++ b/src/client/Player.hx @@ -186,24 +186,17 @@ class Player { public function addVideoItem(item:VideoItem, atEnd:Bool):Void { final url = item.url.htmlEscape(true); final itemEl = Utils.nodeFromString( - '<li class="queue_entry pluid-0" title="${Lang.get("addedBy")}: ${item.author}"> - <a class="qe_title" href="$url" target="_blank">${item.title.htmlEscape()}</a> - <span class="qe_time">${duration(item.duration)}</span> - <div class="qe_clear"></div> - <div class="btn-group"> - <button class="btn btn-xs btn-default qbtn-play"> - <span class="glyphicon glyphicon-play"></span>${Lang.get("play")} - </button> - <button class="btn btn-xs btn-default qbtn-next"> - <span class="glyphicon glyphicon-share-alt"></span>${Lang.get("setNext")} - </button> - <button class="btn btn-xs btn-default qbtn-tmp"> - <span class="glyphicon glyphicon-flag"></span> - </button> - <button class="btn btn-xs btn-default qbtn-delete"> - <span class="glyphicon glyphicon-trash"></span>${Lang.get("delete")} - </button> - </div> + '<li class="queue_entry info" title="${Lang.get("addedBy")}: ${item.author}"> + <header> + <span class="qe_time">${duration(item.duration)}</span> + <h4><a class="qe_title" href="$url" target="_blank">${item.title.htmlEscape()}</a></h4> + </header> + <span class="controls"> + <button class="qbtn-play" title="${Lang.get("play")}"><ion-icon name="play"></ion-icon></button> + <button class="qbtn-next" title="${Lang.get("setNext")}"><ion-icon name="arrow-up"></ion-icon></button> + <button class="qbtn-tmp"><ion-icon></ion-icon></button> + <button class="qbtn-delete" title="${Lang.get("delete")}"><ion-icon name="close"></ion-icon></button> + </span> </li>' ); items.addItem(item, atEnd, itemPos); @@ -214,8 +207,10 @@ class Player { } function setItemElementType(item:Element, isTemp:Bool):Void { - final text = isTemp ? Lang.get("makePermanent") : Lang.get("makeTemporary"); - item.querySelector(".qbtn-tmp").innerHTML = '<span class="glyphicon glyphicon-flag"></span>$text'; + final btn = item.querySelector(".qbtn-tmp"); + btn.title = isTemp ? Lang.get("makePermanent") : Lang.get("makeTemporary"); + final iconType = isTemp ? "lock-open" : "lock-closed"; + btn.firstElementChild.setAttribute("name", iconType); if (isTemp) item.classList.add("queue_temp"); else item.classList.remove("queue_temp"); } diff --git a/src/client/Split.hx b/src/client/Split.hx index 338b96f..66055d0 100644 --- a/src/client/Split.hx +++ b/src/client/Split.hx @@ -2,9 +2,6 @@ package client; @:native("Split") extern class Split { - function new(divs:Array<String>, opts:Dynamic):Void; - function getSizes():Array<Int>; - function setSizes(sizes:Array<Int>):Void; - function collapse(index:Int):Void; - function destroy(?preserveStyles:Bool = false, ?preserveGutters:Bool = false):Void; + function new(options:Any):Void; + function destroy(?immediate:Bool = true):Void; } |
