Add mobile nav notification badges
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {displayRelayUrl} from "@welshman/util"
|
import {displayRelayUrl} from "@welshman/util"
|
||||||
import {fly, slide} from "@lib/transition"
|
import {fly} from "@lib/transition"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Popover from "@lib/components/Popover.svelte"
|
import Popover from "@lib/components/Popover.svelte"
|
||||||
@@ -55,17 +55,6 @@
|
|||||||
|
|
||||||
const addRoom = () => pushModal(RoomCreate, {url}, {replaceState})
|
const addRoom = () => pushModal(RoomCreate, {url}, {replaceState})
|
||||||
|
|
||||||
const getDelay = (reset = false) => {
|
|
||||||
if (reset) {
|
|
||||||
delay = 0
|
|
||||||
} else {
|
|
||||||
delay += 50
|
|
||||||
}
|
|
||||||
|
|
||||||
return delay
|
|
||||||
}
|
|
||||||
|
|
||||||
let delay = 0
|
|
||||||
let showMenu = false
|
let showMenu = false
|
||||||
let replaceState = false
|
let replaceState = false
|
||||||
let element: Element
|
let element: Element
|
||||||
@@ -120,53 +109,37 @@
|
|||||||
</Popover>
|
</Popover>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div in:fly={{delay: getDelay(true)}}>
|
<SecondaryNavItem href={makeSpacePath(url)}>
|
||||||
<SecondaryNavItem href={makeSpacePath(url)}>
|
<Icon icon="home-smile" /> Home
|
||||||
<Icon icon="home-smile" /> Home
|
</SecondaryNavItem>
|
||||||
</SecondaryNavItem>
|
<SecondaryNavItem href={threadsPath} notification={$threadsNotification}>
|
||||||
</div>
|
<Icon icon="notes-minimalistic" /> Threads
|
||||||
<div in:fly={{delay: getDelay()}}>
|
</SecondaryNavItem>
|
||||||
<SecondaryNavItem href={threadsPath} notification={$threadsNotification}>
|
<div class="h-2" />
|
||||||
<Icon icon="notes-minimalistic" /> Threads
|
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
|
||||||
</SecondaryNavItem>
|
<MenuSpaceRoomItem {url} room={GENERAL} />
|
||||||
</div>
|
|
||||||
<div transition:slide={{delay: getDelay()}}>
|
|
||||||
<div class="h-2" />
|
|
||||||
<SecondaryNavHeader>Your Rooms</SecondaryNavHeader>
|
|
||||||
</div>
|
|
||||||
<div transition:slide={{delay: getDelay()}}>
|
|
||||||
<MenuSpaceRoomItem {url} room={GENERAL} />
|
|
||||||
</div>
|
|
||||||
{#each rooms as room, i (room)}
|
{#each rooms as room, i (room)}
|
||||||
<div transition:slide={{delay: getDelay()}}>
|
<MenuSpaceRoomItem {url} {room} />
|
||||||
<MenuSpaceRoomItem {url} {room} />
|
|
||||||
</div>
|
|
||||||
{/each}
|
{/each}
|
||||||
{#if otherRooms.length > 0}
|
{#if otherRooms.length > 0}
|
||||||
<div transition:slide={{delay: getDelay()}}>
|
<div class="h-2" />
|
||||||
<div class="h-2" />
|
<SecondaryNavHeader>
|
||||||
<SecondaryNavHeader>
|
{#if rooms.length > 0}
|
||||||
{#if rooms.length > 0}
|
Other Rooms
|
||||||
Other Rooms
|
{:else}
|
||||||
{:else}
|
Rooms
|
||||||
Rooms
|
{/if}
|
||||||
{/if}
|
</SecondaryNavHeader>
|
||||||
</SecondaryNavHeader>
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#each otherRooms as room, i (room)}
|
{#each otherRooms as room, i (room)}
|
||||||
<div transition:slide={{delay: getDelay()}}>
|
<SecondaryNavItem href={makeSpacePath(url, room)}>
|
||||||
<SecondaryNavItem href={makeSpacePath(url, room)}>
|
<Icon icon="hashtag" />
|
||||||
<Icon icon="hashtag" />
|
{room}
|
||||||
{room}
|
|
||||||
</SecondaryNavItem>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
<div in:fly={{delay: getDelay()}}>
|
|
||||||
<SecondaryNavItem on:click={addRoom}>
|
|
||||||
<Icon icon="add-circle" />
|
|
||||||
Create room
|
|
||||||
</SecondaryNavItem>
|
</SecondaryNavItem>
|
||||||
</div>
|
{/each}
|
||||||
|
<SecondaryNavItem on:click={addRoom}>
|
||||||
|
<Icon icon="add-circle" />
|
||||||
|
Create room
|
||||||
|
</SecondaryNavItem>
|
||||||
</SecondaryNavSection>
|
</SecondaryNavSection>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Divider from "@lib/components/Divider.svelte"
|
import Divider from "@lib/components/Divider.svelte"
|
||||||
import CardButton from "@lib/components/CardButton.svelte"
|
import CardButton from "@lib/components/CardButton.svelte"
|
||||||
import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
|
import MenuSpacesItem from "@app/components/MenuSpacesItem.svelte"
|
||||||
import RelayName from "@app/components/RelayName.svelte"
|
|
||||||
import RelayDescription from "@app/components/RelayDescription.svelte"
|
|
||||||
import SpaceAdd from "@app/components/SpaceAdd.svelte"
|
import SpaceAdd from "@app/components/SpaceAdd.svelte"
|
||||||
import {userMembership, getMembershipUrls, PLATFORM_RELAY} from "@app/state"
|
import {userMembership, getMembershipUrls, PLATFORM_RELAY} from "@app/state"
|
||||||
import {makeSpacePath} from "@app/routes"
|
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
|
|
||||||
const addSpace = () => pushModal(SpaceAdd)
|
const addSpace = () => pushModal(SpaceAdd)
|
||||||
@@ -17,23 +13,11 @@
|
|||||||
|
|
||||||
<div class="column menu gap-2">
|
<div class="column menu gap-2">
|
||||||
{#if PLATFORM_RELAY}
|
{#if PLATFORM_RELAY}
|
||||||
<Link replaceState href={makeSpacePath(PLATFORM_RELAY)}>
|
<MenuSpacesItem url={PLATFORM_RELAY} />
|
||||||
<CardButton>
|
|
||||||
<div slot="icon"><SpaceAvatar url={PLATFORM_RELAY} /></div>
|
|
||||||
<div slot="title"><RelayName url={PLATFORM_RELAY} /></div>
|
|
||||||
<div slot="info"><RelayDescription url={PLATFORM_RELAY} /></div>
|
|
||||||
</CardButton>
|
|
||||||
</Link>
|
|
||||||
<Divider />
|
<Divider />
|
||||||
{:else if getMembershipUrls($userMembership).length > 0}
|
{:else if getMembershipUrls($userMembership).length > 0}
|
||||||
{#each getMembershipUrls($userMembership) as url (url)}
|
{#each getMembershipUrls($userMembership) as url (url)}
|
||||||
<Link replaceState href={makeSpacePath(url)}>
|
<MenuSpacesItem {url} />
|
||||||
<CardButton>
|
|
||||||
<div slot="icon"><SpaceAvatar {url} /></div>
|
|
||||||
<div slot="title"><RelayName {url} /></div>
|
|
||||||
<div slot="info"><RelayDescription {url} /></div>
|
|
||||||
</CardButton>
|
|
||||||
</Link>
|
|
||||||
{/each}
|
{/each}
|
||||||
<Divider />
|
<Divider />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Link from "@lib/components/Link.svelte"
|
||||||
|
import CardButton from "@lib/components/CardButton.svelte"
|
||||||
|
import SpaceAvatar from "@app/components/SpaceAvatar.svelte"
|
||||||
|
import RelayName from "@app/components/RelayName.svelte"
|
||||||
|
import RelayDescription from "@app/components/RelayDescription.svelte"
|
||||||
|
import {makeSpacePath} from "@app/routes"
|
||||||
|
import {deriveNotification, SPACE_FILTERS} from "@app/notifications"
|
||||||
|
|
||||||
|
export let url
|
||||||
|
|
||||||
|
const path = makeSpacePath(url)
|
||||||
|
const notification = deriveNotification(path, SPACE_FILTERS, url)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Link replaceState href={path}>
|
||||||
|
<CardButton>
|
||||||
|
<div slot="icon"><SpaceAvatar {url} /></div>
|
||||||
|
<div slot="title" class="flex gap-1">
|
||||||
|
<RelayName {url} />
|
||||||
|
{#if $notification}
|
||||||
|
<div class="relative top-1 h-2 w-2 rounded-full bg-primary" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div slot="info"><RelayDescription {url} /></div>
|
||||||
|
</CardButton>
|
||||||
|
</Link>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
import PrimaryNavItemSpace from "@app/components/PrimaryNavItemSpace.svelte"
|
import PrimaryNavItemSpace from "@app/components/PrimaryNavItemSpace.svelte"
|
||||||
import {userMembership, getMembershipUrls, PLATFORM_RELAY, PLATFORM_LOGO} from "@app/state"
|
import {userMembership, getMembershipUrls, PLATFORM_RELAY, PLATFORM_LOGO} from "@app/state"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {deriveNotification, CHAT_FILTERS} from "@app/notifications"
|
import {deriveNotification, spacesNotification, CHAT_FILTERS} from "@app/notifications"
|
||||||
|
|
||||||
const chatNotification = deriveNotification("/chat", CHAT_FILTERS)
|
const chatNotification = deriveNotification("/chat", CHAT_FILTERS)
|
||||||
|
|
||||||
@@ -76,10 +76,10 @@
|
|||||||
<PrimaryNavItem title="Notes" href="/notes">
|
<PrimaryNavItem title="Notes" href="/notes">
|
||||||
<Avatar icon="notes-minimalistic" class="!h-10 !w-10" />
|
<Avatar icon="notes-minimalistic" class="!h-10 !w-10" />
|
||||||
</PrimaryNavItem>
|
</PrimaryNavItem>
|
||||||
<PrimaryNavItem title="Messages" href="/chat">
|
<PrimaryNavItem title="Messages" href="/chat" notification={$chatNotification}>
|
||||||
<Avatar icon="letter" class="!h-10 !w-10" />
|
<Avatar icon="letter" class="!h-10 !w-10" />
|
||||||
</PrimaryNavItem>
|
</PrimaryNavItem>
|
||||||
<PrimaryNavItem title="Spaces" on:click={showSpacesMenu}>
|
<PrimaryNavItem title="Spaces" on:click={showSpacesMenu} notification={$spacesNotification}>
|
||||||
<Avatar icon="settings-minimalistic" class="!h-10 !w-10" />
|
<Avatar icon="settings-minimalistic" class="!h-10 !w-10" />
|
||||||
</PrimaryNavItem>
|
</PrimaryNavItem>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,15 @@ import {repository, pubkey} from "@welshman/app"
|
|||||||
import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib"
|
import {prop, max, sortBy, assoc, lt, now} from "@welshman/lib"
|
||||||
import type {Filter} from "@welshman/util"
|
import type {Filter} from "@welshman/util"
|
||||||
import {DIRECT_MESSAGE} from "@welshman/util"
|
import {DIRECT_MESSAGE} from "@welshman/util"
|
||||||
import {MESSAGE, THREAD, COMMENT, deriveEventsForUrl} from "@app/state"
|
import {makeSpacePath} from "@app/routes"
|
||||||
|
import {
|
||||||
|
MESSAGE,
|
||||||
|
THREAD,
|
||||||
|
COMMENT,
|
||||||
|
deriveEventsForUrl,
|
||||||
|
getMembershipUrls,
|
||||||
|
userMembership,
|
||||||
|
} from "@app/state"
|
||||||
|
|
||||||
// Checked state
|
// Checked state
|
||||||
|
|
||||||
@@ -49,3 +57,16 @@ export const deriveNotification = (path: string, filters: Filter[], url?: string
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const spacesNotification = derived(
|
||||||
|
[pubkey, checked, userMembership, deriveEvents(repository, {filters: SPACE_FILTERS})],
|
||||||
|
([$pubkey, $checked, $userMembership, $events]) => {
|
||||||
|
return getMembershipUrls($userMembership).some(url => {
|
||||||
|
const path = makeSpacePath(url)
|
||||||
|
const lastChecked = max([$checked["*"], $checked[path]])
|
||||||
|
const [latestEvent] = sortBy($e => -$e.created_at, $events)
|
||||||
|
|
||||||
|
return latestEvent?.pubkey !== $pubkey && lt(lastChecked, latestEvent?.created_at)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import {sleep} from "@welshman/lib"
|
|
||||||
|
|
||||||
export let delay = 1
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#await sleep(delay)}
|
|
||||||
<!-- pass -->
|
|
||||||
{:then}
|
|
||||||
<slot />
|
|
||||||
{/await}
|
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
class:bg-base-300={active}
|
class:bg-base-300={active}
|
||||||
class:tooltip={title}
|
class:tooltip={title}
|
||||||
data-tip={title}>
|
data-tip={title}>
|
||||||
{#if !active && notification}
|
|
||||||
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary" />
|
|
||||||
{/if}
|
|
||||||
<slot />
|
<slot />
|
||||||
|
{#if !active && notification}
|
||||||
|
<div class="absolute right-2 top-2 h-2 w-2 rounded-full bg-primary" />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
class:bg-base-300={active}
|
class:bg-base-300={active}
|
||||||
class:tooltip={title}
|
class:tooltip={title}
|
||||||
data-tip={title}>
|
data-tip={title}>
|
||||||
{#if !active && notification}
|
|
||||||
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary" />
|
|
||||||
{/if}
|
|
||||||
<slot />
|
<slot />
|
||||||
|
{#if !active && notification}
|
||||||
|
<div class="absolute right-2 top-2 h-2 w-2 rounded-full bg-primary" />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import "@src/app.css"
|
import "@src/app.css"
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {get, derived} from "svelte/store"
|
import {get, derived} from "svelte/store"
|
||||||
|
import {page} from "$app/stores"
|
||||||
import {dev} from "$app/environment"
|
import {dev} from "$app/environment"
|
||||||
import {identity, uniq, sleep, take, sortBy, ago, now, HOUR, WEEK, Worker} from "@welshman/lib"
|
import {identity, uniq, sleep, take, sortBy, ago, now, HOUR, WEEK, Worker} from "@welshman/lib"
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
import type {TrustedEvent} from "@welshman/util"
|
||||||
@@ -229,7 +230,9 @@
|
|||||||
{:then}
|
{:then}
|
||||||
<div data-theme={$theme}>
|
<div data-theme={$theme}>
|
||||||
<AppContainer>
|
<AppContainer>
|
||||||
<slot />
|
{#key $page.url.pathname}
|
||||||
|
<slot />
|
||||||
|
{/key}
|
||||||
</AppContainer>
|
</AppContainer>
|
||||||
<ModalContainer />
|
<ModalContainer />
|
||||||
<div class="tippy-target" />
|
<div class="tippy-target" />
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {page} from "$app/stores"
|
|
||||||
import {ctx} from "@welshman/lib"
|
import {ctx} from "@welshman/lib"
|
||||||
import {WRAP} from "@welshman/util"
|
import {WRAP} from "@welshman/util"
|
||||||
import type {TrustedEvent} from "@welshman/util"
|
import type {TrustedEvent} from "@welshman/util"
|
||||||
@@ -56,22 +55,17 @@
|
|||||||
<Icon icon="magnifer" />
|
<Icon icon="magnifer" />
|
||||||
<input bind:value={term} class="grow" type="text" />
|
<input bind:value={term} class="grow" type="text" />
|
||||||
</label>
|
</label>
|
||||||
{#key $page.params.chat}
|
<div class="overflow-auto">
|
||||||
<div class="overflow-auto">
|
{#each chats as { id, pubkeys, messages } (id)}
|
||||||
{#each chats as { id, pubkeys, messages } (id)}
|
<ChatItem {id} {pubkeys} {messages} />
|
||||||
<ChatItem {id} {pubkeys} {messages} />
|
{/each}
|
||||||
{/each}
|
{#await promise}
|
||||||
{#await promise}
|
<div class="border-t border-solid border-base-100 px-6 py-4 text-xs">
|
||||||
<div class="border-t border-solid border-base-100 px-6 py-4 text-xs">
|
<Spinner loading>Loading conversations...</Spinner>
|
||||||
<Spinner loading>Loading conversations...</Spinner>
|
</div>
|
||||||
</div>
|
{/await}
|
||||||
{/await}
|
</div>
|
||||||
</div>
|
|
||||||
{/key}
|
|
||||||
</SecondaryNav>
|
</SecondaryNav>
|
||||||
|
|
||||||
<Page>
|
<Page>
|
||||||
{#key JSON.stringify($page.params)}
|
<slot />
|
||||||
<slot />
|
|
||||||
{/key}
|
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {page} from "$app/stores"
|
||||||
|
import {onDestroy} from "svelte"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ContentSearch from "@lib/components/ContentSearch.svelte"
|
import ContentSearch from "@lib/components/ContentSearch.svelte"
|
||||||
@@ -6,12 +8,17 @@
|
|||||||
import ChatStart from "@app/components/ChatStart.svelte"
|
import ChatStart from "@app/components/ChatStart.svelte"
|
||||||
import {chatSearch} from "@app/state"
|
import {chatSearch} from "@app/state"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
|
import {setChecked} from "@app/notifications"
|
||||||
|
|
||||||
let term = ""
|
let term = ""
|
||||||
|
|
||||||
const startChat = () => pushModal(ChatStart)
|
const startChat = () => pushModal(ChatStart)
|
||||||
|
|
||||||
$: chats = $chatSearch.searchOptions(term).filter(c => c.pubkeys.length > 1)
|
$: chats = $chatSearch.searchOptions(term).filter(c => c.pubkeys.length > 1)
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
setChecked($page.url.pathname)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="hidden min-h-screen md:hero">
|
<div class="hidden min-h-screen md:hero">
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount, onDestroy} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
import Page from "@lib/components/Page.svelte"
|
import Page from "@lib/components/Page.svelte"
|
||||||
import Delay from "@lib/components/Delay.svelte"
|
|
||||||
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
|
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
|
||||||
import MenuSpace from "@app/components/MenuSpace.svelte"
|
import MenuSpace from "@app/components/MenuSpace.svelte"
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
import {setChecked} from "@app/notifications"
|
import {setChecked} from "@app/notifications"
|
||||||
import {checkRelayConnection, checkRelayAuth} from "@app/commands"
|
import {checkRelayConnection, checkRelayAuth} from "@app/commands"
|
||||||
import {decodeRelay} from "@app/state"
|
import {decodeRelay} from "@app/state"
|
||||||
|
import {deriveNotification, SPACE_FILTERS} from "@app/notifications"
|
||||||
|
|
||||||
$: url = decodeRelay($page.params.relay)
|
const url = decodeRelay($page.params.relay)
|
||||||
|
|
||||||
|
const notification = deriveNotification($page.url.pathname, SPACE_FILTERS, url)
|
||||||
|
|
||||||
const ifLet = <T,>(x: T | undefined, f: (x: T) => void) => (x === undefined ? undefined : f(x))
|
const ifLet = <T,>(x: T | undefined, f: (x: T) => void) => (x === undefined ? undefined : f(x))
|
||||||
|
|
||||||
@@ -24,24 +26,21 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have to watch this one, since on mobile the badge wil be visible when active
|
||||||
|
$: {
|
||||||
|
if ($notification) {
|
||||||
|
setChecked($page.url.pathname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
checkConnection()
|
checkConnection()
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
|
||||||
setChecked($page.url.pathname)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#key url}
|
<SecondaryNav>
|
||||||
<Delay>
|
<MenuSpace {url} />
|
||||||
<SecondaryNav>
|
</SecondaryNav>
|
||||||
<MenuSpace {url} />
|
<Page>
|
||||||
</SecondaryNav>
|
<slot />
|
||||||
<Page>
|
</Page>
|
||||||
{#key $page.params.room}
|
|
||||||
<slot />
|
|
||||||
{/key}
|
|
||||||
</Page>
|
|
||||||
</Delay>
|
|
||||||
{/key}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user