Add tooltip support with bits-ui

This commit is contained in:
Justin Edmund 2025-09-15 04:03:19 -07:00
parent a0075ae494
commit 7cb055a79f
5 changed files with 119 additions and 25 deletions

View file

@ -1,6 +1,11 @@
// Import themes
@use 'themes/themes';
@use 'themes/spacing';
@use 'themes/tooltip';
:root {
--main-max-width: 820px; // Default max-width for main content
}
html {
background-color: var(--background);
@ -28,10 +33,11 @@ ul {
}
main {
max-width: 820px;
max-width: var(--main-max-width);
margin: 0 auto;
padding: 0 spacing.$unit-2x;
width: 100%;
transition: max-width 0.3s ease;
// Responsive padding for smaller screens
@media (max-width: 768px) {

View file

@ -1,15 +1,16 @@
<script lang="ts">
import type { PartyView } from '$lib/api/schemas/party'
import type { Party } from '$lib/types/api/party'
import WeaponRep from '$lib/components/reps/WeaponRep.svelte'
import SummonRep from '$lib/components/reps/SummonRep.svelte'
import CharacterRep from '$lib/components/reps/CharacterRep.svelte'
import Icon from '$lib/components/Icon.svelte'
import Tooltip from '$lib/components/ui/Tooltip.svelte'
export let party: PartyView
export let party: Party
export let href: string = `/teams/${party.shortcode}`
export let loading = false
let currentView: 'weapons' | 'summons' | 'characters' = 'summons'
let currentView: 'weapons' | 'summons' | 'characters' = 'weapons'
function displayName(input: any): string {
if (!input) return '—'
@ -24,7 +25,7 @@
class={`gridRep ${loading ? 'hidden' : 'visible'}`}
role="link"
tabindex="0"
on:mouseleave={() => (currentView = 'summons')}
on:mouseleave={() => (currentView = 'weapons')}
>
<a {href} data-sveltekit-preload-data="hover">
<div class="info">
@ -36,19 +37,31 @@
<div class="pills">
{#if party.chargeAttack}
<span class="pill chargeAttack" title="Charge Attack">
<Icon name="charge-attack" size={16} />
</span>
<Tooltip content="Charge Attack">
{#snippet children()}
<span class="pill chargeAttack">
<Icon name="charge-attack" size={16} />
</span>
{/snippet}
</Tooltip>
{/if}
{#if party.fullAuto}
<span class="pill fullAuto" title="Full Auto">
<Icon name="full-auto" size={16} />
</span>
<Tooltip content="Full Auto">
{#snippet children()}
<span class="pill fullAuto">
<Icon name="full-auto" size={16} />
</span>
{/snippet}
</Tooltip>
{/if}
{#if party.raid?.group?.extra}
<span class="pill extra" title="Extra">
<Icon name="extra-grid" size={16} />
</span>
<Tooltip content="Extra">
{#snippet children()}
<span class="pill extra">
<Icon name="extra-grid" size={16} />
</span>
{/snippet}
</Tooltip>
{/if}
</div>
</div>
@ -121,7 +134,7 @@
&:hover {
background: var(--grid-rep-hover);
border-color: rgba(0, 0, 0, 0.1);
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
}
&:hover .indicators {
@ -227,7 +240,6 @@
li {
flex-grow: 1;
padding: $unit 0;
position: relative;
&:hover .indicator,

View file

@ -0,0 +1,59 @@
<script lang="ts">
import { Tooltip as TooltipBase } from 'bits-ui'
import type { Snippet } from 'svelte'
interface TooltipProps {
content: string
children: Snippet
delayDuration?: number
disableCloseOnTriggerClick?: boolean
disabled?: boolean
disableHoverableContent?: boolean
}
const {
content,
children,
delayDuration = 200,
disableCloseOnTriggerClick = false,
disabled = false,
disableHoverableContent = false
}: TooltipProps = $props()
</script>
<TooltipBase.Root
{delayDuration}
{disableCloseOnTriggerClick}
{disabled}
{disableHoverableContent}
>
<TooltipBase.Trigger>
{#snippet child({ props })}
<span {...props}>
{@render children()}
</span>
{/snippet}
</TooltipBase.Trigger>
<TooltipBase.Content class="tooltip-content" sideOffset={8}>
{content}
</TooltipBase.Content>
</TooltipBase.Root>
<style lang="scss">
@use '$src/themes/layout';
@use '$src/themes/typography';
@use '$src/themes/spacing';
:global(.tooltip-content) {
background: var(--tooltip-bg, #2a2a2a);
color: var(--tooltip-text, white);
padding: spacing.$unit-half spacing.$unit;
border-radius: layout.$item-corner-small;
font-size: typography.$font-small;
font-weight: typography.$medium;
z-index: 1000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
max-width: 250px;
line-height: 1.4;
}
</style>

View file

@ -4,14 +4,12 @@
import '$src/app.scss'
import Navigation from '$lib/components/Navigation.svelte'
import { Tooltip } from 'bits-ui'
// Get `data` and `children` from the router via $props()
// Use a more flexible type that allows additional properties from child pages
const { data, children } = $props<{
data: {
isAuthenticated: boolean
account: { username: string; userId: string; role: number } | null
currentUser: unknown | null
}
data: any // Allow any data to pass through from child pages
children: () => any
}>()
</script>
@ -20,7 +18,9 @@
<link rel="icon" href={favicon} />
</svelte:head>
<main>
<Navigation isAuthenticated={data?.isAuthenticated} username={data?.account?.username} />
{@render children?.()}
</main>
<Tooltip.Provider>
<main>
<Navigation isAuthenticated={data?.isAuthenticated} username={data?.account?.username} />
{@render children?.()}
</main>
</Tooltip.Provider>

17
src/themes/_tooltip.scss Normal file
View file

@ -0,0 +1,17 @@
@use 'layout';
@use 'typography';
@use 'spacing';
// Global tooltip styles for bits-ui
[data-tooltip-content] {
background: var(--tooltip-bg, #2a2a2a);
color: var(--tooltip-text, white);
padding: spacing.$unit-half spacing.$unit;
border-radius: layout.$item-corner-small;
font-size: typography.$font-small;
font-weight: typography.$medium;
z-index: 1000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
max-width: 250px;
line-height: 1.4;
}