callback/public/components.js

183 lines
No EOL
6.6 KiB
JavaScript

nr.defineComponent({
name: "login",
template: `
<div style="height: 100vh; width: 100vw;" class="d-flex justify-content-center align-items-center">
<div id="login" class="card" style="max-width: 30rem; flex: 1 1 auto;">
<div class="header w-100 d-flex justify-content-center">
<img src="/favicon.png" style="width: 3rem;">
</div>
<div class="header">Welcome to <code>callback</code>.</div>
<div class="body">
<div class="fill-error alert m-0 m-top-2" style="display: none;">
error
</div>
<div class="textfield m-0 m-bottom-2 m-top-2">
<span class="label">Username</span>
<input type="text" placeholder="">
</div>
<div class="fill-primary linear-progress indeterminate m-bottom-2" style="display: none;"><div></div></div>
<button class="small w-100 fill-primary btn" type="submit">Login</button>
</div>
</div>
</div>
`,
beforeCreate: () => {
return { useShadowRoot: false }
},
afterCreate: (shadowRoot, config = {}, env) => {
const compName = nr.components[nr.mountedComponents[env.mountingTo]].name;
const ctx = nr.findComponentById(env.cid);
const form = {
loginButton: ctx.querySelector('button'),
progressBar: ctx.querySelector('.linear-progress'),
usernameField: ctx.querySelector('.textfield input'),
errorContainer: ctx.querySelector('.alert')
}
if (localStorage.getItem('username')) {
form.usernameField.value = localStorage.getItem('username');
handleLogin();
}
form.loginButton.addEventListener('click', handleLogin);
function showError(error) {
form.progressBar.style.display = 'none';
form.loginButton.disabled = false;
form.usernameField.disabled = false;
form.errorContainer.style.display = 'block';
form.errorContainer.textContent = error;
form.usernameField.focus();
}
function handleLogin() {
try {
form.errorContainer.style.display = 'none';
form.progressBar.style.display = 'block';
form.loginButton.disabled = true;
form.usernameField.disabled = true;
const username = form.usernameField.value;
if (!username) throw new Error('Username cannot be empty');
console.log(`[${compName}] Trying to connect as ${username}`);
let protocol
switch (window.location.protocol) {
case 'http:':
protocol = 'ws:';
break;
case 'https:':
protocol = 'wss:';
break;
default:
throw new Error('Unknown page protocol');
}
window.callback = {
socket: new WebSocket(`${protocol}//${window.location.host}?u=${encodeURIComponent(username)}`)
}
function handleWSLogin(message) {
try {
const res = JSON.parse(message.data);
if (res.error) throw new Error(res.message);
localStorage.setItem('username', username);
console.log(`[${compName}] Logged in as ${username}`)
nr.unmount(env.mountingTo);
nr.mount(config?.appComponent || 'callback', env.mountingTo)
} catch (e) {
showError(e.message);
console.error(e);
}
}
window.callback.socket.addEventListener('open', console.log(`[${compName}] Connected to websocket`));
window.callback.socket.addEventListener('message', handleWSLogin);
} catch (e) {
showError(e.message);
console.error(e);
}
}
}
});
nr.defineComponent({
name: 'callback',
template: `
<div class="d-flex">
<div class="d-flex" style="height: 100vh; width: 100vw; position: fixed; left: -100%; transition: left 0.25s ease-out; z-index: 1000" id="sidebar">
<div class="navdrawer modal" id="sidebarbody">
<div style="all: unset;">
<div class="d-flex w-100 justify-content-space-between align-items-center">
<img src="/favicon.png" style="width: 1.5rem" alt="Logo" class="m-right-3">
<div class="w-100 d-flex align-items-center">
<span class="text-bold" style="margin-right: auto;">Chats</span>
<button class="small fill-primary btn w-50">New</button>
</div>
</div>
</div>
<div id="chats">
<div class="active">
<span class="label">Label</span>
</div>
<div>
<span class="label">Label</span>
</div>
</div>
</div>
</div>
<div class="d-flex flex-column w-100" style="height: 100vh;">
<div style="background-color: var(--md-sys-color-surface-container)" class="d-flex align-items-center w-100 p-3 gap-3">
<span class="material-symbols-outlined" id="menutoggle">menu</span>
<span>Person</span>
</div>
<div style="height: 100%;">
CHATDIV
</div>
<div style="background-color: var(--md-sys-color-surface-container)" class="d-flex align-items-center w-100">
<div class="textfield m-0 w-100 m-left-3">
<span class="label">Message</span>
<input type="text" placeholder="">
</div>
<button type="submit" class="material-symbols-outlined fill-primary btn m-right-3" disabled>send</button>
</div>
</div>
</div>
`,
beforeCreate: () => {
return { useShadowRoot: false }
},
afterCreate: () => {
const sidebar = document.querySelector('#sidebar');
const sidebarBody = document.querySelector('#sidebarbody');
const menutoggle = document.querySelector('#menutoggle');
menutoggle.addEventListener('click', () => {
sidebar.style.left = "0";
});
sidebar.addEventListener('click', (event) => {
if (!sidebarBody.contains(event.target)) {
sidebar.style.left = "-100%";
}
});
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize);
const fortyRemInPixels = 65 * rootFontSize;
if (entry.contentRect.width > fortyRemInPixels) {
sidebar.style.position = 'static';
sidebarBody.classList.remove('modal');
sidebarBody.classList.add('standart');
menutoggle.style.display = 'none';
} else {
sidebar.style.position = 'fixed';
sidebarBody.classList.remove('standart');
sidebarBody.classList.add('modal');
menutoggle.style.display = 'block';
}
}
});
resizeObserver.observe(document.body);
}
})