frontend: add unread indicator

This commit is contained in:
hippoz 2022-04-28 18:40:38 +03:00
parent 686aba5541
commit 7f3735502f
Signed by: hippoz
GPG key ID: 7C52899193467641
4 changed files with 44 additions and 9 deletions

View file

@ -1,6 +1,6 @@
<script> <script>
import { afterUpdate, beforeUpdate, onMount } from "svelte"; import { afterUpdate, beforeUpdate, onMount } from "svelte";
import { messagesStoreProvider, showSidebar } from "../stores.js"; import { messagesStoreProvider, showSidebar, smallViewport } from "../stores.js";
import Message from "./Message.svelte"; import Message from "./Message.svelte";
export let channelId; export let channelId;
@ -51,8 +51,7 @@
// TODO: hack // TODO: hack
// showSidebar is false on small viewports // showSidebar is false on small viewports
// scrolling to bottom when the virtual keyboard pops up does not work on chromium purely based on isScrolledToBottom for some reason // scrolling to bottom when the virtual keyboard pops up does not work on chromium purely based on isScrolledToBottom for some reason
const isSmallViewport = !$showSidebar; if (isScrolledToBottom || $smallViewport) {
if (isScrolledToBottom || isSmallViewport) {
scrollAnchor.scrollIntoView(false); scrollAnchor.scrollIntoView(false);
} }
}; };

View file

@ -40,6 +40,9 @@
<HashIcon /> <HashIcon />
</div> </div>
<span>{ channel.name }</span> <span>{ channel.name }</span>
{#if channel._hasUnreads}
<span class="unread-indicator"></span>
{/if}
{#if $userInfoStore && channel.owner_id === $userInfoStore.id} {#if $userInfoStore && channel.owner_id === $userInfoStore.id}
<button class="icon-button icon-button-auto" on:click|stopPropagation="{ () => overlayStore.open('editChannel', { channel }) }"> <button class="icon-button icon-button-auto" on:click|stopPropagation="{ () => overlayStore.open('editChannel', { channel }) }">
<MoreVerticalIcon /> <MoreVerticalIcon />
@ -63,6 +66,11 @@
</div> </div>
<style> <style>
.unread-indicator {
color: var(--purple-2);
margin-left: auto;
}
.sidebar-container { .sidebar-container {
background-color: var(--background-color-1); background-color: var(--background-color-1);
border-right: 1px solid var(--background-color-2); border-right: 1px solid var(--background-color-2);

View file

@ -1,4 +1,3 @@
import { writable } from "svelte/store";
import gateway, { GatewayEventType } from "./gateway"; import gateway, { GatewayEventType } from "./gateway";
import logging from "./logging"; import logging from "./logging";
import request from "./request"; import request from "./request";
@ -22,6 +21,11 @@ class Store {
}; };
} }
set(value) {
this.value = value;
this.updated();
}
updated() { updated() {
storeLog(`updated(): calling ${this._handlers.length} handlers - value changed`, this.value); storeLog(`updated(): calling ${this._handlers.length} handlers - value changed`, this.value);
this._handlers.forEach(e => { this._handlers.forEach(e => {
@ -30,6 +34,11 @@ class Store {
} }
} }
export const selectedChannel = new Store({ id: -1, name: "none", creator_id: -1 });
export const showSidebar = new Store(false);
export const showChannelView = new Store(true);
export const smallViewport = new Store(false);
class ChannelsStore extends Store { class ChannelsStore extends Store {
constructor() { constructor() {
super(gateway.channels || []); super(gateway.channels || []);
@ -63,6 +72,30 @@ class ChannelsStore extends Store {
this.value[index] = data; this.value[index] = data;
this.updated(); this.updated();
}); });
gateway.subscribe(GatewayEventType.MessageCreate, ({ channel_id }) => {
const index = this.value.findIndex(e => e.id === channel_id);
if (index === -1)
return;
if (!this.value[index])
return;
if (selectedChannel.value.id === channel_id)
return;
this.value[index]._hasUnreads = true;
this.updated();
});
selectedChannel.subscribe(({ id }) => {
const index = this.value.findIndex(e => e.id === id);
if (index === -1)
return;
if (!this.value[index])
return;
if (!this.value[index]._hasUnreads)
return;
this.value[index]._hasUnreads = false;
this.updated();
});
} }
} }
@ -270,7 +303,3 @@ export const gatewayStatus = new GatewayStatusStore();
export const messagesStoreProvider = new MessagesStoreProvider(); export const messagesStoreProvider = new MessagesStoreProvider();
export const userInfoStore = new UserInfoStore(); export const userInfoStore = new UserInfoStore();
export const overlayStore = new OverlayStore(); export const overlayStore = new OverlayStore();
export const selectedChannel = writable({ id: -1, name: "none", creator_id: -1 });
export const showSidebar = writable(false);
export const showChannelView = writable(true);
export const smallViewport = writable(false);

View file

@ -8,6 +8,5 @@
"esModuleInterop": true, "esModuleInterop": true,
"strict": true, "strict": true,
"outDir": "./dist", "outDir": "./dist",
"rootDir": "./src"
} }
} }