feat: implement live channel sidebar

This commit is contained in:
dvdrw 2023-02-14 00:21:42 +01:00
parent a1bd44ffb3
commit 38f926b32f
Signed by: dvdrw
GPG Key ID: 044B8425E3CD03E0
5 changed files with 114 additions and 10 deletions

8
package-lock.json generated
View File

@ -13,7 +13,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/svelte-fontawesome": "^0.2.0", "@fortawesome/svelte-fontawesome": "^0.2.0",
"detect-it": "^4.0.1", "detect-it": "^4.0.1",
"fedwave-chat-client": "^0.0.1", "fedwave-chat-client": "^0.0.2",
"jose": "^4.11.2", "jose": "^4.11.2",
"svrollbar": "^0.12.0" "svrollbar": "^0.12.0"
}, },
@ -1605,9 +1605,9 @@
} }
}, },
"node_modules/fedwave-chat-client": { "node_modules/fedwave-chat-client": {
"version": "0.0.1", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/fedwave-chat-client/-/fedwave-chat-client-0.0.1.tgz", "resolved": "https://registry.npmjs.org/fedwave-chat-client/-/fedwave-chat-client-0.0.2.tgz",
"integrity": "sha512-VP7OJELCx1V0c26QbgF+mLoMq4EyPLbrjIylAvS12hv2XVlmGJRqnrh6kCVHqSr6ZwirjlM/eLSDgJ2jWXMiyw==", "integrity": "sha512-r4rvOGVEvb09LrIrWOF4D1yEd/9duxameFlnJltOZxXagPkzS5RhJagIOKO0L+37moUHOVv/cMu3Gg+YFDA0Pg==",
"dependencies": { "dependencies": {
"socket.io-client": "^3.1.3" "socket.io-client": "^3.1.3"
} }

View File

@ -38,7 +38,7 @@
"@fortawesome/free-solid-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/svelte-fontawesome": "^0.2.0", "@fortawesome/svelte-fontawesome": "^0.2.0",
"detect-it": "^4.0.1", "detect-it": "^4.0.1",
"fedwave-chat-client": "^0.0.1", "fedwave-chat-client": "^0.0.2",
"jose": "^4.11.2", "jose": "^4.11.2",
"svrollbar": "^0.12.0" "svrollbar": "^0.12.0"
} }

View File

@ -5,7 +5,7 @@
export let size: string = 'var(--avatar-size)'; export let size: string = 'var(--avatar-size)';
</script> </script>
<button class="avatar pa-0 border-0" style:--color="{color}" style:--size="{size}" on:click> <button class="avatar pa-0 border-0 shrink-0" style:--color="{color}" style:--size="{size}" on:click>
<img src="{avatar}" alt="{`${username}'s avatar`}"> <img src="{avatar}" alt="{`${username}'s avatar`}">
</button> </button>

View File

@ -3,19 +3,54 @@
export let mobile = false; export let mobile = false;
import { FontAwesomeIcon as FA } from '@fortawesome/svelte-fontawesome'; import { FontAwesomeIcon as FA } from '@fortawesome/svelte-fontawesome';
import { faHome, faPerson } from '@fortawesome/free-solid-svg-icons'; import { faHome, faPerson, faCircle } from '@fortawesome/free-solid-svg-icons';
import { channels, room } from './chat';
import Avatar from './Avatar.svelte';
let selected = "channels";
</script> </script>
<div class="sidebar h-100vh d-flex" bind:clientWidth class:mobile="{mobile}"> <div class="sidebar h-100vh d-flex" bind:clientWidth class:mobile="{mobile}">
<div class="overlay" /> <div class="overlay" />
<div class="servers d-flex col"> <div class="servers shrink-0 d-flex col">
<button class="selected"> <button
class:selected="{selected === 'whispers'}"
on:click="{() => selected = 'whispers'}">
<FA size="2x" icon="{faPerson}" /> <FA size="2x" icon="{faPerson}" />
</button> </button>
<button> <button
class:selected="{selected === 'channels'}"
on:click="{() => selected = 'channels'}">
<FA size="2x" icon="{faHome}" /> <FA size="2x" icon="{faHome}" />
</button> </button>
</div> </div>
{#if selected === 'whispers'}
<div class="whispers grow-1 mw-0"></div>
{:else if selected === 'channels'}
<div class="channels grow-1 d-flex col mw-0 py-8">
{#each $channels.sort((a, b) => b.viewCount - a.viewCount) as channel}
<a href="{channel.name}"
class="channel d-flex align-center mb-8 mx-8 pa-6 radius-12"
class:selected="{$room === channel.name.toLowerCase()}">
<Avatar username="{channel.name}"
avatar="{channel.avatar}" />
<div class="channel-name mw-0 ellipsis ml-8">
{channel.name}
</div>
{#if false && channel.live}
<div class="channel-live ml-2 mt-8 color-red">
<FA icon="{faCircle}" size="xs" />
</div>
{/if}
<div class="spacer"/>
<div class="channel-viewers px-6 py-2 radius-pill">
{channel.viewCount + channel.viewCountRTC}
</div>
</a>
{/each}
</div>
{/if}
</div> </div>
<style lang="scss"> <style lang="scss">
@ -48,6 +83,15 @@
pointer-events: var(--should-display); pointer-events: var(--should-display);
} }
.channel-live {
align-self: normal;
font-size: 8px;
}
.channel-viewers {
font-weight: 700;
}
.servers { .servers {
width: var(--sidebar-server-select-width); width: var(--sidebar-server-select-width);
background-color: var(--base-500); background-color: var(--base-500);
@ -75,6 +119,29 @@
background-color: var(--base-700); background-color: var(--base-700);
color: var(--base-300); color: var(--base-300);
} }
}
}
a {
background-color: var(--base-400);
color: var(--base-700);
transition-property: background-color, color, border-radius;
transition-duration: 80ms;
transition-timing-function: ease-out;
&:hover {
background-color: var(--base-300);
}
&.selected {
background-color: var(--base-700);
color: var(--base-300);
& .channel-viewers {
color: var(--red);
}
} }
} }
</style> </style>

View File

@ -97,10 +97,46 @@ globalMode.subscribe((v) => {
export const shouldTweet = writable(false); export const shouldTweet = writable(false);
export type User = {
color: string;
page: string;
username: string;
unum: number;
};
export type Channel = Record<
| 'avatar'
| 'channel'
| 'cover'
| 'desc'
| 'name'
| 'src'
| 'thumbnail'
| 'title'
| 'type'
| 'url'
| 'user',
string
> &
Record<'live' | 'nsfw', boolean> &
Record<'viewCount' | 'viewCountRTC', number> & {
users: Record<string, { watching: string[]; data: User }>[];
};
let setChannels: Subscriber<any> | undefined;
export const channels = readable<Channel[]>(chat.channelViewers, (setf) => {
setChannels = setf;
return () => {
setChannels = undefined;
};
});
chat.onUpdateUsernames = (vs) => setChannels?.(vs) as any;
// Essentially a shared_ptr idiom. When nobody is subscribed to this, the chat // Essentially a shared_ptr idiom. When nobody is subscribed to this, the chat
// d/c's. // d/c's.
export const chat_lock = readable(null, () => { export const chat_lock = readable(null, () => {
const release_connected = connected.subscribe(() => {}); const release_connected = connected.subscribe(() => {});
const release_channels = channels.subscribe(() => {});
const creds = get(credentials); const creds = get(credentials);
@ -111,6 +147,7 @@ export const chat_lock = readable(null, () => {
setConnected?.(false); setConnected?.(false);
release_connected(); release_connected();
release_channels();
}; };
}); });