Detailseite: Auslagern der Detailseite in kleine Komponenten
This commit is contained in:
parent
604facd288
commit
b20ba213e7
9
components.d.ts
vendored
9
components.d.ts
vendored
@ -26,6 +26,10 @@ declare module 'vue' {
|
|||||||
AppStepper: typeof import('./src/@core/components/AppStepper.vue')['default']
|
AppStepper: typeof import('./src/@core/components/AppStepper.vue')['default']
|
||||||
AppTextarea: typeof import('./src/@core/components/app-form-elements/AppTextarea.vue')['default']
|
AppTextarea: typeof import('./src/@core/components/app-form-elements/AppTextarea.vue')['default']
|
||||||
AppTextField: typeof import('./src/@core/components/app-form-elements/AppTextField.vue')['default']
|
AppTextField: typeof import('./src/@core/components/app-form-elements/AppTextField.vue')['default']
|
||||||
|
BookActions: typeof import('./src/components/bookdetail/BookActions.vue')['default']
|
||||||
|
BookDetails: typeof import('./src/components/bookdetail/BookDetails.vue')['default']
|
||||||
|
BookShops: typeof import('./src/components/bookdetail/BookShops.vue')['default']
|
||||||
|
BookStats: typeof import('./src/components/bookdetail/BookStats.vue')['default']
|
||||||
Buchkarten: typeof import('./src/components/Buchkarten.vue')['default']
|
Buchkarten: typeof import('./src/components/Buchkarten.vue')['default']
|
||||||
Buecherdatenbank: typeof import('./src/pages/buecherdatenbank.vue')['default']
|
Buecherdatenbank: typeof import('./src/pages/buecherdatenbank.vue')['default']
|
||||||
BuyNow: typeof import('./src/@core/components/BuyNow.vue')['default']
|
BuyNow: typeof import('./src/@core/components/BuyNow.vue')['default']
|
||||||
@ -48,17 +52,22 @@ declare module 'vue' {
|
|||||||
ErrorHeader: typeof import('./src/components/ErrorHeader.vue')['default']
|
ErrorHeader: typeof import('./src/components/ErrorHeader.vue')['default']
|
||||||
Fieberkurve: typeof import('./src/components/Fieberkurve.vue')['default']
|
Fieberkurve: typeof import('./src/components/Fieberkurve.vue')['default']
|
||||||
I18n: typeof import('./src/@core/components/I18n.vue')['default']
|
I18n: typeof import('./src/@core/components/I18n.vue')['default']
|
||||||
|
MoreBooksFromAuthor: typeof import('./src/components/bookdetail/MoreBooksFromAuthor.vue')['default']
|
||||||
MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default']
|
MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default']
|
||||||
Notifications: typeof import('./src/@core/components/Notifications.vue')['default']
|
Notifications: typeof import('./src/@core/components/Notifications.vue')['default']
|
||||||
PaymentProvidersDialog: typeof import('./src/components/dialogs/PaymentProvidersDialog.vue')['default']
|
PaymentProvidersDialog: typeof import('./src/components/dialogs/PaymentProvidersDialog.vue')['default']
|
||||||
PricingPlanDialog: typeof import('./src/components/dialogs/PricingPlanDialog.vue')['default']
|
PricingPlanDialog: typeof import('./src/components/dialogs/PricingPlanDialog.vue')['default']
|
||||||
ProductDescriptionEditor: typeof import('./src/@core/components/ProductDescriptionEditor.vue')['default']
|
ProductDescriptionEditor: typeof import('./src/@core/components/ProductDescriptionEditor.vue')['default']
|
||||||
ReferAndEarnDialog: typeof import('./src/components/dialogs/ReferAndEarnDialog.vue')['default']
|
ReferAndEarnDialog: typeof import('./src/components/dialogs/ReferAndEarnDialog.vue')['default']
|
||||||
|
ReviewForm: typeof import('./src/components/bookdetail/ReviewForm.vue')['default']
|
||||||
|
Reviews: typeof import('./src/components/bookdetail/Reviews.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
ScrollToTop: typeof import('./src/@core/components/ScrollToTop.vue')['default']
|
ScrollToTop: typeof import('./src/@core/components/ScrollToTop.vue')['default']
|
||||||
ShareProjectDialog: typeof import('./src/components/dialogs/ShareProjectDialog.vue')['default']
|
ShareProjectDialog: typeof import('./src/components/dialogs/ShareProjectDialog.vue')['default']
|
||||||
|
ShopButtons: typeof import('./src/components/bookdetail/ShopButtons.vue')['default']
|
||||||
Shortcuts: typeof import('./src/@core/components/Shortcuts.vue')['default']
|
Shortcuts: typeof import('./src/@core/components/Shortcuts.vue')['default']
|
||||||
|
SimilarBooks: typeof import('./src/components/bookdetail/SimilarBooks.vue')['default']
|
||||||
TablePagination: typeof import('./src/@core/components/TablePagination.vue')['default']
|
TablePagination: typeof import('./src/@core/components/TablePagination.vue')['default']
|
||||||
TheCustomizer: typeof import('./src/@core/components/TheCustomizer.vue')['default']
|
TheCustomizer: typeof import('./src/@core/components/TheCustomizer.vue')['default']
|
||||||
ThemeSwitcher: typeof import('./src/@core/components/ThemeSwitcher.vue')['default']
|
ThemeSwitcher: typeof import('./src/@core/components/ThemeSwitcher.vue')['default']
|
||||||
|
|||||||
75
src/components/bookdetail/BookActions.vue
Normal file
75
src/components/bookdetail/BookActions.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="pa-3 mb-4" variant="outlined">
|
||||||
|
<VCardTitle>Deine Aktionen</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<VBtn :color="liked ? 'primary' : 'grey'" @click="toggleLike" variant="outlined">
|
||||||
|
<VIcon
|
||||||
|
start
|
||||||
|
:icon="liked ? 'tabler-heart-filled' : 'tabler-heart'"
|
||||||
|
class="transition-transform"
|
||||||
|
:class="liked ? 'scale-125' : ''"
|
||||||
|
/>
|
||||||
|
{{ liked ? 'Gefällt mir' : 'Gefällt mir nicht mehr' }}
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn :color="readingStatus ? 'primary' : 'grey'" @click="toggleReadingStatus" variant="outlined">
|
||||||
|
<VIcon icon="tabler-book" start />
|
||||||
|
{{ readingStatus ? 'Gelesen' : 'Noch nicht gelesen' }}
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn :color="wishlist ? 'primary' : 'grey'" @click="toggleWishlist" variant="outlined">
|
||||||
|
<VIcon icon="tabler-bookmark" start />
|
||||||
|
{{ wishlist ? 'Auf der Wunschliste' : 'Zur Wunschliste' }}
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn :color="collection ? 'primary' : 'grey'" @click="toggleCollection" variant="outlined">
|
||||||
|
<VIcon icon="tabler-archive" start />
|
||||||
|
{{ collection ? 'In Sammlung' : 'Zur Sammlung hinzufügen' }}
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
|
||||||
|
<!-- Snackbar -->
|
||||||
|
<VSnackbar v-model="snackbar" :timeout="2000" location="top right" color="success">
|
||||||
|
{{ snackbarText }}
|
||||||
|
</VSnackbar>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const liked = ref(false)
|
||||||
|
const readingStatus = ref(false)
|
||||||
|
const wishlist = ref(false)
|
||||||
|
const collection = ref(false)
|
||||||
|
|
||||||
|
const snackbar = ref(false)
|
||||||
|
const snackbarText = ref('')
|
||||||
|
|
||||||
|
function showFeedback(text) {
|
||||||
|
snackbarText.value = text
|
||||||
|
snackbar.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleLike() {
|
||||||
|
liked.value = !liked.value
|
||||||
|
showFeedback(liked.value ? 'Zur Favoritenliste hinzugefügt ✅' : 'Aus Favoriten entfernt ❌')
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleReadingStatus() {
|
||||||
|
readingStatus.value = !readingStatus.value
|
||||||
|
showFeedback(readingStatus.value ? 'Als gelesen markiert 📘' : 'Markierung entfernt ❌')
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWishlist() {
|
||||||
|
wishlist.value = !wishlist.value
|
||||||
|
showFeedback(wishlist.value ? 'Zur Wunschliste hinzugefügt 🎁' : 'Von Wunschliste entfernt ❌')
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleCollection() {
|
||||||
|
collection.value = !collection.value
|
||||||
|
showFeedback(collection.value ? 'Zur Sammlung hinzugefügt 📚' : 'Aus Sammlung entfernt ❌')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
24
src/components/bookdetail/BookDetails.vue
Normal file
24
src/components/bookdetail/BookDetails.vue
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<template>
|
||||||
|
<VCard
|
||||||
|
class="pa-3 elevation-1"
|
||||||
|
variant="outlined"
|
||||||
|
style="border-left: 6px solid var(--v-theme-primary); background-color: #f9f9ff"
|
||||||
|
>
|
||||||
|
<VCardTitle>
|
||||||
|
<VIcon icon="tabler-info-circle" start /> Buchdetails
|
||||||
|
</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<strong>ISBN:</strong> {{ book.isbn || '–' }}<br />
|
||||||
|
<strong>Sprache:</strong> {{ book.language }}<br />
|
||||||
|
<strong>Seiten:</strong> {{ book.pageCount }}<br />
|
||||||
|
<strong>Verlag:</strong> {{ book.publishers || '–' }}<br />
|
||||||
|
<strong>Veröffentlicht:</strong> {{ book.publishedDate }}
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
book: Object,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
56
src/components/bookdetail/BookShops.vue
Normal file
56
src/components/bookdetail/BookShops.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="pa-3 mb-4" variant="outlined">
|
||||||
|
<VCardTitle>Shops</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #FF9900; background-color: #FFF3E0;"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-brand-amazon" /> Amazon
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #005B9F; background-color: #E3F2FD;"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-book" /> Hugendubel
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #333333; background-color: #F5F5F5;"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-brand-apple" /> Apple
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #009245; background-color: #E8F5E9;"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-book-2" /> Thalia
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// keine Props nötig – statisch dargestellt
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.shop-btn:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
16
src/components/bookdetail/BookStats.vue
Normal file
16
src/components/bookdetail/BookStats.vue
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="pa-3" variant="outlined">
|
||||||
|
<VCardTitle>Community-Statistik</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<VList density="compact">
|
||||||
|
<VListItem prepend-icon="tabler-library">In 47 Bibliotheken</VListItem>
|
||||||
|
<VListItem prepend-icon="tabler-bookmark">Auf 20 Merkzettel</VListItem>
|
||||||
|
<VListItem prepend-icon="tabler-book">4 Leser*innen lesen es gerade</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// Kein extra Code notwendig
|
||||||
|
</script>
|
||||||
48
src/components/bookdetail/MoreBooksFromAuthor.vue
Normal file
48
src/components/bookdetail/MoreBooksFromAuthor.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="authorName && booksByAuthor.length">
|
||||||
|
<VCard class="mt-6" elevation="0">
|
||||||
|
<VCardTitle>Weitere Bücher von {{ authorName }}</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="b in booksByAuthor"
|
||||||
|
:key="b.id"
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
|
<RouterLink :to="`/buchdetailseite/${b.id}`">
|
||||||
|
<VCard class="hover:scale-105 transition-transform duration-200">
|
||||||
|
<VImg :src="b.image" height="180" cover />
|
||||||
|
<VCardText class="text-sm font-semibold">
|
||||||
|
{{ b.title }}
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</RouterLink>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed} from 'vue'
|
||||||
|
import {books} from '@/components/buecherdatenbank'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
book: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const authorName = computed(() => props.book?.authors?.[0]?.name || '')
|
||||||
|
|
||||||
|
const booksByAuthor = computed(() => {
|
||||||
|
if (!authorName.value) return []
|
||||||
|
return books.filter(
|
||||||
|
b => b.authors?.[0]?.name === authorName.value && b.id !== props.book.id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
45
src/components/bookdetail/ReviewForm.vue
Normal file
45
src/components/bookdetail/ReviewForm.vue
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="mt-6" variant="outlined">
|
||||||
|
<VCardTitle>
|
||||||
|
<VIcon icon="tabler-pencil" start />
|
||||||
|
Eigene Rezension schreiben
|
||||||
|
</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<VTextarea
|
||||||
|
v-model="reviewText"
|
||||||
|
label="Was denkst du über dieses Buch?"
|
||||||
|
rows="3"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
<div class="mt-2 d-flex align-center justify-space-between">
|
||||||
|
<div class="d-flex align-center gap-2">
|
||||||
|
<span>Bewertung:</span>
|
||||||
|
<VRating v-model="reviewRating" color="primary" />
|
||||||
|
</div>
|
||||||
|
<VBtn :disabled="!canSubmit" color="primary" @click="submitReview">
|
||||||
|
Absenden
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const reviewText = ref('')
|
||||||
|
const reviewRating = ref(0)
|
||||||
|
|
||||||
|
const canSubmit = computed(() => {
|
||||||
|
return reviewText.value.trim().length > 0 && reviewRating.value > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
function submitReview() {
|
||||||
|
console.log('Neue Rezension:', {
|
||||||
|
text: reviewText.value,
|
||||||
|
rating: reviewRating.value,
|
||||||
|
})
|
||||||
|
reviewText.value = ''
|
||||||
|
reviewRating.value = 0
|
||||||
|
}
|
||||||
|
</script>
|
||||||
44
src/components/bookdetail/Reviews.vue
Normal file
44
src/components/bookdetail/Reviews.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="mt-6" variant="outlined">
|
||||||
|
<VCardTitle>
|
||||||
|
<VIcon icon="tabler-star" start /> Rezensionen & Bewertungen
|
||||||
|
</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<VCard
|
||||||
|
v-for="(review, index) in reviews"
|
||||||
|
:key="index"
|
||||||
|
class="mb-3 pa-3"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
|
<div class="d-flex justify-space-between align-center">
|
||||||
|
<span><strong>{{ review.name }}</strong> am {{ review.date }}</span>
|
||||||
|
<VRating v-model="review.rating" readonly density="compact" size="small" />
|
||||||
|
</div>
|
||||||
|
<p class="mt-2">{{ review.text }}</p>
|
||||||
|
</VCard>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const reviews = [
|
||||||
|
{
|
||||||
|
name: 'Anna L.',
|
||||||
|
date: '03.04.2025',
|
||||||
|
rating: 4,
|
||||||
|
text: 'Ein inspirierendes Buch – hat mich zum Nachdenken gebracht!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Jonas M.',
|
||||||
|
date: '18.02.2025',
|
||||||
|
rating: 3,
|
||||||
|
text: 'Starker Mittelteil, etwas schwaches Ende. Trotzdem lesenswert.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'LeserIn',
|
||||||
|
date: '22.01.2025',
|
||||||
|
rating: 5,
|
||||||
|
text: 'Ich konnte es nicht aus der Hand legen! Spannung pur.',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
55
src/components/bookdetail/ShopButtons.vue
Normal file
55
src/components/bookdetail/ShopButtons.vue
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="pa-3 mb-4" variant="outlined">
|
||||||
|
<VCardTitle>Shops</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<div class="d-flex flex-column gap-2">
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #FF9900; background-color: #FFF3E0"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-brand-amazon" /> Amazon
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #005B9F; background-color: #E3F2FD"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-book" /> Hugendubel
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #333333; background-color: #F5F5F5"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-brand-apple" /> Apple
|
||||||
|
</VBtn>
|
||||||
|
|
||||||
|
<VBtn
|
||||||
|
block
|
||||||
|
variant="outlined"
|
||||||
|
style="border-color: #009245; background-color: #E8F5E9"
|
||||||
|
class="text-black shop-btn"
|
||||||
|
>
|
||||||
|
<VIcon start icon="tabler-book-2" /> Thalia
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// keine Props nötig aktuell
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.shop-btn:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
34
src/components/bookdetail/SimilarBooks.vue
Normal file
34
src/components/bookdetail/SimilarBooks.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<VCard class="mt-6" elevation="0">
|
||||||
|
<VCardTitle>Ähnliche Bücher</VCardTitle>
|
||||||
|
<VCardText>
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="similar in similarBooks"
|
||||||
|
:key="similar.id"
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
|
<RouterLink :to="`/buchdetailseite/${similar.id}`">
|
||||||
|
<VCard class="hover:scale-105 transition-transform duration-200">
|
||||||
|
<VImg :src="similar.image" height="180" cover />
|
||||||
|
<VCardText>
|
||||||
|
<div class="text-sm font-semibold">{{ similar.title }}</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</RouterLink>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
similarBooks: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -2,84 +2,20 @@
|
|||||||
<VContainer class="py-6">
|
<VContainer class="py-6">
|
||||||
<VCard class="pa-4" elevation="2">
|
<VCard class="pa-4" elevation="2">
|
||||||
<VRow>
|
<VRow>
|
||||||
<!-- Cover & Blöcke -->
|
<!-- Linke Spalte -->
|
||||||
<VCol cols="12" md="3">
|
<VCol cols="12" md="3">
|
||||||
<div class="mb-4" style="aspect-ratio: 2/3; overflow: hidden;">
|
<div class="mb-4" style="aspect-ratio: 2/3; overflow: hidden;">
|
||||||
<VImg :src="book.image" height="100%" width="100%" cover class="elevation-1" />
|
<VImg :src="book.image" height="100%" width="100%" cover class="elevation-1" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Shoplinks mit Farben -->
|
<BookShops />
|
||||||
<VCard class="pa-3 mb-4" variant="outlined">
|
<BookActions />
|
||||||
<VCardTitle>Shops</VCardTitle>
|
<BookStats />
|
||||||
<VCardText>
|
|
||||||
<div class="d-flex flex-column gap-2">
|
|
||||||
|
|
||||||
<VBtn block variant="outlined" style="border-color: #FF9900; background-color: #FFF3E0;" class="text-black shop-btn">
|
|
||||||
<VIcon start icon="tabler-brand-amazon" /> Amazon
|
|
||||||
</VBtn>
|
|
||||||
|
|
||||||
<VBtn block variant="outlined" style="border-color: #005B9F; background-color: #E3F2FD;" class="text-black shop-btn">
|
|
||||||
<VIcon start icon="tabler-book" /> Hugendubel
|
|
||||||
</VBtn>
|
|
||||||
|
|
||||||
<VBtn block variant="outlined" style="border-color: #333333; background-color: #F5F5F5;" class="text-black shop-btn">
|
|
||||||
<VIcon start icon="tabler-brand-apple" /> Apple
|
|
||||||
</VBtn>
|
|
||||||
|
|
||||||
<VBtn block variant="outlined" style="border-color: #009245; background-color: #E8F5E9;" class="text-black shop-btn">
|
|
||||||
<VIcon start icon="tabler-book-2" /> Thalia
|
|
||||||
</VBtn>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
|
|
||||||
<!-- Benutzeraktionen -->
|
|
||||||
<VCard class="pa-3 mb-4" variant="outlined">
|
|
||||||
<VCardTitle>Deine Aktionen</VCardTitle>
|
|
||||||
<VCardText>
|
|
||||||
<div class="d-flex flex-column gap-2">
|
|
||||||
<VBtn :color="liked ? 'primary' : 'grey'" @click="toggleLike" variant="outlined">
|
|
||||||
<VIcon
|
|
||||||
start
|
|
||||||
:icon="liked ? 'tabler-heart-filled' : 'tabler-heart'"
|
|
||||||
class="transition-transform"
|
|
||||||
:class="liked ? 'scale-125' : ''"
|
|
||||||
/>
|
|
||||||
{{ liked ? 'Gefällt mir' : 'Gefällt mir nicht mehr' }}
|
|
||||||
</VBtn>
|
|
||||||
<VBtn :color="readingStatus ? 'primary' : 'grey'" @click="toggleReadingStatus" variant="outlined">
|
|
||||||
<VIcon icon="tabler-book" start />
|
|
||||||
{{ readingStatus ? 'Gelesen' : 'Noch nicht gelesen' }}
|
|
||||||
</VBtn>
|
|
||||||
<VBtn :color="wishlist ? 'primary' : 'grey'" @click="toggleWishlist" variant="outlined">
|
|
||||||
<VIcon icon="tabler-bookmark" start />
|
|
||||||
{{ wishlist ? 'Auf der Wunschliste' : 'Zur Wunschliste' }}
|
|
||||||
</VBtn>
|
|
||||||
<VBtn :color="collection ? 'primary' : 'grey'" @click="toggleCollection" variant="outlined">
|
|
||||||
<VIcon icon="tabler-archive" start />
|
|
||||||
{{ collection ? 'In Sammlung' : 'Zur Sammlung hinzufügen' }}
|
|
||||||
</VBtn>
|
|
||||||
</div>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
|
|
||||||
<!-- Community-Statistik -->
|
|
||||||
<VCard class="pa-3" variant="outlined">
|
|
||||||
<VCardTitle>Community-Statistik</VCardTitle>
|
|
||||||
<VCardText>
|
|
||||||
<VList density="compact">
|
|
||||||
<VListItem prepend-icon="tabler-library">In 47 Bibliotheken</VListItem>
|
|
||||||
<VListItem prepend-icon="tabler-bookmark">Auf 20 Merkzettel</VListItem>
|
|
||||||
<VListItem prepend-icon="tabler-book">4 Leser*innen lesen es gerade</VListItem>
|
|
||||||
</VList>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
</VCol>
|
</VCol>
|
||||||
|
|
||||||
<!-- Hauptbereich -->
|
<!-- Rechte Spalte -->
|
||||||
<VCol cols="12" md="9">
|
<VCol cols="12" md="9">
|
||||||
|
<!-- Titel & Autor -->
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h1 class="text-h4 font-weight-bold mb-1">{{ book.title }}</h1>
|
<h1 class="text-h4 font-weight-bold mb-1">{{ book.title }}</h1>
|
||||||
<h2 class="text-subtitle-1">von {{ book.authors[0]?.name }}</h2>
|
<h2 class="text-subtitle-1">von {{ book.authors[0]?.name }}</h2>
|
||||||
@ -99,18 +35,25 @@
|
|||||||
</VChip>
|
</VChip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<VRow class="mb-4">
|
||||||
<!-- Fieberkurve -->
|
<!-- Fieberkurve -->
|
||||||
<VCard class="mb-6 elevation-3" variant="outlined" style="border: 2px dashed var(--v-theme-primary);">
|
<VCol cols="12" md="8">
|
||||||
|
<VCard class="elevation-3" variant="outlined" style="border: 2px dashed var(--v-theme-primary);">
|
||||||
<VCardTitle>
|
<VCardTitle>
|
||||||
<VIcon icon="tabler-activity" start /> Fieberkurve (Lesedynamik)
|
<VIcon icon="tabler-activity" start /> Fieberkurve (Lesedynamik)
|
||||||
</VCardTitle>
|
</VCardTitle>
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<Fieberkurve :isStatic="true" :defaultValues="book.fieberkurve" class="mb-2" />
|
<Fieberkurve :isStatic="true" :defaultValues="book.fieberkurve" class="mb-2" />
|
||||||
<!-- <p class="text-caption text-muted">
|
|
||||||
Die Skoutz-Fieberkurve zeigt, wie emotional spannend das Buch im Verlauf empfunden wird.
|
|
||||||
</p>-->
|
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
|
||||||
|
<!-- Buchdetails -->
|
||||||
|
<VCol cols="12" md="4">
|
||||||
|
<BookDetails :book="book" />
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
|
||||||
|
|
||||||
<!-- Inhaltsangabe -->
|
<!-- Inhaltsangabe -->
|
||||||
<VCard class="mb-4 elevation-1" variant="outlined" style="border-left: 6px solid var(--v-theme-primary); background-color: #f9f9ff;">
|
<VCard class="mb-4 elevation-1" variant="outlined" style="border-left: 6px solid var(--v-theme-primary); background-color: #f9f9ff;">
|
||||||
@ -120,23 +63,7 @@
|
|||||||
<VCardText class="text-body-1">{{ book.blurb }}</VCardText>
|
<VCardText class="text-body-1">{{ book.blurb }}</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
<!-- Buchdetails & Infos -->
|
<!-- Weitere Informationen -->
|
||||||
<VRow>
|
|
||||||
<VCol cols="12" md="6">
|
|
||||||
<VCard class="pa-3 elevation-1" variant="outlined" style="border-left: 6px solid var(--v-theme-primary); background-color: #f9f9ff;">
|
|
||||||
<VCardTitle>
|
|
||||||
<VIcon icon="tabler-info-circle" start /> Buchdetails
|
|
||||||
</VCardTitle>
|
|
||||||
<VCardText>
|
|
||||||
<strong>ISBN:</strong> {{ book.isbn || '–' }}<br />
|
|
||||||
<strong>Sprache:</strong> {{ book.language }}<br />
|
|
||||||
<strong>Seiten:</strong> {{ book.pageCount }}<br />
|
|
||||||
<strong>Verlag:</strong> {{ book.publishers || '–' }}<br />
|
|
||||||
<strong>Veröffentlicht:</strong> {{ book.publishedDate }}
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
</VCol>
|
|
||||||
<VCol cols="12" md="6">
|
|
||||||
<VCard class="pa-3 elevation-1" variant="outlined">
|
<VCard class="pa-3 elevation-1" variant="outlined">
|
||||||
<VCardTitle>
|
<VCardTitle>
|
||||||
<VIcon icon="tabler-link" start /> Weitere Informationen
|
<VIcon icon="tabler-link" start /> Weitere Informationen
|
||||||
@ -152,95 +79,25 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VCol>
|
|
||||||
</VRow>
|
|
||||||
|
|
||||||
<!-- Bücher vom gleichen Autor -->
|
|
||||||
<VCard class="mt-6" elevation="0">
|
|
||||||
<VCardTitle>Weitere Bücher von {{ book.authors[0]?.name }}</VCardTitle>
|
|
||||||
<VCardText>
|
|
||||||
<VRow>
|
|
||||||
<VCol
|
|
||||||
v-for="b in authorBooks"
|
|
||||||
:key="b.id"
|
|
||||||
cols="12"
|
|
||||||
sm="6"
|
|
||||||
md="3"
|
|
||||||
>
|
|
||||||
<RouterLink :to="`/buchdetailseite/${b.id}`">
|
|
||||||
<VCard class="hover:scale-105 transition-transform duration-200">
|
|
||||||
<VImg :src="b.image" height="180" cover />
|
|
||||||
<VCardText class="text-sm font-semibold">
|
|
||||||
{{ b.title }}
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
</RouterLink>
|
|
||||||
</VCol>
|
|
||||||
</VRow>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Weitere Bücher vom Autor -->
|
||||||
|
<MoreBooksFromAuthor :book="book" />
|
||||||
|
|
||||||
<!-- Rezensionen -->
|
<!-- Rezensionen -->
|
||||||
<VCard class="mt-6" variant="outlined">
|
<Reviews :reviews="reviews" />
|
||||||
<VCardTitle><VIcon icon="tabler-star" start /> Rezensionen & Bewertungen</VCardTitle>
|
<ReviewForm />
|
||||||
<VCardText>
|
|
||||||
<VCard
|
|
||||||
v-for="(review, index) in reviews"
|
|
||||||
:key="index"
|
|
||||||
class="mb-3 pa-3"
|
|
||||||
variant="outlined"
|
|
||||||
>
|
|
||||||
<div class="d-flex justify-space-between align-center">
|
|
||||||
<span><strong>{{ review.name }}</strong> am {{ review.date }}</span>
|
|
||||||
<VRating v-model="review.rating" readonly density="compact" size="small" />
|
|
||||||
</div>
|
|
||||||
<p class="mt-2">{{ review.text }}</p>
|
|
||||||
</VCard>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
<!-- eigene Rezensionen abgeben -->
|
|
||||||
<VCardText>
|
|
||||||
<VTextarea label="Eigene Rezension schreiben" rows="3" variant="outlined" />
|
|
||||||
<VBtn color="primary" class="mt-2">Absenden</VBtn>
|
|
||||||
</VCardText>
|
|
||||||
|
|
||||||
|
<!-- Ähnliche Bücher -->
|
||||||
|
<SimilarBooks :similarBooks="similarBooks" />
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCard>
|
||||||
|
|
||||||
<!-- Snackbar -->
|
<!-- Snackbar -->
|
||||||
<VSnackbar v-model="snackbar" :timeout="2000" location="top right" color="success">
|
<VSnackbar v-model="snackbar" :timeout="2000" location="top right" color="success">
|
||||||
{{ snackbarText }}
|
{{ snackbarText }}
|
||||||
</VSnackbar>
|
</VSnackbar>
|
||||||
|
|
||||||
<!-- Ähnliche Bücher -->
|
|
||||||
<VCard class="mt-6" elevation="0">
|
|
||||||
<VCardTitle>Ähnliche Bücher</VCardTitle>
|
|
||||||
<VCardText>
|
|
||||||
<VRow>
|
|
||||||
<VCol
|
|
||||||
v-for="similar in similarBooks"
|
|
||||||
:key="similar.id"
|
|
||||||
cols="12"
|
|
||||||
sm="6"
|
|
||||||
md="3"
|
|
||||||
>
|
|
||||||
<RouterLink :to="`/buchdetailseite/${similar.id}`">
|
|
||||||
<VCard class="hover:scale-105 transition-transform duration-200">
|
|
||||||
<VImg :src="similar.image" height="180" cover />
|
|
||||||
<VCardText>
|
|
||||||
<div class="text-sm font-semibold">{{ similar.title }}</div>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
</RouterLink>
|
|
||||||
</VCol>
|
|
||||||
</VRow>
|
|
||||||
</VCardText>
|
|
||||||
</VCard>
|
|
||||||
</VCol>
|
|
||||||
</VRow>
|
|
||||||
</VCard>
|
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -250,16 +107,21 @@ import { useRoute } from 'vue-router'
|
|||||||
import { books } from '@/components/buecherdatenbank'
|
import { books } from '@/components/buecherdatenbank'
|
||||||
import Fieberkurve from '@/components/Fieberkurve.vue'
|
import Fieberkurve from '@/components/Fieberkurve.vue'
|
||||||
|
|
||||||
|
// Komponenten
|
||||||
|
import BookShops from '@/components/bookdetail/BookShops.vue'
|
||||||
|
import BookActions from '@/components/bookdetail/BookActions.vue'
|
||||||
|
import BookStats from '@/components/bookdetail/BookStats.vue'
|
||||||
|
import BookDetails from '@/components/bookdetail/BookDetails.vue'
|
||||||
|
import MoreBooksFromAuthor from '@/components/bookdetail/MoreBooksFromAuthor.vue'
|
||||||
|
import Reviews from '@/components/bookdetail/Reviews.vue'
|
||||||
|
import ReviewForm from '@/components/bookdetail/ReviewForm.vue'
|
||||||
|
import SimilarBooks from '@/components/bookdetail/SimilarBooks.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const id = parseInt(route.params.id)
|
const id = parseInt(route.params.id)
|
||||||
const book = books.find(b => b.id === id) || {}
|
const book = books.find(b => b.id === id) || {}
|
||||||
|
|
||||||
const liked = ref(false)
|
|
||||||
const readingStatus = ref(false)
|
|
||||||
const wishlist = ref(false)
|
|
||||||
const collection = ref(false)
|
|
||||||
const snackbar = ref(false)
|
const snackbar = ref(false)
|
||||||
snackbar.value = false
|
|
||||||
const snackbarText = ref('')
|
const snackbarText = ref('')
|
||||||
|
|
||||||
function showFeedback(text) {
|
function showFeedback(text) {
|
||||||
@ -267,23 +129,6 @@ function showFeedback(text) {
|
|||||||
snackbar.value = true
|
snackbar.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleLike() {
|
|
||||||
liked.value = !liked.value
|
|
||||||
showFeedback(liked.value ? 'Zur Favoritenliste hinzugefügt ✅' : 'Aus Favoriten entfernt ❌')
|
|
||||||
}
|
|
||||||
function toggleReadingStatus() {
|
|
||||||
readingStatus.value = !readingStatus.value
|
|
||||||
showFeedback(readingStatus.value ? 'Als gelesen markiert 📘' : 'Markierung entfernt ❌')
|
|
||||||
}
|
|
||||||
function toggleWishlist() {
|
|
||||||
wishlist.value = !wishlist.value
|
|
||||||
showFeedback(wishlist.value ? 'Zur Wunschliste hinzugefügt 🎁' : 'Von Wunschliste entfernt ❌')
|
|
||||||
}
|
|
||||||
function toggleCollection() {
|
|
||||||
collection.value = !collection.value
|
|
||||||
showFeedback(collection.value ? 'Zur Sammlung hinzugefügt 📚' : 'Aus Sammlung entfernt ❌')
|
|
||||||
}
|
|
||||||
|
|
||||||
const authorBooks = computed(() => {
|
const authorBooks = computed(() => {
|
||||||
if (!book?.authors?.[0]?.name) return []
|
if (!book?.authors?.[0]?.name) return []
|
||||||
return books.filter(b => b.authors?.[0]?.name === book.authors[0].name && b.id !== book.id)
|
return books.filter(b => b.authors?.[0]?.name === book.authors[0].name && b.id !== book.id)
|
||||||
@ -319,11 +164,3 @@ const genreIcon = genre => {
|
|||||||
return icons[genre] || 'tabler-book'
|
return icons[genre] || 'tabler-book'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.shop-btn:hover {
|
|
||||||
transform: scale(1.02);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user