Manage blazor development, razor and razor.cs and any blazor component editing skills
ComponentName.razorComponentName.razor.csComponentName.razor.cssLocalizedComponentBase<ComponentName>LocalizedComponentBase<ComponentName>, ComponentName.resx file in Resources folderMotoRentPageTitle custom componentTablerHeader with title and some description in propertyPreTitleboolean property named Loading in try-finally when loading datacol-3 for filters, and col-9 for tablesLoadingSkeleton - NOT Dimmer for loading statesLoading (not Busy, IsLoading, etc.)if (this.Loading) return; at start of load method to avoid double loadingLoading = false<LoadingSkeleton Loading="@Loading" Mode="Skeleton.PlaceholderMode.Table">
// Table content
</LoadingSkeleton>
<LoadingSkeleton Loading="@Loading" Mode="Skeleton.PlaceholderMode.Card">
// Card content
</LoadingSkeleton>
<LoadingSkeleton Loading="@Loading" Mode="Skeleton.PlaceholderMode.Text">
// Text content
</LoadingSkeleton>
private bool Loading { get; set; }
private async Task LoadDataAsync()
{
if (this.Loading) return; // Prevent double loading
try
{
this.Loading = true;
// Load data...
}
finally
{
this.Loading = false;
}
}
@page "/motorbikes"
@inherits LocalizedComponentBase<MotorbikeList>
@inject MotorbikeService MotorbikeService
@* title and header with custom component *@
<MotoRentPageTitle>@Localizer["Motorbikes"]</MotoRentPageTitle>
<TablerHeader Title="@Localizer["Motorbikes"]" PreTitle="@Localizer["List of all motorbikes"]">
<div class="d-flex justify-content-end">
<div class="px-2">
<a href="@("/motorbikes/create")" class="btn btn-primary">
<i class="ti ti-plus me-2"></i>
@Localizer["Create new motorbike"]
</a>
</div>
</div>
</TablerHeader>
@* Loading with LoadingSkeleton *@
<LoadingSkeleton Loading="@Loading" Mode="Skeleton.PlaceholderMode.Table">
<table class="table table-vcenter">
<thead>
<tr>
<th>@CommonLocalizer["Name"]</th>
<th>@Localizer["LicensePlate"]</th>
<th>@Localizer["Status"]</th>
</tr>
</thead>
<tbody>
@foreach (var motorbike in this.Motorbikes)
{
<tr>
<td>@motorbike.Brand @motorbike.Model</td>
<td>@motorbike.LicensePlate</td>
<td>
<span class="badge @GetStatusBadgeClass(motorbike.Status)">
@Localizer[motorbike.Status]
</span>
</td>
</tr>
}
</tbody>
</table>
</LoadingSkeleton>
@code {
private List<Motorbike> Motorbikes {get;} = [];
private bool Loading {get; set;}
protected override async Task OnParametersSetAsync()
{
if(this.Loading) return; // avoid double loading
try
{
this.Loading = true;
var query = this.DataContext.CreateQuery<Motorbike>()
.Where(x => x.MotorbikeId > 0)
.OrderByDescending(x => x.Brand);
var load = await this.DataContext.LoadAsync(query, includeTotalRows: true);
this.Motorbikes.Clear();
this.Motorbikes.AddRange(load.ItemCollection);
}
finally
{
this.Loading = false;
}
}
private static string GetStatusBadgeClass(string status) => status switch
{
"Available" => "bg-success-lt",
"Rented" => "bg-primary-lt",
"Maintenance" => "bg-warning-lt",
_ => "bg-secondary-lt"
};
}
.razor.css files instead of inline <style> blocks for better organization::deep combinator to style child componentsThis project uses Tabler CSS framework which supports light/dark themes via data-bs-theme attribute.
DO use Tabler's built-in CSS variables:
/* These automatically adapt to light/dark theme */