This commit is contained in:
2025-10-27 22:50:13 -04:00
parent 2fecd5b315
commit 468b51a121
3 changed files with 149 additions and 105 deletions

View File

@@ -39,9 +39,40 @@
.pdp-skeleton__block--options { .pdp-skeleton__block--options {
min-height: 160px; min-height: 160px;
} }
/* === PDP (Telerik bridge) === */
.t-pdp .product__name { line-height: 1.1; margin-top: .25rem; }
.t-pdp .product__price-new { color: #e53935; font-weight: 700; font-size: 1.75rem; }
/* Space option groups */
.t-pdp .product__option { margin-bottom: 1.25rem; }
.t-pdp .product__option-label { text-transform: uppercase; font-size: .8rem; color: #6c757d; letter-spacing: .02em; margin-bottom: .5rem; }
/* RadioGroup: make Kendo radios look like the template's radio-select */
.t-pdp .t-pdp-radio.k-radio-group { display: grid; gap: .35rem; }
.t-pdp .t-pdp-radio .k-radio-item { display: flex; align-items: center; gap: .5rem; padding: .125rem 0; }
.t-pdp .t-pdp-radio .k-radio-label { font-size: 1rem; }
.t-pdp .t-pdp-radio input.k-radio:checked + .k-radio-label { font-weight: 600; }
/* NumericTextBox sizing/spacing */
.t-pdp .t-pdp-number .k-numerictextbox,
.t-pdp .t-pdp-qty .k-numerictextbox { display: inline-flex; }
.t-pdp .product__actions-item { display: inline-flex; align-items: center; }
/* TabStrip headers: resemble template tabs underline */
.t-pdp .t-pdp-tabstrip .k-tabstrip-items { border-bottom: 1px solid #e9ecef; }
.t-pdp .t-pdp-tabstrip .k-item .k-link { padding: .75rem 1rem; color: #6c757d; }
.t-pdp .t-pdp-tabstrip .k-item.k-active .k-link { color: #e53935; border-bottom: 2px solid #e53935; }
/* Spec table tweaks */
.t-pdp .product__tab-specification table { margin-top: .5rem; }
/* Gallery image sizing */
.t-pdp .product__gallery img { max-width: 100%; height: auto; display: block; }
</style> </style>
<div class="container my-4"> <div class="block">
<div class="container container--max--xl t-pdp">
@if (_isLoading) @if (_isLoading)
{ {
if (HasTelerikSkeleton) if (HasTelerikSkeleton)
@@ -75,6 +106,8 @@
<div class="product product--layout--standard"> <div class="product product--layout--standard">
<div class="product__content"> <div class="product__content">
<div class="row g-4 g-lg-5 align-items-start">
<div class="col-12 col-lg-6">
<div class="product__gallery"> <div class="product__gallery">
<div class="product-gallery"> <div class="product-gallery">
<div class="product-gallery__featured"> <div class="product-gallery__featured">
@@ -82,7 +115,10 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="col-12 col-lg-6">
<div class="product__info"> <div class="product__info">
<!-- keep the existing meta, name, price, description, options, and actions exactly as below -->
<div class="product__meta mb-2"> <div class="product__meta mb-2">
<ul class="product__meta-list list-unstyled mb-2"> <ul class="product__meta-list list-unstyled mb-2">
@if (!string.IsNullOrWhiteSpace(product.Sku)) @if (!string.IsNullOrWhiteSpace(product.Sku))
@@ -140,7 +176,7 @@
@if (optionIsChoice) @if (optionIsChoice)
{ {
<TelerikRadioGroup TValue="string" TItem="ChoiceItem" <TelerikRadioGroup TValue="string" TItem="ChoiceItem"
Class="product__option-group" Class="t-pdp-radio product__option-group"
Data="@BuildChoiceItems(option)" Data="@BuildChoiceItems(option)"
TextField="@nameof(ChoiceItem.Text)" TextField="@nameof(ChoiceItem.Text)"
ValueField="@nameof(ChoiceItem.Value)" ValueField="@nameof(ChoiceItem.Value)"
@@ -156,6 +192,8 @@
Max="@option.Max" Max="@option.Max"
Step="@ResolveStep(option)" Step="@ResolveStep(option)"
Format="n2" Format="n2"
Size="@Telerik.Blazor.ThemeConstants.NumericTextBox.Size.Large"
Class="t-pdp-number"
Width="200px" /> Width="200px" />
@if (!string.IsNullOrWhiteSpace(option.Unit)) @if (!string.IsNullOrWhiteSpace(option.Unit))
{ {
@@ -180,6 +218,8 @@
Min="1" Min="1"
Step="1" Step="1"
Format="n0" Format="n0"
Size="@Telerik.Blazor.ThemeConstants.NumericTextBox.Size.Large"
Class="t-pdp-qty"
Width="150px" /> Width="150px" />
</div> </div>
<div class="product__actions-item"> <div class="product__actions-item">
@@ -192,10 +232,12 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<div class="card product__tabs product-tabs product-tabs--layout--full mt-5"> <div class="card product__tabs product-tabs product-tabs--layout--full mt-5">
<div class="card-body"> <div class="card-body">
<TelerikTabStrip TabPosition="TabPosition.Top" Class="product-tabs__strip"> <TelerikTabStrip TabPosition="TabPosition.Top" Class="t-pdp-tabstrip product-tabs__strip">
<TabStripTab Title="Description"> <TabStripTab Title="Description">
<div class="product__tab-description"> <div class="product__tab-description">
@if (!string.IsNullOrWhiteSpace(product.Description)) @if (!string.IsNullOrWhiteSpace(product.Description))
@@ -240,7 +282,8 @@
</div> </div>
</div> </div>
} }
</div> </div> <!-- /.container -->
</div> <!-- /.block -->
@code { @code {
private const string DocsAttributeKey = "catalog.product.docs"; private const string DocsAttributeKey = "catalog.product.docs";

View File

@@ -132,7 +132,7 @@ public static class Products
} }
} }
public sealed class DetailService(IModuleClient moduleClient) public sealed class DetailService(IModuleClient moduleClient) : IProductDisplayService
{ {
public async Task<Result<ProductDisplayModel>> Get(string slug, CancellationToken cancellationToken) public async Task<Result<ProductDisplayModel>> Get(string slug, CancellationToken cancellationToken)
{ {

View File

@@ -49,6 +49,7 @@ public class Module : IModule
builder.Services.AddScoped<Products.ListingService>(); builder.Services.AddScoped<Products.ListingService>();
builder.Services.AddScoped<Products.DetailService>(); builder.Services.AddScoped<Products.DetailService>();
builder.Services.AddScoped<IProductListingService>(sp => sp.GetRequiredService<Products.ListingService>()); builder.Services.AddScoped<IProductListingService>(sp => sp.GetRequiredService<Products.ListingService>());
builder.Services.AddScoped<IProductDisplayService>(sp => sp.GetRequiredService<Products.DetailService>());
builder.Services.AddScoped<IHomePageService>(sp => sp.GetRequiredService<Home.Service>()); builder.Services.AddScoped<IHomePageService>(sp => sp.GetRequiredService<Home.Service>());
return builder; return builder;