diff options
| author | Fuwn <[email protected]> | 2023-10-26 15:41:57 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-10-26 15:41:57 -0700 |
| commit | 9bac3b6b6a9103841a3456436c65af66549a83da (patch) | |
| tree | 4273c0ebe5567109daf8b7a4d2c92d51694677cf /src/routes/user | |
| parent | fix(feeds): html encode title (diff) | |
| parent | feat: move back to bun (diff) | |
| download | due.moe-9bac3b6b6a9103841a3456436c65af66549a83da.tar.xz due.moe-9bac3b6b6a9103841a3456436c65af66549a83da.zip | |
merge: branch 'badges'
Diffstat (limited to 'src/routes/user')
| -rw-r--r-- | src/routes/user/[user]/+page.server.ts | 5 | ||||
| -rw-r--r-- | src/routes/user/[user]/+page.svelte | 64 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.server.ts | 11 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.svelte | 125 |
4 files changed, 205 insertions, 0 deletions
diff --git a/src/routes/user/[user]/+page.server.ts b/src/routes/user/[user]/+page.server.ts new file mode 100644 index 00000000..76d2d889 --- /dev/null +++ b/src/routes/user/[user]/+page.server.ts @@ -0,0 +1,5 @@ +export const load = ({ params }) => { + return { + username: params.user + }; +}; diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte new file mode 100644 index 00000000..858e6aec --- /dev/null +++ b/src/routes/user/[user]/+page.svelte @@ -0,0 +1,64 @@ +<script lang="ts"> + import { user, type User } from '$lib/AniList/user'; + import { onMount } from 'svelte'; + + export let data; + + let userData: User | undefined = undefined; + + onMount(() => { + user(data.username).then((profile) => { + userData = profile; + }); + }); + + // 8.5827814569536423841e0 +</script> + +{#if userData === null} + Could not load user profile for <a + href={`https://anilist.co/user/${data.username}`} + target="_blank">@{data.username}</a + >. + + <p /> + + Does this user exist? +{:else if userData === undefined} + Loading ... +{:else} + <div class="user-grid"> + <p> + <a + href={`https://anilist.co/user/${userData.name}`} + target="_blank" + title={String(userData.id)} + > + <img src={userData.avatar.large} alt="" width="100vw" /> + </a> + </p> + + <div> + <p> + <a + href={`https://anilist.co/user/${userData.name}`} + target="_blank" + title={String(userData.id)}>@{userData.name}</a + > + • <a href={`/user/${userData.name}/badges`}>Badge Wall</a> + </p> + + This user has watched {(userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1)} days of + anime and read + {((userData.statistics.manga.chaptersRead * 8.58) / 60 / 24).toFixed(1)} days of manga. + </div> + </div> +{/if} + +<style> + .user-grid { + display: flex; + flex-wrap: wrap; + column-gap: 1.5em; + } +</style> diff --git a/src/routes/user/[user]/badges/+page.server.ts b/src/routes/user/[user]/badges/+page.server.ts new file mode 100644 index 00000000..4be5bcd2 --- /dev/null +++ b/src/routes/user/[user]/badges/+page.server.ts @@ -0,0 +1,11 @@ +import { user } from '$lib/AniList/user.js'; +import { getUserBadges } from '$lib/userBadgesDatabase.js'; + +export const load = async ({ params }) => { + const badges = getUserBadges((await user(params.user)).id); + + return { + username: params.user, + badges + }; +}; diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte new file mode 100644 index 00000000..324d568e --- /dev/null +++ b/src/routes/user/[user]/badges/+page.svelte @@ -0,0 +1,125 @@ +<script lang="ts"> + import { userIdentity } from '$lib/AniList/identity.js'; + import type { Badge } from '$lib/userBadgesDatabase.js'; + import { onMount } from 'svelte'; + + export let data; + + let editMode = false; + let currentUserIdentity: ReturnType<typeof userIdentity>; + + onMount(async () => { + if (data.user) { + currentUserIdentity = userIdentity(data.user); + } else { + currentUserIdentity = new Promise((resolve) => + resolve({ + name: 'Guest', + id: -1 + }) + ); + } + }); + + const submitBadge = () => { + const imageURL = document.querySelector('input[name="image_url"]') as HTMLInputElement; + const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement; + const description = document.querySelector('input[name="description"]') as HTMLInputElement; + + fetch( + `/api/badges/add?image=${encodeURIComponent(imageURL.value)}&post=${encodeURIComponent( + activityURL.value + )}&description=${encodeURIComponent(description.value)}`, + { + method: 'POST' + } + ).then(() => { + imageURL.value = ''; + activityURL.value = ''; + description.value = ''; + }); + }; + + const removeBadge = (badge: Badge) => { + fetch(`/api/badges/remove?id=${badge.id}`, { + method: 'POST' + }).then(() => { + (document.querySelector(`#badge-${badge.id}`) as HTMLAnchorElement).style.display = 'none'; + }); + }; +</script> + +{#await currentUserIdentity} + Loading ... +{:then identity} + {@const isOwner = identity && identity.name === data.username} + <p> + <a href={`/user/${data.username}`}>Back to Profile</a> + {#if isOwner} + • + <a href={`#`} on:click={() => (editMode = !editMode)}> + {editMode ? 'Disable' : 'Enable'} Edit Mode + </a> + {/if} + </p> + + {#if editMode && isOwner} + <p> + Delete mode is enabled. Click on an image to delete it. There is no confirmation, so be + careful! + </p> + + <p> + <input type="text" placeholder="Image URL" name="image_url" minlength="1" maxlength="1000" /> + <input + type="text" + placeholder="Activity URL" + name="activity_url" + minlength="1" + maxlength="1000" + /> + <input + type="text" + placeholder="Description (Optional)" + name="description" + minlength="1" + maxlength="1000" + /> + <a href={`#`} on:click={submitBadge}>Add Badge</a> + </p> + {/if} + + <div id="badges"> + {#each data.badges as badge} + {#if editMode} + <a href={`#`} on:click={() => removeBadge(badge)} id={`badge-${badge.id}`}> + <img src={badge.image} alt={badge.description} /> + </a> + {:else} + <a href={badge.post} target="_blank" id={`badge-${badge.id}`}> + <img src={badge.image} alt={badge.description} /> + </a> + {/if} + {/each} + </div> +{/await} + +<style> + /* body { + margin: 0; + padding: 0; + text-align: center; + background-color: #151f2e; + } */ + + img { + width: 100%; + height: auto; + } + + #badges { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(8%, 1fr)); + grid-gap: 0; + } +</style> |