Files

140 lines
5.9 KiB
Vue

<script setup lang="ts">
import AppLayout from '@/Shared/Layouts/AppLayout.vue';
import { Head, Link, router } from '@inertiajs/vue3';
import type { ConsoleData, ScraperResultData } from '@/types';
import { ref } from 'vue';
interface Props {
consoles: ConsoleData[];
user: {
name: string;
email: string;
};
}
defineProps<Props>();
const searchQuery = ref('');
const selectedConsole = ref('');
const results = ref<ScraperResultData[]>([]);
const isSearching = ref(false);
const selectedGameSlug = ref<string | null>(null);
const search = async () => {
if (searchQuery.value.length < 2) return;
isSearching.value = true;
try {
const response = await fetch(
route('scraper.search') + '?query=' + encodeURIComponent(searchQuery.value) +
(selectedConsole.value ? '&console=' + selectedConsole.value : '')
);
const data = await response.json();
results.value = data.results || [];
} catch (error) {
console.error('Search failed:', error);
}
isSearching.value = false;
};
const selectGame = (slug: string) => {
selectedGameSlug.value = slug;
};
const applyCover = async (gameSlug: string, coverUrl: string) => {
router.post(route('scraper.apply', gameSlug), {
cover_url: coverUrl,
}, {
preserveScroll: true,
});
};
</script>
<template>
<AppLayout title="Cover Scraper" :user="user">
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">Cover Scraper</h2>
</template>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
<!-- Search Form -->
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
<div class="flex gap-4">
<div class="flex-1">
<input
v-model="searchQuery"
type="text"
placeholder="Search for a game..."
class="w-full border-gray-300 rounded-md shadow-sm focus:ring-purple-500 focus:border-purple-500"
@keyup.enter="search"
/>
</div>
<select
v-model="selectedConsole"
class="border-gray-300 rounded-md shadow-sm focus:ring-purple-500 focus:border-purple-500"
>
<option value="">All Consoles</option>
<option v-for="console in consoles" :key="console.id" :value="console.slug">
{{ console.name }}
</option>
</select>
<button
@click="search"
:disabled="isSearching"
class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded disabled:opacity-50"
>
{{ isSearching ? 'Searching...' : 'Search' }}
</button>
</div>
</div>
<!-- Results -->
<div v-if="results.length > 0" class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
<h3 class="text-lg font-semibold mb-4">Search Results</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="result in results"
:key="result.id"
class="border rounded-lg p-4 hover:shadow-md transition"
>
<div class="flex gap-4">
<div class="w-20 h-28 bg-gray-200 rounded overflow-hidden flex-shrink-0">
<img
v-if="result.coverUrl"
:src="result.coverUrl"
:alt="result.title"
class="w-full h-full object-cover"
/>
<div v-else class="w-full h-full flex items-center justify-center text-gray-400 text-xs">
No cover
</div>
</div>
<div class="flex-1">
<div class="font-medium">{{ result.title }}</div>
<div class="text-sm text-gray-500">{{ result.year }}</div>
<div class="text-xs text-gray-400 mt-1">Source: {{ result.source }}</div>
<div class="mt-2 flex gap-2">
<button
v-if="result.coverUrl"
@click="selectGame(result.title)"
class="text-xs bg-purple-100 text-purple-700 px-2 py-1 rounded hover:bg-purple-200"
>
Apply Cover
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Empty State -->
<div v-else-if="searchQuery && !isSearching" class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-12 text-center">
<p class="text-gray-500">No results found for "{{ searchQuery }}".</p>
</div>
</div>
</div>
</AppLayout>
</template>