Stable run with tailwind
This commit is contained in:
@@ -1,69 +1,80 @@
|
||||
<div class="col-12 col-md-6 col-lg-4 mb-4 h-100">
|
||||
<div class="d-flex flex-column h-100 justify-content-between">
|
||||
@namespace MidrandBooks.Components
|
||||
@using Microsoft.AspNetCore.Components
|
||||
@using MidrandBooks.Models
|
||||
|
||||
<div class="card border-0 p-4 position-relative book-grid-card d-flex flex-column justify-content-between"
|
||||
style="background-color: #F1F1F1; border-radius: var(--mb-radius); cursor: pointer; min-height: 280px;"
|
||||
@onclick="OnCardClick">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
@if (IsNew)
|
||||
{
|
||||
<span class="badge rounded-pill px-3 py-2 badge-new-arrival" style="background-color: var(--mb-accent-red); font-weight: 500;">New</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div></div>
|
||||
}
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button class="btn bg-white rounded-circle d-flex align-items-center justify-content-center p-2 shadow-sm border-0 btn-cart-icon"
|
||||
style="width: 32px; height: 32px; transition: all 0.2s ease;"
|
||||
title="Add to Cart"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
@onclick="HandleAddToCart" @onclick:stopPropagation>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--mb-text-dark)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="9" cy="21" r="1"></circle>
|
||||
<circle cx="20" cy="21" r="1"></circle>
|
||||
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button class="btn bg-white rounded-circle d-flex align-items-center justify-content-center p-2 shadow-sm border-0"
|
||||
style="width: 32px; height: 32px;">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--mb-text-dark)" stroke-width="2.5">
|
||||
<line x1="7" y1="17" x2="17" y2="7" />
|
||||
<polyline points="7,7 17,7 17,17" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="book-card-@Book.Id" class="group relative flex flex-col justify-between rounded-2xl border border-slate-200/60 bg-white p-3 shadow-sm transition-all hover:shadow-md hover:-translate-y-0.5">
|
||||
|
||||
<!-- Cover Artwork Block -->
|
||||
<div class="relative aspect-[3/4] rounded-xl overflow-hidden shadow-sm bg-slate-50 cursor-pointer" @onclick="HandleSelect">
|
||||
@if (!string.IsNullOrEmpty(Book.CoverUrl))
|
||||
{
|
||||
<img src="@Book.CoverUrl"
|
||||
alt="@Book.Title"
|
||||
referrerpolicy="no-referrer"
|
||||
class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="h-full w-full bg-gradient-to-br @(Book.CoverColor) p-4 flex flex-col justify-between text-white transition-transform duration-500 group-hover:scale-105">
|
||||
<div class="absolute top-0 right-0 h-16 w-16 bg-white/5 rounded-full blur-sm pointer-events-none" />
|
||||
<span class="text-[8px] font-mono font-bold tracking-widest block uppercase text-white/40">@Book.Category</span>
|
||||
<span class="text-sm font-serif font-extrabold line-clamp-3 leading-tight text-white">@Book.Title</span>
|
||||
<span class="text-[9px] font-sans text-white/70 truncate block font-semibold">By @Book.Author</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center flex-grow-1 my-2">
|
||||
@if (!string.IsNullOrWhiteSpace(BookImageUrl))
|
||||
{
|
||||
<img src="@BookImageUrl" class="img-fluid book-shadow" style="max-height: 240px; object-fit: contain;" alt="@Title" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="book-spine-fallback bg-dark d-flex align-items-center justify-content-center text-center p-3 text-white-50 shadow-sm"
|
||||
style="width: 50%; max-width: 140px; aspect-ratio: 2 / 3; border-radius: 6px; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.05em; line-height: 1.4; box-shadow: 0 10px 24px rgba(0,0,0,0.16);">
|
||||
<div style="max-width: 100%; overflow: hidden; word-break: break-word;">
|
||||
@Category.ToUpper()<br><span class="opacity-50" style="font-size: 0.55rem;">EDITION</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<!-- Book Spine Shadow -->
|
||||
<div class="absolute top-0 bottom-0 left-0 w-2 bg-gradient-to-r from-black/25 to-transparent" />
|
||||
|
||||
<!-- Formats and Badges -->
|
||||
<div class="absolute top-2 right-2 flex flex-col gap-1 items-end z-10">
|
||||
@if (Book.Bestseller)
|
||||
{
|
||||
<span class="px-2 py-0.5 rounded-full text-[8px] font-mono font-extrabold uppercase bg-amber-500 text-slate-900 border border-amber-400 shadow-sm">
|
||||
Bestseller
|
||||
</span>
|
||||
}
|
||||
@if (Book.Trending)
|
||||
{
|
||||
<span class="px-2 py-0.5 rounded-full text-[8px] font-mono font-extrabold uppercase bg-violet-600 text-white border border-violet-500 shadow-sm">
|
||||
Trending
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-start mt-3 mb-2 px-2" style="cursor: pointer;" @onclick="OnCardClick">
|
||||
<div style="max-width: 72%;">
|
||||
<span class="fw-medium text-dark d-block text-truncate product-card-title" style="font-size: 0.95rem; line-height: 1.25;">@Title</span>
|
||||
<span class="text-muted small d-block text-truncate mt-1" style="font-size: 0.8rem;">by @Author</span>
|
||||
</div>
|
||||
<span class="font-monospace fw-semibold text-secondary pt-0.5" style="font-size: 0.9rem; white-space: nowrap;">R @Price.ToString("N0")</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Block -->
|
||||
<div class="mt-3 flex-1 flex flex-col justify-between space-y-2">
|
||||
<div>
|
||||
<span class="text-[9px] font-mono font-bold text-violet-600 uppercase tracking-wider block">@Book.Category</span>
|
||||
<h4 class="font-serif text-sm font-bold text-slate-800 leading-tight line-clamp-1 mt-0.5 hover:text-violet-600 cursor-pointer" @onclick="HandleSelect">
|
||||
@Book.Title
|
||||
</h4>
|
||||
<span class="text-[10px] text-slate-500 font-medium">@Book.Author</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between border-t border-slate-100 pt-2">
|
||||
<div>
|
||||
<span class="text-[8px] font-mono font-bold text-slate-400 block uppercase">South African Price</span>
|
||||
<span class="font-mono text-xs font-bold text-slate-900">R @Book.Price.ToString("F2")</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded bg-amber-50 text-amber-700 text-[10px] font-mono font-bold border border-amber-200/50">
|
||||
★ @Book.Rating.ToString("F1")
|
||||
</span>
|
||||
<span class="text-[9px] font-mono text-slate-400">(@Book.ReviewsCount)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public BookModel Book { get; set; } = new();
|
||||
[Parameter] public EventCallback<BookModel> OnSelectBook { get; set; }
|
||||
|
||||
private async Task HandleSelect()
|
||||
{
|
||||
await OnSelectBook.InvokeAsync(Book);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user