diff options
| author | Kit La Touche <kit@transneptune.net> | 2024-10-09 15:32:52 -0400 |
|---|---|---|
| committer | Kit La Touche <kit@transneptune.net> | 2024-10-09 15:32:52 -0400 |
| commit | bd53a51af835478d23bef4772ce7e50553dc3fdf (patch) | |
| tree | 3f190a47b9f704c412d0ff684b959abf003b8e5b /hi-ui/src/lib/components | |
| parent | dd62b823e01934a0f841256fdb17b551091896bf (diff) | |
Move a lot of things around
Diffstat (limited to 'hi-ui/src/lib/components')
| -rw-r--r-- | hi-ui/src/lib/components/ActiveChannel.svelte | 27 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/Channel.svelte | 21 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/ChannelList.svelte | 18 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/CreateChannelForm.svelte | 23 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/LogIn.svelte | 35 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/LogOut.svelte | 22 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/Message.svelte | 31 | ||||
| -rw-r--r-- | hi-ui/src/lib/components/MessageInput.svelte | 30 |
8 files changed, 207 insertions, 0 deletions
diff --git a/hi-ui/src/lib/components/ActiveChannel.svelte b/hi-ui/src/lib/components/ActiveChannel.svelte new file mode 100644 index 0000000..978e952 --- /dev/null +++ b/hi-ui/src/lib/components/ActiveChannel.svelte @@ -0,0 +1,27 @@ +<script> + import { activeChannel, messages } from '$lib/store'; + import Message from './Message.svelte'; + + let container; + $: messageList = $activeChannel.isSet() ? $messages.inChannel($activeChannel.get()) : []; + + // TODO: eventually, store scroll height/last unread in channel? scroll there? + + let scroll = (message) => { + message.scrollIntoView(); + } +</script> + +<div class="container" bind:this={container}> + {#each messageList as message} + <div use:scroll> + <Message {...message} /> + </div> + {/each} +</div> + +<style> + .container { + overflow: scroll; + } +</style> diff --git a/hi-ui/src/lib/components/Channel.svelte b/hi-ui/src/lib/components/Channel.svelte new file mode 100644 index 0000000..97fea1f --- /dev/null +++ b/hi-ui/src/lib/components/Channel.svelte @@ -0,0 +1,21 @@ +<script> + import { activeChannel } from '$lib/store'; + + export let id; + export let name; + let active = false; + + activeChannel.subscribe((value) => { + active = value.is(id); + }); +</script> + +<li + class="rounded-full" + class:bg-slate-400={active} +> +<a href="/ch/{id}"> + <span class="badge bg-primary-500">#</span> + <span class="flex-auto">{name}</span> +</a> +</li> diff --git a/hi-ui/src/lib/components/ChannelList.svelte b/hi-ui/src/lib/components/ChannelList.svelte new file mode 100644 index 0000000..e0e5f06 --- /dev/null +++ b/hi-ui/src/lib/components/ChannelList.svelte @@ -0,0 +1,18 @@ +<script> + import { channelsList } from '$lib/store'; + import Channel from './Channel.svelte'; + + let channels; + + channelsList.subscribe((value) => { + channels = value.channels; + }); +</script> + +<nav class="list-nav"> + <ul> + {#each channels as channel} + <Channel {...channel} /> + {/each} + </ul> +</nav> diff --git a/hi-ui/src/lib/components/CreateChannelForm.svelte b/hi-ui/src/lib/components/CreateChannelForm.svelte new file mode 100644 index 0000000..ddcf486 --- /dev/null +++ b/hi-ui/src/lib/components/CreateChannelForm.svelte @@ -0,0 +1,23 @@ +<script> + import { createChannel } from '$lib/apiServer'; + + let name = ''; + let disabled = false; + + async function handleSubmit(event) { + disabled = true; + const response = await createChannel(name); + if (200 <= response.status && response.status < 300) { + name = ''; + } + disabled = false; + } +</script> + +<form on:submit|preventDefault={handleSubmit} class="form form-row flex-nowrap"> + <input type="text" placeholder="create channel" bind:value={name} disabled={disabled} class="input flex-auto h-6 w-9/12" /> + <button type="submit" class="flex-none w-6 h-6">➕</button> +</form> + +<style> +</style> diff --git a/hi-ui/src/lib/components/LogIn.svelte b/hi-ui/src/lib/components/LogIn.svelte new file mode 100644 index 0000000..2836e6d --- /dev/null +++ b/hi-ui/src/lib/components/LogIn.svelte @@ -0,0 +1,35 @@ +<script> + import { logIn } from '$lib/apiServer'; + import { currentUser } from '$lib/store'; + + let disabled = false; + let username = ''; + let password = ''; + + async function handleLogin(event) { + disabled = true; + const response = await logIn(username, password); + if (200 <= response.status && response.status < 300) { + currentUser.update(() => ({ username })); + username = ''; + password = ''; + } + disabled = false; + } +</script> + +<div class="card m-4 p-4"> + <form on:submit|preventDefault={handleLogin}> + <label class="label" for="username"> + username + <input class="input" name="username" type="text" placeholder="username" bind:value={username} disabled={disabled}> + </label> + <label class="label" for="password"> + password + <input class="input" name="password" type="password" placeholder="password" bind:value={password} disabled={disabled}> + </label> + <button class="btn variant-filled" type="submit"> + sign in or up + </button> + </form> +</div> diff --git a/hi-ui/src/lib/components/LogOut.svelte b/hi-ui/src/lib/components/LogOut.svelte new file mode 100644 index 0000000..01bef1b --- /dev/null +++ b/hi-ui/src/lib/components/LogOut.svelte @@ -0,0 +1,22 @@ +<script> + import { logOut} from '$lib/apiServer'; + import { currentUser } from '$lib/store'; + + async function handleLogout(event) { + const response = await logOut(); + if (200 <= response.status && response.status < 300) { + currentUser.update(() => null); + } + } +</script> + +<form on:submit|preventDefault={handleLogout}> + @{$currentUser.username} + <button + class="border-slate-500 border-solid border-2 font-bold p-1 rounded" + type="submit" + >log out</button> +</form> + +<style> +</style> diff --git a/hi-ui/src/lib/components/Message.svelte b/hi-ui/src/lib/components/Message.svelte new file mode 100644 index 0000000..5b51492 --- /dev/null +++ b/hi-ui/src/lib/components/Message.svelte @@ -0,0 +1,31 @@ +<script> + import SvelteMarkdown from 'svelte-markdown'; + import { currentUser } from '$lib/store'; + import { deleteMessage } from '$lib/apiServer'; + + export let at; // XXX: Omitted for now. + export let sender; + export let message; + + let timestamp = new Date(at).toTimeString(); +</script> + +<div class="card card-hover m-4 relative"> + <span class="chip variant-soft sticky top-o left-0"> + <!-- TODO: should this show up for only the first of a run? --> + @{sender.name}: + </span> + <span class="timestamp chip variant-soft absolute top-0 right-0">{at}</span> + <section class="p-4"> + <SvelteMarkdown source={message.body} /> + </section> +</div> + +<style> + .card .timestamp { + display: none; + } + .card:hover .timestamp { + display: flex; + } +</style> diff --git a/hi-ui/src/lib/components/MessageInput.svelte b/hi-ui/src/lib/components/MessageInput.svelte new file mode 100644 index 0000000..b33574b --- /dev/null +++ b/hi-ui/src/lib/components/MessageInput.svelte @@ -0,0 +1,30 @@ +<script> + import { tick } from 'svelte'; + import { postToChannel } from '$lib/apiServer'; + import { activeChannel } from '$lib/store'; + + let input; + let value; + let disabled; + activeChannel.subscribe((value) => { + disabled = !value.isSet(); + if (input && !disabled) { + input.focus(); + } + }); + + async function handleSubmit(event) { + disabled = true; + // TODO try/catch: + await postToChannel($activeChannel.get(), value); + value = ''; + disabled = false; + await tick(); + input.focus(); + } +</script> + +<form on:submit|preventDefault={handleSubmit} class="flex flex-row flex-nowrap"> + <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">»</button> +</form> |
