basic noita parsing

This commit is contained in:
2026-05-10 01:45:29 +02:00
parent 119fdc2a51
commit 69b6b46ee2
14 changed files with 1117 additions and 38 deletions
+77 -29
View File
@@ -1,5 +1,10 @@
<script setup lang="ts">
import { ref, computed } from "vue";
import { ref, onMounted } from "vue";
interface Objective {
objectiv_id: string;
count: number;
}
const userInfo = ref({
username: "Player",
@@ -11,6 +16,8 @@ const userInfo = ref({
const uploadedFiles = ref<File[]>([]);
const isUploading = ref(false);
const isDragover = ref(false);
const objectives = ref<Objective[]>([]);
const isLoadingObjectives = ref(false);
const handleFileUpload = (event: Event) => {
const input = event.target as HTMLInputElement;
@@ -78,6 +85,24 @@ const submitRun = async () => {
const goHome = () => {
window.location.href = "/";
};
const fetchObjectives = async () => {
isLoadingObjectives.value = true;
try {
const response = await fetch("/api/noita/objectives");
if (!response.ok) throw new Error("Failed to fetch objectives");
objectives.value = await response.json();
} catch (error) {
console.error("Error fetching objectives:", error);
} finally {
isLoadingObjectives.value = false;
}
};
onMounted(() => {
fetchObjectives();
});
</script>
<template>
@@ -149,25 +174,15 @@ const goHome = () => {
</h2>
<!-- Upload Area -->
<div
@dragover="handleDragover"
@dragleave="handleDragleave"
@drop="handleDrop"
:class="[
'border-2 border-dashed rounded-lg p-8 text-center transition-colors cursor-pointer bg-base-200/50 mb-6',
isDragover ? 'border-primary bg-primary/10' : 'border-base-300 hover:border-primary'
]"
>
<input
type="file"
multiple
@change="handleFileUpload"
class="hidden"
id="file-upload"
accept="video/*,image/*"
/>
<div @dragover="handleDragover" @dragleave="handleDragleave" @drop="handleDrop" :class="[
'border-2 border-dashed rounded-lg p-8 text-center transition-colors cursor-pointer bg-base-200/50 mb-6',
isDragover ? 'border-primary bg-primary/10' : 'border-base-300 hover:border-primary'
]">
<input type="file" multiple @change="handleFileUpload" class="hidden" id="file-upload"
accept="video/*,image/*" />
<label for="file-upload" class="cursor-pointer flex flex-col items-center gap-3">
<i :class="['mdi text-4xl', isDragover ? 'mdi-cloud-check text-primary' : 'mdi-file-upload text-base-content/50']"></i>
<i
:class="['mdi text-4xl', isDragover ? 'mdi-cloud-check text-primary' : 'mdi-file-upload text-base-content/50']"></i>
<div>
<p class="font-semibold">Click to upload or drag and drop</p>
<p class="text-sm text-base-content/70">Video or image files (MP4, PNG, etc.)</p>
@@ -179,16 +194,14 @@ const goHome = () => {
<div v-if="uploadedFiles.length > 0" class="mb-6">
<p class="font-semibold mb-3">Selected Files:</p>
<div class="space-y-2">
<div v-for="(file, index) in uploadedFiles" :key="index" class="flex items-center gap-3 bg-base-200 p-3 rounded-lg">
<div v-for="(file, index) in uploadedFiles" :key="index"
class="flex items-center gap-3 bg-base-200 p-3 rounded-lg">
<i class="mdi mdi-file text-primary"></i>
<div class="flex-1 min-w-0">
<p class="font-medium truncate">{{ file.name }}</p>
<p class="text-xs text-base-content/70">{{ (file.size / 1024 / 1024).toFixed(2) }} MB</p>
</div>
<button
@click="uploadedFiles.splice(index, 1)"
class="btn btn-ghost btn-xs"
>
<button @click="uploadedFiles.splice(index, 1)" class="btn btn-ghost btn-xs">
<i class="mdi mdi-close"></i>
</button>
</div>
@@ -201,11 +214,8 @@ const goHome = () => {
<i class="mdi mdi-folder-open mr-2"></i>
Choose Files
</label>
<button
@click="submitRun"
:disabled="uploadedFiles.length === 0 || isUploading"
:class="['btn btn-primary flex-1', { 'loading': isUploading }]"
>
<button @click="submitRun" :disabled="uploadedFiles.length === 0 || isUploading"
:class="['btn btn-primary flex-1', { 'loading': isUploading }]">
<i v-if="!isUploading" class="mdi mdi-send mr-2"></i>
{{ isUploading ? 'Submitting...' : 'Submit Run' }}
</button>
@@ -216,6 +226,44 @@ const goHome = () => {
</p>
</div>
</div>
<!-- Objectives Table -->
<div class="card bg-base-100 shadow-lg mt-8">
<div class="card-body">
<h2 class="card-title text-2xl mb-6">
<i class="mdi mdi-view-list text-purple-500 mr-2"></i>
Your Objectives
</h2>
<div v-if="isLoadingObjectives" class="flex justify-center py-8">
<span class="loading loading-spinner loading-lg"></span>
</div>
<div v-else-if="objectives.length === 0" class="text-center py-8">
<p class="text-base-content/70 mb-2">No objectives completed yet</p>
<p class="text-sm text-base-content/50">Submit your runs to unlock objectives!</p>
</div>
<div v-else class="overflow-x-auto">
<table class="table table-zebra w-full">
<thead>
<tr>
<th>Objective ID</th>
<th class="text-right">Count</th>
</tr>
</thead>
<tbody>
<tr v-for="obj in objectives" :key="obj.objectiv_id">
<td class="font-medium">{{ obj.objectiv_id }}</td>
<td class="text-right">
<span class="badge badge-primary badge-lg">{{ obj.count }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>