forked from coracle/flotilla
Work on swapping nav out depending on current page
This commit is contained in:
@@ -6,52 +6,56 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import {page} from "$app/stores"
|
||||
import {goto} from '$app/navigation'
|
||||
import {derived} from 'svelte/store'
|
||||
import {identity} from '@welshman/lib'
|
||||
import {tweened} from 'svelte/motion'
|
||||
import {quintOut} from 'svelte/easing'
|
||||
import {identity, nth} from '@welshman/lib'
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
|
||||
import SpaceAdd from '@app/components/SpaceAdd.svelte'
|
||||
import {session} from "@app/base"
|
||||
import {deriveGroupMembership, makeGroupId, loadGroup, deriveProfile, qualifiedGroupsById, splitGroupId} from "@app/state"
|
||||
import {userProfile, userGroupsByNom, makeGroupId, loadGroup, deriveProfile, qualifiedGroupsById, splitGroupId} from "@app/state"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {getPrimaryNavItemIndex} from "@app/routes"
|
||||
|
||||
const activeOffset = tweened(-44, {
|
||||
duration: 300,
|
||||
easing: quintOut
|
||||
})
|
||||
|
||||
const addSpace = () => pushModal(SpaceAdd)
|
||||
|
||||
const browseSpaces = () => goto("/browse")
|
||||
const gotoHome = () => goto("/home")
|
||||
|
||||
const gotoSpaces = () => goto("/spaces")
|
||||
|
||||
$: profile = deriveProfile($session?.pubkey)
|
||||
$: membership = deriveGroupMembership($session?.pubkey)
|
||||
$: userGroupsByNom = derived([membership, qualifiedGroupsById], ([$membership, $qualifiedGroupsById]) => {
|
||||
const $userGroupsByNom = new Map()
|
||||
const gotoSpace = (nom: string) => goto(`/spaces/${nom}`)
|
||||
|
||||
for (const id of $membership?.ids || []) {
|
||||
const [url, nom] = splitGroupId(id)
|
||||
const group = $qualifiedGroupsById.get(id)
|
||||
const groups = $userGroupsByNom.get(nom) || []
|
||||
const gotoSettings = () => goto("/settings")
|
||||
|
||||
loadGroup(nom, [url])
|
||||
let element: HTMLElement
|
||||
|
||||
if (group) {
|
||||
groups.push(group)
|
||||
}
|
||||
// Set the active highlight element to the offset of the nav item we're focused on
|
||||
$: {
|
||||
if (element) {
|
||||
const index = getPrimaryNavItemIndex($page)
|
||||
const navItems: any = Array.from(element.querySelectorAll('.z-nav-item') || [])
|
||||
|
||||
$userGroupsByNom.set(nom, groups)
|
||||
activeOffset.set(navItems[index].offsetTop - 44)
|
||||
}
|
||||
|
||||
return $userGroupsByNom
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative w-14 bg-base-100">
|
||||
<div class="absolute -top-[44px] z-nav-active ml-2 h-[144px] w-12 bg-base-300" />
|
||||
<div class="relative w-14 bg-base-100" bind:this={element}>
|
||||
<div class="absolute z-nav-active ml-2 h-[144px] w-12 bg-base-300" style={`top: ${$activeOffset}px`} />
|
||||
<div class="flex h-full flex-col justify-between">
|
||||
<div>
|
||||
<PrimaryNavItem title={$profile?.name}>
|
||||
<PrimaryNavItem title={$userProfile?.name} on:click={gotoHome}>
|
||||
<div class="!flex w-10 items-center justify-center rounded-full border border-solid border-base-300">
|
||||
{#if $profile?.picture}
|
||||
<img alt="" src={$profile.picture} />
|
||||
{#if $userProfile?.picture}
|
||||
<img alt="" src={$userProfile.picture} />
|
||||
{:else}
|
||||
<Icon icon="user-rounded" size={7} />
|
||||
{/if}
|
||||
@@ -59,7 +63,7 @@
|
||||
</PrimaryNavItem>
|
||||
{#each $userGroupsByNom.entries() as [nom, qualifiedGroups] (nom)}
|
||||
{@const qualifiedGroup = qualifiedGroups[0]}
|
||||
<PrimaryNavItem title={qualifiedGroup?.group.name}>
|
||||
<PrimaryNavItem title={qualifiedGroup?.group.name} on:click={() => gotoSpace(nom)}>
|
||||
<div class="w-10 rounded-full border border-solid border-base-300">
|
||||
<img alt={qualifiedGroup?.group.name} src={qualifiedGroup?.group.picture} />
|
||||
</div>
|
||||
@@ -70,14 +74,14 @@
|
||||
<Icon size={7} icon="add-circle" />
|
||||
</div>
|
||||
</PrimaryNavItem>
|
||||
<PrimaryNavItem title="Browse Spaces" on:click={browseSpaces}>
|
||||
<PrimaryNavItem title="Browse Spaces" on:click={gotoSpaces}>
|
||||
<div class="!flex w-10 items-center justify-center">
|
||||
<Icon size={6} icon="compass-big" />
|
||||
</div>
|
||||
</PrimaryNavItem>
|
||||
</div>
|
||||
<div>
|
||||
<PrimaryNavItem title="Settings">
|
||||
<PrimaryNavItem title="Settings" on:click={gotoSettings}>
|
||||
<div class="!flex w-10 items-center justify-center">
|
||||
<Icon size={7} icon="settings" />
|
||||
</div>
|
||||
|
||||
@@ -1,23 +1,50 @@
|
||||
<script lang="ts">
|
||||
import {page} from "$app/stores"
|
||||
import {fly} from '@lib/transition'
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import SecondaryNavItem from "@lib/components/SecondaryNavItem.svelte"
|
||||
import {getPrimaryNavItem} from '@app/routes'
|
||||
</script>
|
||||
|
||||
<div class="flex w-60 flex-col gap-1 bg-base-300 px-2 py-4">
|
||||
<SecondaryNavItem href="/home">
|
||||
<Icon icon="home-smile" /> Home
|
||||
</SecondaryNavItem>
|
||||
<SecondaryNavItem href="/people">
|
||||
<Icon icon="user-heart" /> People
|
||||
</SecondaryNavItem>
|
||||
<SecondaryNavItem href="/notes">
|
||||
<Icon icon="clipboard-text" /> Saved Notes
|
||||
</SecondaryNavItem>
|
||||
<div
|
||||
class="text-stark-content flex items-center justify-between px-4 py-2 text-sm font-bold uppercase">
|
||||
Conversations
|
||||
<div class="cursor-pointer">
|
||||
<Icon icon="add-circle" class="bg-stark-content" />
|
||||
{#if getPrimaryNavItem($page) === 'discover'}
|
||||
<div in:fly>
|
||||
<SecondaryNavItem href="/spaces">
|
||||
<Icon icon="widget" /> Spaces
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
</div>
|
||||
<div in:fly={{delay: 50}}>
|
||||
<SecondaryNavItem href="/themes">
|
||||
<Icon icon="pallete-2" /> Themes
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
{:else if getPrimaryNavItem($page) === 'space'}
|
||||
<!-- pass -->
|
||||
{:else if getPrimaryNavItem($page) === 'settings'}
|
||||
<!-- pass -->
|
||||
{:else}
|
||||
<div in:fly>
|
||||
<SecondaryNavItem href="/home">
|
||||
<Icon icon="home-smile" /> Home
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
<div in:fly={{delay: 50}}>
|
||||
<SecondaryNavItem href="/people">
|
||||
<Icon icon="user-heart" /> People
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
<div in:fly={{delay: 100}}>
|
||||
<SecondaryNavItem href="/notes">
|
||||
<Icon icon="clipboard-text" /> Saved Notes
|
||||
</SecondaryNavItem>
|
||||
</div>
|
||||
<div
|
||||
in:fly={{delay: 150}}
|
||||
class="text-stark-content flex items-center justify-between px-4 py-2 text-sm font-bold uppercase">
|
||||
Conversations
|
||||
<div class="cursor-pointer">
|
||||
<Icon icon="add-circle" class="bg-stark-content" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import type {Page} from '@sveltejs/kit'
|
||||
import {userGroupsByNom} from '@app/state'
|
||||
|
||||
export const getPrimaryNavItem = ($page: Page) => {
|
||||
if ($page.route?.id?.match('^/(spaces|themes)$')) return 'discover'
|
||||
if ($page.route?.id?.startsWith('/spaces')) return 'space'
|
||||
if ($page.route?.id?.startsWith('/settings')) return 'settings'
|
||||
return 'home'
|
||||
}
|
||||
|
||||
export const getPrimaryNavItemIndex = ($page: Page) => {
|
||||
switch (getPrimaryNavItem($page)) {
|
||||
case 'discover':
|
||||
return userGroupsByNom.get().size + 2
|
||||
case 'space':
|
||||
return Array.from(userGroupsByNom.get().keys()).findIndex(nom => nom === $page.params.nom) + 1
|
||||
case 'settings':
|
||||
return userGroupsByNom.get().size + 3
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
+40
-2
@@ -454,8 +454,8 @@ export const groupMemberships = deriveEventsMapped<PublishedGroupMembership>({
|
||||
})
|
||||
|
||||
export const {
|
||||
indexStore: groupMembershipsByPubkey,
|
||||
getIndex: getGroupMembersipsByPubkey,
|
||||
indexStore: groupMembershipByPubkey,
|
||||
getIndex: getGroupMembersipByPubkey,
|
||||
deriveItem: deriveGroupMembership,
|
||||
loadItem: loadGroupMembership,
|
||||
// getItem: getGroupMembership,
|
||||
@@ -470,3 +470,41 @@ export const {
|
||||
filters: [{kinds: [GROUPS], authors: [pubkey]}],
|
||||
})
|
||||
})
|
||||
|
||||
// User stuff
|
||||
|
||||
export const userProfile = derived([pk, profilesByPubkey], ([$pk, $profilesByPubkey]) => {
|
||||
if (!$pk) return null
|
||||
|
||||
loadProfile($pk)
|
||||
|
||||
return $profilesByPubkey.get($pk)
|
||||
})
|
||||
|
||||
export const userMembership = derived([pk, groupMembershipByPubkey], ([$pk, $groupMembershipByPubkey]) => {
|
||||
if (!$pk) return null
|
||||
|
||||
loadGroupMembership($pk)
|
||||
|
||||
return $groupMembershipByPubkey.get($pk)
|
||||
})
|
||||
|
||||
export const userGroupsByNom = withGetter(derived([userMembership, qualifiedGroupsById], ([$userMembership, $qualifiedGroupsById]) => {
|
||||
const $userGroupsByNom = new Map()
|
||||
|
||||
for (const id of $userMembership?.ids || []) {
|
||||
const [url, nom] = splitGroupId(id)
|
||||
const group = $qualifiedGroupsById.get(id)
|
||||
const groups = $userGroupsByNom.get(nom) || []
|
||||
|
||||
loadGroup(nom, [url])
|
||||
|
||||
if (group) {
|
||||
groups.push(group)
|
||||
}
|
||||
|
||||
$userGroupsByNom.set(nom, groups)
|
||||
}
|
||||
|
||||
return $userGroupsByNom
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user