diff options
| author | Fuwn <[email protected]> | 2024-05-05 01:07:58 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-05-05 01:07:58 -0700 |
| commit | db40d18312fae54723d88964159e44a7e7d8cb6b (patch) | |
| tree | 584ea4e3926dfc8e3bab249882185993f4d60b26 | |
| parent | fix(input.css): input y alignment (diff) | |
| download | due.moe-db40d18312fae54723d88964159e44a7e7d8cb6b.tar.xz due.moe-db40d18312fae54723d88964159e44a7e7d8cb6b.zip | |
feat(user): drag and drop pinned categories
| -rwxr-xr-x | bun.lockb | bin | 173947 -> 174306 bytes | |||
| -rw-r--r-- | package.json | 1 | ||||
| -rw-r--r-- | src/lib/Database/userPreferences.ts | 14 | ||||
| -rw-r--r-- | src/routes/api/preferences/+server.ts | 13 | ||||
| -rw-r--r-- | src/routes/user/[user]/+page.svelte | 93 |
5 files changed, 118 insertions, 3 deletions
| Binary files differ diff --git a/package.json b/package.json index db12dfd7..da8e9ced 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "lz-string": "^1.5.0", "modern-screenshot": "^4.4.33", "rss-parser": "^3.13.0", + "sortablejs": "^1.15.2", "string-similarity": "^4.0.4", "svelte-i18n": "^4.0.0", "svelte-markdown": "^0.4.1", diff --git a/src/lib/Database/userPreferences.ts b/src/lib/Database/userPreferences.ts index 9f55e110..c3ef5c04 100644 --- a/src/lib/Database/userPreferences.ts +++ b/src/lib/Database/userPreferences.ts @@ -140,3 +140,17 @@ export const togglePinnedBadgeWallCategory = async (userId: number, category: st pinned_badge_wall_categories: pinnedCategories.join(',') }); }; + +export const setPinnedBadgeWallCategories = async (userId: number, categories: string) => { + const userPreferences = await getUserPreferences(userId); + + if (!userPreferences) return null; + + return await setUserPreferences(userId, { + updated_at: new Date().toISOString(), + pinned_hololive_streams: userPreferences.pinned_hololive_streams, + hide_missing_badges: userPreferences.hide_missing_badges, + badge_wall_css: userPreferences.badge_wall_css, + pinned_badge_wall_categories: categories + }); +}; diff --git a/src/routes/api/preferences/+server.ts b/src/routes/api/preferences/+server.ts index 2fe2ccfe..0291dd0c 100644 --- a/src/routes/api/preferences/+server.ts +++ b/src/routes/api/preferences/+server.ts @@ -5,7 +5,8 @@ import { setCSS, setBiography, toggleHideAWCBadges, - togglePinnedBadgeWallCategory + togglePinnedBadgeWallCategory, + setPinnedBadgeWallCategories } from '$lib/Database/userPreferences'; const unauthorised = new Response('Unauthorised', { status: 401 }); @@ -66,6 +67,16 @@ export const PUT = async ({ url, cookies, request }) => { } ); + if (url.searchParams.get('setCategories') !== null) + return Response.json( + await setPinnedBadgeWallCategories(userId, url.searchParams.get('setCategories') || ''), + { + headers: { + 'Access-Control-Allow-Origin': 'https://due.moe' + } + } + ); + if (url.searchParams.get('biography') !== null) return Response.json(await setBiography(userId, (await request.text()).slice(0, 3000)), { headers: { diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte index 097007f0..3c443ae6 100644 --- a/src/routes/user/[user]/+page.svelte +++ b/src/routes/user/[user]/+page.svelte @@ -20,6 +20,7 @@ import SvelteMarkdown from 'svelte-markdown'; import MarkdownLink from '$lib/MarkdownLink.svelte'; import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte'; + import type { DragEventHandler } from 'svelte/elements'; export let data; @@ -27,6 +28,8 @@ let error = false; let schedule: ParseResult | undefined = undefined; let preferences: UserPreferences | undefined = undefined; + let draggedCategory: string | null = null; + let draggedOverCategory: string | null = null; $: displayBadges = (username: string, badges: number | string) => $locale({ @@ -42,6 +45,81 @@ .catch(() => (error = true)); }); + const handleDragStart = ( + event: DragEvent & { currentTarget: EventTarget & HTMLDivElement }, + category: string | null + ) => { + draggedCategory = category; + + if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'; + }; + + const handleDragOver = (event: any) => { + event.preventDefault(); + + event.dataTransfer.dropEffect = 'move'; + }; + + const handleDragEnter = ( + event: DragEvent & { currentTarget: EventTarget & HTMLDivElement }, + category: string | null + ) => { + event.preventDefault(); + + if (draggedCategory !== category && preferences && draggedCategory) { + draggedOverCategory = category; + + const categories = preferences.pinned_badge_wall_categories.split(','); + const draggedIndex = categories.indexOf(draggedCategory); + const targetIndex = categories.indexOf(category); + + categories.splice(draggedIndex, 1); + categories.splice(targetIndex, 0, draggedCategory); + + preferences.pinned_badge_wall_categories = categories.join(','); + } + }; + + const handleDragLeave = ( + event: DragEvent & { currentTarget: EventTarget & HTMLDivElement }, + category: string + ) => { + event.preventDefault(); + + if (draggedOverCategory === category && preferences && draggedCategory) { + draggedOverCategory = null; + + const categories = preferences.pinned_badge_wall_categories.split(','); + const draggedIndex = categories.indexOf(draggedCategory); + + categories.splice(draggedIndex, 1); + categories.splice(categories.indexOf(category) + 1, 0, draggedCategory); + + preferences.pinned_badge_wall_categories = categories.join(','); + } + }; + + const handleDrop = (event: { preventDefault: () => void }) => { + event.preventDefault(); + + if (userData && preferences) { + fetch( + root( + `/api/preferences?id=${userData.id}&setCategories=${preferences.pinned_badge_wall_categories}` + ), + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(refreshPreferences); + } + + draggedCategory = null; + draggedOverCategory = null; + }; + onMount(async () => { schedule = typeSchedule( parseScheduleHtml( @@ -248,10 +326,21 @@ <div class="pinned-categories"> {#each preferences.pinned_badge_wall_categories.split(',') as category} - <span class="card card-small pinned-category"> + <div + class="card card-small pinned-category" + draggable="true" + on:dragstart={(event) => handleDragStart(event, category)} + on:dragover={handleDragOver} + on:dragenter={(event) => handleDragEnter(event, category)} + on:dragleave={(event) => handleDragLeave(event, category)} + on:drop={handleDrop} + role="button" + tabindex="0" + > <span class="pinned-category-name"> {category} </span> + <button on:click={() => { if (userData) @@ -260,7 +349,7 @@ }).then(refreshPreferences); }}>Remove</button > - </span> + </div> {/each} <span class="card card-small pinned-category"> |