172 lines
5.6 KiB
Vue
172 lines
5.6 KiB
Vue
<template>
|
|
<div
|
|
class="card bg-base-100 shadow-lg hover:shadow-2xl transition-shadow duration-300"
|
|
:class="responses?.length == 0 ? 'shadow-red-900' : 'shadow-primary-300'"
|
|
>
|
|
<div class="card-body">
|
|
<div class="flex items-start justify-between">
|
|
<div class="flex-1">
|
|
<h3 class="card-title text-lg font-bold">{{ puzzle.title }}</h3>
|
|
<p class="text-sm text-base-content/70 mb-2">
|
|
by {{ puzzle.author_name }}
|
|
</p>
|
|
|
|
<div class="flex items-center gap-2 mb-3">
|
|
<div class="badge badge-primary badge-sm">
|
|
{{ puzzle.steam_item_id }}
|
|
</div>
|
|
<div class="badge badge-ghost badge-sm">ID: {{ puzzle.id }}</div>
|
|
</div>
|
|
|
|
<p
|
|
v-if="puzzle.description"
|
|
class="text-sm text-base-content/80 mb-4"
|
|
>
|
|
{{ puzzle.description }}
|
|
</p>
|
|
|
|
<div
|
|
v-if="puzzle.tags && puzzle.tags.length > 0"
|
|
class="flex flex-wrap gap-1 mb-4"
|
|
>
|
|
<span
|
|
v-for="tag in puzzle.tags.slice(0, 3)"
|
|
:key="tag"
|
|
class="badge badge-outline badge-xs"
|
|
>
|
|
{{ tag }}
|
|
</span>
|
|
<span
|
|
v-if="puzzle.tags.length > 3"
|
|
class="badge badge-outline badge-xs"
|
|
>
|
|
+{{ puzzle.tags.length - 3 }} more
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col items-end gap-2">
|
|
<div class="tooltip" data-tip="View on Steam Workshop">
|
|
<a
|
|
:href="`https://steamcommunity.com/workshop/filedetails/?id=${puzzle.steam_item_id}`"
|
|
target="_blank"
|
|
class="btn btn-ghost btn-sm btn-square"
|
|
>
|
|
<i class="mdi mdi-steam text-lg"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Responses Table -->
|
|
<div v-if="responses && responses.length > 0" class="mt-6">
|
|
<div class="divider">
|
|
<span class="text-sm font-medium"
|
|
>Solutions ({{ responses.length }})</span
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<table class="table table-xs">
|
|
<thead>
|
|
<tr>
|
|
<th>Cost</th>
|
|
<th>Cycles</th>
|
|
<th>Area</th>
|
|
<th>Files</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="response in responses"
|
|
:key="response.id"
|
|
class="hover"
|
|
>
|
|
<td>
|
|
<span
|
|
v-if="response.final_cost || response.cost"
|
|
class="badge badge-success badge-xs"
|
|
>
|
|
{{ response.final_cost || response.cost }}
|
|
</span>
|
|
<span v-else class="text-base-content/50">-</span>
|
|
</td>
|
|
<td>
|
|
<span
|
|
v-if="response.final_cycles || response.cycles"
|
|
class="badge badge-info badge-xs"
|
|
>
|
|
{{ response.final_cycles || response.cycles }}
|
|
</span>
|
|
<span v-else class="text-base-content/50">-</span>
|
|
</td>
|
|
<td>
|
|
<span
|
|
v-if="response.final_area || response.area"
|
|
class="badge badge-warning badge-xs"
|
|
>
|
|
{{ response.final_area || response.area }}
|
|
</span>
|
|
<span v-else class="text-base-content/50">-</span>
|
|
</td>
|
|
<td>
|
|
<div class="flex items-center gap-1">
|
|
<span class="badge badge-ghost badge-xs">{{
|
|
response.files?.length || 0
|
|
}}</span>
|
|
<div
|
|
v-if="response.files?.length"
|
|
class="tooltip"
|
|
:data-tip="
|
|
response.files
|
|
.map((f) => f.original_filename || f.file?.name)
|
|
.join(', ')
|
|
"
|
|
>
|
|
<i class="mdi mdi-information-outline text-xs"></i>
|
|
</div>
|
|
<div
|
|
v-if="response.needs_manual_validation"
|
|
class="tooltip"
|
|
data-tip="Needs manual validation"
|
|
>
|
|
<i class="mdi mdi-alert-circle text-xs text-warning"></i>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- No responses state -->
|
|
<div
|
|
v-else
|
|
class="mt-6 text-center py-4 border-2 border-dashed border-base-300 rounded-lg hover:border-primary transition-colors duration-300 cursor-pointer"
|
|
@click="openSubmissionModal"
|
|
>
|
|
<i class="mdi mdi-upload text-2xl text-base-content/40"></i>
|
|
<p class="text-sm text-base-content/60 mt-2">No solutions yet</p>
|
|
<p class="text-xs text-base-content/40">
|
|
Upload solutions using the submit button
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { SteamCollectionItem, PuzzleResponse } from "@/types";
|
|
import { useSubmissionsStore } from "@/stores/submissions";
|
|
|
|
interface Props {
|
|
puzzle: SteamCollectionItem;
|
|
responses?: PuzzleResponse[];
|
|
}
|
|
|
|
defineProps<Props>();
|
|
|
|
const { openSubmissionModal } = useSubmissionsStore();
|
|
</script>
|