diff options
| author | Fuwn <[email protected]> | 2024-04-21 19:51:49 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-04-21 19:51:49 -0700 |
| commit | eebeaa378d49cc8adb597d00fd05bcc314779888 (patch) | |
| tree | d2862e4f952525280a341e44810c261548a07a3f /src/lib/User | |
| parent | refactor(TextTransition): move to Layout (diff) | |
| download | due.moe-eebeaa378d49cc8adb597d00fd05bcc314779888.tar.xz due.moe-eebeaa378d49cc8adb597d00fd05bcc314779888.zip | |
refactor(lib): move componenets to modules
Diffstat (limited to 'src/lib/User')
| -rw-r--r-- | src/lib/User/BadgeWall/FallbackBadge.svelte | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/lib/User/BadgeWall/FallbackBadge.svelte b/src/lib/User/BadgeWall/FallbackBadge.svelte new file mode 100644 index 00000000..f6eee93f --- /dev/null +++ b/src/lib/User/BadgeWall/FallbackBadge.svelte @@ -0,0 +1,120 @@ +<script lang="ts"> + import locale from '$stores/locale'; + import { tweened } from 'svelte/motion'; + import type { Badge } from '../../Database/userBadges'; + import Tooltip from '../../Tooltip/LinkedTooltip.svelte'; + import { databaseTimeToDate } from '../../Utility/time'; + import { cubicOut } from 'svelte/easing'; + import { dev } from '$app/environment'; + + export let source: string | null | undefined; + export let alternative: string | null | undefined; + export let fallback: string | null | undefined; + export let maxReplaceCount = 1; + export let replaceDelay = 1000; + export let error = 'https://i2.kym-cdn.com/photos/images/newsfeed/000/290/992/0aa.jpg'; + export let hideOnError = false; + export let badge: Badge; + export let style = ''; + export let selectedBadge: Badge | null = null; + + let replaceCount = 0; + let badgeReference: HTMLImageElement; + const mouse = tweened( + { x: 0, y: 0 }, + { + duration: 75, + easing: cubicOut + } + ); + + const delayedReplace = (event: Event, image: string | undefined | null) => { + if (replaceCount >= maxReplaceCount) return; + + setTimeout(() => { + (event.target as HTMLImageElement).src = image || ''; + + replaceCount += 1; + }, replaceDelay); + }; + + const handleMouseMove = (event: MouseEvent) => { + const boundingRectangle = badgeReference.getBoundingClientRect(); + const factor = 1.25; + const limit = 50; + + if ($mouse.x === 0 && $mouse.y === 0) $mouse = { x: event.clientX, y: event.clientY }; + + $mouse.x += + (-(event.clientX - boundingRectangle.left - boundingRectangle.width / 2) - $mouse.x) * factor; + $mouse.y += + (-(event.clientY - boundingRectangle.top - boundingRectangle.height / 2) - $mouse.y) * factor; + $mouse.x = Math.max(Math.min($mouse.x, limit), -limit); + $mouse.y = Math.max(Math.min($mouse.y, limit), -limit); + }; + + const handleMouseLeave = () => { + $mouse = { x: 0, y: 0 }; + }; +</script> + +{#if replaceCount < maxReplaceCount} + <Tooltip + content={`${dev ? `${badge.id}\n` : ''}${ + badge.time ? $locale().dateFormatter(databaseTimeToDate(badge.time)) : '' + }${badge.description ? `\n${badge.description}` : ''}${ + badge.designer ? `\nDesigner: ${badge.designer}` : '' + }${badge.source ? `\nSource: ${badge.source}` : ''}`} + id={`badge-${badge.id}`} + pin={`badge-${badge.id}`} + pinPosition="top" + relative + > + <a + href={'#'} + target="_blank" + class="badge-container badge" + on:mousemove={handleMouseMove} + on:mouseleave={handleMouseLeave} + on:click={(e) => { + e.preventDefault(); + + selectedBadge = badge; + }} + > + <img + src={source} + alt={alternative} + loading="lazy" + class="badge" + bind:this={badgeReference} + style="transform: perspective(1000px) rotateX({$mouse.y / 10}deg) rotateY({-$mouse.x / + 10}deg); ${style}" + on:error={(e) => delayedReplace(e, fallback)} + /> + </a> + </Tooltip> +{:else if !hideOnError} + <img src={error} alt="Not found" loading="lazy" class="badge" /> +{/if} + +<style lang="scss"> + $transition: transform 0.325s ease; + + .badge { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + transition: $transition; + box-sizing: border-box; + border-radius: 8px; + } + + .badge:hover { + transform: scale(1.075); + position: relative; + z-index: 2; + transition: $transition; + } +</style> |