flotilla/src/app/components/MenuSpace.svelte

187 lines
6.1 KiB
Svelte
Raw Normal View History

2024-10-21 21:35:12 +00:00
<script lang="ts">
import {onMount} from "svelte"
2025-06-30 17:25:34 +00:00
import {displayRelayUrl, getTagValue} from "@welshman/util"
import {deriveRelay} from "@welshman/app"
2024-11-14 20:16:44 +00:00
import {fly} from "@lib/transition"
2024-10-21 21:35:12 +00:00
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
import Popover from "@lib/components/Popover.svelte"
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
import SecondaryNavHeader from "@lib/components/SecondaryNavHeader.svelte"
import SecondaryNavSection from "@lib/components/SecondaryNavSection.svelte"
import SpaceInvite from "@app/components/SpaceInvite.svelte"
import SpaceExit from "@app/components/SpaceExit.svelte"
import SpaceJoin from "@app/components/SpaceJoin.svelte"
import ProfileList from "@app/components/ProfileList.svelte"
import AlertAdd from "@app/components/AlertAdd.svelte"
2025-06-30 17:25:34 +00:00
import Alerts from "@app/components/Alerts.svelte"
2024-10-21 21:35:12 +00:00
import RoomCreate from "@app/components/RoomCreate.svelte"
2024-11-14 18:53:13 +00:00
import MenuSpaceRoomItem from "@app/components/MenuSpaceRoomItem.svelte"
2024-10-21 21:35:12 +00:00
import {
2024-12-17 01:07:52 +00:00
userRoomsByUrl,
hasMembershipUrl,
memberships,
2024-12-10 21:02:41 +00:00
deriveUserRooms,
deriveOtherRooms,
hasNip29,
2025-06-30 17:25:34 +00:00
alerts,
2024-10-21 21:35:12 +00:00
} from "@app/state"
2024-12-16 19:24:10 +00:00
import {notifications} from "@app/notifications"
2024-10-21 21:35:12 +00:00
import {pushModal} from "@app/modal"
import {makeSpacePath} from "@app/routes"
const {url} = $props()
2024-10-21 21:35:12 +00:00
const relay = deriveRelay(url)
2025-05-29 17:42:43 +00:00
const chatPath = makeSpacePath(url, "chat")
2024-11-14 18:53:13 +00:00
const threadsPath = makeSpacePath(url, "threads")
2025-01-29 00:48:33 +00:00
const calendarPath = makeSpacePath(url, "calendar")
2024-12-10 21:02:41 +00:00
const userRooms = deriveUserRooms(url)
const otherRooms = deriveOtherRooms(url)
2025-06-30 17:25:34 +00:00
const hasAlerts = $derived($alerts.some(a => getTagValue("feed", a.tags)?.includes(url)))
2024-11-14 18:53:13 +00:00
2024-10-21 21:35:12 +00:00
const openMenu = () => {
showMenu = true
}
const toggleMenu = () => {
showMenu = !showMenu
}
const showMembers = () =>
pushModal(
ProfileList,
2025-04-15 18:03:27 +00:00
{url, pubkeys: members, title: `Members of`, subtitle: displayRelayUrl(url)},
2024-10-24 22:48:45 +00:00
{replaceState},
)
const createInvite = () => pushModal(SpaceInvite, {url}, {replaceState})
2024-10-21 21:35:12 +00:00
const leaveSpace = () => pushModal(SpaceExit, {url}, {replaceState})
2024-10-21 21:35:12 +00:00
const joinSpace = () => pushModal(SpaceJoin, {url}, {replaceState})
2024-10-21 21:35:12 +00:00
const addRoom = () => pushModal(RoomCreate, {url}, {replaceState})
2024-10-21 21:35:12 +00:00
2025-06-30 17:25:34 +00:00
const manageAlerts = () => {
const component = hasAlerts ? Alerts : AlertAdd
const params = {url, channel: "push", hideSpaceField: true}
pushModal(component, params, {replaceState})
2025-06-30 16:38:43 +00:00
}
2025-02-04 00:37:14 +00:00
let showMenu = $state(false)
let replaceState = $state(false)
2025-02-04 00:37:14 +00:00
let element: Element | undefined = $state()
2024-10-21 21:35:12 +00:00
const members = $derived(
2025-02-04 00:37:14 +00:00
$memberships.filter(l => hasMembershipUrl(l, url)).map(l => l.event.pubkey),
)
2024-10-21 21:35:12 +00:00
onMount(() => {
2025-02-04 00:37:14 +00:00
replaceState = Boolean(element?.closest(".drawer"))
2024-10-21 21:35:12 +00:00
})
</script>
2025-06-30 17:25:34 +00:00
<div bind:this={element} class="flex h-full flex-col justify-between">
2025-06-30 16:38:43 +00:00
<SecondaryNavSection>
<div>
<SecondaryNavItem class="w-full !justify-between" onclick={openMenu}>
2025-06-30 16:38:43 +00:00
<strong class="ellipsize flex items-center gap-3">
{displayRelayUrl(url)}
</strong>
<Icon icon="alt-arrow-down" />
</SecondaryNavItem>
{#if showMenu}
<Popover hideOnClick onClose={toggleMenu}>
<ul
transition:fly
class="menu absolute z-popover mt-2 w-full gap-1 rounded-box bg-base-100 p-2 shadow-xl">
<li>
<Button onclick={showMembers}>
<Icon icon="user-rounded" />
View Members ({members.length})
2024-10-22 18:41:42 +00:00
</Button>
</li>
<li>
<Button onclick={createInvite}>
<Icon icon="link-round" />
Create Invite
2024-10-22 18:41:42 +00:00
</Button>
</li>
<li>
2024-12-17 01:07:52 +00:00
{#if $userRoomsByUrl.has(url)}
<Button onclick={leaveSpace} class="text-error">
<Icon icon="exit" />
Leave Space
</Button>
{:else}
<Button onclick={joinSpace} class="bg-primary text-primary-content">
<Icon icon="login-2" />
Join Space
</Button>
{/if}
</li>
</ul>
</Popover>
{/if}
</div>
2024-11-22 01:21:27 +00:00
<div class="flex min-h-0 flex-col gap-1 overflow-auto">
<SecondaryNavItem {replaceState} href={makeSpacePath(url)}>
2024-11-21 22:25:57 +00:00
<Icon icon="home-smile" /> Home
</SecondaryNavItem>
<SecondaryNavItem
{replaceState}
href={threadsPath}
notification={$notifications.has(threadsPath)}>
2024-11-21 22:25:57 +00:00
<Icon icon="notes-minimalistic" /> Threads
</SecondaryNavItem>
<SecondaryNavItem
{replaceState}
href={calendarPath}
notification={$notifications.has(calendarPath)}>
2025-01-29 00:48:33 +00:00
<Icon icon="calendar-minimalistic" /> Calendar
</SecondaryNavItem>
{#if hasNip29($relay)}
2025-05-29 17:42:43 +00:00
{#if $userRooms.length > 0}
<div class="h-2"></div>
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
{/if}
{#each $userRooms as room, i (room)}
<MenuSpaceRoomItem {replaceState} notify {url} {room} />
{/each}
{#if $otherRooms.length > 0}
<div class="h-2"></div>
<SecondaryNavHeader>
{#if $userRooms.length > 0}
Other Rooms
{:else}
Rooms
{/if}
</SecondaryNavHeader>
{/if}
{#each $otherRooms as room, i (room)}
<MenuSpaceRoomItem {replaceState} {url} {room} />
{/each}
<SecondaryNavItem {replaceState} onclick={addRoom}>
<Icon icon="add-circle" />
Create room
</SecondaryNavItem>
2025-05-29 17:42:43 +00:00
{:else}
<SecondaryNavItem
{replaceState}
href={chatPath}
notification={$notifications.has(chatPath)}>
<Icon icon="chat-round" /> Chat
</SecondaryNavItem>
{/if}
2025-06-30 17:25:34 +00:00
</div>
</SecondaryNavSection>
2025-06-30 16:38:43 +00:00
<div class="p-4">
2025-06-30 17:25:34 +00:00
<button class="btn btn-neutral btn-sm w-full" onclick={manageAlerts}>
2025-06-30 16:38:43 +00:00
<Icon icon="bell" />
Manage Alerts
</button>
</div>
</div>