Work on swapping nav out depending on current page

This commit is contained in:
Jon Staab
2024-08-14 13:38:55 -07:00
parent 697e893ae6
commit 30175c00e0
7 changed files with 152 additions and 44 deletions

View File

@@ -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>

View File

@@ -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>

22
src/app/routes.ts Normal file
View File

@@ -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
}
}

View File

@@ -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
}))

View File

@@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 12.0261C2 17.1723 5.86713 21.413 10.8468 21.9863C11.5816 22.0709 12.2938 21.7576 12.8168 21.2333C13.4703 20.5781 13.4703 19.5159 12.8168 18.8607C12.2938 18.3364 11.8674 17.5541 12.2619 16.9268C13.8385 14.4192 22 20.178 22 12.0261C22 6.48884 17.5228 2 12 2C6.47715 2 2 6.48884 2 12.0261Z" stroke="#1C274C" stroke-width="1.5"/>
<circle cx="17.5" cy="11.5" r="0.75" stroke="#1C274C" stroke-width="1.5"/>
<circle cx="6.5" cy="11.5" r="0.75" stroke="#1C274C" stroke-width="1.5"/>
<path d="M10.335 7C10.335 7.41421 9.9992 7.75 9.58499 7.75C9.17078 7.75 8.83499 7.41421 8.83499 7C8.83499 6.58579 9.17078 6.25 9.58499 6.25C9.9992 6.25 10.335 6.58579 10.335 7Z" stroke="#1C274C" stroke-width="1.5"/>
<path d="M15.25 7C15.25 7.41421 14.9142 7.75 14.5 7.75C14.0858 7.75 13.75 7.41421 13.75 7C13.75 6.58579 14.0858 6.25 14.5 6.25C14.9142 6.25 15.25 6.58579 15.25 7Z" stroke="#1C274C" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1008 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.5 6.5C2.5 4.61438 2.5 3.67157 3.08579 3.08579C3.67157 2.5 4.61438 2.5 6.5 2.5C8.38562 2.5 9.32843 2.5 9.91421 3.08579C10.5 3.67157 10.5 4.61438 10.5 6.5C10.5 8.38562 10.5 9.32843 9.91421 9.91421C9.32843 10.5 8.38562 10.5 6.5 10.5C4.61438 10.5 3.67157 10.5 3.08579 9.91421C2.5 9.32843 2.5 8.38562 2.5 6.5Z" stroke="#1C274C" stroke-width="1.5"/>
<path d="M13.5 17.5C13.5 15.6144 13.5 14.6716 14.0858 14.0858C14.6716 13.5 15.6144 13.5 17.5 13.5C19.3856 13.5 20.3284 13.5 20.9142 14.0858C21.5 14.6716 21.5 15.6144 21.5 17.5C21.5 19.3856 21.5 20.3284 20.9142 20.9142C20.3284 21.5 19.3856 21.5 17.5 21.5C15.6144 21.5 14.6716 21.5 14.0858 20.9142C13.5 20.3284 13.5 19.3856 13.5 17.5Z" stroke="#1C274C" stroke-width="1.5"/>
<path d="M2.5 17.5C2.5 15.6144 2.5 14.6716 3.08579 14.0858C3.67157 13.5 4.61438 13.5 6.5 13.5C8.38562 13.5 9.32843 13.5 9.91421 14.0858C10.5 14.6716 10.5 15.6144 10.5 17.5C10.5 19.3856 10.5 20.3284 9.91421 20.9142C9.32843 21.5 8.38562 21.5 6.5 21.5C4.61438 21.5 3.67157 21.5 3.08579 20.9142C2.5 20.3284 2.5 19.3856 2.5 17.5Z" stroke="#1C274C" stroke-width="1.5"/>
<path d="M13.5 6.5C13.5 4.61438 13.5 3.67157 14.0858 3.08579C14.6716 2.5 15.6144 2.5 17.5 2.5C19.3856 2.5 20.3284 2.5 20.9142 3.08579C21.5 3.67157 21.5 4.61438 21.5 6.5C21.5 8.38562 21.5 9.32843 20.9142 9.91421C20.3284 10.5 19.3856 10.5 17.5 10.5C15.6144 10.5 14.6716 10.5 14.0858 9.91421C13.5 9.32843 13.5 8.38562 13.5 6.5Z" stroke="#1C274C" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -25,12 +25,14 @@
import LinkRound from "@assets/icons/Link Round.svg?dataurl"
import Login from "@assets/icons/Login.svg?dataurl"
import Login2 from "@assets/icons/Login 2.svg?dataurl"
import Pallete2 from "@assets/icons/Pallete 2.svg?dataurl"
import Plain from "@assets/icons/Plain.svg?dataurl"
import RemoteControllerMinimalistic from "@assets/icons/Remote Controller Minimalistic.svg?dataurl"
import Settings from "@assets/icons/Settings.svg?dataurl"
import UFO3 from "@assets/icons/UFO 3.svg?dataurl"
import UserHeart from "@assets/icons/User Heart.svg?dataurl"
import UserRounded from "@assets/icons/User Rounded.svg?dataurl"
import Widget from "@assets/icons/Widget.svg?dataurl"
import WiFiRouterRound from "@assets/icons/Wi-Fi Router Round.svg?dataurl"
export let icon
@@ -56,12 +58,14 @@
"link-round": LinkRound,
"login": Login,
"login-2": Login2,
'pallete-2': Pallete2,
plain: Plain,
'remote-controller-minimalistic': RemoteControllerMinimalistic,
settings: Settings,
"ufo-3": UFO3,
"user-heart": UserHeart,
"user-rounded": UserRounded,
"widget": Widget,
"wifi-router-round": WiFiRouterRound,
})