Skip to content

Commit

Permalink
Scroll to chat end button
Browse files Browse the repository at this point in the history
  • Loading branch information
RblSb committed Jun 20, 2023
1 parent cdf7f00 commit c476a16
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 54 deletions.
88 changes: 63 additions & 25 deletions res/client.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions res/css/des.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:root {
--background-video: #000;
--background-chat: #111;
--scroll-to-end-bg: #fff;
--midground: #888;
--foreground: #bbb;
--accent: #0055ff;
Expand Down Expand Up @@ -646,8 +647,27 @@ footer#footer {
font-style: italic;
}

#scroll-to-chat-end {
transition: opacity 200ms;
position: absolute;
margin-left: auto;
top: -4em;
right: 1em;
padding: 0.8em;
border-radius: 50%;
background-color: var(--scroll-to-end-bg);
}

#scroll-to-chat-end ion-icon {
color: var(--midground);
}

/* Chat input */

#chat-inputs-wrapper {
position: relative;
}

#chatbox {
padding-top: 1rem;
border-top: .063rem solid;
Expand Down
45 changes: 25 additions & 20 deletions res/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -185,29 +185,34 @@ <h4>${chat}</h4>
</ul>
<!-- Messages -->
<div id="messagebuffer"></div>
<!-- Message input -->
<div id="chatbox">
<input id="chatline" type="text" placeholder="${chatlinePlaceholder}">
<button id="smilesbtn" title="${emotes}">
<ion-icon name="happy"></ion-icon>
<div id="chat-inputs-wrapper">
<button id="scroll-to-chat-end" style="display: none; opacity: 0;" class="active">
<ion-icon name="arrow-down" role="img" class="md hydrated" aria-label="arrow down"></ion-icon>
</button>
</div>
<div id="smiles-wrap" class="collapsible">
<div id="smiles-list"></div>
</div>
<!-- Guest login -->
<div id="guestlogin" style="display: none;">
<label>${enterAsGuest}</label>
<input id="guestname" type="text" placeholder="${yourName}">
</div>
<div id="guestpassword" style="display: none;">
<label>${enterUserPassword}</label>
<div id="passwordbox">
<input id="guestpass" type="text" placeholder="${yourPassword}">
<button id="guestpass_icon">
<ion-icon name="eye"></ion-icon>
<!-- Message input -->
<div id="chatbox">
<input id="chatline" type="text" placeholder="${chatlinePlaceholder}">
<button id="smilesbtn" title="${emotes}">
<ion-icon name="happy"></ion-icon>
</button>
</div>
<div id="smiles-wrap" class="collapsible">
<div id="smiles-list"></div>
</div>
<!-- Guest login -->
<div id="guestlogin" style="display: none;">
<label>${enterAsGuest}</label>
<input id="guestname" type="text" placeholder="${yourName}">
</div>
<div id="guestpassword" style="display: none;">
<label>${enterUserPassword}</label>
<div id="passwordbox">
<input id="guestpass" type="text" placeholder="${yourPassword}">
<button id="guestpass_icon">
<ion-icon name="eye"></ion-icon>
</button>
</div>
</div>
</div>
</aside>

Expand Down
19 changes: 19 additions & 0 deletions src/client/Buttons.hx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,25 @@ class Buttons {
}
}

final scrollToChatEndBtn = ge("#scroll-to-chat-end");
function scrollToChatEndBtnAnim():Void {
if (scrollToChatEndBtn.style.opacity == "0") return;
scrollToChatEndBtn.style.opacity = "0";
scrollToChatEndBtn.addEventListener("transitionend", e -> {
scrollToChatEndBtn.style.display = "none";
}, {once: true});
}
scrollToChatEndBtn.onclick = e -> {
main.scrollChatToEnd();
scrollToChatEndBtnAnim();
}
// hide scroll button when chat is scrolled to the end
final msgBuf = ge("#messagebuffer");
msgBuf.onscroll = e -> {
if (msgBuf.offsetHeight + msgBuf.scrollTop < msgBuf.scrollHeight - 1) return;
scrollToChatEndBtnAnim();
}

ge("#clearchatbtn").onclick = e -> {
if (main.isAdmin()) main.send({type: ClearChat});
}
Expand Down
28 changes: 20 additions & 8 deletions src/client/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Main {
}

function new() {
haxe.Log.trace = Utils.nativeTrace;
player = new Player(this);
host = Browser.location.hostname;
if (host == "") host = "localhost";
Expand Down Expand Up @@ -790,22 +791,22 @@ class Main {
ws.send(Json.stringify(data));
}

static function chatMessageConnected():Void {
function chatMessageConnected():Void {
final div = document.createDivElement();
div.className = "server-msg-reconnect";
div.textContent = Lang.get("msgConnected");
final msgBuf = ge("#messagebuffer");
msgBuf.appendChild(div);
msgBuf.scrollTop = msgBuf.scrollHeight;
scrollChatToEnd();
}

static function chatMessageDisconnected():Void {
function chatMessageDisconnected():Void {
final div = document.createDivElement();
div.className = "server-msg-disconnect";
div.textContent = Lang.get("msgDisconnected");
final msgBuf = ge("#messagebuffer");
msgBuf.appendChild(div);
msgBuf.scrollTop = msgBuf.scrollHeight;
scrollChatToEnd();
}

public static function serverMessage(text:String, isText = true, withTimestamp = true):Void {
Expand Down Expand Up @@ -897,7 +898,8 @@ class Main {
text = filter.regex.replace(text, filter.replace);
}
textDiv.innerHTML = text;
final isInChatEnd = msgBuf.scrollTop + msgBuf.clientHeight >= msgBuf.scrollHeight - 1;
final isInChatEnd = msgBuf.scrollTop
+ msgBuf.clientHeight >= msgBuf.scrollHeight - 50;

if (isInChatEnd) { // scroll chat to end after images loaded
for (img in textDiv.getElementsByTagName("img")) {
Expand All @@ -917,17 +919,27 @@ class Main {
while (msgBuf.children.length > 200) {
msgBuf.removeChild(msgBuf.firstChild);
}
msgBuf.scrollTop = msgBuf.scrollHeight;
}
if (name == personal.name) {
msgBuf.scrollTop = msgBuf.scrollHeight;
if (isInChatEnd || name == personal.name) {
scrollChatToEnd();
} else {
showScrollToChatEndBtn();
}
if (onBlinkTab == null) blinkTabWithTitle("*Chat*");
}

function showScrollToChatEndBtn() {
final btn = ge("#scroll-to-chat-end");
btn.style.display = "block";
Timer.delay(() -> btn.style.opacity = "1", 0);
}

function onChatImageLoaded(e:Event):Void {
scrollChatToEnd();
(cast e.target : Element).onload = null;
final btn = ge("#scroll-to-chat-end");
btn.style.opacity = "0";
btn.style.display = "none";
}

var emoteMaxSize:Null<Int>;
Expand Down
9 changes: 9 additions & 0 deletions src/client/Utils.hx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ import js.html.Element;
import js.html.URL;

class Utils {
public static function nativeTrace(msg:Dynamic, ?infos:haxe.PosInfos):Void {
final fileData = '${infos.fileName}:${infos.lineNumber}';
var args:Array<Dynamic> = [fileData, msg];
if (infos.customParams != null) args = args.concat(infos.customParams);
js.Browser.window.console.log(
...haxe.Rest.of(args)
);
}

public static function isTouch():Bool {
return js.Syntax.code("'ontouchstart' in window");
}
Expand Down
Loading

0 comments on commit c476a16

Please sign in to comment.