add half-working client
This commit is contained in:
141
client/scrolling_textbox.ts
Normal file
141
client/scrolling_textbox.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { DELAY_WORDS } from "./settings";
|
||||
import { el, sleep } from "./tools";
|
||||
|
||||
export class ScrollingTextBox {
|
||||
private dom_root: HTMLDivElement;
|
||||
|
||||
private prev_line_words: HTMLDivElement[];
|
||||
private cur_line_words: HTMLDivElement[];
|
||||
|
||||
private prev_line: HTMLParagraphElement;
|
||||
private current_line: HTMLParagraphElement;
|
||||
|
||||
public constructor() {
|
||||
this.dom_root = el.div([], ["scrolling-textbox"]);
|
||||
this.cur_line_words = [];
|
||||
this.prev_line_words = [];
|
||||
|
||||
this.current_line = el.div(this.cur_line_words, ["paragraph", "active"]);
|
||||
this.prev_line = el.div(this.prev_line_words, ["paragraph", "previous"]);
|
||||
|
||||
this.dom_root.appendChild(this.prev_line);
|
||||
this.dom_root.appendChild(this.current_line);
|
||||
}
|
||||
|
||||
public async update_current(text: string): Promise<void> {
|
||||
this.update_words(this.current_line, this.cur_line_words, text);
|
||||
await sleep(10);
|
||||
this.show_new_words(this.cur_line_words);
|
||||
}
|
||||
|
||||
public async finish_line(text: string): Promise<void> {
|
||||
this.update_words(this.current_line, this.cur_line_words, text, true);
|
||||
const current_height = this.current_line.getBoundingClientRect().height;
|
||||
this.prev_line.style.transform = `translateY(calc(-100% - ${current_height}px))`;
|
||||
this.current_line.style.transform = "translateY(-100%)";
|
||||
this.current_line.style.color = "grey";
|
||||
await sleep(500);
|
||||
this.dom_root.removeChild(this.prev_line);
|
||||
this.prev_line = this.current_line;
|
||||
this.prev_line_words = this.cur_line_words;
|
||||
this.prev_line.className = "paragraph previous";
|
||||
this.current_line = el.div([], ["paragraph", "active"]);
|
||||
this.cur_line_words = [];
|
||||
this.dom_root.appendChild(this.current_line);
|
||||
await sleep(10);
|
||||
}
|
||||
|
||||
public async add_line(text: string): Promise<void> {
|
||||
const current_height = this.current_line.getBoundingClientRect().height;
|
||||
const next_words = this.make_words(text);
|
||||
const next_line = el.div(next_words, ["paragraph", "previous"]);
|
||||
next_line.style.transform = `translateY(${current_height}px)`;
|
||||
next_line.style.opacity = "0";
|
||||
this.dom_root.appendChild(next_line);
|
||||
await sleep(50);
|
||||
next_line.style.transform = "translateY(0px)";
|
||||
next_line.style.opacity = "1";
|
||||
this.current_line.style.transform = "translateY(-100%)";
|
||||
this.current_line.style.color = "grey";
|
||||
this.prev_line.style.transform = `translateY(calc(-100% - ${current_height}px))`;
|
||||
await sleep(500);
|
||||
this.dom_root.removeChild(this.prev_line);
|
||||
this.prev_line = this.current_line;
|
||||
this.prev_line_words = this.cur_line_words;
|
||||
this.prev_line.className = "paragraph previous";
|
||||
this.current_line = next_line;
|
||||
this.current_line.className = "paragraph active";
|
||||
this.cur_line_words = next_words;
|
||||
}
|
||||
|
||||
private async show_new_words(words: HTMLParagraphElement[]): Promise<void> {
|
||||
for (const word of words) {
|
||||
if (word.style.opacity != "0") { continue; }
|
||||
word.style.opacity = "1";
|
||||
word.style.transform = "scale(100%)";
|
||||
await sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
private update_words(
|
||||
parent: HTMLDivElement,
|
||||
words: HTMLParagraphElement[],
|
||||
new_text: string,
|
||||
override: boolean = false,
|
||||
): void {
|
||||
const new_words = new_text.split(" ");
|
||||
if (!override) {
|
||||
for (let i = 0; i < DELAY_WORDS; ++i) { new_words.pop(); }
|
||||
}
|
||||
if (words.length > new_words.length) {
|
||||
this.trim_words(parent, words, new_words.length);
|
||||
for (let i = 0; i < new_words.length; ++i) {
|
||||
if (words[i].innerText == new_words[i]) { continue; }
|
||||
words[i].innerText = new_words[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
const to_push: HTMLParagraphElement[] = [];
|
||||
for (let i = 0; i < new_words.length; ++i) {
|
||||
if (i < words.length) {
|
||||
if (new_words[i] == words[i].innerText) { continue; }
|
||||
words[i].innerText = new_words[i];
|
||||
continue;
|
||||
}
|
||||
const word = el.p(new_words[i], ["word"]);
|
||||
if (!override) {
|
||||
word.style.opacity = "0";
|
||||
word.style.transform = "scale(0)";
|
||||
}
|
||||
words.push(word);
|
||||
to_push.push(word);
|
||||
}
|
||||
parent.append(...to_push);
|
||||
}
|
||||
|
||||
private trim_words(
|
||||
parent: HTMLDivElement,
|
||||
words: HTMLParagraphElement[],
|
||||
target_length: number
|
||||
): void {
|
||||
if (target_length >= words.length || words.length == 0) { return; }
|
||||
for (let i = words.length - 1; i >= target_length; --i) {
|
||||
const word = words.pop();
|
||||
if (word === undefined) { continue; }
|
||||
parent.removeChild(word);
|
||||
}
|
||||
}
|
||||
|
||||
private make_words(text: string): HTMLDivElement[] {
|
||||
const words = text.split(" ");
|
||||
let res = [];
|
||||
for (const word of words) {
|
||||
res.push(el.p(word, ["word"]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public get dom(): HTMLDivElement {
|
||||
return this.dom_root;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user