185 lines
4.8 KiB
TypeScript
185 lines
4.8 KiB
TypeScript
import { isMobileOrTablet, rand } from '../../common/helper';
|
|
import seedrandom from 'seedrandom';
|
|
|
|
const nameColorPallete = {
|
|
H: [1, 360],
|
|
S: [30, 100],
|
|
L: [50, 100],
|
|
};
|
|
|
|
export class Chat {
|
|
public element = document.createElement('div');
|
|
private _history = document.createElement('div');
|
|
private _wrapper = document.createElement('div');
|
|
private _mobToggle = document.createElement('button');
|
|
private _inpBox = document.createElement('div');
|
|
private _input = document.createElement('input');
|
|
private _visible = true;
|
|
private _rehide = false;
|
|
private _keyhandler = true;
|
|
|
|
private _sendFn?: (message: string) => void;
|
|
|
|
get visible() {
|
|
return this._visible;
|
|
}
|
|
|
|
initialize() {
|
|
this.element.classList.add('chat__wrapper');
|
|
this._wrapper.classList.add('chat');
|
|
this._history.classList.add('chat__history');
|
|
this._inpBox.classList.add('chat__input-wrapper');
|
|
this._input.classList.add('chat__input');
|
|
this._mobToggle.classList.add('chat__toggle');
|
|
|
|
this._inpBox.append(this._input);
|
|
this._wrapper.append(this._history, this._inpBox);
|
|
this.element.append(this._mobToggle, this._wrapper);
|
|
|
|
this._input.setAttribute(
|
|
'placeholder',
|
|
'Type a message here and press Enter to send...',
|
|
);
|
|
|
|
this._input.setAttribute('maxlength', '260');
|
|
|
|
this._input.addEventListener('keydown', (e) => {
|
|
e.stopPropagation();
|
|
if (e.key === 'Enter') {
|
|
if (!this._input.value?.trim()) {
|
|
this._input.blur();
|
|
|
|
if (this._rehide) {
|
|
this.hide();
|
|
this._rehide = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (this._sendFn) {
|
|
this._sendFn(this._input.value);
|
|
}
|
|
|
|
this._input.value = null;
|
|
|
|
if (this._rehide) {
|
|
this.hide();
|
|
this._rehide = false;
|
|
}
|
|
} else if (e.key === 'Escape') {
|
|
this._input.blur();
|
|
this._input.value = null;
|
|
|
|
if (this._rehide) {
|
|
this.hide();
|
|
this._rehide = false;
|
|
}
|
|
}
|
|
});
|
|
|
|
this._input.addEventListener('focus', () => {
|
|
this.element.classList.add('focused');
|
|
});
|
|
|
|
this._input.addEventListener('blur', () => {
|
|
this.element.classList.remove('focused');
|
|
});
|
|
|
|
this._mobToggle.addEventListener('click', () => {
|
|
if (this._visible) {
|
|
this.hide();
|
|
} else {
|
|
this.focus();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('keydown', (e) => {
|
|
if (!this._keyhandler) {
|
|
return;
|
|
}
|
|
|
|
if (e.key === 'Enter' && (e.target as HTMLElement).tagName !== 'INPUT') {
|
|
this.focus(!this.visible);
|
|
}
|
|
});
|
|
|
|
document.body.append(this.element);
|
|
|
|
if (!isMobileOrTablet()) {
|
|
this.show();
|
|
} else {
|
|
this.hide();
|
|
}
|
|
}
|
|
|
|
public registerSendFunction(fn: (message: string) => void) {
|
|
this._sendFn = fn;
|
|
}
|
|
|
|
public show() {
|
|
this._visible = true;
|
|
this._wrapper.classList.add('visible');
|
|
this._wrapper.classList.remove('invisible');
|
|
}
|
|
|
|
public hide() {
|
|
this._visible = false;
|
|
this._wrapper.classList.remove('visible');
|
|
this._wrapper.classList.add('invisible');
|
|
}
|
|
|
|
public focus(rehide = false) {
|
|
if (!this._visible) {
|
|
this.show();
|
|
}
|
|
this._input.focus();
|
|
this._rehide = rehide;
|
|
}
|
|
|
|
public addMessage(sender: string, message: string, meta?: any) {
|
|
const msg = document.createElement('div');
|
|
const msgSender = document.createElement('div');
|
|
const msgTime = document.createElement('div');
|
|
const msgContent = document.createElement('div');
|
|
|
|
msg.classList.add('chat__message');
|
|
msgTime.classList.add('chat__message-timestamp');
|
|
msgSender.classList.add('chat__message-sender');
|
|
msgContent.classList.add('chat__message-content');
|
|
|
|
msg.append(msgTime, msgSender, msgContent);
|
|
|
|
const stamp = meta?.time ? new Date(meta.time) : new Date();
|
|
|
|
// TODO: timestamp utility
|
|
msgTime.innerText = `${stamp.getHours().toString().padStart(2, '0')}:${stamp
|
|
.getMinutes()
|
|
.toString()
|
|
.padStart(2, '0')}`;
|
|
msgSender.innerText = sender;
|
|
msgSender.style.setProperty('--name-color', this.getNameColor(sender));
|
|
msgContent.innerText = message;
|
|
|
|
// const bottomed = this._history.scrollTop ,this._history.scrollHeight;
|
|
this._history.append(msg);
|
|
this._history.scrollTop = this._history.scrollHeight;
|
|
|
|
setTimeout(() => {
|
|
msg.classList.add('chat__message--old');
|
|
}, 5000);
|
|
}
|
|
|
|
public getNameColor(name: string) {
|
|
const randgen = seedrandom(name);
|
|
const h = rand(randgen, nameColorPallete.H[0], nameColorPallete.H[1]);
|
|
const s = rand(randgen, nameColorPallete.S[0], nameColorPallete.S[1]);
|
|
const l = rand(randgen, nameColorPallete.L[0], nameColorPallete.L[1]);
|
|
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
|
|
}
|
|
|
|
public setKeyHandlerEnabled(isEnabled: boolean) {
|
|
this._keyhandler = isEnabled;
|
|
}
|
|
}
|