aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbun.lockbbin173947 -> 174306 bytes
-rw-r--r--package.json1
-rw-r--r--src/lib/Database/userPreferences.ts14
-rw-r--r--src/routes/api/preferences/+server.ts13
-rw-r--r--src/routes/user/[user]/+page.svelte93
5 files changed, 118 insertions, 3 deletions
diff --git a/bun.lockb b/bun.lockb
index b9761c64..b4c00cc4 100755
--- a/bun.lockb
+++ b/bun.lockb
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">