Small fixes (#141)

* fix: save task as Json rather than string

* fix: pull objects before creating game in database

* fix: strips relative dirs from version information

* fix: #132

* fix: lint

* fix: news object ids and small tweaks

* fix: notification styling errors

* fix: lint
This commit is contained in:
DecDuck
2025-07-20 14:56:15 +10:00
committed by GitHub
parent 661dcf86a8
commit 45848d175e
14 changed files with 57 additions and 91 deletions

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex grow flex-col gap-y-5 overflow-y-auto px-6 py-4"> <div class="flex grow flex-col gap-y-5 overflow-y-auto px-6 py-4">
<span class="inline-flex items-center gap-x-2 font-semibold text-zinc-100"> <span class="inline-flex items-center gap-x-2 font-semibold text-zinc-100">
<UserIcon class="size-5" /> {{ $t("account.settings") }} <UserIcon class="size-5" /> {{ $t("account.title") }}
</span> </span>
<nav class="flex flex-1 flex-col"> <nav class="flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7"> <ul role="list" class="flex flex-1 flex-col gap-y-7">
@@ -74,7 +74,7 @@ const navigation: (NavigationItem & { icon: Component; count?: number })[] = [
count: notifications.value.length, count: notifications.value.length,
}, },
{ {
label: t("settings"), label: t("account.settings"),
route: "/account/settings", route: "/account/settings",
prefix: "/account/settings", prefix: "/account/settings",
icon: WrenchScrewdriverIcon, icon: WrenchScrewdriverIcon,

View File

@@ -91,9 +91,7 @@
:src="useObject(article.imageObjectId)" :src="useObject(article.imageObjectId)"
class="absolute blur-sm inset-0 w-full h-full object-cover transition-all duration-200 group-hover:scale-110" class="absolute blur-sm inset-0 w-full h-full object-cover transition-all duration-200 group-hover:scale-110"
/> />
<div <div class="absolute inset-0 bg-zinc-900/50" />
class="absolute inset-0 bg-gradient-to-b from-transparent to-zinc-800 transition-all duration-200"
/>
</div> </div>
<h3 class="relative text-sm font-medium text-zinc-100"> <h3 class="relative text-sm font-medium text-zinc-100">

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="relative inline-block group"> <div class="relative inline-block group/relative-time">
<!-- Visible relative time --> <!-- Visible relative time -->
<time :datetime="isoDate" class="text-sm text-muted-foreground"> <time :datetime="isoDate" class="text-sm text-muted-foreground">
{{ DateTime.fromJSDate(date).toRelative({ locale: $i18n.locale }) }} {{ DateTime.fromJSDate(date).toRelative({ locale: $i18n.locale }) }}
@@ -8,7 +8,7 @@
<!-- Custom tooltip that shows on hover --> <!-- Custom tooltip that shows on hover -->
<div <div
role="tooltip" role="tooltip"
class="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 rounded bg-zinc-900 text-white text-xs whitespace-nowrap shadow z-10 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" class="absolute bottom-full left-1/2 -translate-x-1/2 mb-1 px-2 py-1 rounded bg-zinc-900 text-white text-xs whitespace-nowrap shadow z-10 opacity-0 group-hover/relative-time:opacity-100 transition-opacity pointer-events-none"
aria-hidden="true" aria-hidden="true"
> >
{{ $d(date, "long") }} {{ $d(date, "long") }}

View File

@@ -19,8 +19,8 @@
"title": "Notifications", "title": "Notifications",
"unread": "Unread Notifications" "unread": "Unread Notifications"
}, },
"settings": "Account Settings", "settings": "Settings",
"title": "Account" "title": "Account Settings"
}, },
"actions": "Actions", "actions": "Actions",
"adminTitle": "Admin Dashboard | Drop", "adminTitle": "Admin Dashboard | Drop",

View File

@@ -40,14 +40,16 @@
{{ notification.description }} {{ notification.description }}
</p> </p>
<div class="mt-4 flex flex-wrap gap-2"> <div class="mt-4 flex flex-wrap gap-2">
<a <NuxtLink
v-for="action in notification.actions" v-for="[name, href] in notification.actions.map((v) =>
:key="action" v.split('|'),
:href="action.split('|')[1]" )"
:key="href"
:href="href"
class="inline-flex items-center rounded-md bg-blue-400/10 px-2 py-1 text-xs font-medium text-blue-400 ring-1 ring-inset ring-blue-400/20 transition-all duration-200 hover:bg-blue-400/20 hover:scale-105 active:scale-95" class="inline-flex items-center rounded-md bg-blue-400/10 px-2 py-1 text-xs font-medium text-blue-400 ring-1 ring-inset ring-blue-400/20 transition-all duration-200 hover:bg-blue-400/20 hover:scale-105 active:scale-95"
> >
{{ action.split("|")[0] }} {{ name }}
</a> </NuxtLink>
</div> </div>
</div> </div>
<div class="ml-4 flex flex-shrink-0 items-center gap-x-2"> <div class="ml-4 flex flex-shrink-0 items-center gap-x-2">
@@ -57,7 +59,7 @@
<button <button
v-if="!notification.read" v-if="!notification.read"
type="button" type="button"
class="inline-flex items-center rounded-md bg-zinc-400/10 px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-400/20 transition-all duration-200 hover:bg-zinc-400/20 hover:scale-105 active:scale-95" class="inline-flex gap-x-1 items-center rounded-md bg-zinc-400/10 px-2 py-1 text-xs font-medium text-zinc-400 ring-1 ring-inset ring-zinc-400/20 transition-all duration-200 hover:bg-zinc-400/20 hover:scale-105 active:scale-95"
@click="markAsRead(notification.id)" @click="markAsRead(notification.id)"
> >
<CheckIcon class="size-3" /> <CheckIcon class="size-3" />
@@ -65,7 +67,7 @@
</button> </button>
<button <button
type="button" type="button"
class="inline-flex items-center rounded-md bg-red-400/10 px-2 py-1 text-xs font-medium text-red-400 ring-1 ring-inset ring-red-400/20 transition-all duration-200 hover:bg-red-400/20 hover:scale-105 active:scale-95" class="inline-flex gap-x-1 items-center rounded-md bg-red-400/10 px-2 py-1 text-xs font-medium text-red-400 ring-1 ring-inset ring-red-400/20 transition-all duration-200 hover:bg-red-400/20 hover:scale-105 active:scale-95"
@click="deleteNotification(notification.id)" @click="deleteNotification(notification.id)"
> >
<TrashIcon class="size-3" /> <TrashIcon class="size-3" />

View File

@@ -86,7 +86,7 @@
</div> </div>
<div class="px-4 py-10 sm:px-6 lg:px-8 lg:py-6 grow"> <div class="px-4 py-10 sm:px-6 lg:px-8 lg:py-6 grow">
<NuxtPage /> <NuxtPage :articles="news" />
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,12 +1,16 @@
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<template> <template>
<div> <div>
<div v-if="article" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div v-if="article" class="px-4 sm:px-6 lg:px-8">
<!-- Banner header with blurred background --> <!-- Banner header with blurred background -->
<div class="relative w-full h-[300px] mb-8 rounded-lg overflow-hidden"> <div class="relative w-full h-[300px] mb-8 rounded-lg overflow-hidden">
<div v-if="article.imageObjectId" class="absolute inset-0"> <div class="absolute inset-0">
<img <img
:src="useObject(article.imageObjectId)" :src="
article.imageObjectId
? useObject(article.imageObjectId)
: '/wallpapers/news-placeholder.jpg'
"
alt="" alt=""
class="w-full h-full object-cover blur-sm scale-110" class="w-full h-full object-cover blur-sm scale-110"
/> />
@@ -14,12 +18,6 @@
class="absolute inset-0 bg-gradient-to-b from-transparent to-zinc-950" class="absolute inset-0 bg-gradient-to-b from-transparent to-zinc-950"
/> />
</div> </div>
<div v-else>
<!-- Fallback gradient background when no image -->
<div
class="absolute inset-0 bg-gradient-to-b from-zinc-800 to-zinc-900"
/>
</div>
<div class="relative h-full flex flex-col justify-end p-8"> <div class="relative h-full flex flex-col justify-end p-8">
<div class="flex items-center gap-x-3 mb-6"> <div class="flex items-center gap-x-3 mb-6">
@@ -73,7 +71,7 @@
<!-- Article content - markdown --> <!-- Article content - markdown -->
<div <div
class="mx-auto prose prose-invert prose-lg" class="mx-auto prose prose-blue prose-invert prose-lg"
v-html="renderedContent" v-html="renderedContent"
/> />
</div> </div>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col max-w-4xl mx-auto"> <div class="flex flex-col px-8">
<div class="mb-8"> <div class="mb-8">
<div class="flex flex-col gap-y-4"> <div class="flex flex-col gap-y-4">
<div> <div>
@@ -14,7 +14,11 @@
</div> </div>
<!-- Articles list --> <!-- Articles list -->
<TransitionGroup name="article-list" tag="div" class="space-y-6"> <TransitionGroup
name="article-list"
tag="div"
class="gap-6 grid sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5"
>
<NuxtLink <NuxtLink
v-for="article in articles" v-for="article in articles"
:key="article.id" :key="article.id"
@@ -26,8 +30,11 @@
> >
<div class="relative h-48 w-full overflow-hidden"> <div class="relative h-48 w-full overflow-hidden">
<img <img
v-if="article.imageObjectId" :src="
:src="useObject(article.imageObjectId)" article.imageObjectId
? useObject(article.imageObjectId)
: '/wallpapers/news-placeholder.jpg'
"
alt="" alt=""
class="h-full w-full object-cover object-center transition-all duration-500 group-hover:scale-110 scale-105" class="h-full w-full object-cover object-center transition-all duration-500 group-hover:scale-110 scale-105"
/> />

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@@ -51,7 +51,7 @@ export default defineEventHandler(async (h3) => {
tags: parsedTags, tags: parsedTags,
...(imageId && { image: imageId }), ...(imageId && { imageObjectId: imageId }),
authorId: "system", authorId: "system",
}); });

View File

@@ -147,14 +147,14 @@ class LibraryManager {
}> = []; }> = [];
const files = await library.versionReaddir(game.libraryPath, versionName); const files = await library.versionReaddir(game.libraryPath, versionName);
for (const file of files) { for (const filename of files) {
const filename = path.basename(file); const basename = path.basename(filename);
const dotLocation = file.lastIndexOf("."); const dotLocation = filename.lastIndexOf(".");
const ext = dotLocation == -1 ? "" : file.slice(dotLocation); const ext = dotLocation == -1 ? "" : filename.slice(dotLocation);
for (const [platform, checkExts] of Object.entries(fileExts)) { for (const [platform, checkExts] of Object.entries(fileExts)) {
for (const checkExt of checkExts) { for (const checkExt of checkExts) {
if (checkExt != ext) continue; if (checkExt != ext) continue;
const fuzzyValue = fuzzy(filename, game.mName); const fuzzyValue = fuzzy(basename, game.mName);
options.push({ options.push({
filename, filename,
platform, platform,

View File

@@ -197,8 +197,8 @@ export class MetadataHandler {
{}, {},
["internal:read"], ["internal:read"],
wrapTaskContext(context, { wrapTaskContext(context, {
min: 63, min: 60,
max: 100, max: 95,
prefix: "[object import] ", prefix: "[object import] ",
}), }),
); );
@@ -227,6 +227,13 @@ export class MetadataHandler {
context?.progress(60); context?.progress(60);
logger.info(`Successfully fetched all metadata.`);
logger.info(`Importing objects...`);
await pullObjects();
progress(95);
await prisma.game.create({ await prisma.game.create({
data: { data: {
id: gameId, id: gameId,
@@ -262,12 +269,6 @@ export class MetadataHandler {
}, },
}); });
progress(63);
logger.info(`Successfully fetched all metadata.`);
logger.info(`Importing objects...`);
await pullObjects();
logger.info(`Finished game import.`); logger.info(`Finished game import.`);
}, },
}); });

View File

@@ -8,7 +8,7 @@ class NewsManager {
description: string; description: string;
tags: string[]; tags: string[];
authorId: string; authorId: string;
image?: string; imageObjectId?: string;
}) { }) {
return await prisma.article.create({ return await prisma.article.create({
data: { data: {
@@ -23,7 +23,7 @@ class NewsManager {
})), })),
}, },
...(data.image && { image: data.image }), ...(data.imageObjectId && { imageObjectId: data.imageObjectId }),
author: { author: {
connect: { connect: {
id: data.authorId, id: data.authorId,

View File

@@ -72,7 +72,7 @@ class TaskHandler {
this.taskCreators.set(task.taskGroup, task.build); this.taskCreators.set(task.taskGroup, task.build);
} }
create(task: Task) { async create(task: Task) {
let updateCollectTimeout: NodeJS.Timeout | undefined; let updateCollectTimeout: NodeJS.Timeout | undefined;
let updateCollectResolves: Array<(value: unknown) => void> = []; let updateCollectResolves: Array<(value: unknown) => void> = [];
let logOffset: number = 0; let logOffset: number = 0;
@@ -131,44 +131,6 @@ class TaskHandler {
const taskPool = this.taskPool; const taskPool = this.taskPool;
// Create a pino transport that replicates the old log function behavior
// const taskLogger = pino({
// hooks: {
// logMethod(args, method) {
// // Combine all arguments into a single string message
// const message = args.map(String).join(" ");
// const now = new Date();
// const pad = (n: number, width = 2) =>
// n.toString().padStart(width, "0");
// const year = now.getUTCFullYear();
// const month = pad(now.getUTCMonth() + 1);
// const day = pad(now.getUTCDate());
// const hours = pad(now.getUTCHours());
// const minutes = pad(now.getUTCMinutes());
// const seconds = pad(now.getUTCSeconds());
// const milliseconds = pad(now.getUTCMilliseconds(), 3);
// const logObj = {
// timestamp: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds} UTC`,
// message,
// };
// // Push the formatted log string to the task's log array
// const taskEntry = taskPool.get(task.id);
// if (taskEntry) {
// taskEntry.log.push(JSON.stringify(logObj));
// updateAllClients();
// }
// // Optionally, still call the original method if you want logs elsewhere
// method.apply(this, args);
// },
// },
// });
// Custom writable stream to capture logs // Custom writable stream to capture logs
const logStream = new Writable({ const logStream = new Writable({
objectMode: true, objectMode: true,
@@ -227,7 +189,7 @@ class TaskHandler {
endTime: undefined, endTime: undefined,
}); });
updateAllClients(true); await updateAllClients(true);
droplet.callAltThreadFunc(async () => { droplet.callAltThreadFunc(async () => {
const taskEntry = this.taskPool.get(task.id); const taskEntry = this.taskPool.get(task.id);
@@ -267,9 +229,7 @@ class TaskHandler {
acls: taskEntry.acls, acls: taskEntry.acls,
...(taskEntry.error ...(taskEntry.error ? { error: taskEntry.error } : undefined),
? { error: JSON.stringify(taskEntry.error) }
: undefined),
}, },
}); });