Compare commits

..

5 Commits

11 changed files with 75 additions and 39 deletions
@@ -17,7 +17,6 @@
</script> </script>
<link rel="stylesheet" href="_content/Enciphered.Blazor.UIComponents/css/app.css" /> <link rel="stylesheet" href="_content/Enciphered.Blazor.UIComponents/css/app.css" />
<link rel="stylesheet" href="@Assets["css/app.css"]" /> <link rel="stylesheet" href="@Assets["css/app.css"]" />
<link rel="stylesheet" href="@Assets["Enciphered.Blazor.UIComponents.Demo.styles.css"]" />
<ImportMap /> <ImportMap />
<link rel="icon" type="image/svg+xml" href="enci_white.svg" /> <link rel="icon" type="image/svg+xml" href="enci_white.svg" />
<HeadOutlet /> <HeadOutlet />
@@ -1,4 +1,5 @@
@page "/weather" @page "/weather"
@using Enciphered.Blazor.UIComponents
@attribute [StreamRendering] @attribute [StreamRendering]
<PageTitle>Weather</PageTitle> <PageTitle>Weather</PageTitle>
@@ -13,27 +14,20 @@
} }
else else
{ {
<table class="table"> <Table Items="forecasts">
<thead> <Columns>
<tr> <th>Date</th>
<th>Date</th> <th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th> <th aria-label="Temperature in Farenheit">Temp. (F)</th>
<th aria-label="Temperature in Farenheit">Temp. (F)</th> <th>Summary</th>
<th>Summary</th> </Columns>
</tr> <RowTemplate Context="forecast">
</thead> <td>@forecast.Date.ToShortDateString()</td>
<tbody> <td>@forecast.TemperatureC</td>
@foreach (var forecast in forecasts) <td>@forecast.TemperatureF</td>
{ <td>@forecast.Summary</td>
<tr> </RowTemplate>
<td>@forecast.Date.ToShortDateString()</td> </Table>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
} }
@code { @code {
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Enciphered.Blazor.UIComponents\Enciphered.Blazor.UIComponents.csproj" /> <ProjectReference Include="..\Enciphered.Blazor.UIComponents\Enciphered.Blazor.UIComponents.csproj" />
</ItemGroup> </ItemGroup>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<Target Name="TailwindBuild" BeforeTargets="Build"> <Target Name="TailwindBuild" BeforeTargets="Build">
<Exec Command="npx @tailwindcss/cli -i Styles/app.css -o wwwroot/css/app.css --minify" /> <Exec Command="npx @tailwindcss/cli -i Styles/app.css -o wwwroot/css/app.css --minify" />
</Target> </Target>
File diff suppressed because one or more lines are too long
@@ -1,9 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Razor"> <Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<PublishAot>true</PublishAot>
<IsPackable>true</IsPackable>
<PackageId>Enciphered.Blazor.UIComponents</PackageId>
<Version>0.0.1</Version>
<Authors>shaamilahmed</Authors>
<Company>nciphered</Company>
<Description>Pure static SSR Blazor component library styled with Tailwind CSS v4 and shadcn/ui. All interactivity powered by vanilla JS. htmx-powered form validation.</Description>
<PackageTags>blazor;ui;components;tailwind;htmx;ssr;static</PackageTags>
<RepositoryUrl>https://git.nciphered.com/shaamilahmed/Enciphered.Blazor.UIComponents</RepositoryUrl>
<PackageLicenseExpression></PackageLicenseExpression>
<PackageProjectUrl>https://git.nciphered.com/shaamilahmed/Enciphered.Blazor.UIComponents</PackageProjectUrl>
<PackageIcon>enci_white.png</PackageIcon>
</PropertyGroup> </PropertyGroup>
<Target Name="TailwindBuild" BeforeTargets="Build"> <Target Name="TailwindBuild" BeforeTargets="Build">
@@ -12,11 +25,11 @@
<ItemGroup> <ItemGroup>
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <None Include="./Logo/enci_white.png" Pack="true" PackagePath="\" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.14" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -1,19 +1,22 @@
using System.Globalization; using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Enciphered.Blazor.UIComponents.Validation; namespace Enciphered.Blazor.UIComponents.Validation;
public static class FormModelBinder public static class FormModelBinder
{ {
public static TModel Bind<TModel>(IFormCollection form) where TModel : new() public static TModel Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TModel>(IFormCollection form) where TModel : new()
{ {
var model = new TModel(); var model = new TModel();
var props = typeof(TModel).GetProperties(BindingFlags.Public | BindingFlags.Instance) PropertyInfo[] props = typeof(TModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
.Where(p => p.CanWrite);
foreach (var prop in props) foreach (var prop in props)
{ {
if (!prop.CanWrite) continue;
var key = form.Keys.FirstOrDefault(k => var key = form.Keys.FirstOrDefault(k =>
string.Equals(k, prop.Name, StringComparison.OrdinalIgnoreCase)); string.Equals(k, prop.Name, StringComparison.OrdinalIgnoreCase));
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
@@ -17,7 +18,7 @@ public static class HtmxFormValidationExtensions
return MapEndpoints(endpoints, basePath, validator, successMessage, onSuccess); return MapEndpoints(endpoints, basePath, validator, successMessage, onSuccess);
} }
public static RouteGroupBuilder MapFormValidation<TValidator, TModel>( public static RouteGroupBuilder MapFormValidation<TValidator, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TModel>(
this IEndpointRouteBuilder endpoints, this IEndpointRouteBuilder endpoints,
string basePath, string basePath,
Func<TModel, Task> onSuccess, Func<TModel, Task> onSuccess,
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1,26 @@
@namespace Enciphered.Blazor.UIComponents
@typeparam TItem
<div class="w-full overflow-auto rounded-md border border-zinc-800">
<table class="w-full caption-bottom text-sm">
<thead class="bg-zinc-900/50">
<tr class="border-b border-zinc-800 transition-colors">
@Columns
</tr>
</thead>
<tbody class="[&_tr:last-child]:border-0">
@foreach (TItem item in Items)
{
<tr class="border-b border-zinc-800 transition-colors hover:bg-zinc-900/50 text-center">
@RowTemplate(item)
</tr>
}
</tbody>
</table>
</div>
@code {
[Parameter] public required IReadOnlyList<TItem> Items { get; set; }
[Parameter] public required RenderFragment Columns { get; set; }
[Parameter] public required RenderFragment<TItem> RowTemplate { get; set; }
}
File diff suppressed because one or more lines are too long
@@ -595,7 +595,7 @@ export function init() {
syncValidationStyling(); syncValidationStyling();
}); });
document.addEventListener('blazor:enhanced-load', () => { window.Blazor.addEventListener('enhancedload', () => {
initComponents(); initComponents();
if (typeof htmx !== 'undefined') htmx.process(document.body); if (typeof htmx !== 'undefined') htmx.process(document.body);
}); });