172 lines
11 KiB
Plaintext
172 lines
11 KiB
Plaintext
@using Microsoft.AspNetCore.Components.Forms
|
|
|
|
<div class="create-product-shell">
|
|
|
|
<div class="book-preview-drawer @(string.IsNullOrEmpty(ActivePreviewUrl) ? "" : "is-open")">
|
|
@if (!string.IsNullOrEmpty(ActivePreviewUrl))
|
|
{
|
|
<button type="button" class="btn-close-preview-floating" title="Collapse Frame" @onclick="ClosePreviewDrawer">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
|
|
<div class="drawer-portrait-frame">
|
|
<img src="@ActivePreviewUrl" alt="Active Book Design Preview" />
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="create-product-container">
|
|
<EditForm Model="@ProductModel" OnValidSubmit="HandleValidSubmit" class="form-entry-canvas">
|
|
<DataAnnotationsValidator />
|
|
|
|
<div class="form-scroll-viewport">
|
|
|
|
<div class="form-section-header">
|
|
<span class="field-accent-tag">PRODUCT MASTER LEDGER</span>
|
|
<p>Provision catalog items metadata, book cover assets, and supplementary chapter telemetry designs.</p>
|
|
</div>
|
|
|
|
<div class="form-text-inputs-section">
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Book Title</label>
|
|
<InputText @bind-Value="ProductModel.Name" class="console-input" placeholder="e.g., Neuromancer" />
|
|
<ValidationMessage For="@(() => ProductModel.Name)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Short Summary</label>
|
|
<InputText @bind-Value="ProductModel.Summary" class="console-input" placeholder="Brief catchphrase description metadata line..." />
|
|
<ValidationMessage For="@(() => ProductModel.Summary)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
|
|
<div class="console-field-row">
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Base Ledger Price (ZAR)</label>
|
|
<InputNumber @bind-Value="ProductModel.Price" class="console-input" placeholder="0.00" />
|
|
<ValidationMessage For="@(() => ProductModel.Price)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">ISBN Reference</label>
|
|
<InputText @bind-Value="ProductModel.Isbn" class="console-input" placeholder="e.g., 978-0393312836" />
|
|
<ValidationMessage For="@(() => ProductModel.Isbn)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="console-field-row">
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Author / Creator</label>
|
|
<InputText @bind-Value="ProductModel.Author" class="console-input" placeholder="e.g., William Gibson" />
|
|
<ValidationMessage For="@(() => ProductModel.Author)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Date of Publication</label>
|
|
<ConsoleDatePicker @bind-Value="ProductModel.PublishDate" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Copyright Information</label>
|
|
<InputText @bind-Value="ProductModel.CopyrightInfo" class="console-input" placeholder="e.g., © 1984 William Gibson. All rights reserved." />
|
|
<ValidationMessage For="@(() => ProductModel.CopyrightInfo)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Full Catalog Description</label>
|
|
<InputTextArea @bind-Value="ProductModel.Description" class="console-textarea" rows="4" placeholder="Enter extended markdown contents..." />
|
|
<ValidationMessage For="@(() => ProductModel.Description)" style="color: #ff5722; font-size: 0.75rem;" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-media-deck-section">
|
|
<div class="form-section-header" style="margin-bottom: 1rem; padding-bottom: 0.5rem;">
|
|
<p style="text-transform: uppercase; font-weight: 600; color: #cbd5e1; font-size: 0.8rem; letter-spacing: 0.05em;">Media Assets Node Array</p>
|
|
</div>
|
|
|
|
<div class="media-deck-row">
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Primary Cover</label>
|
|
<div class="book-cover-dropzone">
|
|
<InputFile OnChange="HandleMainImageUpload" accept=".png,.jpg,.jpeg,.webp" class="hidden-file-input" id="main-image-file" />
|
|
|
|
@if (string.IsNullOrEmpty(ProductModel.ImageUrl))
|
|
{
|
|
<label for="main-image-file" class="dropzone-interactive-layer">
|
|
<div class="empty-slot-blueprint">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
<line x1="12" y1="5" x2="12" y2="19"></line>
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
</svg>
|
|
<span style="font-size: 0.7rem; font-family: monospace; color: #475569; margin-top: 0.5rem;">UPLOAD COVER</span>
|
|
</div>
|
|
</label>
|
|
}
|
|
else
|
|
{
|
|
<div class="dropzone-active-preview">
|
|
<img src="@ProductModel.ImageUrl" alt="Main Book Cover" />
|
|
|
|
<div class="image-actions-overlay">
|
|
<button type="button" class="btn-micro-action" title="Preview Image" @onclick="() => SetPreviewActive(ProductModel.ImageUrl)">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
|
</button>
|
|
<button type="button" class="btn-micro-action danger" title="Remove Asset" @onclick="ClearMainImage">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="console-field-group">
|
|
<label class="console-field-label">Additional Media Slots</label>
|
|
<div class="thumbnail-deck-grid">
|
|
@for (int i = 0; i < 5; i++)
|
|
{
|
|
var index = i;
|
|
<div class="thumbnail-slot-node @(HasAssetAt(index) ? "populated" : "empty")">
|
|
@if (HasAssetAt(index))
|
|
{
|
|
<img src="@ProductModel.Thumbnails[index]" alt="Slot @(index + 1)" />
|
|
|
|
<div class="image-actions-overlay">
|
|
<button type="button" class="btn-micro-action" title="Preview Image" @onclick="() => SetPreviewActive(ProductModel.Thumbnails[index])">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
|
</button>
|
|
<button type="button" class="btn-micro-action danger" title="Remove Asset" @onclick="() => RemoveThumbnailAt(index)">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
|
</button>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<InputFile OnChange="@(e => HandleThumbnailUpload(e, index))" accept=".png,.jpg,.jpeg,.webp" class="hidden-file-input" id="@($"thumb-file-{index}")" />
|
|
<label for="@($"thumb-file-{index}")" class="empty-slot-blueprint">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
<line x1="12" y1="5" x2="12" y2="19"></line>
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
</svg>
|
|
<span style="font-size: 0.65rem; font-family: monospace; margin-top: 0.25rem;">0@(index + 1)</span>
|
|
</label>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-action-footer">
|
|
<button type="submit" class="btn-apply-filters">Commit Record Ledger</button>
|
|
</div>
|
|
</EditForm>
|
|
</div>
|
|
</div> |