Files
milinda-pitch/js/components/book-review-item.js
rubberducky 3dbe404443 feature/book-page (#4)
Co-authored-by: Tim Rijkse <trijkse@gmail.com>
Reviewed-on: #4
2026-01-16 08:46:03 +00:00

129 lines
2.9 KiB
JavaScript

/**
* Book Review Item Component
* Individual review with rating, author, date, and text
*/
class BookReviewItem extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.render();
}
get rating() {
return parseInt(this.getAttribute("rating") || "5", 10);
}
get author() {
return this.getAttribute("author") || "Anoniem";
}
get date() {
return this.getAttribute("date") || "";
}
renderStars() {
const rating = Math.min(5, Math.max(0, this.rating));
const fullStars = rating;
const emptyStars = 5 - rating;
let stars = "";
for (let i = 0; i < fullStars; i++) {
stars += `<span class="star filled">★</span>`;
}
for (let i = 0; i < emptyStars; i++) {
stars += `<span class="star empty">☆</span>`;
}
return stars;
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
.review {
padding-bottom: var(--spacing-lg, 1.5rem);
border-bottom: 1px solid var(--color-border, #e2e8f0);
}
:host(:last-child) .review {
border-bottom: none;
padding-bottom: 0;
}
.review-header {
display: flex;
flex-direction: column;
gap: var(--spacing-xs, 0.25rem);
margin-bottom: var(--spacing-sm, 0.5rem);
}
.stars {
display: flex;
gap: 2px;
}
.star {
font-size: 16px;
line-height: 1;
}
.star.filled {
color: var(--color-purple, #951d51);
}
.star.empty {
color: var(--color-border, #e2e8f0);
}
.review-meta {
display: flex;
align-items: center;
gap: var(--spacing-sm, 0.5rem);
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 14px;
line-height: 20px;
}
.author {
font-weight: 500;
color: var(--color-text, #1e293b);
}
.date {
color: var(--color-text-light, #64748b);
font-weight: 300;
}
.review-text {
font-family: var(--font-family-outfit, "Outfit", sans-serif);
font-size: 16px;
font-weight: 400;
line-height: 26px;
color: var(--color-text, #1e293b);
margin: 0;
}
</style>
<article class="review">
<div class="review-header">
<div class="stars">${this.renderStars()}</div>
<div class="review-meta">
<span class="author">${this.author}</span>
${this.date ? `<span class="date">• ${this.date}</span>` : ""}
</div>
</div>
<p class="review-text">
<slot></slot>
</p>
</article>
`;
}
}
customElements.define("book-review-item", BookReviewItem);