Replace game with soundtrack terminology and add fuzzy/exact search
Build and Test / build (push) Successful in 24s
Release Docker Image / build-and-push (push) Successful in 12m29s

- Replace all 'game' references with 'soundtrack' throughout frontend (112 occurrences)
- Add radio buttons for fuzzy/exact search in SearchModal
- Fuzzy search is default and uses /findfuzzy endpoint
- Exact search uses existing /find endpoint
- Fix syntax errors in SyncProgressModal from previous refactoring

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Sansan committed 2026-07-03 23:06:30 +02:00
1 parent fb36038cc8
commit 8b5aa3adf0
10 files changed
+156 -114

No files matched your search

+60 -18
View File
@@ -4,20 +4,30 @@
<div class="modalContainer">
<div class="modalWrapper">
<span class="closeModalImg" @click="closeModal">&times;</span>
<h1>Search Games</h1>
<h1>Search Soundtracks</h1>
<div class="searchTypeContainer">
<label class="radioLabel">
<input type="radio" v-model="searchType" value="fuzzy">
<span>Fuzzy Search</span>
</label>
<label class="radioLabel">
<input type="radio" v-model="searchType" value="exact">
<span>Exact Search</span>
</label>
</div>
<div class="searchContainer">
<input
type="text"
v-model="searchTerm"
@input="debouncedSearch"
placeholder="Search for games..."
placeholder="Search for soundtracks..."
class="searchInput"
/>
<div v-if="searchTerm.length > 0" class="searchResults">
<div v-if="loading" class="loading">Searching...</div>
<div v-else-if="results.length > 0" class="resultsList">
<div v-for="game in results" :key="game" class="resultItem">
{{ game }}
<div v-for="soundtrack in results" :key="soundtrack" class="resultItem">
{{ soundtrack }}
</div>
</div>
<div v-else class="noResults">No results found</div>
@@ -38,6 +48,7 @@ export default {
results: [],
loading: false,
searchTimeout: null,
searchType: "fuzzy",
};
},
methods: {
@@ -45,6 +56,7 @@ export default {
this.show = true;
this.searchTerm = "";
this.results = [];
this.searchType = "fuzzy";
},
closeModal() {
this.show = false;
@@ -78,49 +90,70 @@ export default {
}
this.loading = true;
try {
const endpoint = this.searchType === 'fuzzy' ? '/findfuzzy' : '/find';
const response = await this.axios({
method: "post",
url: `${window.__RUNTIME_CONFIG__.API_HOSTNAME}/find`,
url: `${window.__RUNTIME_CONFIG__.API_HOSTNAME}${endpoint}`,
data: new URLSearchParams({ search_term: this.searchTerm }),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
// Parse games from HTML response
this.results = this.parseGamesFromResponse(response.data);
// Parse soundtracks from HTML response
this.results = this.parseSoundtracksFromResponse(response.data);
} catch (error) {
console.error("Error searching games:", error);
console.error("Error searching soundtracks:", error);
this.results = [];
} finally {
this.loading = false;
}
},
parseGamesFromResponse(htmlData) {
// The server returns HTML from FoundGames templ component
// It generates divs containing game names in <p> tags
const games = [];
parseSoundtracksFromResponse(htmlData) {
// The server returns HTML from FoundSoundtracks templ component
// It generates divs containing soundtrack names in <p> tags
const soundtracks = [];
const parser = new DOMParser();
const doc = parser.parseFromString(htmlData, "text/html");
// Find all p tags inside divs (the templ generates <div><p>{game}</p></div>)
// Find all p tags inside divs (the templ generates <div><p>{soundtrack}</p></div>)
const pTags = doc.querySelectorAll("div p");
for (const p of pTags) {
const gameName = p.textContent.trim();
if (gameName) {
games.push(gameName);
const soundtrackName = p.textContent.trim();
if (soundtrackName) {
soundtracks.push(soundtrackName);
}
}
return games;
return soundtracks;
},
},
};
</script>
<style scoped>
.searchTypeContainer {
display: flex;
gap: 20px;
margin-top: 15px;
margin-bottom: 15px;
}
.radioLabel {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 1rem;
}
.radioLabel input[type="radio"] {
margin: 0;
accent-color: #ff9c00;
}
.searchContainer {
width: 100%;
margin-top: 20px;
margin-top: 10px;
}
.searchInput {
@@ -177,6 +210,15 @@ export default {
}
@media only screen and (max-width: 1000px) {
.searchTypeContainer {
flex-wrap: wrap;
gap: 10px;
}
.radioLabel {
font-size: 0.9rem;
}
.searchInput {
font-size: 1rem;
padding: 10px;