instance pane

main
jerl 2024-06-12 21:52:23 -07:00
parent 02294b0327
commit b8b7a7edd6
4 changed files with 100 additions and 42 deletions

View File

@ -94,7 +94,26 @@ function expandInstance(event) {
this.children[0].classList.toggle('collapsed'); this.children[0].classList.toggle('collapsed');
} }
function instanceClicked(event) {} function instanceClicked(event) {
let instance = this.parentElement.parentElement.instance;
let div = document.getElementById('instance');
if (div.classList.contains('hidden')) {
let disconnect = document.getElementById('disconnect');
if (window.instancelist[0] === instance)
disconnect.classList.add('hidden');
else
disconnect.classList.remove('hidden');
document.getElementById('instancename').textContent = instance.url;
let userlist = document.getElementById('userlist');
userlist.innerHTML = '';
instance.emit('list_users', {}, msg =>
userlist.innerHTML = msg.users.map(user =>
`<p>${user.displayname}</p>`).join('\n')
);
div.instance = instance;
}
div.classList.toggle('hidden');
}
function saveInstances() { function saveInstances() {
localStorage.setItem('instances', JSON.stringify( localStorage.setItem('instances', JSON.stringify(
@ -110,10 +129,9 @@ async function addInstance() {
let instancediv = this.parentElement.parentElement; let instancediv = this.parentElement.parentElement;
if (!this.textContent) if (!this.textContent)
return instancediv.remove(); return instancediv.remove();
let url = (/^[\w-]+:.+/.test(this.textContent) ? '' : 'https://') + this.textContent; if (window.instancelist.find(i => i.url === this.textContent))
if (window.instancelist.find(i => i.url === url))
return instancediv.remove(); return instancediv.remove();
let instance = await connectInstance(url); let instance = await connectInstance(this.textContent);
instancediv.instance = instance; instancediv.instance = instance;
await authenticateInstance(instancediv, true); await authenticateInstance(instancediv, true);
this.contentEditable = false; this.contentEditable = false;
@ -130,13 +148,29 @@ async function addInstance() {
// main app html // main app html
document.body.append(html.node` document.body.append(html.node`
<div id='profile' class='column hidden'>
<p><strong>profile</strong></p>
<label class='heading'>display name</label>
<input id='newname' onkeyup=${function(event) {
if (window.displayname === this.value)
document.getElementById('savename').classList.add('hidden');
else if (event.key === 'Enter')
changeName();
else
document.getElementById('savename').classList.remove('hidden');
}}>
<button class='hidden' id='savename' onclick=${changeName}>save</button>
<label class='heading'>authentication requests</label>
<div id='authrequests'></div>
</div>
<hr class='separator' color='#505050'>
<div id='home' class='column'> <div id='home' class='column'>
<div id='instancelist'> <div id='instancelist'>
<h3>vybe</h3> <h3>vybe</h3>
<p id='instances'>instances:<button onclick=${() => { <p id='instances'>instances:<button onclick=${() => {
let div = html.node` let div = html.node`
<div> <div>
<div class='instance'> <div class='instancetitle'>
<span></span> <span></span>
<span onblur=${addInstance} onkeydown=${function(event) { <span onblur=${addInstance} onkeydown=${function(event) {
if (event.key === 'Enter') { if (event.key === 'Enter') {
@ -156,23 +190,22 @@ document.body.append(html.node`
}>${window.name}</div> }>${window.name}</div>
</div> </div>
<hr class='separator' color='#505050'> <hr class='separator' color='#505050'>
<!-- create thread column goes here --> <div id='instance' class='column hidden'>
<hr class='separator' color='#505050'> <div class='content'>
<div id='profile' class='column hidden'> <p>instance: <strong id='instancename'></strong></p>
<p><strong>profile</strong></p> <h4>users</h4>
<label class='heading'>display name</label> <div id='userlist'>
<input id='newname' onkeyup=${function(event) {
if (window.displayname === this.value)
document.getElementById('savename').classList.add('hidden');
else if (event.key === 'Enter')
changeName();
else
document.getElementById('savename').classList.remove('hidden');
}}>
<button class='hidden' id='savename' onclick=${changeName}>save</button>
<label class='heading'>authentication requests</label>
<div id='authrequests'></div>
</div> </div>
</div>
<button id='disconnect' onclick=${function(event) {
document.getElementById('instance' + this.parentElement.instance.id).remove();
window.instancelist.splice(window.instancelist.indexOf(this.parentElement.instance), 1);
saveInstances();
document.getElementById('instance').classList.add('hidden');
}}>disconnect</button>
</div>
<hr class='separator' color='#505050'>
<!-- create thread column goes here -->
<hr class='separator' color='#505050'> <hr class='separator' color='#505050'>
`); `);
@ -180,7 +213,7 @@ for (let i = 0; i < instancelist.length; ++i) {
let instance = instancelist[i]; let instance = instancelist[i];
let div = html.node` let div = html.node`
<div> <div>
<div class='instance'> <div class='instancetitle'>
<span class='expander' onclick=${expandInstance}> <span class='expander' onclick=${expandInstance}>
<span class='arrow'></span> <span class='arrow'></span>
</span> </span>

View File

@ -71,11 +71,12 @@
max-width: 800px; max-width: 800px;
} }
:not(#register) > p { :not(#register) > p {
margin: 5px 1px; margin-block: 5px;
word-wrap: break-word;
} }
.thread:hover, .thread:hover,
.tab:hover, .tab:hover,
.instance > span:hover, .instancetitle > span:hover,
#user:hover { #user:hover {
background-color: #333; background-color: #333;
} }
@ -86,7 +87,7 @@
color: #fff; color: #fff;
} }
label.heading { label.heading {
margin: 10px 1px 4px; margin: 10px 0 4px;
display: block; display: block;
} }
h3 { h3 {
@ -106,18 +107,22 @@
margin: 8px 2px; margin: 8px 2px;
} }
.separator:has(+ .separator), .separator:has(+ .separator),
*.hidden + .separator,
.separator:has(+ *.hidden), .separator:has(+ *.hidden),
.separator:last-child { .separator:last-child {
display: none; display: none;
} }
.instance { .content {
flex: 1;
}
.instancetitle {
margin: 2px; margin: 2px;
> span { > span {
display: table-cell; display: table-cell;
background-color: #222; background-color: #222;
padding-block: 6px;
} }
> .title { > .title {
padding-block: 6px;
width: 100%; width: 100%;
} }
} }
@ -142,9 +147,12 @@
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
} }
#instancelist > :not(div) { #instancelist {
overflow-y: auto;
> :not(div) {
margin: 3px; margin: 3px;
} }
}
#instances { #instances {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -166,6 +174,15 @@
#profile { #profile {
max-width: 250px; max-width: 250px;
} }
#instance {
display: flex;
flex-direction: column;
justify-content: space-between;
max-width: 250px;
}
#disconnect {
width: fit-content;
}
.thread { .thread {
padding: 2px 3px; padding: 2px 3px;
white-space: pre; white-space: pre;
@ -187,7 +204,7 @@
} }
#content { #content {
margin: 2px; margin: 2px;
flex: 1; min-width: 300px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@ -237,11 +254,8 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
#members { #members {
flex: 1; min-width: 140px;
max-width: 250px; max-width: 250px;
> * {
margin: 4px;
}
} }
#editthread { #editthread {
max-width: fit-content; max-width: fit-content;

View File

@ -129,7 +129,7 @@ function newThread() {
name.value = ''; name.value = '';
} }
document.querySelector('#home + .separator').insertAdjacentElement('afterend', html.node` document.querySelector('#instance + .separator').insertAdjacentElement('afterend', html.node`
<form id='createthread' class='column' onsubmit=${event => { <form id='createthread' class='column' onsubmit=${event => {
event.preventDefault(); event.preventDefault();
let name = document.getElementById('newthreadname').value; let name = document.getElementById('newthreadname').value;
@ -164,7 +164,7 @@ function newThread() {
} }
); );
}}> }}>
<h3>create thread</h3> <h4>create thread</h4>
<label for='newthreadname' class='heading'>thread name</label> <label for='newthreadname' class='heading'>thread name</label>
<p id='newnameempty' class='hidden'>name cannot be empty</p> <p id='newnameempty' class='hidden'>name cannot be empty</p>
<input type='text' id='newthreadname' /> <input type='text' id='newthreadname' />
@ -237,6 +237,7 @@ function editThread() {
editThread(); editThread();
}); });
}}> }}>
<h4>edit thread</h4>
<label for='editthreadname' class='heading'>thread name</label> <label for='editthreadname' class='heading'>thread name</label>
<input type='text' id='editthreadname' /> <input type='text' id='editthreadname' />
<p id='nameempty' class='hidden'>name cannot be empty</p> <p id='nameempty' class='hidden'>name cannot be empty</p>
@ -260,7 +261,7 @@ function editThread() {
form['private_post'].checked = true; form['private_post'].checked = true;
else else
form['private_view'].checked = true; form['private_view'].checked = true;
document.querySelector('#thread').append(form); document.body.append(form);
document.getElementById('edit').textContent = 'cancel'; document.getElementById('edit').textContent = 'cancel';
} }
@ -289,7 +290,7 @@ async function loadThreads(instancediv, select) {
if (!document.getElementById('thread')) if (!document.getElementById('thread'))
document.body.append(html.node` document.body.append(html.node`
<div id='thread' class='column hidden'> <div id='thread' class='column hidden'>
<div id='content'> <div id='content' class='content'>
<div id='titlebar'> <div id='titlebar'>
<span id='title'>thread: <strong id='threadname'>meow</strong></span> <span id='title'>thread: <strong id='threadname'>meow</strong></span>
<button id='edit' class='hidden' onclick=${editThread}>edit</button> <button id='edit' class='hidden' onclick=${editThread}>edit</button>
@ -309,14 +310,14 @@ async function loadThreads(instancediv, select) {
<div id='stream' class='tabcontent hidden'></div> <div id='stream' class='tabcontent hidden'></div>
</div> </div>
<hr class='separator' color='#505050'> <hr class='separator' color='#505050'>
<div id='members' class='hidden'> <div id='members' class='column hidden'>
<p id='visibility'></p> <p id='visibility'></p>
<p><strong>members</strong></p> <h4>members</h4>
<div id='memberlist'> <div id='memberlist'>
</div> </div>
</div> </div>
<hr class='separator' color='#505050'> </div>
</div>`); <hr class='separator' color='#505050'>`);
if (!instancediv.children['threads']) { if (!instancediv.children['threads']) {
instancediv.append(html.node` instancediv.append(html.node`

View File

@ -249,6 +249,15 @@ async function get_user(msg, respond) {
}); });
} }
async function list_users(msg, respond) {
return respond({
success: true,
users: (await db.query(`
select id, name, coalesce(displayname, name) as displayname
from user`)).rows
});
}
async function get_keys(msg, respond) { async function get_keys(msg, respond) {
// validate inputs // validate inputs
if (!Array.isArray(msg.ids)) { if (!Array.isArray(msg.ids)) {
@ -276,5 +285,6 @@ module.exports = {
authorize_key: authwrap(authorize_key), authorize_key: authwrap(authorize_key),
update_user: authwrap(update_user), update_user: authwrap(update_user),
get_user, get_user,
list_users: authwrap(list_users),
get_keys get_keys
}; };