aboutsummaryrefslogtreecommitdiff
path: root/src/lib/User
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-10-09 00:41:20 -0700
committerFuwn <[email protected]>2024-10-09 00:41:43 -0700
commit998b63a35256ac985a5a2714dd1ca451af4dfd8a (patch)
tree50796121a9d5ab0330fdc5d7e098bda2860d9726 /src/lib/User
parentfeat(graphql): add badgeCount field (diff)
downloaddue.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.tar.xz
due.moe-998b63a35256ac985a5a2714dd1ca451af4dfd8a.zip
chore(prettier): use spaces instead of tabs
Diffstat (limited to 'src/lib/User')
-rw-r--r--src/lib/User/BadgeWall/AWC.svelte166
-rw-r--r--src/lib/User/BadgeWall/BadgePreview.svelte438
-rw-r--r--src/lib/User/BadgeWall/Badges.svelte166
-rw-r--r--src/lib/User/BadgeWall/FallbackBadge.svelte216
-rw-r--r--src/lib/User/BadgeWall/badge.ts2
-rw-r--r--src/lib/User/BadgeWall/badges.css8
6 files changed, 498 insertions, 498 deletions
diff --git a/src/lib/User/BadgeWall/AWC.svelte b/src/lib/User/BadgeWall/AWC.svelte
index ba8a22ea..1cf82a1b 100644
--- a/src/lib/User/BadgeWall/AWC.svelte
+++ b/src/lib/User/BadgeWall/AWC.svelte
@@ -1,100 +1,100 @@
<script lang="ts">
- import type { AWCBadgesGroup } from '$lib/Data/awc';
- import { cdn, thumbnail } from '$lib/Utility/image';
- import type { Preferences } from '../../../graphql/$types';
- import FallbackBadge from './FallbackBadge.svelte';
- import './badges.css';
+ import type { AWCBadgesGroup } from '$lib/Data/awc';
+ import { cdn, thumbnail } from '$lib/Utility/image';
+ import type { Preferences } from '../../../graphql/$types';
+ import FallbackBadge from './FallbackBadge.svelte';
+ import './badges.css';
- export let awcPromise: Promise<Response>;
- export let categoryFilter: string | null;
- export let isOwner: boolean;
- export let preferences: Preferences;
+ export let awcPromise: Promise<Response>;
+ export let categoryFilter: string | null;
+ export let isOwner: boolean;
+ export let preferences: Preferences;
- const awcBadgesGrouped = (awcResponse: string): AWCBadgesGroup[] => {
- return Array.from(
- new DOMParser().parseFromString(awcResponse, 'text/html').querySelectorAll('.container')
- )
- .map((c) => {
- const container = c as HTMLDivElement;
- const header = container.querySelector('.container-header') as HTMLDivElement;
+ const awcBadgesGrouped = (awcResponse: string): AWCBadgesGroup[] => {
+ return Array.from(
+ new DOMParser().parseFromString(awcResponse, 'text/html').querySelectorAll('.container')
+ )
+ .map((c) => {
+ const container = c as HTMLDivElement;
+ const header = container.querySelector('.container-header') as HTMLDivElement;
- if (!header) return;
+ if (!header) return;
- if (!['Anime', 'Manga', 'Special'].includes(header.innerText)) return;
+ if (!['Anime', 'Manga', 'Special'].includes(header.innerText)) return;
- if (header.innerText === 'Special') {
- return {
- group: header.innerText,
- badges: Array.from(container.querySelectorAll('.badge-display img')).map((b) => {
- const badge = b as HTMLImageElement;
+ if (header.innerText === 'Special') {
+ return {
+ group: header.innerText,
+ badges: Array.from(container.querySelectorAll('.badge-display img')).map((b) => {
+ const badge = b as HTMLImageElement;
- return {
- link: '#',
- description: badge.alt,
- image: badge.src.includes('placeholder')
- ? cdn('https://awc.moe/static/images/badge-placeholder.png')
- : badge.src
- };
- })
- };
- }
+ return {
+ link: '#',
+ description: badge.alt,
+ image: badge.src.includes('placeholder')
+ ? cdn('https://awc.moe/static/images/badge-placeholder.png')
+ : badge.src
+ };
+ })
+ };
+ }
- return {
- group: header.innerText,
- badges: Array.from(container.querySelectorAll('.badge-display a')).map((b) => {
- const badge = b as HTMLAnchorElement;
- const image = badge.querySelector('img') as HTMLImageElement;
+ return {
+ group: header.innerText,
+ badges: Array.from(container.querySelectorAll('.badge-display a')).map((b) => {
+ const badge = b as HTMLAnchorElement;
+ const image = badge.querySelector('img') as HTMLImageElement;
- return {
- link: badge.href,
- description: image.alt,
- image: image.src.includes('placeholder')
- ? cdn('https://awc.moe/static/images/badge-placeholder.png')
- : image.src
- };
- })
- };
- })
- .filter((b) => b !== undefined) as AWCBadgesGroup[];
- };
+ return {
+ link: badge.href,
+ description: image.alt,
+ image: image.src.includes('placeholder')
+ ? cdn('https://awc.moe/static/images/badge-placeholder.png')
+ : image.src
+ };
+ })
+ };
+ })
+ .filter((b) => b !== undefined) as AWCBadgesGroup[];
+ };
</script>
{#await awcPromise then badges}
- {#if badges}
- {#await badges.clone().text() then text}
- {@const parsedBadges = awcBadgesGrouped(text)}
+ {#if badges}
+ {#await badges.clone().text() then text}
+ {@const parsedBadges = awcBadgesGrouped(text)}
- {#if parsedBadges.length > 0}
- {#each parsedBadges as group}
- <details open={categoryFilter || isOwner ? false : true}>
- <summary>
- Anime Watching Club <span class="opaque">|</span>
- {group.group}
- </summary>
+ {#if parsedBadges.length > 0}
+ {#each parsedBadges as group}
+ <details open={categoryFilter || isOwner ? false : true}>
+ <summary>
+ Anime Watching Club <span class="opaque">|</span>
+ {group.group}
+ </summary>
- <p />
+ <p />
- <div class="badges">
- {#each group.badges as badge, index}
- <div id={`badge-${index}`}>
- <FallbackBadge
- {badge}
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
- hideOnError={preferences.hide_missing_badges}
- awc
- {index}
- {preferences}
- />
- </div>
- {/each}
- </div>
- </details>
+ <div class="badges">
+ {#each group.badges as badge, index}
+ <div id={`badge-${index}`}>
+ <FallbackBadge
+ {badge}
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ hideOnError={preferences.hide_missing_badges}
+ awc
+ {index}
+ {preferences}
+ />
+ </div>
+ {/each}
+ </div>
+ </details>
- <p />
- {/each}
- {/if}
- {/await}
- {/if}
+ <p />
+ {/each}
+ {/if}
+ {/await}
+ {/if}
{/await}
diff --git a/src/lib/User/BadgeWall/BadgePreview.svelte b/src/lib/User/BadgeWall/BadgePreview.svelte
index 107ed483..7a54cbc4 100644
--- a/src/lib/User/BadgeWall/BadgePreview.svelte
+++ b/src/lib/User/BadgeWall/BadgePreview.svelte
@@ -1,145 +1,145 @@
<script lang="ts">
- import { thumbnail } from '$lib/Utility/image';
- import type { Badge } from '$lib/Database/SB/User/badges';
- import { cdn } from '$lib/Utility/image';
- import { databaseTimeToDate } from '$lib/Utility/time';
- import locale from '$stores/locale';
- import { onMount } from 'svelte';
- import root from '$lib/Utility/root';
- import ParallaxImage from '$lib/Image/ParallaxImage.svelte';
-
- export let selectedBadge: Badge | undefined;
- export let onNext: () => void = () => {};
- export let onPrevious: () => void = () => {};
- export let hasNext: boolean;
- export let hasPrevious: boolean;
-
- let source = cdn(thumbnail(selectedBadge?.image || '')) || '';
- let badgeReference: HTMLImageElement;
-
- $: {
- if (selectedBadge && selectedBadge.image) {
- const image = new Image();
-
- image.src = cdn(selectedBadge.image) || '';
- image.onload = () => {
- source = image.src;
- };
- }
- }
-
- $: {
- if (selectedBadge)
- fetch(root(`/api/badges?incrementClickCount=${selectedBadge.id}`), {
- method: 'PUT'
- });
- }
-
- onMount(() => {
- badgeReference = document.querySelector('.badge-container-image') as HTMLImageElement;
-
- const handleClickOutside = (event: any) => {
- if (event.target.classList.contains('popup')) selectedBadge = undefined;
- };
-
- document.addEventListener('click', handleClickOutside);
-
- return () => {
- document.removeEventListener('click', handleClickOutside);
- };
- });
-
- const classifySource = (source: string) => {
- let name = source;
- const sourceLower = source.toLowerCase();
-
- if (sourceLower.includes('pixiv.net')) {
- name = 'Pixiv';
- } else if (sourceLower.includes('twitter.com') || sourceLower.includes('x.com')) {
- name = 'X (Twitter)';
- } else if (sourceLower.includes('zerochan.net')) {
- name = 'Zerochan';
- } else if (sourceLower.includes('imgur.com')) {
- name = 'Imgur';
- } else if (sourceLower.includes('lofter.com')) {
- name = 'Lofter';
- }
-
- return `<a href="${source}" target="_blank">${name}</a>`;
- };
-
- const classifyDesigner = (designer: string) => {
- let name = designer;
- let userLink = designer;
- const designerLower = designer.toLowerCase();
- const anilistUser = designer.match(/https?:\/\/anilist\.co\/user\/([^/]+)\/?/);
-
- if (anilistUser) {
- name = anilistUser[1];
- } else if (designerLower.startsWith('@')) {
- name = designer.replace('@', '');
- userLink = `https://anilist.co/user/${name}/`;
- } else if (!designerLower.startsWith('http')) {
- userLink = `https://anilist.co/user/${name}/`;
- }
-
- return `<a href="${userLink}" target="_blank">@${name}</a>`;
- };
-
- const onClick = (event: MouseEvent) => {
- event.preventDefault();
-
- if (
- event.clientX <
- badgeReference.getBoundingClientRect().left + badgeReference.getBoundingClientRect().width / 2
- ) {
- onPrevious();
- } else {
- onNext();
- }
- };
+ import { thumbnail } from '$lib/Utility/image';
+ import type { Badge } from '$lib/Database/SB/User/badges';
+ import { cdn } from '$lib/Utility/image';
+ import { databaseTimeToDate } from '$lib/Utility/time';
+ import locale from '$stores/locale';
+ import { onMount } from 'svelte';
+ import root from '$lib/Utility/root';
+ import ParallaxImage from '$lib/Image/ParallaxImage.svelte';
+
+ export let selectedBadge: Badge | undefined;
+ export let onNext: () => void = () => {};
+ export let onPrevious: () => void = () => {};
+ export let hasNext: boolean;
+ export let hasPrevious: boolean;
+
+ let source = cdn(thumbnail(selectedBadge?.image || '')) || '';
+ let badgeReference: HTMLImageElement;
+
+ $: {
+ if (selectedBadge && selectedBadge.image) {
+ const image = new Image();
+
+ image.src = cdn(selectedBadge.image) || '';
+ image.onload = () => {
+ source = image.src;
+ };
+ }
+ }
+
+ $: {
+ if (selectedBadge)
+ fetch(root(`/api/badges?incrementClickCount=${selectedBadge.id}`), {
+ method: 'PUT'
+ });
+ }
+
+ onMount(() => {
+ badgeReference = document.querySelector('.badge-container-image') as HTMLImageElement;
+
+ const handleClickOutside = (event: any) => {
+ if (event.target.classList.contains('popup')) selectedBadge = undefined;
+ };
+
+ document.addEventListener('click', handleClickOutside);
+
+ return () => {
+ document.removeEventListener('click', handleClickOutside);
+ };
+ });
+
+ const classifySource = (source: string) => {
+ let name = source;
+ const sourceLower = source.toLowerCase();
+
+ if (sourceLower.includes('pixiv.net')) {
+ name = 'Pixiv';
+ } else if (sourceLower.includes('twitter.com') || sourceLower.includes('x.com')) {
+ name = 'X (Twitter)';
+ } else if (sourceLower.includes('zerochan.net')) {
+ name = 'Zerochan';
+ } else if (sourceLower.includes('imgur.com')) {
+ name = 'Imgur';
+ } else if (sourceLower.includes('lofter.com')) {
+ name = 'Lofter';
+ }
+
+ return `<a href="${source}" target="_blank">${name}</a>`;
+ };
+
+ const classifyDesigner = (designer: string) => {
+ let name = designer;
+ let userLink = designer;
+ const designerLower = designer.toLowerCase();
+ const anilistUser = designer.match(/https?:\/\/anilist\.co\/user\/([^/]+)\/?/);
+
+ if (anilistUser) {
+ name = anilistUser[1];
+ } else if (designerLower.startsWith('@')) {
+ name = designer.replace('@', '');
+ userLink = `https://anilist.co/user/${name}/`;
+ } else if (!designerLower.startsWith('http')) {
+ userLink = `https://anilist.co/user/${name}/`;
+ }
+
+ return `<a href="${userLink}" target="_blank">@${name}</a>`;
+ };
+
+ const onClick = (event: MouseEvent) => {
+ event.preventDefault();
+
+ if (
+ event.clientX <
+ badgeReference.getBoundingClientRect().left + badgeReference.getBoundingClientRect().width / 2
+ ) {
+ onPrevious();
+ } else {
+ onNext();
+ }
+ };
</script>
{#if selectedBadge}
- <div class="badge-preview">
- <div class="badge-preview-badge">
- {#if selectedBadge.image}
- <div role="img" class="badge-container">
- <a href={'#'} on:click={onClick} class="badge-container-image">
- <ParallaxImage
- {source}
- alternativeText="selectedBadge.description"
- limit={100}
- duration={1500}
- />
- </a>
- </div>
-
- <p />
- {/if}
- </div>
-
- <div class="badge-preview-information">
- {#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}
-
- <p />
- {/if}
-
- {#if selectedBadge.designer}
- <b>Designer:</b>
-
- <!-- {#if selectedBadge.designer.startsWith('http')}
+ <div class="badge-preview">
+ <div class="badge-preview-badge">
+ {#if selectedBadge.image}
+ <div role="img" class="badge-container">
+ <a href={'#'} on:click={onClick} class="badge-container-image">
+ <ParallaxImage
+ {source}
+ alternativeText="selectedBadge.description"
+ limit={100}
+ duration={1500}
+ />
+ </a>
+ </div>
+
+ <p />
+ {/if}
+ </div>
+
+ <div class="badge-preview-information">
+ {#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}
+
+ <p />
+ {/if}
+
+ {#if selectedBadge.designer}
+ <b>Designer:</b>
+
+ <!-- {#if selectedBadge.designer.startsWith('http')}
<a href={selectedBadge.designer} target="_blank">
{selectedBadge.designer}
</a>
@@ -150,96 +150,96 @@
{:else}
{selectedBadge.designer}
{/if} -->
- {@html classifyDesigner(selectedBadge.designer)}
+ {@html classifyDesigner(selectedBadge.designer)}
- <br />
- {/if}
+ <br />
+ {/if}
- {#if selectedBadge.post && selectedBadge.post !== '#'}
- <b>{selectedBadge.post.includes('forum') ? 'Forum' : 'Activity'}:</b>
+ {#if selectedBadge.post && selectedBadge.post !== '#'}
+ <b>{selectedBadge.post.includes('forum') ? 'Forum' : 'Activity'}:</b>
- <a href={selectedBadge.post} target="_blank">
- {selectedBadge.post}
- </a>
+ <a href={selectedBadge.post} target="_blank">
+ {selectedBadge.post}
+ </a>
- <br />
- {/if}
+ <br />
+ {/if}
- {#if selectedBadge.source}
- <b>Source:</b>
+ {#if selectedBadge.source}
+ <b>Source:</b>
- {#if selectedBadge.source.startsWith('http')}
- <!-- <a href={selectedBadge.source} target="_blank">
+ {#if selectedBadge.source.startsWith('http')}
+ <!-- <a href={selectedBadge.source} target="_blank">
{selectedBadge.source}
</a> -->
- {@html classifySource(selectedBadge.source)}
- {: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}
-
- <b>SauceNAO:</b>
- <a href={`https://saucenao.com/search.php?url=${selectedBadge.image}`} target="_blank">
- Search
- </a>
-
- <div class="badge-preview-seek">
- {#if hasPrevious}
- <button on:click={onPrevious}>Previous</button>
- {/if}
-
- {#if hasNext}
- <button on:click={onNext} style="float: right;">Next</button>
- {/if}
- </div>
- </div>
- </div>
+ {@html classifySource(selectedBadge.source)}
+ {: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}
+
+ <b>SauceNAO:</b>
+ <a href={`https://saucenao.com/search.php?url=${selectedBadge.image}`} target="_blank">
+ Search
+ </a>
+
+ <div class="badge-preview-seek">
+ {#if hasPrevious}
+ <button on:click={onPrevious}>Previous</button>
+ {/if}
+
+ {#if hasNext}
+ <button on:click={onNext} style="float: right;">Next</button>
+ {/if}
+ </div>
+ </div>
+ </div>
{/if}
<style>
- :global(.badge-preview img) {
- border-radius: 8px;
- max-height: 50vh;
- height: auto;
- width: 100%;
- }
-
- .badge-container {
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .badge-preview {
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- gap: 1rem;
- }
-
- @media (max-width: 768px) {
- .badge-preview {
- flex-direction: column;
- }
- }
-
- .badge-preview-seek {
- padding-top: 2rem;
- }
+ :global(.badge-preview img) {
+ border-radius: 8px;
+ max-height: 50vh;
+ height: auto;
+ width: 100%;
+ }
+
+ .badge-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .badge-preview {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ gap: 1rem;
+ }
+
+ @media (max-width: 768px) {
+ .badge-preview {
+ flex-direction: column;
+ }
+ }
+
+ .badge-preview-seek {
+ padding-top: 2rem;
+ }
</style>
diff --git a/src/lib/User/BadgeWall/Badges.svelte b/src/lib/User/BadgeWall/Badges.svelte
index c4da3118..b233d0c3 100644
--- a/src/lib/User/BadgeWall/Badges.svelte
+++ b/src/lib/User/BadgeWall/Badges.svelte
@@ -1,98 +1,98 @@
<script lang="ts">
- import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
- import tooltip from '$lib/Tooltip/tooltip';
- import locale from '$stores/locale';
- import { databaseTimeToDate } from '$lib/Utility/time';
- import FallbackImage from '$lib/Image/FallbackImage.svelte';
- import { cdn, thumbnail } from '$lib/Utility/image';
- import FallbackBadge from './FallbackBadge.svelte';
- import type { Preferences } from '../../../graphql/$types';
- import type { IndexedBadge } from './badge';
+ import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
+ import tooltip from '$lib/Tooltip/tooltip';
+ import locale from '$stores/locale';
+ import { databaseTimeToDate } from '$lib/Utility/time';
+ import FallbackImage from '$lib/Image/FallbackImage.svelte';
+ import { cdn, thumbnail } from '$lib/Utility/image';
+ import FallbackBadge from './FallbackBadge.svelte';
+ import type { Preferences } from '../../../graphql/$types';
+ import type { IndexedBadge } from './badge';
- export let ungroupedBadges: IndexedBadge[];
- export let groupedBadges: [string, IndexedBadge[]][];
- export let categoryFilter: string | null;
- export let editMode: boolean;
- export let preferences: Preferences | undefined;
- export let selectedBadge: IndexedBadge | undefined = undefined;
+ export let ungroupedBadges: IndexedBadge[];
+ export let groupedBadges: [string, IndexedBadge[]][];
+ export let categoryFilter: string | null;
+ export let editMode: boolean;
+ export let preferences: Preferences | undefined;
+ export let selectedBadge: IndexedBadge | undefined = undefined;
</script>
{#if ungroupedBadges.length === 0}
- <div class="card">
- No due.moe registered badges found for this user. <a
- href={'#'}
- on:click={(e) => e.preventDefault()}
- title="This alert does not include AWC badges."
- use:tooltip>?</a
- >
- </div>
+ <div class="card">
+ No due.moe registered badges found for this user. <a
+ href={'#'}
+ on:click={(e) => e.preventDefault()}
+ title="This alert does not include AWC badges."
+ use:tooltip>?</a
+ >
+ </div>
{/if}
{#each groupedBadges as [category, unsortedBadges]}
- {@const badges = unsortedBadges.sort(
- (a, b) => new Date(b.time || 0).getTime() - new Date(a.time || 0).getTime()
- )}
+ {@const badges = unsortedBadges.sort(
+ (a, b) => new Date(b.time || 0).getTime() - new Date(a.time || 0).getTime()
+ )}
- <details open={categoryFilter ? categoryFilter === category : true}>
- <summary>{category}</summary>
+ <details open={categoryFilter ? categoryFilter === category : true}>
+ <summary>{category}</summary>
- <p />
+ <p />
- <div class="badges">
- {#each badges as badge}
- <div id={`badge-${badge.id}`}>
- {#if editMode}
- <LinkedTooltip
- content={`${
- badge.time ? $locale().dateFormatter(databaseTimeToDate(badge.time)) : ''
- }${badge.description ? `\n${badge.description}` : ''}${
- badge.designer ? `\nDesigner: ${badge.designer}` : ''
- }${badge.source ? `\nSource: ${badge.source}` : ''}`}
- pin={`badge-${badge.id}`}
- pinPosition="top"
- relative
- >
- <a
- href={`#`}
- on:click={() => {
- selectedBadge = badge;
+ <div class="badges">
+ {#each badges as badge}
+ <div id={`badge-${badge.id}`}>
+ {#if editMode}
+ <LinkedTooltip
+ content={`${
+ badge.time ? $locale().dateFormatter(databaseTimeToDate(badge.time)) : ''
+ }${badge.description ? `\n${badge.description}` : ''}${
+ badge.designer ? `\nDesigner: ${badge.designer}` : ''
+ }${badge.source ? `\nSource: ${badge.source}` : ''}`}
+ pin={`badge-${badge.id}`}
+ pinPosition="top"
+ relative
+ >
+ <a
+ href={`#`}
+ on:click={() => {
+ selectedBadge = badge;
- const hiddenInput = document.querySelector('input[name="hidden"]');
+ const hiddenInput = document.querySelector('input[name="hidden"]');
- if (hiddenInput instanceof HTMLInputElement)
- hiddenInput.value = badge.hidden ? 'Hidden' : 'Shown';
- }}
- >
- <FallbackImage
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
- style={badge.hidden || badge.shadow_hidden
- ? 'filter: grayscale(100%); opacity: 50%;'
- : ''}
- />
- </a>
- </LinkedTooltip>
- {:else}
- <FallbackBadge
- {badge}
- bind:selectedBadge
- source={cdn(thumbnail(badge.image))}
- alternative={badge.description}
- fallback={thumbnail(badge.image)}
- hideOnError={preferences ? preferences.hide_missing_badges : true}
- style={badge.hidden || badge.shadow_hidden
- ? 'filter: grayscale(100%); opacity: 50%;'
- : ''}
- {preferences}
- />
- {/if}
- </div>
- {/each}
- </div>
- </details>
+ if (hiddenInput instanceof HTMLInputElement)
+ hiddenInput.value = badge.hidden ? 'Hidden' : 'Shown';
+ }}
+ >
+ <FallbackImage
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ style={badge.hidden || badge.shadow_hidden
+ ? 'filter: grayscale(100%); opacity: 50%;'
+ : ''}
+ />
+ </a>
+ </LinkedTooltip>
+ {:else}
+ <FallbackBadge
+ {badge}
+ bind:selectedBadge
+ source={cdn(thumbnail(badge.image))}
+ alternative={badge.description}
+ fallback={thumbnail(badge.image)}
+ hideOnError={preferences ? preferences.hide_missing_badges : true}
+ style={badge.hidden || badge.shadow_hidden
+ ? 'filter: grayscale(100%); opacity: 50%;'
+ : ''}
+ {preferences}
+ />
+ {/if}
+ </div>
+ {/each}
+ </div>
+ </details>
- {#if groupedBadges[groupedBadges.length - 1][0] !== category}
- <p />
- {/if}
+ {#if groupedBadges[groupedBadges.length - 1][0] !== category}
+ <p />
+ {/if}
{/each}
diff --git a/src/lib/User/BadgeWall/FallbackBadge.svelte b/src/lib/User/BadgeWall/FallbackBadge.svelte
index 0e690443..35a50a7d 100644
--- a/src/lib/User/BadgeWall/FallbackBadge.svelte
+++ b/src/lib/User/BadgeWall/FallbackBadge.svelte
@@ -1,130 +1,130 @@
<script lang="ts">
- import { classifyDesignerName } from './badge';
- import locale from '$stores/locale';
- import { tweened } from 'svelte/motion';
- import type { Badge } from '../../Database/SB/User/badges';
- import Tooltip from '../../Tooltip/LinkedTooltip.svelte';
- import { databaseTimeToDate } from '../../Utility/time';
- import { cubicOut } from 'svelte/easing';
- import { dev } from '$app/environment';
- import type { Preferences } from '../../../graphql/$types';
+ import { classifyDesignerName } from './badge';
+ import locale from '$stores/locale';
+ import { tweened } from 'svelte/motion';
+ import type { Badge } from '../../Database/SB/User/badges';
+ import Tooltip from '../../Tooltip/LinkedTooltip.svelte';
+ import { databaseTimeToDate } from '../../Utility/time';
+ import { cubicOut } from 'svelte/easing';
+ import { dev } from '$app/environment';
+ import type { Preferences } from '../../../graphql/$types';
- 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;
- export let awc = false;
- export let index: number | null = null;
- export let preferences: Preferences | undefined;
+ 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;
+ export let awc = false;
+ export let index: number | null = null;
+ export let preferences: Preferences | undefined;
- let replaceCount = 0;
- let badgeReference: HTMLImageElement;
- const mouse = tweened(
- { x: 0, y: 0 },
- {
- duration: 75,
- easing: cubicOut
- }
- );
+ 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;
+ const delayedReplace = (event: Event, image: string | undefined | null) => {
+ if (replaceCount >= maxReplaceCount) return;
- setTimeout(() => {
- (event.target as HTMLImageElement).src = image || '';
+ setTimeout(() => {
+ (event.target as HTMLImageElement).src = image || '';
- replaceCount += 1;
- }, replaceDelay);
- };
+ replaceCount += 1;
+ }, replaceDelay);
+ };
- const handleMouseMove = (event: MouseEvent) => {
- const boundingRectangle = badgeReference.getBoundingClientRect();
- const factor = 1.25;
- const limit = 50;
+ 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 };
+ 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);
- };
+ $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 };
- };
+ const handleMouseLeave = () => {
+ $mouse = { x: 0, y: 0 };
+ };
- const badgeToAny = (badge: Badge) => badge as any;
+ const badgeToAny = (badge: Badge) => badge as any;
</script>
{#if replaceCount < maxReplaceCount}
- <Tooltip
- content={`${dev && !awc ? `${badge.id} ${badge.click_count}\n` : ''}${
- badge.time ? $locale().dateFormatter(databaseTimeToDate(badge.time)) : ''
- }${badge.description ? `${awc ? '' : '\n'}${badge.description}` : ''}${
- badge.designer ? `\nDesigner: ${classifyDesignerName(badge.designer)}` : ''
- }`}
- pin={`badge-${awc ? index : badge.id}`}
- pinPosition="top"
- relative={preferences &&
- preferences.badge_wall_css !== undefined &&
- preferences.badge_wall_css.includes('backdrop-filter')}
- >
- <a
- href={awc ? badgeToAny(badge).link : '#'}
- target="_blank"
- class="badge-container badge"
- on:mousemove={handleMouseMove}
- on:mouseleave={handleMouseLeave}
- on:click={(e) => {
- if (!awc) {
- e.preventDefault();
+ <Tooltip
+ content={`${dev && !awc ? `${badge.id} ${badge.click_count}\n` : ''}${
+ badge.time ? $locale().dateFormatter(databaseTimeToDate(badge.time)) : ''
+ }${badge.description ? `${awc ? '' : '\n'}${badge.description}` : ''}${
+ badge.designer ? `\nDesigner: ${classifyDesignerName(badge.designer)}` : ''
+ }`}
+ pin={`badge-${awc ? index : badge.id}`}
+ pinPosition="top"
+ relative={preferences &&
+ preferences.badge_wall_css !== undefined &&
+ preferences.badge_wall_css.includes('backdrop-filter')}
+ >
+ <a
+ href={awc ? badgeToAny(badge).link : '#'}
+ target="_blank"
+ class="badge-container badge"
+ on:mousemove={handleMouseMove}
+ on:mouseleave={handleMouseLeave}
+ on:click={(e) => {
+ if (!awc) {
+ 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>
+ 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" />
+ <img src={error} alt="Not found" loading="lazy" class="badge" />
{/if}
<style lang="scss">
- $transition: transform 0.325s ease;
+ $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 {
+ 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;
- }
+ .badge:hover {
+ transform: scale(1.075);
+ position: relative;
+ z-index: 2;
+ transition: $transition;
+ }
</style>
diff --git a/src/lib/User/BadgeWall/badge.ts b/src/lib/User/BadgeWall/badge.ts
index 0c15b9ca..a4ba431f 100644
--- a/src/lib/User/BadgeWall/badge.ts
+++ b/src/lib/User/BadgeWall/badge.ts
@@ -1,4 +1,4 @@
-import type { Badge } from "../../../graphql/user/$types";
+import type { Badge } from '../../../graphql/user/$types';
export interface IndexedBadge extends Badge {
index: number;
diff --git a/src/lib/User/BadgeWall/badges.css b/src/lib/User/BadgeWall/badges.css
index 19f8996f..0dffa860 100644
--- a/src/lib/User/BadgeWall/badges.css
+++ b/src/lib/User/BadgeWall/badges.css
@@ -6,11 +6,11 @@
} */
.badges {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(8%, 1fr));
- gap: 0.25rem;
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(8%, 1fr));
+ gap: 0.25rem;
}
.edit-row-2 {
- margin-top: -1.25rem;
+ margin-top: -1.25rem;
}