diff options
| author | Fuwn <[email protected]> | 2024-04-20 21:52:33 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-04-20 21:53:03 -0700 |
| commit | dd7332b4cb8a8387a801d2b9eb9be6b724d23e78 (patch) | |
| tree | 5bae7a5b411f70f8cf1a916391740dc757423909 /src/lib/User | |
| parent | fix(AiringTime): add hours to weeks and days (diff) | |
| download | due.moe-dd7332b4cb8a8387a801d2b9eb9be6b724d23e78.tar.xz due.moe-dd7332b4cb8a8387a801d2b9eb9be6b724d23e78.zip | |
feat(User): move BadgeWall to User module
Diffstat (limited to 'src/lib/User')
| -rw-r--r-- | src/lib/User/BadgeWall/BadgePreview.svelte | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/lib/User/BadgeWall/BadgePreview.svelte b/src/lib/User/BadgeWall/BadgePreview.svelte new file mode 100644 index 00000000..97ff46ec --- /dev/null +++ b/src/lib/User/BadgeWall/BadgePreview.svelte @@ -0,0 +1,158 @@ +<script lang="ts"> + import { thumbnail } from '$lib/Utility/image.js'; + import type { Badge } from '$lib/Database/userBadges'; + import { cdn } from '$lib/Utility/image'; + import { databaseTimeToDate } from '$lib/Utility/time'; + import locale from '$stores/locale'; + import { onMount } from 'svelte'; + import { cubicOut } from 'svelte/easing'; + import { tweened } from 'svelte/motion'; + + export let selectedBadge: Badge | undefined; + + let badgeReference: HTMLImageElement; + const mouse = tweened( + { x: 0, y: 0 }, + { + duration: 300 * 1.75, + easing: cubicOut + } + ); + + const handleMouseMove = (event: MouseEvent) => { + const boundingRectangle = badgeReference.getBoundingClientRect(); + const factor = 1.25; + const limit = 300 * 1.75; + + 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 }; + }; + + onMount(() => { + if (selectedBadge && selectedBadge.image) { + const image = new Image(); + + image.src = cdn(selectedBadge.image) || ''; + image.onload = () => { + badgeReference.src = image.src; + }; + } + }); +</script> + +{#if selectedBadge} + <div class="badge-preview"> + {#if selectedBadge.image} + <div + on:mousemove={handleMouseMove} + on:mouseleave={handleMouseLeave} + role="img" + class="badge-container" + > + <img + src={cdn(thumbnail(selectedBadge.image))} + bind:this={badgeReference} + style="transform: perspective(1000px) rotateX({$mouse.y / 10}deg) rotateY({-$mouse.x / + 10}deg);" + alt={selectedBadge.description} + /> + </div> + + <p /> + {/if} + + {#if selectedBadge.time} + {$locale().dateFormatter(databaseTimeToDate(selectedBadge.time))} + + {#if (selectedBadge.designer || selectedBadge.source || selectedBadge.post) && !selectedBadge.description} + <p /> + {:else if selectedBadge.description} + <br /> + {/if} + {/if} + + {#if selectedBadge.description} + {selectedBadge.description} + + {#if selectedBadge.designer || selectedBadge.source || selectedBadge.post} + <p /> + {/if} + {/if} + + {#if selectedBadge.designer} + <b>Designer:</b> + + {#if selectedBadge.designer.startsWith('http')} + <a href={selectedBadge.designer} target="_blank"> + {selectedBadge.designer} + </a> + {:else if selectedBadge.designer.startsWith('@')} + <a href="https://anilist.co/user/{selectedBadge.designer.replace('@', '')}" target="_blank"> + {selectedBadge.designer} + </a> + {:else} + {selectedBadge.designer} + {/if} + + <br /> + {/if} + + {#if selectedBadge.post && selectedBadge.post !== '#'} + <b>{selectedBadge.post.includes('forum') ? 'Forum' : 'Activity'}:</b> + + <a href={selectedBadge.post} target="_blank"> + {selectedBadge.post} + </a> + + <br /> + {/if} + + {#if selectedBadge.source} + <b>Source:</b> + + {#if selectedBadge.source.startsWith('http')} + <a href={selectedBadge.source} target="_blank"> + {selectedBadge.source} + </a> + {:else} + {selectedBadge.source} + {/if} + + <br /> + {/if} + + {#if selectedBadge.category} + <b>Category:</b> + + <a href={`?category=${selectedBadge.category}`} on:click={() => (selectedBadge = undefined)}> + {selectedBadge.category} + </a> + + <br /> + {/if} + </div> +{/if} + +<style> + .badge-preview img { + border-radius: 8px; + max-width: 25vh; + width: 100%; + } + + .badge-container { + display: flex; + justify-content: center; + align-items: center; + } +</style> |