fix: update header content to be rendered from index directly

This commit is contained in:
Tim Rijkse
2026-01-14 15:38:21 +01:00
parent dc06a33a72
commit 6816650ea5
7 changed files with 678 additions and 390 deletions

448
book.html
View File

@@ -1,147 +1,345 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="The Midnight Library - Between life and death there is a library"> <meta
<title>The Midnight Library - BookStore</title> name="description"
<link rel="stylesheet" href="css/styles.css"> content="The Midnight Library - Between life and death there is a library"
</head> />
<body> <title>The Midnight Library - BookStore</title>
<div class="mobile-container"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<site-header> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<top-bar></top-bar> <link
<horizontal-scroll-nav></horizontal-scroll-nav> href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap"
<search-bar></search-bar> rel="stylesheet"
</site-header> />
<link rel="stylesheet" href="css/styles.css" />
<site-content> </head>
<div class="book-detail"> <body>
<!-- Back navigation --> <div class="mobile-container">
<a href="index.html" class="back-link"> <site-header>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20"> <top-bar>
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" /> <button slot="menu-button" class="icon-button" aria-label="Menu">
</svg> <svg
Back to Books xmlns="http://www.w3.org/2000/svg"
</a> width="32"
height="32"
<!-- Book Cover --> viewBox="0 0 24 24"
<div class="book-cover"> fill="none"
<div class="book-cover-placeholder"> stroke="#ffffff"
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor"> stroke-width="2"
<path stroke-linecap="round" stroke-linejoin="round" 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" /> stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="4" x2="20" y1="12" y2="12"></line>
<line x1="4" x2="20" y1="6" y2="6"></line>
<line x1="4" x2="20" y1="18" y2="18"></line>
</svg> </svg>
</div> </button>
</div> <a slot="logo" href="index.html" class="logo">BookStore</a>
<div slot="actions" class="actions">
<!-- Book Info --> <button class="icon-button" aria-label="Profile">
<div class="book-info"> <svg
<h1 class="book-title">The Midnight Library</h1> xmlns="http://www.w3.org/2000/svg"
<p class="book-author">by Matt Haig</p> width="32"
height="32"
<div class="book-rating"> viewBox="0 0 24 24"
<div class="stars"> fill="none"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke="#ffffff"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke-width="2"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke-linecap="round"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke-linejoin="round"
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> >
</div> <circle cx="12" cy="8" r="5"></circle>
<span class="rating-text">4.5 (2,847 reviews)</span> <path d="M20 21a8 8 0 0 0-16 0"></path>
</div>
<div class="book-meta">
<div class="meta-item">
<span class="meta-label">Format</span>
<span class="meta-value">Hardcover</span>
</div>
<div class="meta-item">
<span class="meta-label">Pages</span>
<span class="meta-value">304</span>
</div>
<div class="meta-item">
<span class="meta-label">Language</span>
<span class="meta-value">English</span>
</div>
</div>
</div>
<!-- Price & Purchase -->
<div class="purchase-section">
<div class="price-container">
<span class="current-price">$14.99</span>
<span class="original-price">$24.99</span>
<span class="discount-badge">40% OFF</span>
</div>
<div class="purchase-actions">
<button class="btn btn-primary btn-large">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84M7.5 14.25 5.106 5.272M6 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm12.75 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
</svg> </svg>
Add to Cart
</button> </button>
<button class="btn btn-secondary"> <button class="icon-button" aria-label="Shopping basket">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="20" height="20"> <svg
<path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z" /> xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"
></path>
<path d="M3 6h18"></path>
<path d="M16 10a4 4 0 0 1-8 0"></path>
</svg> </svg>
</button> </button>
</div> </div>
</div> </top-bar>
<horizontal-scroll-nav></horizontal-scroll-nav>
<search-bar></search-bar>
</site-header>
<!-- Description --> <site-content>
<div class="book-description"> <div class="book-detail">
<h2 class="section-heading">About this book</h2> <!-- Back navigation -->
<p>Between life and death there is a library, and within that library, the shelves go on forever. Every book provides a chance to try another life you could have lived. To see how things would be if you had made other choices... Would you have done anything different, if you had the chance to undo your regrets?</p> <a href="index.html" class="back-link">
<p>A dazzling novel about all the choices that go into a life well lived, from the internationally bestselling author of Reasons to Stay Alive and How to Stop Time.</p> <svg
</div> xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
width="20"
height="20"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5 8.25 12l7.5-7.5"
/>
</svg>
Back to Books
</a>
<!-- Reviews --> <!-- Book Cover -->
<div class="reviews-section"> <div class="book-cover">
<h2 class="section-heading">Customer Reviews</h2> <div class="book-cover-placeholder">
<svg
<div class="review-card"> xmlns="http://www.w3.org/2000/svg"
<div class="review-header"> fill="none"
<div class="reviewer-info"> viewBox="0 0 24 24"
<span class="reviewer-name">Sarah M.</span> stroke-width="1"
<span class="review-date">December 2025</span> stroke="currentColor"
</div> >
<div class="review-stars"> <path
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke-linecap="round"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> stroke-linejoin="round"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> 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"
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> />
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> </svg>
</div>
</div> </div>
<p class="review-text">This book changed my perspective on life. Beautifully written and deeply thought-provoking. A must-read for anyone going through a difficult time.</p>
</div> </div>
<div class="review-card"> <!-- Book Info -->
<div class="review-header"> <div class="book-info">
<div class="reviewer-info"> <h1 class="book-title">The Midnight Library</h1>
<span class="reviewer-name">James K.</span> <p class="book-author">by Matt Haig</p>
<span class="review-date">November 2025</span>
<div class="book-rating">
<div class="stars">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1"
>
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
</div> </div>
<div class="review-stars"> <span class="rating-text">4.5 (2,847 reviews)</span>
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> </div>
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> <div class="book-meta">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> <div class="meta-item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg> <span class="meta-label">Format</span>
<span class="meta-value">Hardcover</span>
</div>
<div class="meta-item">
<span class="meta-label">Pages</span>
<span class="meta-value">304</span>
</div>
<div class="meta-item">
<span class="meta-label">Language</span>
<span class="meta-value">English</span>
</div> </div>
</div> </div>
<p class="review-text">Great concept and well-executed. The writing flows effortlessly and keeps you engaged throughout. Highly recommend!</p>
</div> </div>
<button class="btn btn-outline btn-full">View All Reviews</button> <!-- Price & Purchase -->
<div class="purchase-section">
<div class="price-container">
<span class="current-price">$14.99</span>
<span class="original-price">$24.99</span>
<span class="discount-badge">40% OFF</span>
</div>
<div class="purchase-actions">
<button class="btn btn-primary btn-large">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
width="20"
height="20"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84M7.5 14.25 5.106 5.272M6 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm12.75 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z"
/>
</svg>
Add to Cart
</button>
<button class="btn btn-secondary">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
width="20"
height="20"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z"
/>
</svg>
</button>
</div>
</div>
<!-- Description -->
<div class="book-description">
<h2 class="section-heading">About this book</h2>
<p>
Between life and death there is a library, and within that
library, the shelves go on forever. Every book provides a chance
to try another life you could have lived. To see how things would
be if you had made other choices... Would you have done anything
different, if you had the chance to undo your regrets?
</p>
<p>
A dazzling novel about all the choices that go into a life well
lived, from the internationally bestselling author of Reasons to
Stay Alive and How to Stop Time.
</p>
</div>
<!-- Reviews -->
<div class="reviews-section">
<h2 class="section-heading">Customer Reviews</h2>
<div class="review-card">
<div class="review-header">
<div class="reviewer-info">
<span class="reviewer-name">Sarah M.</span>
<span class="review-date">December 2025</span>
</div>
<div class="review-stars">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
</div>
</div>
<p class="review-text">
This book changed my perspective on life. Beautifully written
and deeply thought-provoking. A must-read for anyone going
through a difficult time.
</p>
</div>
<div class="review-card">
<div class="review-header">
<div class="reviewer-info">
<span class="reviewer-name">James K.</span>
<span class="review-date">November 2025</span>
</div>
<div class="review-stars">
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg viewBox="0 0 24 24" fill="currentColor">
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1"
>
<path
d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
/>
</svg>
</div>
</div>
<p class="review-text">
Great concept and well-executed. The writing flows effortlessly
and keeps you engaged throughout. Highly recommend!
</p>
</div>
<button class="btn btn-outline btn-full">View All Reviews</button>
</div>
</div> </div>
</div> </site-content>
</site-content>
<site-footer></site-footer> <site-footer></site-footer>
</div> </div>
<script type="module" src="js/app.js"></script> <script type="module" src="js/app.js"></script>
</body> </body>
</html> </html>

View File

@@ -34,8 +34,8 @@ html {
/* Set core body defaults */ /* Set core body defaults */
body { body {
min-height: 100vh; min-height: 100vh;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
line-height: 1.5; line-height: 1.5;
text-rendering: optimizeSpeed; text-rendering: optimizeSpeed;
} }
@@ -93,7 +93,7 @@ textarea:not([rows]) {
html:focus-within { html:focus-within {
scroll-behavior: auto; scroll-behavior: auto;
} }
*, *,
*::before, *::before,
*::after { *::after {
@@ -163,70 +163,71 @@ table {
--color-primary-dark: #1d4ed8; --color-primary-dark: #1d4ed8;
--color-secondary: #64748b; --color-secondary: #64748b;
--color-accent: #f59e0b; --color-accent: #f59e0b;
--color-text: #1e293b; --color-text: #1e293b;
--color-text-light: #64748b; --color-text-light: #64748b;
--color-text-inverse: #ffffff; --color-text-inverse: #ffffff;
--color-background: #ffffff; --color-background: #ffffff;
--color-background-secondary: #f8fafc; --color-background-secondary: #f8fafc;
--color-background-tertiary: #f1f5f9; --color-background-tertiary: #f1f5f9;
--color-border: #e2e8f0; --color-border: #e2e8f0;
--color-border-light: #f1f5f9; --color-border-light: #f1f5f9;
--color-success: #22c55e; --color-success: #22c55e;
--color-error: #ef4444; --color-error: #ef4444;
--color-warning: #f59e0b; --color-warning: #f59e0b;
/* Typography */ /* Typography */
--font-family-base: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', --font-family-base: "Outfit", system-ui, -apple-system, BlinkMacSystemFont,
Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
'Helvetica Neue', sans-serif; sans-serif;
--font-family-heading: var(--font-family-base); --font-family-heading: var(--font-family-base);
--font-size-xs: 0.75rem; /* 12px */ --font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */ --font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */ --font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */ --font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */ --font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */ --font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */ --font-size-3xl: 1.875rem; /* 30px */
--font-weight-normal: 400; --font-weight-normal: 400;
--font-weight-medium: 500; --font-weight-medium: 500;
--font-weight-semibold: 600; --font-weight-semibold: 600;
--font-weight-bold: 700; --font-weight-bold: 700;
--line-height-tight: 1.25; --line-height-tight: 1.25;
--line-height-normal: 1.5; --line-height-normal: 1.5;
--line-height-relaxed: 1.75; --line-height-relaxed: 1.75;
/* Spacing */ /* Spacing */
--spacing-xs: 0.25rem; /* 4px */ --spacing-xs: 0.25rem; /* 4px */
--spacing-sm: 0.5rem; /* 8px */ --spacing-sm: 0.5rem; /* 8px */
--spacing-md: 1rem; /* 16px */ --spacing-md: 1rem; /* 16px */
--spacing-lg: 1.5rem; /* 24px */ --spacing-lg: 1.5rem; /* 24px */
--spacing-xl: 2rem; /* 32px */ --spacing-xl: 2rem; /* 32px */
--spacing-2xl: 3rem; /* 48px */ --spacing-2xl: 3rem; /* 48px */
/* Border Radius */ /* Border Radius */
--radius-sm: 0.25rem; /* 4px */ --radius-sm: 0.25rem; /* 4px */
--radius-md: 0.5rem; /* 8px */ --radius-md: 0.5rem; /* 8px */
--radius-lg: 0.75rem; /* 12px */ --radius-lg: 0.75rem; /* 12px */
--radius-xl: 1rem; /* 16px */ --radius-xl: 1rem; /* 16px */
--radius-full: 9999px; --radius-full: 9999px;
/* Shadows */ /* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1),
0 4px 6px -4px rgb(0 0 0 / 0.1);
/* Transitions */ /* Transitions */
--transition-fast: 150ms ease; --transition-fast: 150ms ease;
--transition-normal: 250ms ease; --transition-normal: 250ms ease;
--transition-slow: 350ms ease; --transition-slow: 350ms ease;
/* Layout */ /* Layout */
--mobile-max-width: 430px; --mobile-max-width: 430px;
--header-height: auto; --header-height: auto;
@@ -244,6 +245,40 @@ body {
background-color: var(--color-background-secondary); background-color: var(--color-background-secondary);
} }
/* ==========================================================================
Top Bar Slotted Content Styles
========================================================================== */
top-bar .icon-button {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
}
top-bar .icon-button svg {
width: 32px;
height: 32px;
}
top-bar .logo {
font-family: var(--font-family-base);
font-size: 1.25rem;
font-weight: 700;
color: #ffffff;
text-decoration: none;
}
top-bar .actions {
display: flex;
align-items: center;
}
/* ========================================================================== /* ==========================================================================
Mobile Container (for desktop viewing) Mobile Container (for desktop viewing)
Centers content in a phone-sized container on larger screens Centers content in a phone-sized container on larger screens
@@ -264,7 +299,7 @@ body {
align-items: flex-start; align-items: flex-start;
padding: var(--spacing-lg) 0; padding: var(--spacing-lg) 0;
} }
.mobile-container { .mobile-container {
max-width: var(--mobile-max-width); max-width: var(--mobile-max-width);
min-height: calc(100vh - var(--spacing-lg) * 2); min-height: calc(100vh - var(--spacing-lg) * 2);

View File

@@ -1,127 +1,192 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="BookStore - Discover and buy your next favorite book"> <meta
<title>BookStore - Home</title> name="description"
<link rel="stylesheet" href="css/styles.css"> content="Milinda - Discover and buy your next favorite book"
</head> />
<body> <title>Milinda - Home</title>
<div class="mobile-container"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<site-header> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<top-bar></top-bar> <link
<horizontal-scroll-nav></horizontal-scroll-nav> href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap"
<search-bar></search-bar> rel="stylesheet"
</site-header> />
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<div class="mobile-container">
<site-header>
<top-bar>
<button slot="menu-button" class="icon-button" aria-label="Menu">
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="4" x2="20" y1="12" y2="12"></line>
<line x1="4" x2="20" y1="6" y2="6"></line>
<line x1="4" x2="20" y1="18" y2="18"></line>
</svg>
</button>
<a slot="logo" href="index.html" class="logo">Milinda</a>
<div slot="actions" class="actions">
<button class="icon-button" aria-label="Profile">
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="8" r="5"></circle>
<path d="M20 21a8 8 0 0 0-16 0"></path>
</svg>
</button>
<button class="icon-button" aria-label="Shopping basket">
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"
></path>
<path d="M3 6h18"></path>
<path d="M16 10a4 4 0 0 1-8 0"></path>
</svg>
</button>
</div>
</top-bar>
<horizontal-scroll-nav></horizontal-scroll-nav>
<search-bar></search-bar>
</site-header>
<site-content> <site-content>
<section class="section"> <section class="section">
<h2 class="section-title">Featured Books</h2> <h2 class="section-title">Featured Books</h2>
<div class="book-grid"> <div class="book-grid">
<book-card <book-card
title="The Midnight Library" title="The Midnight Library"
author="Matt Haig" author="Matt Haig"
price="$14.99" price="$14.99"
rating="4.5" rating="4.5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="Atomic Habits" title="Atomic Habits"
author="James Clear" author="James Clear"
price="$16.99" price="$16.99"
rating="5" rating="5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="The Psychology of Money" title="The Psychology of Money"
author="Morgan Housel" author="Morgan Housel"
price="$12.99" price="$12.99"
rating="4" rating="4"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="Project Hail Mary" title="Project Hail Mary"
author="Andy Weir" author="Andy Weir"
price="$18.99" price="$18.99"
rating="4.5" rating="4.5"
href="book.html" href="book.html"
></book-card> ></book-card>
</div> </div>
</section> </section>
<section class="section"> <section class="section">
<h2 class="section-title">New Releases</h2> <h2 class="section-title">New Releases</h2>
<div class="book-grid"> <div class="book-grid">
<book-card <book-card
title="Tomorrow, and Tomorrow" title="Tomorrow, and Tomorrow"
author="Gabrielle Zevin" author="Gabrielle Zevin"
price="$15.99" price="$15.99"
rating="4" rating="4"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="The House in the Pines" title="The House in the Pines"
author="Ana Reyes" author="Ana Reyes"
price="$13.99" price="$13.99"
rating="3.5" rating="3.5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="Demon Copperhead" title="Demon Copperhead"
author="Barbara Kingsolver" author="Barbara Kingsolver"
price="$19.99" price="$19.99"
rating="5" rating="5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="The Light We Carry" title="The Light We Carry"
author="Michelle Obama" author="Michelle Obama"
price="$17.99" price="$17.99"
rating="4.5" rating="4.5"
href="book.html" href="book.html"
></book-card> ></book-card>
</div> </div>
</section> </section>
<section class="section"> <section class="section">
<h2 class="section-title">Best Sellers</h2> <h2 class="section-title">Best Sellers</h2>
<div class="book-grid"> <div class="book-grid">
<book-card <book-card
title="Where the Crawdads Sing" title="Where the Crawdads Sing"
author="Delia Owens" author="Delia Owens"
price="$11.99" price="$11.99"
rating="4.5" rating="4.5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="The Silent Patient" title="The Silent Patient"
author="Alex Michaelides" author="Alex Michaelides"
price="$14.99" price="$14.99"
rating="4" rating="4"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="Educated" title="Educated"
author="Tara Westover" author="Tara Westover"
price="$13.99" price="$13.99"
rating="4.5" rating="4.5"
href="book.html" href="book.html"
></book-card> ></book-card>
<book-card <book-card
title="Becoming" title="Becoming"
author="Michelle Obama" author="Michelle Obama"
price="$16.99" price="$16.99"
rating="5" rating="5"
href="book.html" href="book.html"
></book-card> ></book-card>
</div> </div>
</section> </section>
</site-content> </site-content>
<site-footer></site-footer> <site-footer></site-footer>
</div> </div>
<script type="module" src="js/app.js"></script> <script type="module" src="js/app.js"></script>
</body> </body>
</html> </html>

View File

@@ -5,16 +5,16 @@
class HorizontalScrollNav extends HTMLElement { class HorizontalScrollNav extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
this.categories = [ this.categories = [
{ id: 'all', label: 'All', active: true }, { id: "all", label: "All", active: true },
{ id: 'fiction', label: 'Fiction', active: false }, { id: "fiction", label: "Fiction", active: false },
{ id: 'non-fiction', label: 'Non-Fiction', active: false }, { id: "non-fiction", label: "Non-Fiction", active: false },
{ id: 'mystery', label: 'Mystery', active: false }, { id: "mystery", label: "Mystery", active: false },
{ id: 'romance', label: 'Romance', active: false }, { id: "romance", label: "Romance", active: false },
{ id: 'sci-fi', label: 'Sci-Fi', active: false }, { id: "sci-fi", label: "Sci-Fi", active: false },
{ id: 'biography', label: 'Biography', active: false }, { id: "biography", label: "Biography", active: false },
{ id: 'history', label: 'History', active: false }, { id: "history", label: "History", active: false },
]; ];
} }
@@ -24,28 +24,30 @@ class HorizontalScrollNav extends HTMLElement {
} }
addEventListeners() { addEventListeners() {
const buttons = this.shadowRoot.querySelectorAll('.nav-pill'); const buttons = this.shadowRoot.querySelectorAll(".nav-pill");
buttons.forEach(button => { buttons.forEach((button) => {
button.addEventListener('click', (e) => { button.addEventListener("click", (e) => {
this.setActiveCategory(e.target.dataset.id); this.setActiveCategory(e.target.dataset.id);
}); });
}); });
} }
setActiveCategory(id) { setActiveCategory(id) {
this.categories = this.categories.map(cat => ({ this.categories = this.categories.map((cat) => ({
...cat, ...cat,
active: cat.id === id active: cat.id === id,
})); }));
this.render(); this.render();
this.addEventListeners(); this.addEventListeners();
// Dispatch custom event for parent components // Dispatch custom event for parent components
this.dispatchEvent(new CustomEvent('category-change', { this.dispatchEvent(
detail: { categoryId: id }, new CustomEvent("category-change", {
bubbles: true, detail: { categoryId: id },
composed: true bubbles: true,
})); composed: true,
})
);
} }
render() { render() {
@@ -61,7 +63,7 @@ class HorizontalScrollNav extends HTMLElement {
overflow-x: auto; overflow-x: auto;
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: none; -ms-overflow-style: none;
padding: var(--spacing-xs, 0.25rem) 0; padding: var(--spacing-xs, 0.25rem) var(--spacing-sm, 0.5rem);
} }
.nav-container::-webkit-scrollbar { .nav-container::-webkit-scrollbar {
@@ -96,18 +98,22 @@ class HorizontalScrollNav extends HTMLElement {
} }
</style> </style>
<nav class="nav-container" role="navigation" aria-label="Book categories"> <nav class="nav-container" role="navigation" aria-label="Book categories">
${this.categories.map(cat => ` ${this.categories
.map(
(cat) => `
<button <button
class="nav-pill ${cat.active ? 'active' : ''}" class="nav-pill ${cat.active ? "active" : ""}"
data-id="${cat.id}" data-id="${cat.id}"
${cat.active ? 'aria-current="true"' : ''} ${cat.active ? 'aria-current="true"' : ""}
> >
${cat.label} ${cat.label}
</button> </button>
`).join('')} `
)
.join("")}
</nav> </nav>
`; `;
} }
} }
customElements.define('horizontal-scroll-nav', HorizontalScrollNav); customElements.define("horizontal-scroll-nav", HorizontalScrollNav);

View File

@@ -5,7 +5,7 @@
class SearchBar extends HTMLElement { class SearchBar extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
} }
connectedCallback() { connectedCallback() {
@@ -14,24 +14,28 @@ class SearchBar extends HTMLElement {
} }
addEventListeners() { addEventListeners() {
const input = this.shadowRoot.querySelector('.search-input'); const input = this.shadowRoot.querySelector(".search-input");
const form = this.shadowRoot.querySelector('.search-form'); const form = this.shadowRoot.querySelector(".search-form");
form.addEventListener('submit', (e) => { form.addEventListener("submit", (e) => {
e.preventDefault(); e.preventDefault();
this.dispatchEvent(new CustomEvent('search', { this.dispatchEvent(
detail: { query: input.value }, new CustomEvent("search", {
bubbles: true, detail: { query: input.value },
composed: true bubbles: true,
})); composed: true,
})
);
}); });
input.addEventListener('input', (e) => { input.addEventListener("input", (e) => {
this.dispatchEvent(new CustomEvent('search-input', { this.dispatchEvent(
detail: { query: e.target.value }, new CustomEvent("search-input", {
bubbles: true, detail: { query: e.target.value },
composed: true bubbles: true,
})); composed: true,
})
);
}); });
} }
@@ -46,6 +50,8 @@ class SearchBar extends HTMLElement {
display: flex; display: flex;
align-items: center; align-items: center;
position: relative; position: relative;
padding: var(--spacing-sm, 0.5rem) var(--spacing-sm, 0.5rem);
background-color: #951D51;
} }
.search-icon { .search-icon {
@@ -95,4 +101,4 @@ class SearchBar extends HTMLElement {
} }
} }
customElements.define('search-bar', SearchBar); customElements.define("search-bar", SearchBar);

View File

@@ -5,7 +5,7 @@
class SiteHeader extends HTMLElement { class SiteHeader extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
} }
connectedCallback() { connectedCallback() {
@@ -27,7 +27,6 @@ class SiteHeader extends HTMLElement {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--spacing-sm, 0.5rem); gap: var(--spacing-sm, 0.5rem);
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
border-bottom: 1px solid var(--color-border, #e2e8f0); border-bottom: 1px solid var(--color-border, #e2e8f0);
} }
</style> </style>
@@ -38,4 +37,4 @@ class SiteHeader extends HTMLElement {
} }
} }
customElements.define('site-header', SiteHeader); customElements.define("site-header", SiteHeader);

View File

@@ -1,11 +1,12 @@
/** /**
* Top Bar Component * Top Bar Component
* Contains logo, menu icon, and cart icon * Contains menu icon, logo, and action buttons (profile, basket)
* Uses slots for content customization from index.html
*/ */
class TopBar extends HTMLElement { class TopBar extends HTMLElement {
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: 'open' }); this.attachShadow({ mode: "open" });
} }
connectedCallback() { connectedCallback() {
@@ -22,89 +23,67 @@ class TopBar extends HTMLElement {
.top-bar { .top-bar {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; height: 80px;
height: 44px; padding: 0 16px;
background-color: #951D51;
} }
.logo { .left-section {
font-size: var(--font-size-xl, 1.25rem);
font-weight: var(--font-weight-bold, 700);
color: var(--color-text, #1e293b);
text-decoration: none;
}
.actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacing-sm, 0.5rem); gap: 16px;
} }
.icon-button { .spacer {
flex: 1;
}
.right-section {
display: flex;
align-items: center;
}
/* Styles for slotted elements */
::slotted([slot="menu-button"]),
::slotted(.icon-button) {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 40px; width: 32px;
height: 40px; height: 32px;
border-radius: var(--radius-md, 0.5rem);
background: transparent; background: transparent;
border: none; border: none;
cursor: pointer; cursor: pointer;
color: var(--color-text, #1e293b); padding: 0;
transition: background-color var(--transition-fast, 150ms ease);
} }
.icon-button:hover { ::slotted([slot="menu-button"] svg),
background-color: var(--color-background-tertiary, #f1f5f9); ::slotted(.icon-button svg) {
width: 32px;
height: 32px;
color: #ffffff;
} }
.icon-button:active { ::slotted([slot="logo"]) {
background-color: var(--color-border, #e2e8f0); font-family: 'Outfit', system-ui, sans-serif;
} font-size: 1.25rem;
font-weight: 700;
.icon-button svg { color: #ffffff;
width: 24px; text-decoration: none;
height: 24px;
}
.cart-badge {
position: relative;
}
.badge {
position: absolute;
top: 4px;
right: 4px;
min-width: 18px;
height: 18px;
padding: 0 5px;
font-size: var(--font-size-xs, 0.75rem);
font-weight: var(--font-weight-semibold, 600);
color: var(--color-text-inverse, #ffffff);
background-color: var(--color-primary, #2563eb);
border-radius: var(--radius-full, 9999px);
display: flex;
align-items: center;
justify-content: center;
} }
</style> </style>
<div class="top-bar"> <div class="top-bar">
<a href="index.html" class="logo">BookStore</a> <div class="left-section">
<div class="actions"> <slot name="menu-button"></slot>
<button class="icon-button" aria-label="Menu"> <slot name="logo"></slot>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> </div>
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> <div class="spacer"></div>
</svg> <div class="right-section">
</button> <slot name="actions"></slot>
<button class="icon-button cart-badge" aria-label="Shopping cart">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84M7.5 14.25 5.106 5.272M6 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm12.75 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
</svg>
<span class="badge">2</span>
</button>
</div> </div>
</div> </div>
`; `;
} }
} }
customElements.define('top-bar', TopBar); customElements.define("top-bar", TopBar);