From f434022e88261f5f4ab844c1de34a93aa17e15db Mon Sep 17 00:00:00 2001 From: ktyl Date: Tue, 9 Jul 2024 01:55:13 +0100 Subject: [PATCH] feat: add much styling, in-flight animations --- index.html | 12 ++-- main.js | 181 ++++++++++++++++++++++++++++++++++++++++++++--------- styles.css | 126 +++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 34 deletions(-) create mode 100644 styles.css diff --git a/index.html b/index.html index cfc8efb..3014cb3 100644 --- a/index.html +++ b/index.html @@ -1,20 +1,22 @@ + +

Hester Gomez

+

(Luna, )

- - - - - +
+ + +
diff --git a/main.js b/main.js index 0ac89ae..1d10988 100644 --- a/main.js +++ b/main.js @@ -1,39 +1,141 @@ +// how to we communicate... +// * in flight +// * arrived! (probably) <- this is the tricky one. we know enough time has passed for the message +// * received to have been received, but we are only halfway to the earliest possible +// * read acknowledgement. +// +// we know the length of the roundtrip: it is 2x the light lag. progress bars show a passage of time, +// it could scroll: +// * along the bottom of the message +// * across the message +// * as it is being sent, a transluscent red bar grows from right to left (towards their messages) +// * while we are waiting for acknowledgement, a similar blue bar brows from left to right +// * next to the message + conversation = [ - { c: 1, message: "hows space"}, - { c: 0, message: "trying to work out if the coffees shit but"}, - { c: 0, message: "taste not happenin"}, - { c: 1, message: "maybe youre being spared"}, - { c: 0, message: "youre right"}, - { c: 0, message: "ship swill is a delicacy to no one"}, - { c: 0, message: "at least the caffeines doing its job"}, - { c: 1, message: "good to hear!"}, - { c: 1, message: "induction today wish me luckk"}, - { c: 0, message: "break a leg!"}, - { c: 1, message: ":)"} + { c: 1, text: "hows space"}, + { c: 0, text: "trying to work out if the coffees shit but"}, + { c: 0, text: "taste not happenin"}, + { c: 1, text: "maybe youre being spared"}, + { c: 0, text: "youre right"}, + { c: 0, text: "ship swill is a delicacy to no one"}, + { c: 0, text: "at least the caffeines doing its job"}, + { c: 1, text: "good to hear!"}, + { c: 1, text: "induction today wish me luckk"}, + { c: 0, text: "break a leg!"}, + { c: 1, text: ":)"} ]; let messageIdx = 1; let title = "hester"; let pings = 0; +function getMessageList() { + return document.getElementById("messages"); +} + +function getMessageElement(messageIdx) { + let list = getMessageList(); + let messageElements = list.getElementsByTagName("li"); + return messageElements[messageIdx]; +} + +class SentMessage { + constructor(oneWayLag, idx) { + this.oneWayLag = oneWayLag; + this.idx = idx; + //this.content = conversation[idx].text; + this.createdTime = Date.now(); + + this.updateBarIntervalId = setInterval(() => { + let elapsed = Math.abs(Date.now() - this.createdTime) / 1000; + let progress = elapsed / this.oneWayLag; + + // divide in half so we measure the round trip + progress /= 2; + + this.setProgress(progress); + }, 10); + } + + setProgress(amount) { + let thisMessage = getMessageElement(this.idx); + let progressBar = thisMessage.getElementsByClassName("progress")[0]; + + if (amount < 0.5) { + this.updateStatus("in flight"); + progressBar.style.backgroundColor = "red"; + amount *= 2; + } + else if (amount < 1) { + this.updateStatus("completing round trip"); + progressBar.style.backgroundColor = "blue"; + amount -= 0.5; + amount *= 2; + } + else { + this.updateStatus("delivered"); + clearInterval(this.updateBarIntervalId); + amount = 0; + } + amount = Math.min(amount, 1); + let percentage = `${amount * 100}%`; + progressBar.style.width = percentage; + + } + + updateStatus(newStatus) { + let thisMessage = getMessageElement(this.idx); + let statusElement = thisMessage.getElementsByClassName("message-status")[0]; + statusElement.innerHTML = newStatus; + } +} + function updateTextBox(message) { - document.getElementById("textbox").value = message; + document.getElementById("textbox-input").value = message; } // show messages up to index function showMessages(idx) { - let messageList = document.getElementById("messages"); + let messageList = getMessageList(); + + // TODO: rebuilding the DOM here clears this status of sent messages. instead of + // rebuilding it completely, append a new message onto the end of the inner html. + // TODO: is this also the juncture to clear the status of previous messages? // clear current messages messageList.innerHTML = ""; // inject messages into ul for (let i = 0; i < idx; i++) { - messageList.innerHTML += `
  • ${conversation[i].message}

  • `; + let message = conversation[i]; + messageList.innerHTML += getMessageHtml(message.text, isMessageOurs(message)); } } +function getMessageHtml(text, isOurs) { + let owner = isOurs ? "ours" : "theirs"; + + // we don't want loading bars on their messages, since we have no idea if one has been sent + // until it arrives + let progressBar = isOurs + ? `
    ` + : ""; + + let statusText = isOurs + ? `

    status

    ` + : ""; + + let message = `
  • + + ${progressBar} + ${text} +
    ${statusText}
  • `; + + return message; +} + function isMessageOurs(message) { if (!message) return false; @@ -53,7 +155,7 @@ function getOurNextMessage(idx) { function getLightLag() { lag = 3.0 + Math.sin(Date.now() / 10000); - return Math.round(lag * 100) / 100; + return Math.round(lag * 10000) / 10000; } function updatePings() { @@ -104,6 +206,7 @@ function waitForIncomingMessages() { messageIdx++; pings++; + // update the chat with their message updateChat(messageIdx); }, delaySeconds * 1000); } @@ -113,46 +216,66 @@ function updatePreviewText(messageIdx) { // display our next message or an empty box let nextMessage = conversation[messageIdx]; let previewText = isMessageOurs(nextMessage) - ? conversation[messageIdx].message + ? conversation[messageIdx].text : ""; updateTextBox(previewText); } -function send() { - // we have interacted with the page so remove all pings - clearPings(); +function sendOurMessage() { + // the message we are sending is the one currently in the text box, so we should construct it + // before advancing the conversation + let oneWayLag = getLightLag(); + let currentMessage = conversation[messageIdx]; + let sentMessage = new SentMessage(oneWayLag, messageIdx); + console.log(sentMessage); - // we are still waiting to receive messages so pressing the button oughtn't do anything - if (!isMessageOurs(conversation[messageIdx])) - return; + // message.send() + // when we send the message, we want to start an interval that updates the progress animation + // message.setProgress() should be a private method that updates the appropriate element - // advance conversation state + // advance conversation with our next message messageIdx++; - + nextMessage = conversation[messageIdx]; + // if the next message is not ours, we need to wait for it: set off a thread that // will update the message index and the displayed messages in a few seconds // we are still waiting to receive messages so pressing the button oughtn't do anything - if (!isMessageOurs(conversation[messageIdx])) { + if (!isMessageOurs(nextMessage)) { waitForIncomingMessages(); } updateChat(messageIdx); } -function updateLightLag(lag) { - document.getElementById("delay").innerHTML = lag.toFixed(2) + " seconds"; +function pressSendButton() { + // we have interacted with the page so remove all pings + clearPings(); + + // peek conversation state + let nextMessage = conversation[messageIdx]; + + // we are still waiting to receive messages so pressing the button oughtn't do anything + if (!isMessageOurs(nextMessage)) + return; + + sendOurMessage(); +} + +function updateLightLag() { + let text = getLightLag().toFixed(5) + " seconds"; + document.getElementById("delay-text").innerHTML = text; } function startLightLagUpdateLoop() { setInterval(() => { - updateLightLag(getLightLag()); + updateLightLag(); }, 1000); } function init() { showMessages(messageIdx); // load the first message into the text box - updateTextBox(conversation[messageIdx].message); + updateTextBox(conversation[messageIdx].text); pings = 1; document.title = title; diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..e491f89 --- /dev/null +++ b/styles.css @@ -0,0 +1,126 @@ +html { + font-family: sans-serif; +} + +h1 { + display: inline; +} + +.delay { + display: inline; +} + +.rounded-rectangle { + border-width: 2px; + border: black; + border-style: solid; + border-radius: 1em; + + padding: 7px; +} + +.message-content { + z-index: 1; + position: absolute; +} + +.message-content.theirs { + background-color: yellow; + left: 0; +} + +.message-content.ours { + background-color: pink; + right: 0; + margin-bottom: 0.5em; +} + +ul { + margin-bottom: 1.5em; + padding: 0; + list-style: none; +} + +li { + height: 2.5em; + width: 100%; + + margin-top: 1.5em; + position: relative; +} + +#textbox { + margin-top: 2em; + padding: 0; +} + +#textbox input { + margin: 0.5em; + margin-left: 0; + + width: 85%; + font-size: 1em; +} + +button { + margin: 0.5em; + padding: 0; + width: 10%; + position: absolute; + right: 0; + font-size: 1em; +} + +/* +.loader-container { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} +*/ + + +.progress-bar { + width: 100%; + height: 100%; + opacity: 80%; + max-width: 400px; + background-color: #e0e0e0; + border-radius: 10px; + overflow: hidden; + position: absolute; + + z-index: -1; + top: 0; + left: 0; +} + +.progress { + opacity: 80%; + width: 0; + height: 100%; + background-color: #ff5c35; + /* + animation: fill 4s infinite; + */ +} + +.message-status { + margin-top: 1em; + position: absolute; + top: 2.3em; + right: 1em; + font-size: .8em; +} + +/* +@keyframes fill { + 0% { + width: 0; + } + 100% { + width: 100%; + } +} +*/