summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorKit La Touche <kit@transneptune.net>2024-10-30 23:26:23 -0400
committerKit La Touche <kit@transneptune.net>2024-10-30 23:26:23 -0400
commit80220d2188e0553304f2c78d225bbe275d8ba572 (patch)
treede0a62325c698197612574c7a9f37dad279581be /ui
parent51aabd07ca5eeaee45a564f8799cc42dc195068c (diff)
parent35b8a914b867237c9c64f33838b1e1f85fc46fb8 (diff)
Merge branch 'main' into wip/mobile
Diffstat (limited to 'ui')
-rw-r--r--ui/lib/apiServer.js18
-rw-r--r--ui/lib/components/ActiveChannel.svelte27
-rw-r--r--ui/lib/components/CreateChannelForm.svelte9
-rw-r--r--ui/lib/components/Message.svelte30
-rw-r--r--ui/lib/components/MessageInput.svelte10
-rw-r--r--ui/lib/components/MessageRun.svelte34
-rw-r--r--ui/lib/store/messages.js3
-rw-r--r--ui/routes/(app)/me/+page.svelte2
-rw-r--r--ui/routes/(login)/invite/[invite]/+page.svelte10
-rw-r--r--ui/routes/(login)/login/+page.svelte10
-rw-r--r--ui/routes/(login)/setup/+page.svelte10
11 files changed, 95 insertions, 68 deletions
diff --git a/ui/lib/apiServer.js b/ui/lib/apiServer.js
index 19dcf60..5c6e5ef 100644
--- a/ui/lib/apiServer.js
+++ b/ui/lib/apiServer.js
@@ -10,20 +10,12 @@ export async function boot() {
return apiServer.get('/boot');
}
-export async function setup(username, password) {
- const data = {
- name: username,
- password,
- };
- return apiServer.post('/setup', data);
+export async function setup(name, password) {
+ return apiServer.post('/setup', { name, password });
}
-export async function logIn(username, password) {
- const data = {
- name: username,
- password,
- };
- return apiServer.post('/auth/login', data);
+export async function logIn(name, password) {
+ return apiServer.post('/auth/login', { name, password });
}
export async function logOut() {
@@ -46,7 +38,7 @@ export async function deleteMessage(messageId) {
// TODO
}
-export async function createInvite(inviteId) {
+export async function createInvite() {
return apiServer.post(`/invite`, {});
}
diff --git a/ui/lib/components/ActiveChannel.svelte b/ui/lib/components/ActiveChannel.svelte
index ece9f55..1b23bc1 100644
--- a/ui/lib/components/ActiveChannel.svelte
+++ b/ui/lib/components/ActiveChannel.svelte
@@ -1,10 +1,33 @@
<script>
import { messages } from '$lib/store';
import Message from './Message.svelte';
+ import MessageRun from './MessageRun.svelte';
export let channel = null;
$: messageList = channel !== null ? $messages.inChannel(channel) : [];
+ function *chunkBy(xs, fn) {
+ let chunk;
+ let key;
+ for (let x of xs) {
+ let newKey = fn(x);
+ if (key !== newKey) {
+ if (chunk !== undefined) {
+ yield [key, chunk];
+ }
+
+ chunk = [x];
+ key = newKey;
+ } else {
+ chunk.push(x);
+ }
+ }
+ if (chunk !== undefined) {
+ yield [key, chunk];
+ }
+ }
+
+
let container;
// TODO: eventually, store scroll height/last unread in channel? scroll there?
@@ -14,9 +37,9 @@
</script>
<div class="container" bind:this={container}>
- {#each messageList as message}
+ {#each chunkBy(messageList, msg => msg.sender) as [sender, messages]}
<div use:scroll>
- <Message {...message} />
+ <MessageRun {sender} {messages} />
</div>
{/each}
</div>
diff --git a/ui/lib/components/CreateChannelForm.svelte b/ui/lib/components/CreateChannelForm.svelte
index ddcf486..b716736 100644
--- a/ui/lib/components/CreateChannelForm.svelte
+++ b/ui/lib/components/CreateChannelForm.svelte
@@ -1,16 +1,17 @@
<script>
import { createChannel } from '$lib/apiServer';
- let name = '';
- let disabled = false;
+ let name = "";
+ let pending = false;
+ $: disabled = pending;
async function handleSubmit(event) {
- disabled = true;
+ pending = true;
const response = await createChannel(name);
if (200 <= response.status && response.status < 300) {
name = '';
}
- disabled = false;
+ pending = false;
}
</script>
diff --git a/ui/lib/components/Message.svelte b/ui/lib/components/Message.svelte
index 2705e4b..ef8ea0b 100644
--- a/ui/lib/components/Message.svelte
+++ b/ui/lib/components/Message.svelte
@@ -1,42 +1,22 @@
<script>
import SvelteMarkdown from 'svelte-markdown';
- import { currentUser, logins } from '$lib/store';
- import { deleteMessage } from '$lib/apiServer';
- export let at; // XXX: Omitted for now.
- export let sender;
+ export let at;
export let body;
-
- let timestamp = new Date(at).toTimeString();
- let name;
- $: name = $logins.get(sender);
- $: ownMessage = $currentUser.id == sender;
</script>
-<div class="card card-hover m-4 relative" class:own-message={ownMessage} class:other-message={!ownMessage}>
- <span class="chip variant-soft sticky top-o left-0">
- <!-- TODO: should this show up for only the first of a run? -->
- @{name}:
- </span>
+<div class="message relative">
<span class="timestamp chip variant-soft absolute top-0 right-0">{at}</span>
- <section class="p-4">
+ <section class="p-1">
<SvelteMarkdown source={body} />
</section>
</div>
<style>
- .card .timestamp {
+ .message .timestamp {
display: none;
}
- .card:hover .timestamp {
+ .message:hover .timestamp {
display: flex;
}
- .own-message {
- width: 80%;
- margin-right: auto;
- }
- .other-message {
- width: 80%;
- margin-left: auto;
- }
</style>
diff --git a/ui/lib/components/MessageInput.svelte b/ui/lib/components/MessageInput.svelte
index b2746e0..03ac7fa 100644
--- a/ui/lib/components/MessageInput.svelte
+++ b/ui/lib/components/MessageInput.svelte
@@ -5,16 +5,16 @@
export let channel = null;
let input;
let value = '';
- let sending = false;
+ let pending = false;
- $: disabled = (channel === null);
+ $: disabled = pending || (channel === null);
async function handleSubmit() {
if (channel !== null) {
- sending = true;
+ pending = true;
// TODO try/catch:
await postToChannel(channel, value);
- sending = false;
+ pending = false;
value = '';
await tick();
input.focus();
@@ -23,6 +23,6 @@
</script>
<form on:submit|preventDefault={handleSubmit} class="flex flex-row flex-nowrap">
- <input bind:this={input} bind:value={value} disabled={sending || disabled} type="search" class="flex-auto h-6 input rounded-r-none" />
+ <input bind:this={input} bind:value={value} disabled={disabled} type="search" class="flex-auto h-6 input rounded-r-none" />
<button color="primary variant-filled-secondary" type="submit" class="flex-none w-6 h-6 btn-icon variant-filled rounded-l-none">&raquo;</button>
</form>
diff --git a/ui/lib/components/MessageRun.svelte b/ui/lib/components/MessageRun.svelte
new file mode 100644
index 0000000..0ecaabc
--- /dev/null
+++ b/ui/lib/components/MessageRun.svelte
@@ -0,0 +1,34 @@
+<script>
+ import { logins, currentUser } from '$lib/store';
+ import Message from '$lib/components/Message.svelte';
+
+ export let sender;
+ export let messages;
+
+ let name;
+ $: name = $logins.get(sender);
+ $: ownMessage = $currentUser.id == sender;
+</script>
+
+<div
+ class="card card-hover m-4 relative"
+ class:own-message={ownMessage}
+ class:other-message={!ownMessage}>
+ <span class="chip variant-soft sticky top-o left-0">
+ @{name}:
+ </span>
+ {#each messages as { at, body }}
+ <Message {at} {body} />
+ {/each}
+</div>
+
+<style>
+ .own-message {
+ width: 80%;
+ margin-right: auto;
+ }
+ .other-message {
+ width: 80%;
+ margin-left: auto;
+ }
+</style>
diff --git a/ui/lib/store/messages.js b/ui/lib/store/messages.js
index 931b8fb..7d1fbe1 100644
--- a/ui/lib/store/messages.js
+++ b/ui/lib/store/messages.js
@@ -17,9 +17,6 @@ export class Messages {
for (let { channel, id, at, sender, body } of messages) {
this.inChannel(channel).push({ id, at, sender, body, });
}
- for (let channel in this.channels) {
- this.channels[channel].sort((a, b) => a.at - b.at);
- }
return this;
}
diff --git a/ui/routes/(app)/me/+page.svelte b/ui/routes/(app)/me/+page.svelte
index 7559dbe..82af3c7 100644
--- a/ui/routes/(app)/me/+page.svelte
+++ b/ui/routes/(app)/me/+page.svelte
@@ -3,7 +3,7 @@
import Invites from '$lib/components/Invites.svelte';
- let currentPassword, newPassword, confirmPassword, passwordForm;
+ let currentPassword = "", newPassword = "", confirmPassword = "", passwordForm;
let pending = false;
$: valid = (newPassword === confirmPassword) && (newPassword !== currentPassword);
$: disabled = pending || !valid;
diff --git a/ui/routes/(login)/invite/[invite]/+page.svelte b/ui/routes/(login)/invite/[invite]/+page.svelte
index 798dfb7..7ae388a 100644
--- a/ui/routes/(login)/invite/[invite]/+page.svelte
+++ b/ui/routes/(login)/invite/[invite]/+page.svelte
@@ -6,19 +6,19 @@
export let data;
- let disabled;
- let username;
- let password;
+ let username = "", password = "";
+ let pending = false;
+ $: disabled = pending;
async function onSubmit() {
- disabled = true;
+ pending = true;
const response = await acceptInvite(data.invite.id, username, password);
if (200 <= response.status && response.status < 300) {
username = '';
password = '';
goto('/');
}
- disabled = false;
+ pending = false;
}
</script>
diff --git a/ui/routes/(login)/login/+page.svelte b/ui/routes/(login)/login/+page.svelte
index 29dba54..0387e4a 100644
--- a/ui/routes/(login)/login/+page.svelte
+++ b/ui/routes/(login)/login/+page.svelte
@@ -4,19 +4,19 @@
import LogIn from '$lib/components/LogIn.svelte';
- let disabled;
- let username;
- let password;
+ let username = "", password = "";
+ let pending = false;
+ $: disabled = pending;
async function onSubmit() {
- disabled = true;
+ pending = true;
const response = await logIn(username, password);
if (200 <= response.status && response.status < 300) {
username = '';
password = '';
goto('/');
}
- disabled = false;
+ pending = false;
}
</script>
diff --git a/ui/routes/(login)/setup/+page.svelte b/ui/routes/(login)/setup/+page.svelte
index 2503502..a1974b8 100644
--- a/ui/routes/(login)/setup/+page.svelte
+++ b/ui/routes/(login)/setup/+page.svelte
@@ -4,19 +4,19 @@
import LogIn from '$lib/components/LogIn.svelte';
- let disabled;
- let username;
- let password;
+ let username = "", password = "";
+ let pending = false;
+ $: disabled = pending;
async function onSubmit() {
- disabled = true;
+ pending = true;
const response = await setup(username, password);
if (200 <= response.status && response.status < 300) {
username = '';
password = '';
goto('/');
}
- disabled = false;
+ pending = false;
}
</script>