Remove no-text rooms, highlight active room, fix custom voice room icons
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
import {waitForThunkError, createRoom, editRoom, joinRoom} from "@welshman/app"
|
import {waitForThunkError, createRoom, editRoom, joinRoom} from "@welshman/app"
|
||||||
import StickerSmileSquare from "@assets/icons/sticker-smile-square.svg?dataurl"
|
import StickerSmileSquare from "@assets/icons/sticker-smile-square.svg?dataurl"
|
||||||
import Hashtag from "@assets/icons/hashtag.svg?dataurl"
|
import Hashtag from "@assets/icons/hashtag.svg?dataurl"
|
||||||
|
import Volume from "@assets/icons/volume.svg?dataurl"
|
||||||
import UploadMinimalistic from "@assets/icons/upload-minimalistic.svg?dataurl"
|
import UploadMinimalistic from "@assets/icons/upload-minimalistic.svg?dataurl"
|
||||||
import {preventDefault} from "@lib/html"
|
import {preventDefault} from "@lib/html"
|
||||||
import FieldInline from "@lib/components/FieldInline.svelte"
|
import FieldInline from "@lib/components/FieldInline.svelte"
|
||||||
@@ -16,15 +17,7 @@
|
|||||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||||
import {pushToast} from "@app/util/toast"
|
import {pushToast} from "@app/util/toast"
|
||||||
import {uploadFile} from "@app/core/commands"
|
import {uploadFile} from "@app/core/commands"
|
||||||
import {deriveHasLivekit} from "@app/core/state"
|
import {deriveHasLivekit, getRoomType, RoomType} from "@app/core/state"
|
||||||
|
|
||||||
type RoomMode = "text" | "voice" | "both"
|
|
||||||
|
|
||||||
const getRoomMode = (room: RoomMeta): RoomMode => {
|
|
||||||
if (room.livekit && room.noText) return "voice"
|
|
||||||
if (room.livekit) return "both"
|
|
||||||
return "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url: string
|
url: string
|
||||||
@@ -37,13 +30,13 @@
|
|||||||
const {url, header, footer, onsubmit, initialValues = makeRoomMeta()}: Props = $props()
|
const {url, header, footer, onsubmit, initialValues = makeRoomMeta()}: Props = $props()
|
||||||
|
|
||||||
const values = $state(initialValues)
|
const values = $state(initialValues)
|
||||||
let roomMode = $state<RoomMode>(getRoomMode(initialValues))
|
let roomType = $state<RoomType>(getRoomType(initialValues))
|
||||||
const relayHasLivekit = deriveHasLivekit(url)
|
const relayHasLivekit = deriveHasLivekit(url)
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
const room = $state.snapshot(values)
|
const room = $state.snapshot(values)
|
||||||
|
|
||||||
if ((roomMode === "voice" || roomMode === "both") && !get(relayHasLivekit)) {
|
if (roomType === RoomType.Voice && !get(relayHasLivekit)) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
theme: "error",
|
theme: "error",
|
||||||
message: "This relay does not support voice rooms.",
|
message: "This relay does not support voice rooms.",
|
||||||
@@ -71,8 +64,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (get(relayHasLivekit)) {
|
if (get(relayHasLivekit)) {
|
||||||
room.livekit = roomMode === "both" || roomMode === "voice"
|
room.livekit = roomType === RoomType.Voice
|
||||||
room.noText = roomMode === "voice"
|
room.noText = false
|
||||||
}
|
}
|
||||||
const editMessage = await waitForThunkError(editRoom(url, room))
|
const editMessage = await waitForThunkError(editRoom(url, room))
|
||||||
|
|
||||||
@@ -171,7 +164,7 @@
|
|||||||
{#if imagePreview}
|
{#if imagePreview}
|
||||||
<ImageIcon src={imagePreview} alt="" class="rounded-lg" />
|
<ImageIcon src={imagePreview} alt="" class="rounded-lg" />
|
||||||
{:else}
|
{:else}
|
||||||
<Icon icon={Hashtag} />
|
<Icon icon={roomType === RoomType.Voice ? Volume : Hashtag} />
|
||||||
{/if}
|
{/if}
|
||||||
<input bind:value={values.name} class="grow" type="text" />
|
<input bind:value={values.name} class="grow" type="text" />
|
||||||
</label>
|
</label>
|
||||||
@@ -195,11 +188,10 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<select
|
<select
|
||||||
class="select select-bordered w-full"
|
class="select select-bordered w-full"
|
||||||
bind:value={roomMode}
|
bind:value={roomType}
|
||||||
aria-label="Room type">
|
aria-label="Room type">
|
||||||
<option value="text">Text only</option>
|
<option value={RoomType.Text}>Text</option>
|
||||||
<option value="both">Text and voice</option>
|
<option value={RoomType.Voice}>Voice</option>
|
||||||
<option value="voice">Voice only</option>
|
|
||||||
</select>
|
</select>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FieldInline>
|
</FieldInline>
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Hashtag from "@assets/icons/hashtag.svg?dataurl"
|
import Hashtag from "@assets/icons/hashtag.svg?dataurl"
|
||||||
|
import Volume from "@assets/icons/volume.svg?dataurl"
|
||||||
|
import VolumeLoud from "@assets/icons/volume-loud.svg?dataurl"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import ImageIcon from "@lib/components/ImageIcon.svelte"
|
import ImageIcon from "@lib/components/ImageIcon.svelte"
|
||||||
import {deriveRoom} from "@app/core/state"
|
import {deriveRoom} from "@app/core/state"
|
||||||
|
import {currentVoiceSession} from "@app/voice"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
h: string
|
h: string
|
||||||
@@ -14,9 +17,25 @@
|
|||||||
const {url, h, size = 5, fallbackIcon = Hashtag}: Props = $props()
|
const {url, h, size = 5, fallbackIcon = Hashtag}: Props = $props()
|
||||||
|
|
||||||
const room = deriveRoom(url, h)
|
const room = deriveRoom(url, h)
|
||||||
|
const isVoiceRoom = $derived($room.livekit)
|
||||||
|
const isVoiceRoomActive = $derived(
|
||||||
|
$currentVoiceSession?.url === url && $currentVoiceSession?.h === h,
|
||||||
|
)
|
||||||
|
const typeIconSrc = $derived(isVoiceRoomActive ? VolumeLoud : Volume)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $room.picture}
|
{#if isVoiceRoom}
|
||||||
|
<div class="flex items-center gap-1 shrink-0">
|
||||||
|
<Icon
|
||||||
|
icon={typeIconSrc}
|
||||||
|
size={size + 1}
|
||||||
|
class={isVoiceRoomActive ? "text-primary -translate-x-0.5" : ""} />
|
||||||
|
{#if $room.picture}
|
||||||
|
<span class="text-base">/</span>
|
||||||
|
<ImageIcon src={$room.picture} {size} alt="" class="rounded-lg" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else if $room.picture}
|
||||||
<ImageIcon src={$room.picture} {size} alt="" class="rounded-lg" />
|
<ImageIcon src={$room.picture} {size} alt="" class="rounded-lg" />
|
||||||
{:else}
|
{:else}
|
||||||
<Icon icon={fallbackIcon} {size} />
|
<Icon icon={fallbackIcon} {size} />
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
import SpaceReports from "@app/components/SpaceReports.svelte"
|
import SpaceReports from "@app/components/SpaceReports.svelte"
|
||||||
import RoomCreate from "@app/components/RoomCreate.svelte"
|
import RoomCreate from "@app/components/RoomCreate.svelte"
|
||||||
import SpaceMenuRoomItem from "@app/components/SpaceMenuRoomItem.svelte"
|
import SpaceMenuRoomItem from "@app/components/SpaceMenuRoomItem.svelte"
|
||||||
import VoiceRoomItem from "@app/components/VoiceRoomItem.svelte"
|
|
||||||
import VoiceWidget from "@app/components/VoiceWidget.svelte"
|
import VoiceWidget from "@app/components/VoiceWidget.svelte"
|
||||||
import SocketStatusIndicator from "@app/components/SocketStatusIndicator.svelte"
|
import SocketStatusIndicator from "@app/components/SocketStatusIndicator.svelte"
|
||||||
import {
|
import {
|
||||||
@@ -47,8 +46,6 @@
|
|||||||
deriveSpaceMembers,
|
deriveSpaceMembers,
|
||||||
deriveUserRooms,
|
deriveUserRooms,
|
||||||
deriveOtherRooms,
|
deriveOtherRooms,
|
||||||
deriveRoomsWithLivekit,
|
|
||||||
deriveRoomsNoText,
|
|
||||||
deriveOtherVoiceRooms,
|
deriveOtherVoiceRooms,
|
||||||
userSpaceUrls,
|
userSpaceUrls,
|
||||||
hasNip29,
|
hasNip29,
|
||||||
@@ -73,8 +70,6 @@
|
|||||||
const calendarPath = makeSpacePath(url, "calendar")
|
const calendarPath = makeSpacePath(url, "calendar")
|
||||||
const userRooms = deriveUserRooms(url)
|
const userRooms = deriveUserRooms(url)
|
||||||
const otherRooms = deriveOtherRooms(url)
|
const otherRooms = deriveOtherRooms(url)
|
||||||
const roomsWithLivekit = deriveRoomsWithLivekit(url)
|
|
||||||
const roomsNoText = deriveRoomsNoText(url)
|
|
||||||
const otherVoiceRooms = deriveOtherVoiceRooms(url)
|
const otherVoiceRooms = deriveOtherVoiceRooms(url)
|
||||||
const members = deriveSpaceMembers(url)
|
const members = deriveSpaceMembers(url)
|
||||||
const userIsAdmin = deriveUserIsSpaceAdmin(url)
|
const userIsAdmin = deriveUserIsSpaceAdmin(url)
|
||||||
@@ -264,14 +259,7 @@
|
|||||||
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
|
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
|
||||||
{/if}
|
{/if}
|
||||||
{#each $userRooms as h (h)}
|
{#each $userRooms as h (h)}
|
||||||
{#if !$roomsNoText.has(h)}
|
<SpaceMenuRoomItem notify {replaceState} {url} {h} />
|
||||||
<SpaceMenuRoomItem notify {replaceState} {url} {h} />
|
|
||||||
{/if}
|
|
||||||
{#if $roomsWithLivekit.has(h)}
|
|
||||||
<div class="hidden md:block">
|
|
||||||
<VoiceRoomItem {url} {h} />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
{/each}
|
||||||
{#if $otherRooms.length > 0}
|
{#if $otherRooms.length > 0}
|
||||||
<div class="h-2"></div>
|
<div class="h-2"></div>
|
||||||
@@ -293,13 +281,11 @@
|
|||||||
<SpaceMenuRoomItem {replaceState} {url} {h} />
|
<SpaceMenuRoomItem {replaceState} {url} {h} />
|
||||||
{/each}
|
{/each}
|
||||||
{#if $otherVoiceRooms.length > 0}
|
{#if $otherVoiceRooms.length > 0}
|
||||||
<div class="hidden md:block">
|
<div class="h-2"></div>
|
||||||
<div class="h-2"></div>
|
<SecondaryNavHeader>Voice Rooms</SecondaryNavHeader>
|
||||||
<SecondaryNavHeader>Voice Rooms</SecondaryNavHeader>
|
{#each $otherVoiceRooms as h (h)}
|
||||||
{#each $otherVoiceRooms as h (h)}
|
<SpaceMenuRoomItem {replaceState} {url} {h} />
|
||||||
<VoiceRoomItem {url} {h} />
|
{/each}
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if $canCreateRoom}
|
{#if $canCreateRoom}
|
||||||
<SecondaryNavItem {replaceState} onclick={addRoom}>
|
<SecondaryNavItem {replaceState} onclick={addRoom}>
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
||||||
import RoomNameWithImage from "@app/components/RoomNameWithImage.svelte"
|
import RoomNameWithImage from "@app/components/RoomNameWithImage.svelte"
|
||||||
import {deriveShouldNotify} from "@app/core/state"
|
import {deriveRoom, deriveShouldNotify, getRoomType, RoomType} from "@app/core/state"
|
||||||
import {notifications} from "@app/util/notifications"
|
import {notifications} from "@app/util/notifications"
|
||||||
import {makeRoomPath} from "@app/util/routes"
|
import {makeRoomPath} from "@app/util/routes"
|
||||||
|
import {joinVoiceRoom, currentVoiceSession} from "@app/voice"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
url: any
|
url: any
|
||||||
@@ -17,15 +18,24 @@
|
|||||||
|
|
||||||
const {url, h, notify = false, replaceState = false}: Props = $props()
|
const {url, h, notify = false, replaceState = false}: Props = $props()
|
||||||
|
|
||||||
|
const room = deriveRoom(url, h)
|
||||||
|
const roomType = $derived(getRoomType($room))
|
||||||
const path = makeRoomPath(url, h)
|
const path = makeRoomPath(url, h)
|
||||||
const shouldNotifyForSpace = deriveShouldNotify(url)
|
const shouldNotifyForSpace = deriveShouldNotify(url)
|
||||||
const shouldNotifyForRoom = deriveShouldNotify(url, h)
|
const shouldNotifyForRoom = deriveShouldNotify(url, h)
|
||||||
const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace)
|
const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace)
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (roomType !== RoomType.Voice) return
|
||||||
|
if ($currentVoiceSession?.url === url && $currentVoiceSession?.h === h) return
|
||||||
|
void joinVoiceRoom(url, h)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SecondaryNavItem
|
<SecondaryNavItem
|
||||||
href={path}
|
href={path}
|
||||||
{replaceState}
|
{replaceState}
|
||||||
|
onclick={handleClick}
|
||||||
notification={notify ? $notifications.has(path) : false}>
|
notification={notify ? $notifications.has(path) : false}>
|
||||||
<RoomNameWithImage {url} {h} />
|
<RoomNameWithImage {url} {h} />
|
||||||
{#if showDifferenceIcon}
|
{#if showDifferenceIcon}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import cx from "classnames"
|
import cx from "classnames"
|
||||||
import {loadProfile, displayProfileByPubkey} from "@welshman/app"
|
import {loadProfile, displayProfileByPubkey} from "@welshman/app"
|
||||||
import Volume from "@assets/icons/volume.svg?dataurl"
|
|
||||||
import VolumeLoud from "@assets/icons/volume-loud.svg?dataurl"
|
|
||||||
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
||||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||||
import RoomImage from "@app/components/RoomImage.svelte"
|
import RoomImage from "@app/components/RoomImage.svelte"
|
||||||
@@ -62,7 +60,7 @@
|
|||||||
{#if joinAbortController}
|
{#if joinAbortController}
|
||||||
<span class="loading loading-spinner loading-sm"></span>
|
<span class="loading loading-spinner loading-sm"></span>
|
||||||
{:else}
|
{:else}
|
||||||
<RoomImage {url} {h} size={4} fallbackIcon={isActive ? VolumeLoud : Volume} />
|
<RoomImage {url} {h} size={4} />
|
||||||
{/if}
|
{/if}
|
||||||
<RoomName {url} {h} />
|
<RoomName {url} {h} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+20
-15
@@ -568,11 +568,19 @@ export const chatSearch = derived(throttled(800, chatsById), $chatsByPubkey => {
|
|||||||
|
|
||||||
// Rooms
|
// Rooms
|
||||||
|
|
||||||
|
export enum RoomType {
|
||||||
|
Text = "text",
|
||||||
|
Voice = "voice",
|
||||||
|
}
|
||||||
|
|
||||||
export type Room = PublishedRoomMeta & {
|
export type Room = PublishedRoomMeta & {
|
||||||
id: string
|
id: string
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getRoomType = (room: {livekit?: boolean}): RoomType =>
|
||||||
|
room.livekit ? RoomType.Voice : RoomType.Text
|
||||||
|
|
||||||
export const makeRoomId = (url: string, h: string) => `${url}'${h}`
|
export const makeRoomId = (url: string, h: string) => `${url}'${h}`
|
||||||
|
|
||||||
export const splitRoomId = (id: string) => id.split("'")
|
export const splitRoomId = (id: string) => id.split("'")
|
||||||
@@ -664,7 +672,7 @@ export const displayRoom = (url: string, h: string) => getRoom(makeRoomId(url, h
|
|||||||
|
|
||||||
export const roomComparator = (url: string) => (h: string) => displayRoom(url, h).toLowerCase()
|
export const roomComparator = (url: string) => (h: string) => displayRoom(url, h).toLowerCase()
|
||||||
|
|
||||||
export const deriveRoomsWithLivekit = (url: string) =>
|
export const deriveVoiceRooms = (url: string) =>
|
||||||
derived(roomsById, $roomsById => {
|
derived(roomsById, $roomsById => {
|
||||||
const set = new Set<string>()
|
const set = new Set<string>()
|
||||||
for (const room of $roomsById.values()) {
|
for (const room of $roomsById.values()) {
|
||||||
@@ -687,20 +695,17 @@ export const deriveRoomsNoText = (url: string) =>
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const deriveOtherVoiceRooms = (url: string) =>
|
export const deriveOtherVoiceRooms = (url: string) =>
|
||||||
derived(
|
derived([deriveVoiceRooms(url), deriveUserRooms(url)], ([$roomsWithLivekit, $userRooms]) => {
|
||||||
[deriveRoomsWithLivekit(url), deriveUserRooms(url)],
|
const rooms: string[] = []
|
||||||
([$roomsWithLivekit, $userRooms]) => {
|
|
||||||
const rooms: string[] = []
|
|
||||||
|
|
||||||
for (const h of $roomsWithLivekit) {
|
for (const h of $roomsWithLivekit) {
|
||||||
if (!$userRooms.includes(h)) {
|
if (!$userRooms.includes(h)) {
|
||||||
rooms.push(h)
|
rooms.push(h)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sortBy(roomComparator(url), uniq(rooms))
|
return sortBy(roomComparator(url), uniq(rooms))
|
||||||
},
|
})
|
||||||
)
|
|
||||||
|
|
||||||
// User space/room lists
|
// User space/room lists
|
||||||
|
|
||||||
@@ -792,12 +797,12 @@ export const deriveUserRooms = (url: string) =>
|
|||||||
|
|
||||||
export const deriveOtherRooms = (url: string) =>
|
export const deriveOtherRooms = (url: string) =>
|
||||||
derived(
|
derived(
|
||||||
[deriveUserRooms(url), deriveRoomsNoText(url), roomsByUrl],
|
[deriveUserRooms(url), deriveVoiceRooms(url), roomsByUrl],
|
||||||
([$userRooms, $roomsNoText, $roomsByUrl]) => {
|
([$userRooms, voiceRooms, $roomsByUrl]) => {
|
||||||
const rooms: string[] = []
|
const rooms: string[] = []
|
||||||
|
|
||||||
for (const {h} of $roomsByUrl.get(url) || []) {
|
for (const {h} of $roomsByUrl.get(url) || []) {
|
||||||
if (!$userRooms.includes(h) && !$roomsNoText.has(h)) {
|
if (!$userRooms.includes(h) && !voiceRooms.has(h)) {
|
||||||
rooms.push(h)
|
rooms.push(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user