diff --git a/MidrandBookshop/Components/Layout/ReconnectModal.razor b/MidrandBookshop/Components/Layout/ReconnectModal.razor index e740b0c..5913b7e 100644 --- a/MidrandBookshop/Components/Layout/ReconnectModal.razor +++ b/MidrandBookshop/Components/Layout/ReconnectModal.razor @@ -1,31 +1,58 @@  -
-
+ \ No newline at end of file diff --git a/MidrandBookshop/Components/Layout/ReconnectModal.razor.css b/MidrandBookshop/Components/Layout/ReconnectModal.razor.css index 3ad3773..53204b6 100644 --- a/MidrandBookshop/Components/Layout/ReconnectModal.razor.css +++ b/MidrandBookshop/Components/Layout/ReconnectModal.razor.css @@ -1,157 +1,218 @@ -.components-reconnect-first-attempt-visible, -.components-reconnect-repeated-attempt-visible, -.components-reconnect-failed-visible, -.components-pause-visible, -.components-resume-failed-visible, -.components-rejoining-animation { - display: none; -} - -#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible, -#components-reconnect-modal.components-reconnect-show .components-rejoining-animation, -#components-reconnect-modal.components-reconnect-paused .components-pause-visible, -#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible, -#components-reconnect-modal.components-reconnect-retrying, -#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible, -#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation, -#components-reconnect-modal.components-reconnect-failed, -#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible { - display: block; -} - +/* ========================================================================== + Midrand Books — Glassine Architectural Veil & Ribbon Strip + ========================================================================== */ +/* --- Native Dialog Element Layout Overrides --- */ #components-reconnect-modal { - background-color: white; - width: 20rem; - margin: 20vh auto; - padding: 2rem; - border: 0; - border-radius: 0.5rem; - box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3); - opacity: 0; - transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete; - animation: components-reconnect-modal-fadeOutOpacity 0.5s both; - &[open] - -{ - animation: components-reconnect-modal-slideUp 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity 0.5s ease-in-out 0.3s; - animation-fill-mode: both; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + max-width: 100vw; + max-height: 100vh; + margin: 0; + padding: 0; + border: none; + background: transparent; + z-index: 99999; + overflow: hidden; } -} - -#components-reconnect-modal::backdrop { - background-color: rgba(0, 0, 0, 0.4); - animation: components-reconnect-modal-fadeInOpacity 0.5s ease-in-out; - opacity: 1; -} - -@keyframes components-reconnect-modal-slideUp { - 0% { - transform: translateY(30px) scale(0.95); + /* Remove default browser modal backdrop blockout to allow custom layering below */ + #components-reconnect-modal::backdrop { + background: transparent; } - 100% { +/* --- Glassine Page Jacket Layer --- + Frosted translucent shield that preserves context visibility while blocking mouse actions +*/ +.glassine-page-jacket { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(251, 251, 250, 0.4); /* Premium warm paper tint */ + backdrop-filter: blur(5px); /* Elegant frosted glass sweep */ + cursor: wait; + animation: glassFadeIn 0.35s ease-out forwards; +} + +@keyframes glassFadeIn { + from { + opacity: 0; + backdrop-filter: blur(0px); + } + + to { + opacity: 1; + backdrop-filter: blur(5px); + } +} + +/* --- The Sliding Ribbon Banner --- */ +.literary-sync-strip { + position: absolute; + top: 0; + left: 0; + width: 100%; + background-color: #FFFFFF; + border-bottom: 1px solid rgba(0, 0, 0, 0.08); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0, 0, 0, 0.02); + padding: 1.1rem 2rem; + box-sizing: border-box; + z-index: 2; + /* Animation kinematics: smooth physical drop slide */ + transform: translateY(-100%); + animation: stripSlideDown 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards; +} + +@keyframes stripSlideDown { + to { transform: translateY(0); } } -@keyframes components-reconnect-modal-fadeInOpacity { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -@keyframes components-reconnect-modal-fadeOutOpacity { - 0% { - opacity: 1; - } - - 100% { - opacity: 0; - } -} - -.components-reconnect-container { - display: flex; - flex-direction: column; +/* --- Ribbon Layout Matrix Grid --- */ +.strip-container { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: auto 1fr auto; align-items: center; - gap: 1rem; + gap: 2.5rem; } -#components-reconnect-modal p { - margin: 0; - text-align: center; +/* Left Node Ticker Elements & Animated Vector */ +.sync-status-indicator { + display: flex; + align-items: center; + gap: 0.85rem; + border-right: 1px solid rgba(0, 0, 0, 0.08); + padding-right: 2rem; } -#components-reconnect-modal button { - border: 0; - background-color: #6b9ed2; - color: white; - padding: 4px 24px; - border-radius: 4px; +.small-tracking { + font-family: var(--bs-font-monospace); + font-size: 0.7rem; + letter-spacing: 0.12em; + color: #111111; + font-weight: 600; } - #components-reconnect-modal button:hover { - background-color: #3b6ea2; - } - - #components-reconnect-modal button:active { - background-color: #6b9ed2; - } - -.components-rejoining-animation { - position: relative; - width: 80px; - height: 80px; +/* Animated Book Helix SVG */ +.literary-helix-loader { + width: 18px; + height: 18px; + color: #111111; } - .components-rejoining-animation div { - position: absolute; - border: 3px solid #0087ff; - opacity: 1; - border-radius: 50%; - animation: components-rejoining-animation 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite; - } +.flipping-leaf-vector { + transform-origin: 12px 12px; + animation: svgLeafFlip 1.6s infinite cubic-bezier(0.4, 0, 0.2, 1); +} - .components-rejoining-animation div:nth-child(2) { - animation-delay: -0.5s; - } - -@keyframes components-rejoining-animation { +@keyframes svgLeafFlip { 0% { - top: 40px; - left: 40px; - width: 0; - height: 0; - opacity: 0; - } - - 4.9% { - top: 40px; - left: 40px; - width: 0; - height: 0; - opacity: 0; - } - - 5% { - top: 40px; - left: 40px; - width: 0; - height: 0; + transform: scaleX(1); opacity: 1; } + 50% { + transform: scaleX(0); + opacity: 0.3; + } + 100% { - top: 0px; - left: 0px; - width: 80px; - height: 80px; + transform: scaleX(-1); opacity: 0; } } + +/* Center Node Text Content */ +.sync-message-body { + font-family: Georgia, 'Times New Roman', serif; + font-size: 0.95rem; + color: #333333; + font-style: italic; +} + +.text-crimson { + color: #A34843; + font-style: normal; + font-weight: 500; +} + +/* Right Node Fine-Press Button Trigger */ +.btn-strip-action { + background: #111111; + color: #FFFFFF; + border: 1px solid #111111; + padding: 0.45rem 1.25rem; + font-family: var(--bs-font-monospace); + font-size: 0.7rem; + letter-spacing: 0.08em; + text-transform: uppercase; + border-radius: 4px; + transition: all 0.2s ease; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + + .btn-strip-action:hover { + background: transparent; + color: #111111; + } + + .btn-strip-action svg { + transition: transform 0.2s ease; + } + + .btn-strip-action:hover svg { + transform: rotate(45deg); + } + +/* --- Display Mechanics Matrix Controllers --- */ +.components-reconnect-first-attempt-visible, +.components-reconnect-repeated-attempt-visible, +.components-reconnect-failed-visible, +.components-pause-visible, +.components-resume-failed-visible { + display: none !important; +} + +#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible, +#components-reconnect-modal.components-reconnect-paused .components-pause-visible, +#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible, +#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible, +#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible { + display: inline-block !important; +} + +#components-reconnect-modal.components-reconnect-failed .btn-strip-action, +#components-reconnect-modal.components-reconnect-paused .btn-strip-action, +#components-reconnect-modal.components-reconnect-resume-failed .btn-strip-action { + display: inline-flex !important; +} + +/* Tablet Parameters Response Collapse Matrix */ +@media (max-width: 768px) { + .strip-container { + grid-template-columns: 1fr; + gap: 0.65rem; + text-align: center; + } + + .sync-status-indicator { + border-right: none; + padding-right: 0; + justify-content: center; + } + + .sync-action-node { + margin-top: 0.25rem; + } +} diff --git a/MidrandBookshop/Components/Layout/ReconnectModal.razor.js b/MidrandBookshop/Components/Layout/ReconnectModal.razor.js index a44de78..bf38930 100644 --- a/MidrandBookshop/Components/Layout/ReconnectModal.razor.js +++ b/MidrandBookshop/Components/Layout/ReconnectModal.razor.js @@ -1,4 +1,3 @@ -// Set up event handlers const reconnectModal = document.getElementById("components-reconnect-modal"); reconnectModal.addEventListener("components-reconnect-state-changed", handleReconnectStateChanged); @@ -24,14 +23,8 @@ async function retry() { document.removeEventListener("visibilitychange", retryWhenDocumentBecomesVisible); try { - // Reconnect will asynchronously return: - // - true to mean success - // - false to mean we reached the server, but it rejected the connection (e.g., unknown circuit ID) - // - exception to mean we didn't reach the server (this can be sync or async) const successful = await Blazor.reconnect(); if (!successful) { - // We have been able to reach the server, but the circuit is no longer available. - // We'll reload the page so the user can continue using the app as quickly as possible. const resumeSuccessful = await Blazor.resumeCircuit(); if (!resumeSuccessful) { location.reload(); @@ -40,7 +33,6 @@ async function retry() { } } } catch (err) { - // We got an exception, server is currently unavailable document.addEventListener("visibilitychange", retryWhenDocumentBecomesVisible); } } @@ -60,4 +52,4 @@ async function retryWhenDocumentBecomesVisible() { if (document.visibilityState === "visible") { await retry(); } -} +} \ No newline at end of file diff --git a/MidrandBookshop/Components/Pages/About.razor b/MidrandBookshop/Components/Pages/About.razor new file mode 100644 index 0000000..ef48fb7 --- /dev/null +++ b/MidrandBookshop/Components/Pages/About.razor @@ -0,0 +1,68 @@ +@page "/about" +@rendermode InteractiveServer +@inject IJSRuntime JSRuntime + +
+
+ Our Story & Vision +

For the Love of the Written Word

+

+ Midrand Books is an independent literary imprint and online bookstore operated by Lite Charms (Pty) Ltd. +

+
+ +
+
+
+ + + +
+
+ +
+
+ +
+

1. A Curated Space for Readers

+

+ At Midrand Books, we believe that an online bookstore should feel just as warm, inspiring, and intentional as a physical corner shop. We aren’t interested in mass-market commercial algorithms; we are interested in books that leave a mark. +

+

+ Operated proudly under Lite Charms (Pty) Ltd, our storefront is designed to showcase beautiful storytelling, critical histories, academic research, and deep technical disciplines. We source fine press editions and trusted literary brands, ensuring that every book we package and deliver across South Africa feels special from the moment it reaches your hands. +

+
+ +
+

2. Empowering New & Independent Voices

+

+ Beyond our role as a bookseller, our truest passion lies in cultivating the next chapter of South African literature. We know how daunting the modern publishing landscape can be for emerging storytellers, experts, and independent creators. +

+

+ That is why we have integrated custom distribution channels into our platform to help self-publishers and local authors get their manuscripts beautifully styled, correctly indexed, and directly in front of avid readers. Side-by-side with heritage publishing houses, we champion the creative freedom of the indie writer. +

+
+ +
+

3. Our Creative Guarantee

+

+ Whether you are an established global author footprint looking for a seamless marketplace, a first-time writer ready to publish your debut book, or a reader hunting for your next great obsession, we welcome you. Midrand Books operates in full compliance with the South African Companies Act, ensuring that your data, transactions, and intellectual property are kept fully safe. +

+
+ +
+
+
+
+ +@code { + private async Task ScrollToSection(string elementId) + { + await JSRuntime.InvokeVoidAsync("eval", $@" + var el = document.getElementById('{elementId}'); + if (el) {{ + el.scrollIntoView({{ behavior: 'smooth', block: 'start' }}); + }} + "); + } +} \ No newline at end of file diff --git a/MidrandBookshop/Components/Pages/About.razor.css b/MidrandBookshop/Components/Pages/About.razor.css new file mode 100644 index 0000000..efaaee3 --- /dev/null +++ b/MidrandBookshop/Components/Pages/About.razor.css @@ -0,0 +1,85 @@ +/* ========================================================================== + Midrand Books — About Page Fine Press Styles + ========================================================================== */ + +.editorial-page-container { + max-width: 1140px; + margin: 0 auto; + padding-left: 1.5rem; + padding-right: 1.5rem; + font-family: system-ui, -apple-system, sans-serif; +} + +.editorial-main-title { + font-size: 2.5rem; + letter-spacing: -0.03em; + color: #111111; + font-family: Georgia, 'Times New Roman', serif; +} + +.tracking-wider { + letter-spacing: 0.12em; +} + +/* --- Index Navigation Controls --- */ +.editorial-nav-index { + position: sticky; + top: 2rem; + border-left: 1px solid rgba(0, 0, 0, 0.08); + padding-left: 1.25rem; +} + +.index-btn { + color: #666666; + background: transparent; + border: none; + padding: 0; + margin: 0; + font-family: inherit; + font-size: inherit; + cursor: pointer; + text-decoration: none; + transition: color 0.2s ease, padding-left 0.2s ease; +} + + .index-btn:hover { + color: #111111; + padding-left: 4px; + } + + .index-btn:focus { + outline: none; + color: #111111; + font-weight: 600; + } + +/* --- Narrative Typography --- */ +.editorial-article-body { + line-height: 1.8; + color: #333333; + font-size: 1rem; +} + +.section-title { + font-family: Georgia, 'Times New Roman', serif; + font-size: 1.35rem; + color: #111111; + margin-bottom: 1.25rem; + font-weight: 500; + scroll-margin-top: 2rem; +} + +.text-muted-serif { + color: #555555; +} + +.editorial-section p { + margin-bottom: 1.2rem; +} + +.protective-credo-callout { + background-color: #FAFAFA; + border: 1px solid rgba(0, 0, 0, 0.05); + padding: 2rem; + border-radius: 8px; +} diff --git a/MidrandBookshop/Components/Pages/Account.razor b/MidrandBookshop/Components/Pages/Account.razor index b8dbb6a..ab816d7 100644 --- a/MidrandBookshop/Components/Pages/Account.razor +++ b/MidrandBookshop/Components/Pages/Account.razor @@ -4,225 +4,237 @@ @rendermode InteractiveServer @attribute [Authorize] -
-

My Account

+
+ +
-
-