Skip to content

Commit

Permalink
feat(item): add dialog for item details
Browse files Browse the repository at this point in the history
  • Loading branch information
DarthGigi committed Jan 7, 2025
1 parent 638e6cf commit ef78f51
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 71 deletions.
88 changes: 85 additions & 3 deletions src/lib/components/Item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import { getRarityClass, removeFormatting, renderLore } from "$lib/shared/helper";
import { cn, flyAndScale } from "$lib/shared/utils";
import type { ProcessedSkyBlockItem, ProcessedSkyblockPet } from "$lib/types/global";
import { Avatar, Button, Tooltip } from "bits-ui";
import { Avatar, Button, Dialog, Tooltip } from "bits-ui";
import Image from "lucide-svelte/icons/image";
import { getContext } from "svelte";
import { writable } from "svelte/store";
import { fade } from "svelte/transition";
import { Drawer } from "vaul-svelte";
type Props = {
Expand All @@ -31,8 +33,18 @@
const shine = $derived(enchanted || skyblockItem.shiny);
const packData = $derived(packConfigs.find((pack) => pack.id === skyblockItem.texture_pack));
const showNumbers = $derived(showCount && (skyblockItem.Count ?? 0) > 1);
const showDialog = writable<boolean>(false);
const showDialogDelayed = writable<boolean>(false);
const isHover = getContext<IsHover>("isHover");
showDialog.subscribe((value) => {
setTimeout(() => showDialogDelayed.set(value), 0);
});
showDialogDelayed.subscribe((value) => {
if (!value) setTimeout(() => showDialog.set(value), 300);
});
</script>

{#snippet item()}
Expand All @@ -56,7 +68,7 @@

{#snippet tooltip()}
<Tooltip.Root group="armor" openDelay={0} closeDelay={0}>
<Tooltip.Trigger class={cn(`nice-colors-dark relative flex aspect-square items-center justify-center overflow-clip rounded-lg`, isInventory ? "p-0" : `p-2 ${bgColor}`, { shine: enchanted })}>
<Tooltip.Trigger class={cn(`nice-colors-dark relative flex aspect-square items-center justify-center overflow-clip rounded-lg`, isInventory ? "p-0" : `p-2 ${bgColor}`, { shine: enchanted })} onclick={() => showDialog.set(!$showDialog)}>
<Avatar.Root>
<Avatar.Image loading="lazy" src={$page.url.origin + piece.texture_path} alt={piece.display_name} class="data-[enchanted=true]:enchanted h-auto w-14 select-none" data-enchanted={enchanted} />
<Avatar.Fallback>
Expand All @@ -72,7 +84,7 @@
</div>
{/if}
</Tooltip.Trigger>
<Tooltip.Content class="z-50 flex max-h-[calc(96%-3rem)] w-max min-w-96 max-w-[calc(100vw-2.5rem)] select-text flex-col overflow-hidden rounded-lg bg-background-lore font-icomoon" transition={flyAndScale} transitionConfig={{ x: -8, duration: 150 }} sideOffset={8} side="right" align="center">
<Tooltip.Content class="pointer-events-none z-50 flex max-h-[calc(96%-3rem)] w-max min-w-96 max-w-[calc(100vw-2.5rem)] select-text flex-col overflow-hidden rounded-lg bg-background-lore font-icomoon" transition={flyAndScale} transitionConfig={{ x: -8, duration: 150 }} sideOffset={8} side="right" align="center">
<div class={cn(`nice-colors-dark flex flex-nowrap items-center justify-center gap-4 p-5`, bgColor)}>
<Avatar.Root>
<Avatar.Image loading="lazy" src={$page.url.origin + piece.texture_path} alt={piece.display_name} class="data-[enchanted=true]:enchanted h-auto w-8 flex-none overflow-hidden" data-enchanted={enchanted} />
Expand Down Expand Up @@ -137,6 +149,76 @@
</Tooltip.Root>
{/snippet}

{#if isHover.current && $showDialog}
<Dialog.Root bind:open={$showDialogDelayed}>
<Dialog.Portal>
<Dialog.Overlay transition={fade} transitionConfig={{ duration: 150 }} class="fixed inset-0 z-40 bg-black/80" />
<Dialog.Content class="fixed left-[50%] top-[50%] z-50 flex max-h-[calc(96%-3rem)] w-max min-w-96 max-w-[calc(100vw-2.5rem)] -translate-x-1/2 -translate-y-1/2 select-text flex-col overflow-hidden rounded-lg bg-background-lore font-icomoon" transition={flyAndScale} transitionConfig={{ x: -8, duration: 150 }}>
<div class={cn(`nice-colors-dark flex flex-nowrap items-center justify-center gap-4 p-5`, bgColor)}>
<Avatar.Root>
<Avatar.Image loading="lazy" src={$page.url.origin + piece.texture_path} alt={piece.display_name} class="data-[enchanted=true]:enchanted h-auto w-8 flex-none overflow-hidden" data-enchanted={enchanted} />
<Avatar.Fallback>
<Image class="size-8" />
</Avatar.Fallback>
</Avatar.Root>

<p class="relative flex-1 text-center text-lg font-semibold uppercase data-[multicolor=true]:rounded-full data-[multicolor=true]:bg-background-lore data-[multicolor=true]:px-2 data-[multicolor=true]:py-1 data-[multicolor=false]:text-text" data-multicolor={isMulticolor}>
{@html isMulticolor ? itemNameHtml : removeFormatting(itemNameHtml)}
</p>
</div>
<div class="mx-auto w-full max-w-md overflow-auto p-6 font-semibold leading-snug">
{#each skyblockItem.lore as lore}
{@html renderLore(lore)}
{/each}
{#if skyblockItem.containsItems && skyblockItem.containsItems.length > 0}
<div class="mt-4 border-t border-text/10 pt-4">
<div class="grid grid-cols-9 gap-1">
{#each skyblockItem.containsItems.slice(0, Math.min(skyblockItem.containsItems.length, 54)) as containedItem}
{#if containedItem.texture_path}
<div class="flex aspect-square items-center justify-center rounded bg-text/[0.04]">
<ContainedItem piece={containedItem} />
</div>
{:else}
<div class="aspect-square rounded bg-text/[0.04]"></div>
{/if}
{/each}
</div>
</div>
{/if}

{#if packData}
<div class="pt-4">
<Button.Root href={packData.link} target="_blank">
<div class="flex items-center justify-between gap-4 rounded-[0.625rem] bg-text/[0.05] p-2 transition-colors hover:bg-text/[0.08]">
<div class="flex items-center gap-2">
<Avatar.Root class="shrink-0 select-none">
<Avatar.Image src="/resourcepacks/{packData.folder}/pack.png" alt={packData.name} class="pointer-events-none aspect-square size-10 h-full select-none rounded-lg" />
<Avatar.Fallback class="flex size-10 items-center justify-center rounded-lg bg-icon/90 text-center font-semibold uppercase">
{packData.name.slice(0, 2)}
</Avatar.Fallback>
</Avatar.Root>
<div class="flex flex-col">
<div class="font-semibold text-link">
<span class="underline">
{packData.name}
</span>
<span class="text-sm text-text/60">{packData.version}</span>
</div>
<div class="text-sm text-text/60">
by <span class="text-text/80">{packData.author}</span>
</div>
</div>
</div>
</div>
</Button.Root>
</div>
{/if}
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
{/if}

{#snippet drawer()}
<Drawer.Root shouldScaleBackground={true} setBackgroundColorOnScale={false}>
<Drawer.Trigger class="nice-colors-dark">
Expand Down
51 changes: 13 additions & 38 deletions src/lib/components/Wardrobe.svelte
Original file line number Diff line number Diff line change
@@ -1,46 +1,21 @@
<script lang="ts">
import Item from "$lib/components/Item.svelte";
import type { IsHover } from "$lib/hooks/is-hover.svelte";
import type { ProcessedSkyBlockItem } from "$types/stats";
import { Avatar, Collapsible } from "bits-ui";
import { getContext } from "svelte";
import { writable } from "svelte/store";
import { slide } from "svelte/transition";
import { Avatar } from "bits-ui";
export let wardrobeItems: ProcessedSkyBlockItem[];
let { wardrobeItems }: { wardrobeItems: ProcessedSkyBlockItem[] } = $props();
const highestItem = wardrobeItems.find((piece) => piece && piece.display_name);
const pieces = ["helmet", "chestplate", "leggings", "boots"];
const isHover = getContext<IsHover>("isHover");
const expanded = writable<boolean>(false);
if (!isHover.current) {
expanded.set(true);
}
</script>

<Collapsible.Root bind:open={$expanded} disabled={!isHover.current}>
<Collapsible.Trigger asChild let:builder>
<div use:builder.action {...builder} class="mt-2 flex flex-col gap-2">
{#if !$expanded}
{#if highestItem}
<Item piece={highestItem} />
{/if}
{:else}
<Collapsible.Content transition={slide} class="flex flex-col gap-2">
{#each wardrobeItems as piece, index}
{#if piece && piece.display_name}
<Item {piece} />
{:else}
<Avatar.Root class="rounded-lg bg-background-lore p-2">
<Avatar.Image class="size-14" loading="eager" src={`/img/textures/item/empty_armor_slot_${pieces[index]}.png`} />
</Avatar.Root>
{/if}
{/each}
</Collapsible.Content>
{/if}
</div>
</Collapsible.Trigger>
</Collapsible.Root>
<div class="mt-2 flex flex-col gap-2">
{#each wardrobeItems as piece, index}
{#if piece && piece.display_name}
<Item {piece} />
{:else}
<Avatar.Root class="rounded-lg bg-background-lore p-2">
<Avatar.Image class="size-14" loading="eager" src={`/img/textures/item/empty_armor_slot_${pieces[index]}.png`} />
</Avatar.Root>
{/if}
{/each}
</div>
50 changes: 20 additions & 30 deletions src/lib/sections/stats/Armor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@
import Bonus from "$lib/components/Bonus.svelte";
import Item from "$lib/components/Item.svelte";
import Wardrobe from "$lib/components/Wardrobe.svelte";
import type { IsHover } from "$lib/hooks/is-hover.svelte";
import Items from "$lib/layouts/stats/Items.svelte";
import { getRarityClass } from "$lib/shared/helper";
import { cn } from "$lib/shared/utils";
import { ScrollArea } from "bits-ui";
import { getContext } from "svelte";
const ctx = getProfileCtx();
const profile = $derived(ctx.profile);
const isHover = getContext<IsHover>("isHover");
const armor = $derived(profile.items.armor);
const equipment = $derived(profile.items.equipment);
const wardrobe = $derived(profile.items.wardrobe);
Expand Down Expand Up @@ -59,31 +55,25 @@

{#if wardrobe.length > 0}
<Items subtitle="Wardrobe">
{#if !isHover.current}
<div class="max-w-full">
<!-- min height was calc by: each piece of armor was 72px with a 8px gap and scrollbar was 2.5px and some more for gap for scrollbar -->
<ScrollArea.Root class="relative min-h-[335px]">
<ScrollArea.Viewport>
<ScrollArea.Content>
<div class="flex flex-row gap-5">
{#each firstWardrobeItems as _, i}
<div class="!min-h-[72px] !min-w-[72px]">
<Wardrobe wardrobeItems={wardrobe[i]} />
</div>
{/each}
</div>
</ScrollArea.Content>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="horizontal" class="mt-2 flex h-2.5 w-full touch-none select-none rounded-full transition-all">
<ScrollArea.Thumb class="flex rounded-full bg-icon" />
</ScrollArea.Scrollbar>
<ScrollArea.Corner />
</ScrollArea.Root>
</div>
{:else}
{#each firstWardrobeItems as _, i}
<Wardrobe wardrobeItems={wardrobe[i]} />
{/each}
{/if}
<div class="max-w-full">
<!-- min height was calc by: each piece of armor was 72px with a 8px gap and scrollbar was 2.5px and some more for gap for scrollbar -->
<ScrollArea.Root class="relative min-h-[335px]" type="auto">
<ScrollArea.Viewport>
<ScrollArea.Content>
<div class="flex flex-row gap-6 md:gap-3">
{#each firstWardrobeItems as _, i}
<div class="min-h-[4.5rem] min-w-[4.5rem]">
<Wardrobe wardrobeItems={wardrobe[i]} />
</div>
{/each}
</div>
</ScrollArea.Content>
</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="horizontal" class="mt-2 flex h-2.5 w-full touch-none select-none rounded-full transition-all">
<ScrollArea.Thumb class="flex rounded-full bg-icon" />
</ScrollArea.Scrollbar>
<ScrollArea.Corner />
</ScrollArea.Root>
</div>
</Items>
{/if}

0 comments on commit ef78f51

Please sign in to comment.