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

270
book.html
View File

@@ -1,16 +1,81 @@
<!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
name="description"
content="The Midnight Library - Between life and death there is a library"
/>
<title>The Midnight Library - BookStore</title> <title>The Midnight Library - BookStore</title>
<link rel="stylesheet" href="css/styles.css"> <link rel="preconnect" href="https://fonts.googleapis.com" />
</head> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<body> <link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<div class="mobile-container"> <div class="mobile-container">
<site-header> <site-header>
<top-bar></top-bar> <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">BookStore</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> <horizontal-scroll-nav></horizontal-scroll-nav>
<search-bar></search-bar> <search-bar></search-bar>
</site-header> </site-header>
@@ -19,8 +84,20 @@
<div class="book-detail"> <div class="book-detail">
<!-- Back navigation --> <!-- Back navigation -->
<a href="index.html" class="back-link"> <a href="index.html" class="back-link">
<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="M15.75 19.5 8.25 12l7.5-7.5" /> 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> </svg>
Back to Books Back to Books
</a> </a>
@@ -28,8 +105,18 @@
<!-- Book Cover --> <!-- Book Cover -->
<div class="book-cover"> <div class="book-cover">
<div class="book-cover-placeholder"> <div class="book-cover-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor"> <svg
<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" /> xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1"
stroke="currentColor"
>
<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"
/>
</svg> </svg>
</div> </div>
</div> </div>
@@ -41,11 +128,36 @@
<div class="book-rating"> <div class="book-rating">
<div class="stars"> <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">
<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> <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> 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 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> </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>
<span class="rating-text">4.5 (2,847 reviews)</span> <span class="rating-text">4.5 (2,847 reviews)</span>
</div> </div>
@@ -76,14 +188,38 @@
<div class="purchase-actions"> <div class="purchase-actions">
<button class="btn btn-primary btn-large"> <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"> <svg
<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" /> 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 Add to Cart
</button> </button>
<button class="btn btn-secondary"> <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"> <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"
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> </svg>
</button> </button>
</div> </div>
@@ -92,8 +228,18 @@
<!-- Description --> <!-- Description -->
<div class="book-description"> <div class="book-description">
<h2 class="section-heading">About this book</h2> <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>
<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> 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> </div>
<!-- Reviews --> <!-- Reviews -->
@@ -107,14 +253,38 @@
<span class="review-date">December 2025</span> <span class="review-date">December 2025</span>
</div> </div>
<div class="review-stars"> <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">
<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> <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> 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 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>
<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>
</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> <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"> <div class="review-card">
@@ -124,14 +294,42 @@
<span class="review-date">November 2025</span> <span class="review-date">November 2025</span>
</div> </div>
<div class="review-stars"> <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">
<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> <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> 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 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> </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> </div>
<p class="review-text">Great concept and well-executed. The writing flows effortlessly and keeps you engaged throughout. Highly recommend!</p> <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> <button class="btn btn-outline btn-full">View All Reviews</button>
@@ -143,5 +341,5 @@
</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;
} }
@@ -180,9 +180,9 @@ table {
--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 */
@@ -220,7 +220,8 @@ table {
/* 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;
@@ -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

View File

@@ -1,16 +1,81 @@
<!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>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<div class="mobile-container"> <div class="mobile-container">
<site-header> <site-header>
<top-bar></top-bar> <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> <horizontal-scroll-nav></horizontal-scroll-nav>
<search-bar></search-bar> <search-bar></search-bar>
</site-header> </site-header>
@@ -123,5 +188,5 @@
</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(
new CustomEvent("category-change", {
detail: { categoryId: id }, detail: { categoryId: id },
bubbles: true, bubbles: true,
composed: 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(
new CustomEvent("search", {
detail: { query: input.value }, detail: { query: input.value },
bubbles: true, bubbles: true,
composed: true composed: true,
})); })
);
}); });
input.addEventListener('input', (e) => { input.addEventListener("input", (e) => {
this.dispatchEvent(new CustomEvent('search-input', { this.dispatchEvent(
new CustomEvent("search-input", {
detail: { query: e.target.value }, detail: { query: e.target.value },
bubbles: true, bubbles: true,
composed: 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);