From 51946a1388e4e33576590350572dd6b5799f99d2 Mon Sep 17 00:00:00 2001 From: Khwezi Mngoma Date: Mon, 18 May 2026 19:19:26 +0200 Subject: [PATCH] Started producer design --- ShopAdmin/Components/CreateProduct.razor | 119 ++++++++ ShopAdmin/Components/CreateProduct.razor.cs | 5 + ShopAdmin/Components/CreateProduct.razor.css | 275 ++++++++++++++++++ .../Components/Pages/Notifications.razor | 4 +- .../Components/Pages/Notifications.razor.css | 42 ++- ShopAdmin/Components/Pages/Products.razor | 114 ++++++++ ShopAdmin/Components/Pages/Products.razor.cs | 5 + ShopAdmin/Components/Pages/Products.razor.css | 205 +++++++++++++ 8 files changed, 766 insertions(+), 3 deletions(-) create mode 100644 ShopAdmin/Components/CreateProduct.razor create mode 100644 ShopAdmin/Components/CreateProduct.razor.cs create mode 100644 ShopAdmin/Components/CreateProduct.razor.css create mode 100644 ShopAdmin/Components/Pages/Products.razor create mode 100644 ShopAdmin/Components/Pages/Products.razor.cs create mode 100644 ShopAdmin/Components/Pages/Products.razor.css diff --git a/ShopAdmin/Components/CreateProduct.razor b/ShopAdmin/Components/CreateProduct.razor new file mode 100644 index 0000000..777a087 --- /dev/null +++ b/ShopAdmin/Components/CreateProduct.razor @@ -0,0 +1,119 @@ +@using Microsoft.AspNetCore.Components.Forms + +
+ + + +
+
+ Initialization Sequence +

Register a new asset node into the core product catalog matrix.

+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ +
+
+
+ +
+ + +
+ @for (int i = 0; i < 5; i++) + { + var index = i; +
+ @if (HasAssetAt(index)) + { + Slot @(index + 1) + + } + else + { +
+ + 0@(index + 1) +
+ } +
+ } +
+
+
+ +
+
+ + +
+
+ +@code { + private Product ProductModel { get; set; } = new(); + + protected override void OnInitialized() + { + ProductModel.Active = true; + ProductModel.Thumbnails ??= new string[0]; + } + + private bool HasAssetAt(int index) => + ProductModel.Thumbnails != null && index < ProductModel.Thumbnails.Length && !string.IsNullOrWhiteSpace(ProductModel.Thumbnails[index]); + + private void RemoveThumbnailAt(int index) + { + if (ProductModel.Thumbnails == null) return; + var list = ProductModel.Thumbnails.ToList(); + if (index < list.Count) + { + list.RemoveAt(index); + ProductModel.Thumbnails = list.ToArray(); + } + } + + private void HandleValidSubmit() + { + // Save operation business logic goes here + } + + public class Product + { + public Guid Id { get; set; } = Guid.NewGuid(); + public string? Name { get; set; } + public string? Summary { get; set; } + public string? Description { get; set; } + public string? ImageUrl { get; set; } + public string[]? Thumbnails { get; set; } + public bool Active { get; set; } + } +} \ No newline at end of file diff --git a/ShopAdmin/Components/CreateProduct.razor.cs b/ShopAdmin/Components/CreateProduct.razor.cs new file mode 100644 index 0000000..502eb96 --- /dev/null +++ b/ShopAdmin/Components/CreateProduct.razor.cs @@ -0,0 +1,5 @@ +namespace ShopAdmin.Components; + +public partial class CreateProduct +{ +} diff --git a/ShopAdmin/Components/CreateProduct.razor.css b/ShopAdmin/Components/CreateProduct.razor.css new file mode 100644 index 0000000..6910574 --- /dev/null +++ b/ShopAdmin/Components/CreateProduct.razor.css @@ -0,0 +1,275 @@ +/* Core Structural Layout Space Configuration */ +.create-product-container { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; +} + +.form-entry-canvas { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; +} + +.form-scroll-viewport { + padding: 2.5rem; + flex: 1; + overflow-y: auto; +} + +.form-section-header { + margin-bottom: 2.5rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); + padding-bottom: 1.25rem; +} + +.field-accent-tag { + font-size: 1rem; + letter-spacing: 0.02em; + color: #ffffff !important; + font-weight: 600; +} + +.form-section-header p { + margin-top: 0.4rem; + font-size: 0.85rem; + color: #64748b; +} + +/* Precise Balanced Grid Matrix Layout */ +.form-grid-layout { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 3.5rem; + align-items: start; +} + +.form-column { + display: flex; + flex-direction: column; + gap: 2rem; +} + +/* Brand Metric Console Inputs Architecture */ +.console-field-group { + display: flex; + flex-direction: column; + gap: 0.75rem; + width: 100%; +} + +.console-field-label { + font-size: 0.88rem; + font-weight: 500; + color: #cbd5e1; + letter-spacing: 0.01em; + user-select: none; +} + +.node-dim-label { + color: #475569; + font-size: 0.75rem; + margin-left: 0.25rem; +} + +/* High-Fidelity Branded Form Controls */ +.console-input, .console-textarea { + width: 100%; + background: #060b13; + border: 1px solid #1e293b; + border-radius: 6px; + padding: 0.9rem 1.1rem; + color: #f8fafc; + font-size: 0.92rem; + font-family: inherit; + outline: none; + transition: border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1); +} + + /* Component Placeholder Styling */ + .console-input::placeholder, .console-textarea::placeholder { + color: #334155; + font-size: 0.88rem; + } + + /* Branded Interactive Focus Transitions */ + .console-input:focus, .console-textarea:focus { + border-color: #00f2fe; + box-shadow: 0 0 0 1px #00f2fe; + } + +.console-textarea { + resize: none; + line-height: 1.6; +} + +/* Asset URL Composite Field Layout Extensions */ +.input-asset-addon { + display: flex; + align-items: stretch; + width: 100%; +} + +.asset-path-input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.asset-preview-stub { + background: #0b131f; + border: 1px solid #1e293b; + border-left: none; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + width: 54px; + color: #475569; + flex-shrink: 0; + transition: border-color 0.2s ease, color 0.2s ease; +} + +/* Keep addon stub borders synced during primary field focus */ +.input-asset-addon:focus-within .asset-path-input { + border-color: #00f2fe; +} + +.input-asset-addon:focus-within .asset-preview-stub { + border-color: #00f2fe; + color: #00f2fe; +} + +/* Layout Space Tuning Adjustments for Media Sections */ +.spacing-top-modifier { + margin-top: 0.25rem; +} + +/* 5-Item Array Asset Matrix Grid */ +.thumbnail-deck-grid { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 0.85rem; +} + +.thumbnail-slot-node { + aspect-ratio: 1 / 1; + background: #060b13; + border: 1px dashed #1e293b; + border-radius: 6px; + position: relative; + overflow: hidden; + transition: border-color 0.2s ease, background 0.2s ease; +} + + .thumbnail-slot-node.empty:hover { + border-color: #ff5722; + background: rgba(255, 87, 34, 0.02); + } + +.empty-slot-blueprint { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + color: #334155; + gap: 0.35rem; + user-select: none; +} + + .empty-slot-blueprint svg { + width: 16px; + height: 16px; + } + + .empty-slot-blueprint span { + font-size: 0.65rem; + font-family: monospace; + letter-spacing: 0.02em; + } + +.thumbnail-slot-node.populated { + border-style: solid; + border-color: #1e293b; +} + + .thumbnail-slot-node.populated img { + width: 100%; + height: 100%; + object-fit: cover; + } + +.btn-clear-slot { + position: absolute; + top: 4px; + right: 4px; + background: #0f172a; + border: 1px solid #334155; + color: #cbd5e1; + border-radius: 4px; + width: 18px; + height: 18px; + font-size: 0.65rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.15s ease, border-color 0.15s ease; +} + + .btn-clear-slot:hover { + border-color: #ff5722; + color: #ff5722; + } + +.thumbnail-slot-node.populated:hover .btn-clear-slot { + opacity: 1; +} + +/* Form Action Control Bar Layout */ +.form-action-footer { + padding: 1.5rem 2.5rem; + background: #04080f; + border-top: 1px solid #1e293b; + display: flex; + justify-content: flex-end; + gap: 1.5rem; + align-items: center; +} + +.btn-console-flat { + background: transparent; + border: none; + color: #64748b; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + padding: 0.6rem 1.2rem; + border-radius: 4px; + transition: color 0.2s ease; +} + + .btn-console-flat:hover { + color: #f1f5f9; + } + +/* Using your brand active cyan color for submission commits */ +.btn-apply-filters { + background: #00f2fe; + border: none; + color: #060b13; + font-weight: 600; + font-size: 0.9rem; + padding: 0.75rem 1.5rem; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s ease, opacity 0.2s ease; +} + + .btn-apply-filters:hover { + background: #00d8e4; + } diff --git a/ShopAdmin/Components/Pages/Notifications.razor b/ShopAdmin/Components/Pages/Notifications.razor index bc8f7f3..b274615 100644 --- a/ShopAdmin/Components/Pages/Notifications.razor +++ b/ShopAdmin/Components/Pages/Notifications.razor @@ -5,6 +5,8 @@ Notifications | Shop Console +
+ @if (NotificationQueryable == null && IsLoading) {
@@ -90,7 +92,7 @@
- +
diff --git a/ShopAdmin/Components/Pages/Notifications.razor.css b/ShopAdmin/Components/Pages/Notifications.razor.css index 57a9868..1f7c0fb 100644 --- a/ShopAdmin/Components/Pages/Notifications.razor.css +++ b/ShopAdmin/Components/Pages/Notifications.razor.css @@ -1,4 +1,5 @@ -/* ========================================================================== + +/* ========================================================================== 1. WORKSPACE LAYOUT & LAYOUT ENGINE BOUNDS ========================================================================== */ @@ -685,4 +686,41 @@ to { opacity: 1; } -} \ No newline at end of file +} + +/* ========================================================================== + X. BROAD VIEWPORT TELEMETRY CANVASES (Circuit Matrix Backdrop) + ========================================================================== */ + +.workspace-ambient-backdrop { + position: fixed; /* Securely locks backdrop layer behind all scroll surfaces */ + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 0; + pointer-events: none; + user-select: none; + /* PERCENT-ENCODED INLINE SVG CIRCUIT GRID ENGINE: + - Uses a highly diluted telemetry orange mix matching your #ff6b35 accent tags. + - Built out of interlocking data nodes, traces, and measurement crosshairs. + */ + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' viewBox='0 0 180 180'%3E%3Cg fill='none' stroke='rgba(255, 107, 53, 0.11)' stroke-width='1.2'%3E%3C!-- Core Element 1: Center Tech Microprocessor Node --%3E%3Crect x='70' y='70' width='40' height='40' rx='3' stroke-width='1.5'/%3E%3Ccircle cx='90' cy='90' r='10' stroke-dasharray='2 2'/%3E%3Ccircle cx='90' cy='90' r='3' fill='rgba(255, 107, 53, 0.05)'/%3E%3C!-- Core Element 2: Radiating Bus Traces %26 Corner Trunks --%3E%3Cpath d='M 90,70 L 90,40 L 70,40 M 90,110 L 90,140 L 110,140 M 70,90 L 40,90 L 40,110 M 110,90 L 140,90 L 140,70'/%3E%3Ccircle cx='70' cy='40' r='2.5' fill='rgba(255, 107, 53, 0.15)'/%3E%3Ccircle cx='110' cy='140' r='2.5' fill='rgba(255, 107, 53, 0.15)'/%3E%3Ccircle cx='40' cy='110' r='2.5' fill='rgba(255, 107, 53, 0.15)'/%3E%3Ccircle cx='140' cy='70' r='2.5' fill='rgba(255, 107, 53, 0.15)'/%3E%3C!-- Core Element 3: Peripheral Data Junctions (Interlocking Corners) --%3E%3Ccircle cx='0' cy='0' r='35' stroke-width='0.8'/%3E%3Ccircle cx='0' cy='0' r='20' stroke-dasharray='4 3'/%3E%3Ccircle cx='180' cy='0' r='35' stroke-width='0.8'/%3E%3Ccircle cx='180' cy='0' r='20' stroke-dasharray='4 3'/%3E%3Ccircle cx='0' cy='180' r='35' stroke-width='0.8'/%3E%3Ccircle cx='0' cy='180' r='20' stroke-dasharray='4 3'/%3E%3Ccircle cx='180' cy='180' r='35' stroke-width='0.8'/%3E%3Ccircle cx='180' cy='180' r='20' stroke-dasharray='4 3'/%3E%3C!-- Target Scope Crosshairs --%3E%3Cpath d='M 0,90 L 15,90 M 180,90 L 165,90 M 90,0 L 90,15 M 90,180 L 90,165' stroke-width='0.8' opacity='0.7'/%3E%3Cpath d='M 25,25 L 35,25 M 25,25 L 25,35 M 155,25 L 145,25 M 155,25 L 155,35 M 25,155 L 35,155 M 25,155 L 25,145 M 155,155 L 145,155 M 155,155 L 155,145' stroke-width='0.9' opacity='0.5'/%3E%3C/g%3E%3C/svg%3E"); + background-repeat: repeat; + background-size: 180px 180px; + /* Radial Mask: Blends perfectly out into your dark layout edges while + keeping text components crisp and legible in the foreground */ + mask-image: radial-gradient(circle at 50% 45%, rgba(0,0,0,0.12) 15%, black 80%); + -webkit-mask-image: radial-gradient(circle at 50% 45%, rgba(0,0,0,0.12) 15%, black 80%); +} + + /* Deep contextual underglow to give your glassmorphism cards an illuminated orange edge */ + .workspace-ambient-backdrop::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient( circle at 50% 45%, rgba(255, 107, 53, 0.04) 0%, rgba(0, 0, 0, 0) 75% ); + } \ No newline at end of file diff --git a/ShopAdmin/Components/Pages/Products.razor b/ShopAdmin/Components/Pages/Products.razor new file mode 100644 index 0000000..eaa6f14 --- /dev/null +++ b/ShopAdmin/Components/Pages/Products.razor @@ -0,0 +1,114 @@ +@page "/products" +@rendermode RenderMode.InteractiveServer + +Products & Pricing | Shop Console + +
+ +
+ + + +
+ + + +
+
+
+
+
+ +
+ @switch (ActiveView) + { + case ProductView.Create: + + break; + case ProductView.ViewAll: +
+ Active Item Ledger +

Awaiting product lookup parameters...

+
+ break; + case ProductView.Prices: +
+ Pricing Matrices +

Awaiting exchange rates configuration profiles...

+
+ break; + case ProductView.Packages: +
+ Kit & Bundle Registers +

Awaiting relational node definitions...

+
+ break; + } +
+ +
+
+ +@code { + // Enum declaration to rigidly manage split view panel state mapping safely + private enum ProductView + { + Create, + ViewAll, + Prices, + Packages + } + + // Default runtime tracking state variables + private ProductView ActiveView { get; set; } = ProductView.Create; + + private void SwitchView(ProductView targetView) + { + ActiveView = targetView; + } +} \ No newline at end of file diff --git a/ShopAdmin/Components/Pages/Products.razor.cs b/ShopAdmin/Components/Pages/Products.razor.cs new file mode 100644 index 0000000..1f14f7c --- /dev/null +++ b/ShopAdmin/Components/Pages/Products.razor.cs @@ -0,0 +1,5 @@ +namespace ShopAdmin.Components.Pages; + +public partial class Products +{ +} diff --git a/ShopAdmin/Components/Pages/Products.razor.css b/ShopAdmin/Components/Pages/Products.razor.css new file mode 100644 index 0000000..5db5f35 --- /dev/null +++ b/ShopAdmin/Components/Pages/Products.razor.css @@ -0,0 +1,205 @@ +/* ========================================================================== + 1. BROAD VIEWPORT KALEIDOSCOPE BACKDROP (The Arrow Targets) + ========================================================================= */ + +.workspace-ambient-backdrop { + position: fixed; /* Securely locks backdrop layer behind all scroll surfaces */ + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 0; + pointer-events: none; + user-select: none; + /* ENHANCED INLINE SVG EXOTIC FRUIT KALEIDOSCOPE + - Increased stroke values from 0.035 up to 0.14 for striking visibility. + - Clean, un-broken cross-browser safe rendering framework. + */ + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='none' stroke='rgba(0, 163, 224, 0.14)' stroke-width='1.2'%3E%3Ccircle cx='80' cy='80' r='75'/%3E%3Ccircle cx='80' cy='80' r='50'/%3E%3Ccircle cx='80' cy='80' r='25'/%3E%3Cpath d='M80,0 L80,160 M0,80 L160,80 M23.43,23.43 L136.57,136.57 M23.43,136.57 L136.57,23.43' stroke-dasharray='3 3' opacity='0.6'/%3E%3Cpolygon points='80,15 95,65 145,80 95,95 80,145 65,95 15,80 65,65' stroke-width='0.8'/%3E%3Ccircle cx='0' cy='0' r='20'/%3E%3Ccircle cx='160' cy='0' r='20'/%3E%3Ccircle cx='0' cy='160' r='20'/%3E%3Ccircle cx='160' cy='160' r='20'/%3E%3C/g%3E%3C/svg%3E"); + background-repeat: repeat; + background-size: 160px 160px; + /* RADIAL VIGNETTE MASK OPTIMIZATION: + Allows the shapes to render significantly sharper as they approach + the outer screen margins. + */ + mask-image: radial-gradient(circle at 50% 45%, rgba(0,0,0,0.15) 20%, black 80%); + -webkit-mask-image: radial-gradient(circle at 50% 45%, rgba(0,0,0,0.15) 20%, black 80%); +} + + /* Vivid ambient brand cyan underglow backing layout layers */ + .workspace-ambient-backdrop::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient( circle at 50% 45%, rgba(0, 163, 224, 0.05) 0%, rgba(0, 0, 0, 0) 80% ); + } + +/* ========================================================================== + 2. MAIN INTERFACE WORKSPACE (The Master Deck Card Block) + ========================================================================== */ + +.console-workspace { + position: relative; + z-index: 1; /* Keeps user actions and console content layers strictly on top */ + max-width: 1340px; + width: 100%; + margin: 0 auto; + padding: 2rem 1.5rem; + box-sizing: border-box; +} + +.split-workspace-deck { + display: grid; + grid-template-columns: 280px auto 1fr; + min-height: 620px; + width: 100%; + position: relative; +} + +/* Translucent Obsidian Glassmorphism panel block */ +.shadow-card { + background: rgba(10, 14, 20, 0.75); + border: 1px solid rgba(255, 255, 255, 0.03); + box-shadow: 0 24px 60px 0 rgba(0, 0, 0, 0.85); + /* Fully separates workspace views from the outer geometric cyan fruit array */ + backdrop-filter: blur(20px); + border-radius: 12px; +} + +/* ========================================================================== + 3. DOMAIN SUB-NAVIGATION CONTROL + ========================================================================== */ + +.domain-menu-list { + display: flex; + flex-direction: column; + gap: 1.75rem; + margin-top: 2rem; +} + +.domain-nav-item { + display: flex; + align-items: flex-start; + gap: 1rem; + cursor: pointer; + transition: all 0.22s ease-in-out; + opacity: 0.45; + user-select: none; + position: relative; +} + + .domain-nav-item:hover { + opacity: 0.85; + transform: translateX(4px); + } + + .domain-nav-item.active { + opacity: 1; + } + + .domain-nav-item .nav-status-node { + width: 6px; + height: 6px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.15); + margin-top: 0.45rem; + flex-shrink: 0; + transition: all 0.25s ease-in-out; + } + + .domain-nav-item.active .nav-status-node { + background: #ff6b35; /* Crisp orange interaction state highlight */ + box-shadow: 0 0 8px 2px rgba(255, 107, 53, 0.4); + } + +.domain-details { + display: flex; + flex-direction: column; + gap: 0.15rem; +} + +.domain-name { + font-size: 0.95rem; + font-weight: 500; + color: #ffffff; + letter-spacing: -0.1px; +} + +.domain-desc { + font-size: 0.76rem; + color: rgba(255, 255, 255, 0.38); + line-height: 1.2; +} + +/* ========================================================================== + 4. CENTRAL SHIELD ARCHITECTURAL DIVIDER AXIS + ========================================================================== */ + +.workspace-wing { + padding: 2.5rem 2rem; + display: flex; + flex-direction: column; +} + +.left-wing.domain-nav { + padding-right: 0.5rem; +} + +.central-divider-axis { + position: relative; + width: 60px; + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} + +.divider-core-line { + width: 1px; + height: 100%; + background: linear-gradient( to bottom, rgba(255, 107, 53, 0) 0%, rgba(255, 107, 53, 0.12) 20%, rgba(255, 107, 53, 0.8) 50%, rgba(255, 107, 53, 0.12) 80%, rgba(255, 107, 53, 0) 100% ); +} + +.camel-glow-left { + position: absolute; + right: 50%; + top: 50%; + transform: translateY(-50%); + width: 45px; + height: 280px; + border-radius: 50% 0 0 50%; + background: radial-gradient( ellipse at right, rgba(255, 107, 53, 0.07) 0%, rgba(255, 107, 53, 0.02) 55%, rgba(0, 0, 0, 0) 85% ); + filter: blur(6px); + pointer-events: none; +} + +.camel-glow-right { + position: absolute; + left: 50%; + top: 50%; + transform: translateY(-50%); + width: 45px; + height: 280px; + border-radius: 0 50% 50% 0; + background: radial-gradient( ellipse at left, rgba(255, 107, 53, 0.07) 0%, rgba(255, 107, 53, 0.02) 55%, rgba(0, 0, 0, 0) 85% ); + filter: blur(6px); + pointer-events: none; +} + +.page-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; +} + +.panel-title-lbl { + font-size: 0.72rem; + color: #ff6b35; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1.5px; +}