diff --git a/book.html b/book.html index bf73bcc..c7b4fae 100644 --- a/book.html +++ b/book.html @@ -1,147 +1,345 @@ - - - - - The Midnight Library - BookStore - - - -
- - - - - - - -
- - - - - - Back to Books - - - -
-
- - + + + + + The Midnight Library - BookStore + + + + + + +
+ + +
-
- - -
-

The Midnight Library

-

by Matt Haig

- -
-
- - - - - -
- 4.5 (2,847 reviews) -
- -
-
- Format - Hardcover -
-
- Pages - 304 -
-
- Language - English -
-
-
- - -
-
- $14.99 - $24.99 - 40% OFF -
- -
- + +
+ -
-
+ + + + - -
-

About this book

-

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?

-

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.

-
+ +
+ + + + + + Back to Books + - -
-

Customer Reviews

- -
-
-
- Sarah M. - December 2025 -
-
- - - - - -
+ +
+
+ + +
-

This book changed my perspective on life. Beautifully written and deeply thought-provoking. A must-read for anyone going through a difficult time.

-
-
-
- James K. - November 2025 + +
+

The Midnight Library

+

by Matt Haig

+ +
+
+ + + + + + + + + + + + + + +
-
- - - - - + 4.5 (2,847 reviews) +
+ +
+
+ Format + Hardcover +
+
+ Pages + 304 +
+
+ Language + English
-

Great concept and well-executed. The writing flows effortlessly and keeps you engaged throughout. Highly recommend!

- + +
+
+ $14.99 + $24.99 + 40% OFF +
+ +
+ + +
+
+ + +
+

About this book

+

+ 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? +

+

+ 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. +

+
+ + +
+

Customer Reviews

+ +
+
+
+ Sarah M. + December 2025 +
+
+ + + + + + + + + + + + + + + +
+
+

+ This book changed my perspective on life. Beautifully written + and deeply thought-provoking. A must-read for anyone going + through a difficult time. +

+
+ +
+
+
+ James K. + November 2025 +
+
+ + + + + + + + + + + + + + + +
+
+

+ Great concept and well-executed. The writing flows effortlessly + and keeps you engaged throughout. Highly recommend! +

+
+ + +
-
- + - -
+ +
- - + + diff --git a/css/styles.css b/css/styles.css index 4cd0d11..1c4aa15 100644 --- a/css/styles.css +++ b/css/styles.css @@ -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; } @@ -93,7 +93,7 @@ textarea:not([rows]) { html:focus-within { scroll-behavior: auto; } - + *, *::before, *::after { @@ -163,70 +163,71 @@ table { --color-primary-dark: #1d4ed8; --color-secondary: #64748b; --color-accent: #f59e0b; - + --color-text: #1e293b; --color-text-light: #64748b; --color-text-inverse: #ffffff; - + --color-background: #ffffff; --color-background-secondary: #f8fafc; --color-background-tertiary: #f1f5f9; - + --color-border: #e2e8f0; --color-border-light: #f1f5f9; - + --color-success: #22c55e; --color-error: #ef4444; --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 */ - --font-size-sm: 0.875rem; /* 14px */ - --font-size-base: 1rem; /* 16px */ - --font-size-lg: 1.125rem; /* 18px */ - --font-size-xl: 1.25rem; /* 20px */ - --font-size-2xl: 1.5rem; /* 24px */ - --font-size-3xl: 1.875rem; /* 30px */ - + + --font-size-xs: 0.75rem; /* 12px */ + --font-size-sm: 0.875rem; /* 14px */ + --font-size-base: 1rem; /* 16px */ + --font-size-lg: 1.125rem; /* 18px */ + --font-size-xl: 1.25rem; /* 20px */ + --font-size-2xl: 1.5rem; /* 24px */ + --font-size-3xl: 1.875rem; /* 30px */ + --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; - + --line-height-tight: 1.25; --line-height-normal: 1.5; --line-height-relaxed: 1.75; - + /* Spacing */ - --spacing-xs: 0.25rem; /* 4px */ - --spacing-sm: 0.5rem; /* 8px */ - --spacing-md: 1rem; /* 16px */ - --spacing-lg: 1.5rem; /* 24px */ - --spacing-xl: 2rem; /* 32px */ - --spacing-2xl: 3rem; /* 48px */ - + --spacing-xs: 0.25rem; /* 4px */ + --spacing-sm: 0.5rem; /* 8px */ + --spacing-md: 1rem; /* 16px */ + --spacing-lg: 1.5rem; /* 24px */ + --spacing-xl: 2rem; /* 32px */ + --spacing-2xl: 3rem; /* 48px */ + /* Border Radius */ - --radius-sm: 0.25rem; /* 4px */ - --radius-md: 0.5rem; /* 8px */ - --radius-lg: 0.75rem; /* 12px */ - --radius-xl: 1rem; /* 16px */ + --radius-sm: 0.25rem; /* 4px */ + --radius-md: 0.5rem; /* 8px */ + --radius-lg: 0.75rem; /* 12px */ + --radius-xl: 1rem; /* 16px */ --radius-full: 9999px; - + /* 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; --transition-normal: 250ms ease; --transition-slow: 350ms ease; - + /* Layout */ --mobile-max-width: 430px; --header-height: auto; @@ -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 @@ -264,7 +299,7 @@ body { align-items: flex-start; padding: var(--spacing-lg) 0; } - + .mobile-container { max-width: var(--mobile-max-width); min-height: calc(100vh - var(--spacing-lg) * 2); diff --git a/index.html b/index.html index e68914e..180b4d1 100644 --- a/index.html +++ b/index.html @@ -1,127 +1,192 @@ - - - - - BookStore - Home - - - -
- - - - - + + + + + Milinda - Home + + + + + + +
+ + + + +
+ + +
+
+ + +
- -
-

Featured Books

-
- - - - -
-
+ +
+

Featured Books

+
+ + + + +
+
-
-

New Releases

-
- - - - -
-
+
+

New Releases

+
+ + + + +
+
-
-

Best Sellers

-
- - - - -
-
-
+
+

Best Sellers

+
+ + + + +
+
+
- -
+ +
- - + + diff --git a/js/components/horizontal-scroll-nav.js b/js/components/horizontal-scroll-nav.js index 0c7bc7d..08a731c 100644 --- a/js/components/horizontal-scroll-nav.js +++ b/js/components/horizontal-scroll-nav.js @@ -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', { - detail: { categoryId: id }, - bubbles: true, - composed: true - })); + this.dispatchEvent( + new CustomEvent("category-change", { + detail: { categoryId: id }, + bubbles: 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 { } `; } } -customElements.define('horizontal-scroll-nav', HorizontalScrollNav); +customElements.define("horizontal-scroll-nav", HorizontalScrollNav); diff --git a/js/components/search-bar.js b/js/components/search-bar.js index e2a39fd..6b1dc13 100644 --- a/js/components/search-bar.js +++ b/js/components/search-bar.js @@ -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', { - detail: { query: input.value }, - bubbles: true, - composed: true - })); + this.dispatchEvent( + new CustomEvent("search", { + detail: { query: input.value }, + bubbles: true, + composed: true, + }) + ); }); - input.addEventListener('input', (e) => { - this.dispatchEvent(new CustomEvent('search-input', { - detail: { query: e.target.value }, - bubbles: true, - composed: true - })); + input.addEventListener("input", (e) => { + this.dispatchEvent( + new CustomEvent("search-input", { + detail: { query: e.target.value }, + bubbles: 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); diff --git a/js/components/site-header.js b/js/components/site-header.js index b30323d..fea9913 100644 --- a/js/components/site-header.js +++ b/js/components/site-header.js @@ -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); } @@ -38,4 +37,4 @@ class SiteHeader extends HTMLElement { } } -customElements.define('site-header', SiteHeader); +customElements.define("site-header", SiteHeader); diff --git a/js/components/top-bar.js b/js/components/top-bar.js index 07ba20c..bdaf489 100644 --- a/js/components/top-bar.js +++ b/js/components/top-bar.js @@ -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; }
- -
- - +
+ + +
+
+
+
`; } } -customElements.define('top-bar', TopBar); +customElements.define("top-bar", TopBar);