aboutsummaryrefslogtreecommitdiff
path: root/src/lib/User
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-04-20 21:52:33 -0700
committerFuwn <[email protected]>2024-04-20 21:53:03 -0700
commitdd7332b4cb8a8387a801d2b9eb9be6b724d23e78 (patch)
tree5bae7a5b411f70f8cf1a916391740dc757423909 /src/lib/User
parentfix(AiringTime): add hours to weeks and days (diff)
downloaddue.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.svelte158
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>