Search existing books

This commit is contained in:
2025-10-14 00:29:53 +02:00
parent f72318b5bc
commit bb0ede6abd
13 changed files with 156 additions and 3 deletions

View File

@@ -8,6 +8,7 @@
"name": "personal-library-manager",
"version": "0.0.0",
"dependencies": {
"bootstrap-icons-vue": "^1.11.3",
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-i18n": "^11.1.12",
@@ -1961,6 +1962,12 @@
"dev": true,
"license": "ISC"
},
"node_modules/bootstrap-icons-vue": {
"version": "1.11.3",
"resolved": "https://registry.npmjs.org/bootstrap-icons-vue/-/bootstrap-icons-vue-1.11.3.tgz",
"integrity": "sha512-Xba1GTDYon8KYSDTKiiAtiyfk4clhdKQYvCQPMkE58+F5loVwEmh0Wi+ECCfowNc9SGwpoSLpSkvg7rhgZBttw==",
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",

View File

@@ -14,6 +14,7 @@
"format": "prettier --write src/"
},
"dependencies": {
"bootstrap-icons-vue": "^1.11.3",
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-i18n": "^11.1.12",

View File

@@ -0,0 +1,47 @@
<script setup>
const props = defineProps({
title: String,
author: String,
imagePath: String,
});
const imagePathOrDefault = (props.imagePath == "" || typeof props.imagePath === 'undefined') ? "../defaultbook.png" : props.imagePath;
</script>
<template>
<div class="box container has-background-dark">
<div class="media">
<div class="media-left">
<figure class="image mb-3">
<img v-bind:src="imagePathOrDefault" v-bind:alt="title">
</figure>
</div>
<div class="media-content">
<div class="is-size-4">{{title}}</div>
<div class="is-size-5 is-italic">{{author}}</div>
</div>
</div>
</div>
</template>
<style scoped>
img {
max-height:100px;
max-width:100px;
height:auto;
width:auto;
}
.box {
transition:ease-in-out 0.04s;
margin-bottom: 15px;
}
.box:hover {
transform: scale(1.01);
transition: ease-in-out 0.02s;
}
</style>

View File

@@ -14,7 +14,7 @@
<div class="navbar-item">
<div class="field has-addons">
<div class="control">
<input v-model="searchterm" class="input" type="text" />
<input v-model="searchterm" @keyup.enter="onSearchClick()" class="input" type="text" />
</div>
<div class="control">
<button @click="onSearchClick()" class="button">

View File

@@ -1,11 +1,31 @@
<script setup>
import BookListElement from './BookListElement.vue';
import { getSearchBooks } from './api.js'
import { onBeforeRouteUpdate } from 'vue-router'
const props = defineProps({
searchterm: String
});
let { data, error } = getSearchBooks(props.searchterm);
onBeforeRouteUpdate(async (to, from) => {
let res = getSearchBooks(to.params.searchterm);
data = res.data;
error = res.error;
})
</script>
<template>
<div> You are searching for {{ searchterm }} </div>
<div class="booksearch">
<div v-if="error">{{$t('searchbook.error', {error: error.message})}}</div>
<div class="booksearchlist" v-else-if="data && data.length > 0" v-for="book in data" :key="book.id">
<BookListElement v-bind="book" />
</div>
<div v-else-if="data === null">{{$t('searchbook.loading')}}</div>
<div v-else>{{$t('searchbook.noresult')}}</div>
</div>
</template>
<style scoped></style>

View File

@@ -28,6 +28,10 @@ export function getMyBooks() {
return useFetch(baseUrl + '/mybooks');
}
export function getSearchBooks(searchterm) {
return useFetch(baseUrl + '/search/' + searchterm);
}
export function postBook(book) {
return genericPostCall('/book', book.value)
}

View File

@@ -28,5 +28,10 @@
"bookbrowser": {
"error": "Error when loading books: {error}",
"loading": "Loading..."
},
"searchbook": {
"error": "Error when loading books: {error}",
"loading": "Loading...",
"noresult": "No results found."
}
}

View File

@@ -28,5 +28,10 @@
"bookbrowser": {
"error": "Erreur pendant le chargement des livres: {error}",
"loading": "Chargement..."
},
"searchbook": {
"error": "Erreur pendant le chargement des livres: {error}",
"loading": "Chargement...",
"noresult": "Aucun résultat trouvé."
}
}