fix: update header content to be rendered from index directly
This commit is contained in:
270
book.html
270
book.html
@@ -1,16 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<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"
|
||||
/>
|
||||
<title>The Midnight Library - BookStore</title>
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<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">
|
||||
<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>
|
||||
<search-bar></search-bar>
|
||||
</site-header>
|
||||
@@ -19,8 +84,20 @@
|
||||
<div class="book-detail">
|
||||
<!-- Back navigation -->
|
||||
<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">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
||||
<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="M15.75 19.5 8.25 12l7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
Back to Books
|
||||
</a>
|
||||
@@ -28,8 +105,18 @@
|
||||
<!-- Book Cover -->
|
||||
<div class="book-cover">
|
||||
<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">
|
||||
<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
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,11 +128,36 @@
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<span class="rating-text">4.5 (2,847 reviews)</span>
|
||||
</div>
|
||||
@@ -76,14 +188,38 @@
|
||||
|
||||
<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
|
||||
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
|
||||
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>
|
||||
@@ -92,8 +228,18 @@
|
||||
<!-- 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>
|
||||
<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 -->
|
||||
@@ -107,14 +253,38 @@
|
||||
<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>
|
||||
<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>
|
||||
<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">
|
||||
@@ -124,14 +294,42 @@
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
@@ -143,5 +341,5 @@
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/app.js"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -34,8 +34,8 @@ html {
|
||||
/* Set core body defaults */
|
||||
body {
|
||||
min-height: 100vh;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
|
||||
line-height: 1.5;
|
||||
text-rendering: optimizeSpeed;
|
||||
}
|
||||
@@ -180,9 +180,9 @@ table {
|
||||
--color-warning: #f59e0b;
|
||||
|
||||
/* Typography */
|
||||
--font-family-base: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||
Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
|
||||
'Helvetica Neue', sans-serif;
|
||||
--font-family-base: "Outfit", system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
--font-family-heading: var(--font-family-base);
|
||||
|
||||
--font-size-xs: 0.75rem; /* 12px */
|
||||
@@ -220,7 +220,8 @@ table {
|
||||
/* Shadows */
|
||||
--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-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 */
|
||||
--transition-fast: 150ms ease;
|
||||
@@ -244,6 +245,40 @@ body {
|
||||
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)
|
||||
Centers content in a phone-sized container on larger screens
|
||||
|
||||
85
index.html
85
index.html
@@ -1,16 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="BookStore - Discover and buy your next favorite book">
|
||||
<title>BookStore - Home</title>
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Milinda - Discover and buy your next favorite book"
|
||||
/>
|
||||
<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">
|
||||
<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>
|
||||
<search-bar></search-bar>
|
||||
</site-header>
|
||||
@@ -123,5 +188,5 @@
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/app.js"></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
class HorizontalScrollNav extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.attachShadow({ mode: "open" });
|
||||
this.categories = [
|
||||
{ id: 'all', label: 'All', active: true },
|
||||
{ id: 'fiction', label: 'Fiction', active: false },
|
||||
{ id: 'non-fiction', label: 'Non-Fiction', active: false },
|
||||
{ id: 'mystery', label: 'Mystery', active: false },
|
||||
{ id: 'romance', label: 'Romance', active: false },
|
||||
{ id: 'sci-fi', label: 'Sci-Fi', active: false },
|
||||
{ id: 'biography', label: 'Biography', active: false },
|
||||
{ id: 'history', label: 'History', active: false },
|
||||
{ id: "all", label: "All", active: true },
|
||||
{ id: "fiction", label: "Fiction", active: false },
|
||||
{ id: "non-fiction", label: "Non-Fiction", active: false },
|
||||
{ id: "mystery", label: "Mystery", active: false },
|
||||
{ id: "romance", label: "Romance", active: false },
|
||||
{ id: "sci-fi", label: "Sci-Fi", active: false },
|
||||
{ id: "biography", label: "Biography", active: false },
|
||||
{ id: "history", label: "History", active: false },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -24,28 +24,30 @@ class HorizontalScrollNav extends HTMLElement {
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
const buttons = this.shadowRoot.querySelectorAll('.nav-pill');
|
||||
buttons.forEach(button => {
|
||||
button.addEventListener('click', (e) => {
|
||||
const buttons = this.shadowRoot.querySelectorAll(".nav-pill");
|
||||
buttons.forEach((button) => {
|
||||
button.addEventListener("click", (e) => {
|
||||
this.setActiveCategory(e.target.dataset.id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setActiveCategory(id) {
|
||||
this.categories = this.categories.map(cat => ({
|
||||
this.categories = this.categories.map((cat) => ({
|
||||
...cat,
|
||||
active: cat.id === id
|
||||
active: cat.id === id,
|
||||
}));
|
||||
this.render();
|
||||
this.addEventListeners();
|
||||
|
||||
// Dispatch custom event for parent components
|
||||
this.dispatchEvent(new CustomEvent('category-change', {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("category-change", {
|
||||
detail: { categoryId: id },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -61,7 +63,7 @@ class HorizontalScrollNav extends HTMLElement {
|
||||
overflow-x: auto;
|
||||
scrollbar-width: 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 {
|
||||
@@ -96,18 +98,22 @@ class HorizontalScrollNav extends HTMLElement {
|
||||
}
|
||||
</style>
|
||||
<nav class="nav-container" role="navigation" aria-label="Book categories">
|
||||
${this.categories.map(cat => `
|
||||
${this.categories
|
||||
.map(
|
||||
(cat) => `
|
||||
<button
|
||||
class="nav-pill ${cat.active ? 'active' : ''}"
|
||||
class="nav-pill ${cat.active ? "active" : ""}"
|
||||
data-id="${cat.id}"
|
||||
${cat.active ? 'aria-current="true"' : ''}
|
||||
${cat.active ? 'aria-current="true"' : ""}
|
||||
>
|
||||
${cat.label}
|
||||
</button>
|
||||
`).join('')}
|
||||
`
|
||||
)
|
||||
.join("")}
|
||||
</nav>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('horizontal-scroll-nav', HorizontalScrollNav);
|
||||
customElements.define("horizontal-scroll-nav", HorizontalScrollNav);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class SearchBar extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.attachShadow({ mode: "open" });
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -14,24 +14,28 @@ class SearchBar extends HTMLElement {
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
const input = this.shadowRoot.querySelector('.search-input');
|
||||
const form = this.shadowRoot.querySelector('.search-form');
|
||||
const input = this.shadowRoot.querySelector(".search-input");
|
||||
const form = this.shadowRoot.querySelector(".search-form");
|
||||
|
||||
form.addEventListener('submit', (e) => {
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('search', {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("search", {
|
||||
detail: { query: input.value },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
input.addEventListener('input', (e) => {
|
||||
this.dispatchEvent(new CustomEvent('search-input', {
|
||||
input.addEventListener("input", (e) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("search-input", {
|
||||
detail: { query: e.target.value },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
composed: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,6 +50,8 @@ class SearchBar extends HTMLElement {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: var(--spacing-sm, 0.5rem) var(--spacing-sm, 0.5rem);
|
||||
background-color: #951D51;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
@@ -95,4 +101,4 @@ class SearchBar extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('search-bar', SearchBar);
|
||||
customElements.define("search-bar", SearchBar);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class SiteHeader extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.attachShadow({ mode: "open" });
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -27,7 +27,6 @@ class SiteHeader extends HTMLElement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm, 0.5rem);
|
||||
padding: var(--spacing-sm, 0.5rem) var(--spacing-md, 1rem);
|
||||
border-bottom: 1px solid var(--color-border, #e2e8f0);
|
||||
}
|
||||
</style>
|
||||
@@ -38,4 +37,4 @@ class SiteHeader extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('site-header', SiteHeader);
|
||||
customElements.define("site-header", SiteHeader);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* 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 {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.attachShadow({ mode: "open" });
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -22,89 +23,67 @@ class TopBar extends HTMLElement {
|
||||
.top-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 44px;
|
||||
height: 80px;
|
||||
padding: 0 16px;
|
||||
background-color: #951D51;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: var(--font-size-xl, 1.25rem);
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
color: var(--color-text, #1e293b);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.actions {
|
||||
.left-section {
|
||||
display: flex;
|
||||
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;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-md, 0.5rem);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--color-text, #1e293b);
|
||||
transition: background-color var(--transition-fast, 150ms ease);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.icon-button:hover {
|
||||
background-color: var(--color-background-tertiary, #f1f5f9);
|
||||
::slotted([slot="menu-button"] svg),
|
||||
::slotted(.icon-button svg) {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.icon-button:active {
|
||||
background-color: var(--color-border, #e2e8f0);
|
||||
}
|
||||
|
||||
.icon-button svg {
|
||||
width: 24px;
|
||||
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;
|
||||
::slotted([slot="logo"]) {
|
||||
font-family: 'Outfit', system-ui, sans-serif;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
<div class="top-bar">
|
||||
<a href="index.html" class="logo">BookStore</a>
|
||||
<div class="actions">
|
||||
<button class="icon-button" aria-label="Menu">
|
||||
<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="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||
</svg>
|
||||
</button>
|
||||
<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 class="left-section">
|
||||
<slot name="menu-button"></slot>
|
||||
<slot name="logo"></slot>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="right-section">
|
||||
<slot name="actions"></slot>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('top-bar', TopBar);
|
||||
customElements.define("top-bar", TopBar);
|
||||
|
||||
Reference in New Issue
Block a user