Compare commits

...

3 Commits

Author SHA1 Message Date
priyanshu_bharti 9ae3c8290a style: Navigation tooltip improvements and Firefox fix
- Refactor PrimaryNavItem and SecondaryNavItem to use 'cx' utility.
- Add tooltip support to SecondaryNavItem and SpaceMenu room items.
- Remove hardcoded tooltip colors from app.css.
- Fix Firefox PrimaryNav tooltip visibility by increasing z-index and adding isolation: isolate.
2026-04-04 23:45:53 +05:30
priyanshu_bharti 503c2bbd40 feat: robust navigation tooltips for Firefox/Zen compatibility (#129) 2026-04-04 23:43:59 +05:30
priyanshu_bharti 41fb6f95b2 feat: show space name on hover in primary nav (#129) 2026-04-04 23:43:59 +05:30
7 changed files with 59 additions and 52 deletions
+4 -9
View File
@@ -32,18 +32,14 @@
</script> </script>
<div <div
class="ml-sai mt-sai mb-sai relative z-nav hidden w-14 flex-shrink-0 bg-base-200 pt-2 md:block"> class="ml-sai mt-sai mb-sai relative z-popover isolate hidden w-14 flex-shrink-0 bg-base-200 pt-2 md:block">
<div class="flex h-full flex-col" class:justify-between={PLATFORM_RELAYS.length === 0}> <div class="flex h-full flex-col" class:justify-between={PLATFORM_RELAYS.length === 0}>
<PrimaryNavSpaces /> <PrimaryNavSpaces />
{#if PLATFORM_RELAYS.length > 0} {#if PLATFORM_RELAYS.length > 0}
<Divider /> <Divider />
{/if} {/if}
<div> <div class="flex flex-col">
<PrimaryNavItem <PrimaryNavItem title="Settings" href="/settings/profile" prefix="/settings">
title="Settings"
href="/settings/profile"
prefix="/settings"
class="tooltip-right">
{#if $userProfile?.picture} {#if $userProfile?.picture}
<ImageIcon alt="Settings" src={$userProfile?.picture} class="rounded-full" size={10} /> <ImageIcon alt="Settings" src={$userProfile?.picture} class="rounded-full" size={10} />
{:else} {:else}
@@ -53,11 +49,10 @@
<PrimaryNavItem <PrimaryNavItem
title="Messages" title="Messages"
onclick={chatHandler} onclick={chatHandler}
class="tooltip-right"
notification={$notifications.has("/chat")}> notification={$notifications.has("/chat")}>
<ImageIcon alt="Messages" src={Letter} size={8} /> <ImageIcon alt="Messages" src={Letter} size={8} />
</PrimaryNavItem> </PrimaryNavItem>
<PrimaryNavItem title="Search" href="/people" class="tooltip-right"> <PrimaryNavItem title="Search" href="/people">
<ImageIcon alt="Search" src={Magnifier} size={8} /> <ImageIcon alt="Search" src={Magnifier} size={8} />
</PrimaryNavItem> </PrimaryNavItem>
</div> </div>
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {displayRelayUrl} from "@welshman/util" import {deriveRelayDisplay} from "@welshman/app"
import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte" import PrimaryNavItem from "@lib/components/PrimaryNavItem.svelte"
import RelayIcon from "@app/components/RelayIcon.svelte" import RelayIcon from "@app/components/RelayIcon.svelte"
import {makeSpacePath, goToSpace} from "@app/util/routes" import {makeSpacePath, goToSpace} from "@app/util/routes"
@@ -12,11 +12,13 @@
const {url}: Props = $props() const {url}: Props = $props()
const onClick = () => goToSpace(url) const onClick = () => goToSpace(url)
const display = $derived(deriveRelayDisplay(url))
</script> </script>
<PrimaryNavItem <PrimaryNavItem
onclick={onClick} onclick={onClick}
title={displayRelayUrl(url)} title={$display}
class="tooltip-right" class="tooltip-right"
notification={$notifications.has(makeSpacePath(url))}> notification={$notifications.has(makeSpacePath(url))}>
<RelayIcon {url} size={10} class="rounded-full" /> <RelayIcon {url} size={10} class="rounded-full" />
+1 -2
View File
@@ -23,7 +23,7 @@
{#each PLATFORM_RELAYS as url (url)} {#each PLATFORM_RELAYS as url (url)}
<PrimaryNavItemSpace {url} /> <PrimaryNavItemSpace {url} />
{:else} {:else}
<PrimaryNavItem title="Home" href="/home" class="tooltip-right"> <PrimaryNavItem title="Home" href="/home">
<ImageIcon alt="Home" src={PLATFORM_LOGO} class="rounded-full" size={10} /> <ImageIcon alt="Home" src={PLATFORM_LOGO} class="rounded-full" size={10} />
</PrimaryNavItem> </PrimaryNavItem>
<Divider /> <Divider />
@@ -33,7 +33,6 @@
<PrimaryNavItem <PrimaryNavItem
href="/spaces" href="/spaces"
title="All Spaces" title="All Spaces"
class="tooltip-right"
prefix="no-highlight" prefix="no-highlight"
notification={otherSpaceNotifications}> notification={otherSpaceNotifications}>
<ImageIcon alt="All Spaces" src={Widget} size={8} /> <ImageIcon alt="All Spaces" src={Widget} size={8} />
+5 -2
View File
@@ -2,7 +2,7 @@
import {derived} from "svelte/store" import {derived} from "svelte/store"
import {displayRelayUrl, EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED} from "@welshman/util" import {displayRelayUrl, EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED} from "@welshman/util"
import {Poll} from "nostr-tools/kinds" import {Poll} from "nostr-tools/kinds"
import {deriveRelay, createSearch, pubkey} from "@welshman/app" import {deriveRelay, deriveRelayDisplay, createSearch, pubkey} from "@welshman/app"
import {fly} from "@lib/transition" import {fly} from "@lib/transition"
import Magnifier from "@assets/icons/magnifier.svg?dataurl" import Magnifier from "@assets/icons/magnifier.svg?dataurl"
import AltArrowDown from "@assets/icons/alt-arrow-down.svg?dataurl" import AltArrowDown from "@assets/icons/alt-arrow-down.svg?dataurl"
@@ -66,6 +66,7 @@
const {url} = $props() const {url} = $props()
const relay = deriveRelay(url) const relay = deriveRelay(url)
const display = deriveRelayDisplay(url)
const chatPath = makeSpacePath(url, "chat") const chatPath = makeSpacePath(url, "chat")
const goalsPath = makeSpacePath(url, "goals") const goalsPath = makeSpacePath(url, "goals")
const threadsPath = makeSpacePath(url, "threads") const threadsPath = makeSpacePath(url, "threads")
@@ -144,7 +145,9 @@
class="relative flex w-full flex-col rounded-xl p-3 transition-all hover:bg-base-100" class="relative flex w-full flex-col rounded-xl p-3 transition-all hover:bg-base-100"
onclick={openMenu}> onclick={openMenu}>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<strong class="flex items-center gap-1 relative"> <strong
class="flex items-center gap-1 relative tooltip tooltip-right"
data-tip={$display}>
<RelayName {url} class="ellipsize" /> <RelayName {url} class="ellipsize" />
<div <div
class="absolute -right-3 top-0 h-2 w-2 rounded-full bg-primary transition-all opacity-0" class="absolute -right-3 top-0 h-2 w-2 rounded-full bg-primary transition-all opacity-0"
+2 -1
View File
@@ -24,12 +24,13 @@
const shouldNotifyForRoom = deriveShouldNotify(url, h) const shouldNotifyForRoom = deriveShouldNotify(url, h)
const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace) const showDifferenceIcon = $derived($shouldNotifyForRoom !== $shouldNotifyForSpace)
const notification = $derived($shouldNotifyForRoom ? $notifications.has(path) : false) const notification = $derived($shouldNotifyForRoom ? $notifications.has(path) : false)
const roomName = $derived($room?.name || h)
</script> </script>
{#if roomType === RoomType.Voice} {#if roomType === RoomType.Voice}
<VoiceRoomItem {url} {h} {replaceState} {notification} /> <VoiceRoomItem {url} {h} {replaceState} {notification} />
{:else} {:else}
<SecondaryNavItem href={path} {replaceState} {notification}> <SecondaryNavItem href={path} title={roomName} {replaceState} {notification}>
<RoomNameWithImage {url} {h} /> <RoomNameWithImage {url} {h} />
{#if showDifferenceIcon} {#if showDifferenceIcon}
<Icon icon={$shouldNotifyForRoom ? Bell : BellOff} size={4} class="opacity-50" /> <Icon icon={$shouldNotifyForRoom ? Bell : BellOff} size={4} class="opacity-50" />
+23 -19
View File
@@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
import cx from "classnames"
import {page} from "$app/stores" import {page} from "$app/stores"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
@@ -13,32 +14,35 @@
} = $props() } = $props()
const active = $derived($page.url?.pathname?.startsWith(prefix || href || "bogus")) const active = $derived($page.url?.pathname?.startsWith(prefix || href || "bogus"))
const wrapperClass = $derived(
cx("relative h-14 w-14 p-1", {
"tooltip tooltip-right": title,
}),
)
const innerClass = $derived(
cx(
"flex h-full w-full cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-base-300",
restProps.class,
),
)
</script> </script>
{#if onclick} <div class={wrapperClass} data-tip={title}>
<Button {onclick} class="relative z-nav-item flex h-14 w-14 items-center justify-center p-1"> {#if onclick}
<div <Button {onclick} class={innerClass}>
class="aspect-square flex-grow cursor-pointer rounded-full {restProps.class} flex items-center justify-center transition-colors hover:bg-base-300"
class:bg-base-300={active}
class:tooltip={title}
data-tip={title}>
{@render children?.()} {@render children?.()}
{#if !active && notification} {#if !active && notification}
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary"></div> <div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary"></div>
{/if} {/if}
</div> </Button>
</Button> {:else}
{:else} <a {href} class={innerClass}>
<a {href} class="relative z-nav-item flex h-14 w-14 items-center justify-center p-1">
<div
class="aspect-square flex-grow cursor-pointer rounded-full {restProps.class} flex items-center justify-center transition-colors hover:bg-base-300"
class:bg-base-300={active}
class:tooltip={title}
data-tip={title}>
{@render children?.()} {@render children?.()}
{#if !active && notification} {#if !active && notification}
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary"></div> <div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary"></div>
{/if} {/if}
</div> </a>
</a> {/if}
{/if} </div>
+20 -17
View File
@@ -21,37 +21,40 @@
</style> </style>
<script lang="ts"> <script lang="ts">
import cx from "classnames"
import {fade} from "@lib/transition" import {fade} from "@lib/transition"
import {page} from "$app/stores" import {page} from "$app/stores"
const {children, href = "", notification = false, replaceState = false, ...restProps} = $props() const {
children,
href = "",
title = "",
notification = false,
replaceState = false,
...restProps
} = $props()
const active = $derived($page.url.pathname === href) const active = $derived($page.url.pathname === href)
const wrapperClass = $derived(
cx(restProps.class, "relative flex flex-shrink-0 items-center gap-3 text-left transition-all", {
"hover:bg-base-100 hover:text-base-content": true,
"text-base-content bg-base-100": active,
"tooltip tooltip-right": title,
}),
)
</script> </script>
{#if href} {#if href}
<a <a {href} {...restProps} data-tip={title} data-sveltekit-replacestate={replaceState} class={wrapperClass}>
{href}
{...restProps}
data-sveltekit-replacestate={replaceState}
class="{restProps.class} relative flex flex-shrink-0 items-center gap-3 text-left transition-all hover:bg-base-100 hover:text-base-content"
class:text-base-content={active}
class:bg-base-100={active}>
{@render children?.()} {@render children?.()}
{#if notification} {#if notification}
<div class="absolute right-[1.15rem] top-5 h-2 w-2 rounded-full bg-primary" transition:fade> <div class="absolute right-[1.15rem] top-5 h-2 w-2 rounded-full bg-primary" transition:fade></div>
</div>
{/if} {/if}
</a> </a>
{:else} {:else}
<button <button {...restProps} data-tip={title} class={wrapperClass}>
{...restProps}
class="{restProps.class} relative flex flex-shrink-0 w-full items-center gap-3 text-left transition-all hover:bg-base-100 hover:text-base-content"
class:text-base-content={active}
class:bg-base-100={active}>
{#if notification} {#if notification}
<div class="absolute right-[1.15rem] top-5 h-2 w-2 rounded-full bg-primary" transition:fade> <div class="absolute right-[1.15rem] top-5 h-2 w-2 rounded-full bg-primary" transition:fade></div>
</div>
{/if} {/if}
{@render children?.()} {@render children?.()}
</button> </button>