${this.title}
${this.rating > 0 ? `` : ''}${this.price}
/**
* Book Card Component
* Reusable card displaying book thumbnail, title, author, and price
*/
class BookCard extends HTMLElement {
static get observedAttributes() {
return ['title', 'author', 'price', 'image', 'href', 'rating'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
if (this.shadowRoot) {
this.render();
}
}
get title() {
return this.getAttribute('title') || 'Book Title';
}
get author() {
return this.getAttribute('author') || 'Author Name';
}
get price() {
return this.getAttribute('price') || '$0.00';
}
get image() {
return this.getAttribute('image') || '';
}
get href() {
return this.getAttribute('href') || 'book.html';
}
get rating() {
return parseFloat(this.getAttribute('rating')) || 0;
}
renderStars(rating) {
const fullStars = Math.floor(rating);
const hasHalf = rating % 1 >= 0.5;
const emptyStars = 5 - fullStars - (hasHalf ? 1 : 0);
let stars = '';
// Full stars
for (let i = 0; i < fullStars; i++) {
stars += ``;
}
// Half star
if (hasHalf) {
stars += ``;
}
// Empty stars
for (let i = 0; i < emptyStars; i++) {
stars += ``;
}
return stars;
}
render() {
// Generate placeholder image if none provided
const imageHtml = this.image
? ``
: `
${this.price}