fix: add book details

This commit is contained in:
Tim Rijkse
2026-01-16 08:51:28 +01:00
parent 7925172039
commit 337f5dbf5b
3 changed files with 470 additions and 147 deletions

158
book.html
View File

@@ -39,154 +39,18 @@
</site-header>
<site-content>
<div class="content-padding">
<push-box>
<img slot="logo" src="images/logo-asoka.png" alt="Asoka Logo" />
<h2 slot="title">
Gespecialiseerd op het vlak van boeddhisme en aanverwante
Oost-West thema's
</h2>
<arrow-button slot="cta" href="#">Meer over Asoka</arrow-button>
</push-box>
</div>
<section class="section section">
<section-title text="Recent verschenen boeken"></section-title>
<div class="book-grid">
<book-card
title="The Midnight Library"
description="A library of infinite possibilities"
author="Matt Haig"
price="$14.99"
rating="4.5"
href="book.html"
theme="dark"
></book-card>
<book-card
title="Atomic Habits"
description="A simple, proven system for breaking bad habits and forming good ones"
author="James Clear"
price="$16.99"
rating="5"
href="book.html"
theme="dark"
></book-card>
<book-card
title="The Psychology of Money"
description="A book about the psychology of money and how it affects our lives"
author="Morgan Housel"
price="$12.99"
rating="4"
href="book.html"
theme="dark"
></book-card>
<book-card
title="Project Hail Mary"
description="A book about the science of space travel and the future of humanity"
author="Andy Weir"
price="$18.99"
rating="4.5"
href="book.html"
theme="dark"
></book-card>
<cta-button href="#">Toon meer recent verschenen boeken</cta-button>
</div>
</section>
<section class="section section-dark">
<section-title text="Meest verkochte boeken"></section-title>
<div class="book-grid">
<book-card
title="The Midnight Library"
description="A library of infinite possibilities"
author="Matt Haig"
price="$14.99"
rating="4.5"
href="book.html"
></book-card>
<book-card
title="Atomic Habits"
description="A simple, proven system for breaking bad habits and forming good ones"
author="James Clear"
price="$16.99"
rating="5"
href="book.html"
></book-card>
<book-card
title="The Psychology of Money"
description="A book about the psychology of money and how it affects our lives"
author="Morgan Housel"
price="$12.99"
rating="4"
href="book.html"
></book-card>
<book-card
title="Project Hail Mary"
description="A book about the science of space travel and the future of humanity"
author="Andy Weir"
price="$18.99"
rating="4.5"
href="book.html"
></book-card>
<cta-button href="#">Toon meer meest verkochte boeken</cta-button>
</div>
</section>
<section class="section">
<section-title text="Onderwerpen"></section-title>
<div class="category-grid">
<category-card
title="Biografie / autobiografie"
icon="images/biografieautobiografie.png"
href="category.html"
></category-card>
<category-card
title="Boeddhisme (algemeen)"
icon="images/boeddhismealgemeen.png"
href="category.html"
></category-card>
<category-card
title="Boeddhisme en het Westen"
icon="images/boeddhisme-en-het-westen.png"
href="category.html"
></category-card>
<category-card
title="Kinderboeken"
icon="images/kinderboeken.png"
href="category.html"
></category-card>
<category-card
title="Meditatie"
icon="images/meditatie.png"
href="category.html"
></category-card>
<category-card
title="Mindfulness"
icon="images/mindfulness.png"
href="category.html"
></category-card>
<category-card
title="Pali-canon"
icon="images/palicanon.png"
href="category.html"
></category-card>
<category-card
title="Theravada"
icon="images/theravada.png"
href="category.html"
></category-card>
<category-card
title="Tibetaans boeddhisme"
icon="images/tibetaans-boeddhisme.png"
href="category.html"
></category-card>
<category-card
title="Vipassana"
icon="images/vipassana.png"
href="category.html"
></category-card>
</div>
<cta-button href="#">Toon alle onderwerpen</cta-button>
<book-details
title="Zen is opendoen"
author="Ayya Khema"
author-href="#"
price="€ 24,95"
isbn="9789056703691"
format="Paperback"
delivery="Direct leverbaar"
categories="Zen|#,Integrale spiritualiteit|#"
ebook-available
></book-details>
</section>
<div class="content-padding">

View File

@@ -19,6 +19,7 @@ import "./components/add-to-cart-button.js";
import "./components/cta-button.js";
import "./components/category-card.js";
import "./components/newsletter-signup.js";
import "./components/book-details.js";
// Import icon components
import "./icons/menu-icon.js";

View File

@@ -0,0 +1,458 @@
/**
* Book Details Component
* Displays book information with cover, metadata, and purchase buttons
*/
import { shoppingBagIcon } from "../icons/shopping-bag.js";
class BookDetails extends HTMLElement {
static get observedAttributes() {
return [
"title",
"author",
"author-href",
"price",
"image",
"isbn",
"format",
"delivery",
"categories",
"ebook-available",
];
}
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
attributeChangedCallback() {
if (this.shadowRoot) {
this.render();
this.setupEventListeners();
}
}
setupEventListeners() {
const addToCartBtn = this.shadowRoot?.querySelector(".btn-cart");
const ebookBtn = this.shadowRoot?.querySelector(".btn-ebook");
const favoriteBtn = this.shadowRoot?.querySelector(".favorite-btn");
if (addToCartBtn) {
addToCartBtn.addEventListener("click", () => {
this.dispatchEvent(
new CustomEvent("add-to-cart", {
bubbles: true,
composed: true,
detail: {
title: this.bookTitle,
price: this.price,
type: "physical",
},
})
);
});
}
if (ebookBtn) {
ebookBtn.addEventListener("click", () => {
this.dispatchEvent(
new CustomEvent("buy-ebook", {
bubbles: true,
composed: true,
detail: {
title: this.bookTitle,
type: "ebook",
},
})
);
});
}
if (favoriteBtn) {
favoriteBtn.addEventListener("click", () => {
favoriteBtn.classList.toggle("active");
this.dispatchEvent(
new CustomEvent("toggle-favorite", {
bubbles: true,
composed: true,
detail: {
title: this.bookTitle,
},
})
);
});
}
}
get bookTitle() {
return this.getAttribute("title") || "Book Title";
}
get author() {
return this.getAttribute("author") || "Author Name";
}
get authorHref() {
return this.getAttribute("author-href") || "#";
}
get price() {
return this.getAttribute("price") || "€ 0,00";
}
get image() {
return this.getAttribute("image") || "";
}
get isbn() {
return this.getAttribute("isbn") || "";
}
get format() {
return this.getAttribute("format") || "Paperback";
}
get delivery() {
return this.getAttribute("delivery") || "Direct leverbaar";
}
get categories() {
return this.getAttribute("categories") || "";
}
get ebookAvailable() {
return this.hasAttribute("ebook-available");
}
renderCategories() {
if (!this.categories) return "";
// Categories are comma-separated, with optional href in format: "Name|href,Name2|href2"
const cats = this.categories.split(",").map((cat) => {
const [name, href] = cat.trim().split("|");
if (href) {
return `<a href="${href}" class="category-link">${name}</a>`;
}
return `<span class="category-text">${name}</span>`;
});
return cats.join('<span class="category-separator"> / </span>');
}
render() {
const imageHtml = this.image
? `<img src="${this.image}" alt="${this.bookTitle}" class="book-cover">`
: `<div class="book-cover placeholder">
<book-open-icon size="48" color="var(--color-text-light)"></book-open-icon>
</div>`;
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
font-family: var(--font-family-outfit, "Outfit", sans-serif);
}
.book-details {
display: flex;
flex-direction: column;
gap: var(--spacing-md, 1rem);
}
/* Header Section */
.header {
display: flex;
flex-direction: column;
gap: var(--spacing-sm, 0.5rem);
}
.title-row {
display: flex;
align-items: center;
gap: var(--spacing-sm, 0.5rem);
}
.title {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 24px;
font-weight: 700;
line-height: 34px;
color: var(--color-text, #1e293b);
margin: 0;
}
.favorite-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: none;
border: none;
cursor: pointer;
padding: 0;
flex-shrink: 0;
}
.favorite-btn svg {
width: 28px;
height: 28px;
transition: transform var(--transition-fast, 150ms ease);
}
.favorite-btn:hover svg {
transform: scale(1.1);
}
.favorite-btn.active svg {
fill: #f59e0b;
}
.author-link {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 300;
line-height: 24px;
color: var(--color-purple, #951d51);
text-decoration: underline;
}
.author-link:hover {
opacity: 0.8;
}
.price {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 700;
line-height: 24px;
color: var(--color-text, #1e293b);
margin: 0;
}
/* Content Section */
.content {
display: flex;
gap: var(--spacing-md, 1rem);
}
.cover-container {
flex-shrink: 0;
width: 110px;
height: 177px;
}
.book-cover {
width: 110px;
height: 177px;
object-fit: cover;
border-radius: var(--radius-sm, 0.25rem);
}
.book-cover.placeholder {
display: flex;
align-items: center;
justify-content: center;
background-color: var(--color-background-tertiary, #f1f5f9);
border-radius: var(--radius-sm, 0.25rem);
}
/* Details Grid */
.details {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--spacing-sm, 0.5rem);
}
.detail-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-sm, 0.5rem);
}
.detail-item {
display: flex;
flex-direction: column;
gap: 0;
}
.detail-item.full-width {
grid-column: 1 / -1;
}
.detail-label {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 12px;
font-weight: 200;
line-height: 24px;
color: var(--color-purple, #951d51);
}
.detail-value {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 300;
line-height: 24px;
color: var(--color-text, #1e293b);
}
.category-link {
color: var(--color-text, #1e293b);
text-decoration: underline;
}
.category-link:hover {
opacity: 0.8;
}
.category-text {
color: var(--color-text, #1e293b);
}
.category-separator {
color: var(--color-text, #1e293b);
}
/* Buttons Section */
.buttons {
display: flex;
flex-direction: column;
gap: var(--spacing-sm, 0.5rem);
}
.btn {
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm, 0.5rem);
padding: 14px var(--spacing-md, 1rem);
border: none;
border-radius: var(--radius-lg, 0.75rem);
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 400;
line-height: 24px;
cursor: pointer;
transition: opacity var(--transition-fast, 150ms ease);
}
.btn:hover {
opacity: 0.9;
}
.btn:active {
opacity: 0.8;
}
.btn-cart {
background-color: var(--color-purple, #951d51);
color: var(--color-text-inverse, #ffffff);
}
.btn-cart svg {
width: 20px;
height: 20px;
}
.btn-ebook {
background-color: var(--color-push-box-bg, #EBEEF4);
color: var(--color-text, #1e293b);
}
.btn-ebook svg {
width: 20px;
height: 20px;
}
</style>
<div class="book-details">
<!-- Header -->
<div class="header">
<div class="title-row">
<h1 class="title">${this.bookTitle}</h1>
<button class="favorite-btn" aria-label="Add to favorites">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
</button>
</div>
<a href="${this.authorHref}" class="author-link">${this.author}</a>
<p class="price">${this.price}</p>
</div>
<!-- Content: Cover + Details -->
<div class="content">
<div class="cover-container">
${imageHtml}
</div>
<div class="details">
${
this.categories
? `
<div class="detail-item full-width">
<span class="detail-label">Categorieën</span>
<span class="detail-value">${this.renderCategories()}</span>
</div>
`
: ""
}
<div class="detail-row">
${
this.isbn
? `
<div class="detail-item">
<span class="detail-label">ISBN</span>
<span class="detail-value">${this.isbn}</span>
</div>
`
: ""
}
<div class="detail-item">
<span class="detail-label">Uitvoering</span>
<span class="detail-value">${this.format}</span>
</div>
</div>
<div class="detail-row">
<div class="detail-item">
<span class="detail-label">Uitvoering</span>
<span class="detail-value">${this.format}</span>
</div>
<div class="detail-item">
<span class="detail-label">Levertijd</span>
<span class="detail-value">${this.delivery}</span>
</div>
</div>
</div>
</div>
<!-- Buttons -->
<div class="buttons">
<button class="btn btn-cart">
${shoppingBagIcon({ size: 20, color: "#ffffff" })}
<span>In winkelwagen</span>
</button>
${
this.ebookAvailable
? `
<button class="btn btn-ebook">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25"></path>
</svg>
<span>Koop eBook</span>
</button>
`
: ""
}
</div>
</div>
`;
}
}
customElements.define("book-details", BookDetails);