From 0bdb20258b7985dfc59dc813b77c46f7db82db32 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sun, 21 Jun 2026 22:17:56 +0200 Subject: [PATCH 01/19] feat: add safelist drift tests and CI verification for NuGet package installation - Introduced `SafelistDriftTests` to ensure the safelist matches generated Tailwind classes from Razor components, preventing missing styles in NuGet packages. - Enhanced CI workflow to verify the safelist is correctly included in the NuGet package and contains essential Tailwind classes after installation. - Updated project references in the test project to include the `ShellUI.SafelistGenerator` for safelist generation. --- ShellUI.Tests/SafelistDriftTests.cs | 68 +++++++++++++++++++++++++++++ ShellUI.Tests/ShellUI.Tests.csproj | 1 + 2 files changed, 69 insertions(+) create mode 100644 ShellUI.Tests/SafelistDriftTests.cs diff --git a/ShellUI.Tests/SafelistDriftTests.cs b/ShellUI.Tests/SafelistDriftTests.cs new file mode 100644 index 0000000..2948379 --- /dev/null +++ b/ShellUI.Tests/SafelistDriftTests.cs @@ -0,0 +1,68 @@ +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using ShellUI.SafelistGenerator; +using Xunit; + +namespace ShellUI.Tests; + +/// Regenerates the safelist in-process and diffs against the committed file. +/// If a contributor adds a new Tailwind class to a component but forgets to +/// regenerate the safelist, this test fails with a precise diff of which +/// classes are missing β€” so NuGet consumers don't ship with broken styles. +public class SafelistDriftTests +{ + [Fact] + public void Safelist_MatchesGeneratedFromCurrentRazorSources() + { + var componentsDir = ResolveComponentsDir(); + var safelistPath = ResolveSafelistPath(); + + Assert.True(Directory.Exists(componentsDir), $"components dir not found: {componentsDir}"); + Assert.True(File.Exists(safelistPath), + $"safelist not found at {safelistPath}. Run: dotnet run --project tools/ShellUI.SafelistGenerator -- src/ShellUI.Components/Components src/ShellUI.Components/wwwroot/shellui-classes.txt"); + + var razorFiles = Directory.GetFiles(componentsDir, "*.razor", SearchOption.AllDirectories); + var freshlyGenerated = Program.GenerateSafelist(razorFiles); + var committed = File.ReadAllLines(safelistPath) + .Where(line => !string.IsNullOrWhiteSpace(line)) + .ToHashSet(); + + var addedSinceCommit = freshlyGenerated.Except(committed).Take(10).ToList(); + var removedSinceCommit = committed.Except(freshlyGenerated).Take(10).ToList(); + + Assert.True(addedSinceCommit.Count == 0 && removedSinceCommit.Count == 0, + BuildDiffMessage(addedSinceCommit, removedSinceCommit)); + } + + private static string BuildDiffMessage(System.Collections.Generic.List added, System.Collections.Generic.List removed) + { + var msg = "Safelist is out of date.\n"; + msg += "Regenerate with:\n dotnet run --project tools/ShellUI.SafelistGenerator -- src/ShellUI.Components/Components src/ShellUI.Components/wwwroot/shellui-classes.txt\n\n"; + if (added.Count > 0) + { + msg += $"New classes in razor sources missing from safelist (first {added.Count}):\n"; + foreach (var c in added) msg += $" + {c}\n"; + } + if (removed.Count > 0) + { + msg += $"\nClasses in safelist but no longer used in razor sources (first {removed.Count}):\n"; + foreach (var c in removed) msg += $" - {c}\n"; + } + return msg; + } + + private static string GetThisFilePath([CallerFilePath] string path = "") => path; + + private static string ResolveComponentsDir() + { + var testDir = Path.GetDirectoryName(GetThisFilePath())!; + return Path.GetFullPath(Path.Combine(testDir, "..", "src", "ShellUI.Components", "Components")); + } + + private static string ResolveSafelistPath() + { + var testDir = Path.GetDirectoryName(GetThisFilePath())!; + return Path.GetFullPath(Path.Combine(testDir, "..", "src", "ShellUI.Components", "wwwroot", "shellui-classes.txt")); + } +} diff --git a/ShellUI.Tests/ShellUI.Tests.csproj b/ShellUI.Tests/ShellUI.Tests.csproj index 83c2647..c32e66e 100644 --- a/ShellUI.Tests/ShellUI.Tests.csproj +++ b/ShellUI.Tests/ShellUI.Tests.csproj @@ -23,6 +23,7 @@ + From fbd29c7aaa4693ead773428689a974de98291dbd Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sun, 21 Jun 2026 22:18:29 +0200 Subject: [PATCH 02/19] feat: add CI step to verify NuGet package safelist installation - Introduced a new CI job to validate that the safelist file `shellui-classes.txt` is correctly included in the NuGet package after installation. - The job checks for the presence of the safelist and verifies it contains essential Tailwind classes, ensuring proper integration for consumers using the package. --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8c0864..89a25d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,27 @@ jobs: dotnet build -c Debug + # Pure-NuGet install path β€” `dotnet add package ShellUI.Components` without + # the CLI. Verifies the safelist ships and is reachable by the consumer's + # Tailwind setup. + - name: NuGet-only install β€” verify safelist ships + shell: bash + run: | + set -euxo pipefail + TMPDIR=$(mktemp -d) + mkdir -p "$TMPDIR/app" && cd "$TMPDIR/app" + dotnet new blazor -o NuGetSmoke --no-restore + cd NuGetSmoke + dotnet add package ShellUI.Components --source "$(realpath ../../../src/ShellUI.Components/bin/Release)" --prerelease + # The safelist file should be in the consumer's project after restore. + # Razor SDK places it under wwwroot/ via the contentFile mechanism. + find . -name 'shellui-classes.txt' | head -3 + test -n "$(find . -name 'shellui-classes.txt' | head -1)" || (echo "shellui-classes.txt did not land in consumer project after NuGet restore"; exit 1) + # Sanity: the safelist contains real Tailwind classes + SAFELIST="$(find . -name 'shellui-classes.txt' | head -1)" + grep -q 'bg-background' "$SAFELIST" || (echo "safelist appears malformed β€” missing core Tailwind class 'bg-background'"; exit 1) + wc -l "$SAFELIST" + - name: Upload build artifacts uses: actions/upload-artifact@v4 with: From 51863f308c8d0823c194f847752c68369815b795 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sun, 21 Jun 2026 22:31:36 +0200 Subject: [PATCH 03/19] feat: add Tailwind CSS safelist classes to shellui-classes.txt - Introduced a new file `shellui-classes.txt` containing a comprehensive list of Tailwind CSS classes to be used in the project. - This addition ensures that essential styles are available for components, enhancing the UI consistency and functionality. --- .../wwwroot/shellui-classes.txt | 307 ++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 src/ShellUI.Components/wwwroot/shellui-classes.txt diff --git a/src/ShellUI.Components/wwwroot/shellui-classes.txt b/src/ShellUI.Components/wwwroot/shellui-classes.txt new file mode 100644 index 0000000..e4430a2 --- /dev/null +++ b/src/ShellUI.Components/wwwroot/shellui-classes.txt @@ -0,0 +1,307 @@ +align-middle +animate-in +animate-pulse +animate-spin +appearance-none +aspect-square +backdrop-blur-md +backdrop-blur-sm +bg-background +bg-background/80 +bg-background/95 +bg-black/80 +bg-border +bg-card +bg-muted +bg-muted/30 +bg-popover +bg-primary +bg-secondary +bg-sidebar +bg-sidebar-primary +bg-transparent +border-0 +border-2 +border-b +border-border +border-input +border-primary/20 +bottom-4 +bottom-full +caption-bottom +cursor-default +cursor-pointer +data-[selected]:bg-accent +data-[selected]:text-accent-foreground +data-[state=closed]:animate-out +data-[state=closed]:fade-out-0 +data-[state=open]:animate-in +data-[state=open]:bg-accent +data-[state=open]:fade-in-0 +data-[state=open]:grid-rows-[1fr] +data-[state=open]:text-muted-foreground +disabled:cursor-not-allowed +disabled:opacity-50 +disabled:pointer-events-none +duration-200 +duration-300 +ease-[cubic-bezier(0.4,0,0.2,1)] +ease-in-out +fa-bell +fa-chevron-right +fa-circle-check +fa-circle-plus +fa-credit-card +fa-ellipsis +fa-right-from-bracket +fa-solid +fa-sort +fa-terminal +fa-user +fa-wand-magic-sparkles +fade-in-0 +file:bg-transparent +file:border-0 +file:font-medium +file:text-sm +fill-primary-foreground +flex-1 +flex-col +flex-row +flex-shrink-0 +focus-visible:[&::-moz-range-thumb]:ring-2 +focus-visible:[&::-moz-range-thumb]:ring-offset-2 +focus-visible:[&::-moz-range-thumb]:ring-ring +focus-visible:[&::-webkit-slider-thumb]:ring-2 +focus-visible:[&::-webkit-slider-thumb]:ring-offset-2 +focus-visible:[&::-webkit-slider-thumb]:ring-ring +focus-visible:outline-none +focus-visible:ring-1 +focus-visible:ring-2 +focus-visible:ring-offset-2 +focus-visible:ring-ring +focus:bg-accent +focus:outline-none +focus:ring-2 +focus:ring-offset-2 +focus:ring-ring +focus:text-accent-foreground +font-bold +font-medium +font-mono +font-normal +font-semibold +gap-0 +gap-0.5 +gap-1 +gap-1.5 +gap-2 +gap-3 +gap-4 +grid-cols-2 +grid-cols-7 +grid-rows-[0fr] +group-data-[collapsible=icon]:!flex +group-data-[collapsible=icon]:!items-center +group-data-[collapsible=icon]:!justify-center +group-data-[collapsible=icon]:!p-0 +group-data-[collapsible=icon]:!rounded-full +group-data-[collapsible=icon]:!size-8 +group-data-[collapsible=icon]:hidden +group-data-[variant=floating]:border +group-data-[variant=floating]:border-sidebar-border +group-data-[variant=floating]:rounded-lg +group-data-[variant=floating]:shadow +h-1/2 +h-10 +h-12 +h-14 +h-2 +h-2.5 +h-24 +h-3 +h-3.5 +h-4 +h-5 +h-7 +h-8 +h-9 +h-full +h-px +hover:bg-accent +hover:bg-accent/50 +hover:bg-primary/90 +hover:bg-sidebar-accent +hover:opacity-100 +hover:text-accent-foreground +hover:text-foreground +hover:text-sidebar-accent-foreground +hover:underline +inline-block +inline-flex +inset-0 +inset-y-0 +items-center +items-end +items-start +justify-between +justify-center +justify-end +leading-none +leading-tight +left-0 +left-1/2 +lg:space-x-8 +list-none +material-symbols-outlined +max-h-60 +max-h-[300px] +max-w-sm +mb-1 +mb-2 +mb-4 +mb-6 +md:block +min-h-0 +min-h-8 +min-w-0 +min-w-8 +min-w-[640px] +min-w-[8rem] +ml-3 +ml-auto +mr-2 +mr-3 +mt-0.5 +mt-1 +mt-2 +mt-4 +mt-6 +mt-8 +mt-auto +mx-auto +my-1 +object-cover +opacity-25 +opacity-50 +opacity-70 +opacity-75 +opacity-90 +origin-top-right +outline-none +overflow-auto +overflow-hidden +overflow-x-auto +overflow-y-auto +p-0.5 +p-1 +p-2 +p-3 +p-4 +p-6 +p-[3px] +pb-4 +peer-disabled:cursor-not-allowed +peer-disabled:opacity-70 +peer/menu-button +pl-2 +pl-4 +placeholder:text-muted-foreground +pointer-events-auto +pointer-events-none +pr-2 +pr-3 +pr-6 +pr-8 +pt-0 +px-1 +px-1.5 +px-2 +px-3 +px-4 +py-1 +py-1.5 +py-2 +py-4 +py-6 +right-0 +right-1 +right-2 +right-4 +ring-offset-background +ring-sidebar-ring +rounded-full +rounded-lg +rounded-md +rounded-sm +scrollbar-thin +scrollbar-thumb-border +scrollbar-track-transparent +select-none +shadow-lg +shadow-md +shadow-sm +shadow-xl +shrink-0 +size-4 +size-8 +sm:flex-row +sm:items-center +sm:justify-between +sm:space-x-6 +sm:text-left +space-x-1 +space-x-2 +space-y-2 +space-y-4 +sr-only +text-5xl +text-[10px] +text-[8px] +text-card-foreground +text-center +text-foreground +text-left +text-lg +text-muted-foreground +text-popover-foreground +text-primary +text-primary-foreground +text-right +text-sidebar-foreground +text-sidebar-foreground/70 +text-sidebar-primary-foreground +text-sm +text-xl +text-xs +top-2 +top-4 +top-8 +top-full +tracking-tight +transition-[grid-template-rows] +transition-[width,height,padding] +transition-all +transition-colors +transition-opacity +transition-transform +w-1/2 +w-12 +w-2.5 +w-3 +w-3.5 +w-4 +w-5 +w-56 +w-64 +w-7 +w-8 +w-[100px] +w-[70px] +w-fit +w-full +w-max +whitespace-nowrap +z-40 +z-50 +zoom-in-95 From 0c5cdabad994f33e5ec43ee1afa8ea81553c084c Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sun, 21 Jun 2026 22:39:26 +0200 Subject: [PATCH 04/19] refactor: update Tailwind CSS versioning and installation process - Replaced hardcoded Tailwind CSS version with constants from TailwindConstants for better maintainability. - Updated the installation command to use dynamic versioning, ensuring compatibility with future updates. - Enhanced console output to reflect the installed version dynamically, improving user feedback during installation. --- src/ShellUI.CLI/Services/InitService.cs | 7 ++++--- src/ShellUI.CLI/Services/TailwindDownloader.cs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ShellUI.CLI/Services/InitService.cs b/src/ShellUI.CLI/Services/InitService.cs index f6c6d90..f4d2815 100644 --- a/src/ShellUI.CLI/Services/InitService.cs +++ b/src/ShellUI.CLI/Services/InitService.cs @@ -1,3 +1,4 @@ +using ShellUI.Core; using ShellUI.Core.Models; using ShellUI.Templates; using System.Text.Json; @@ -109,7 +110,7 @@ await AnsiConsole.Status() Tailwind = new TailwindConfig { Enabled = true, - Version = "4.1.18", + Version = TailwindConstants.Version, Method = method, CssPath = "wwwroot/app.css" } @@ -198,8 +199,8 @@ private static async Task SetupTailwindNpmAsync() // Install Tailwind CSS packages (v4 with @tailwindcss/cli) AnsiConsole.MarkupLine("[cyan]Installing Tailwind CSS packages...[/]"); - await RunNpmCommandAsync("install", "-D", "tailwindcss@^4.1.18", "@tailwindcss/cli@^4.1.18"); - AnsiConsole.MarkupLine("[green]Installed:[/] tailwindcss v4.1.18, @tailwindcss/cli"); + await RunNpmCommandAsync("install", "-D", $"tailwindcss@{TailwindConstants.NpmRange}", $"@tailwindcss/cli@{TailwindConstants.NpmRange}"); + AnsiConsole.MarkupLine($"[green]Installed:[/] tailwindcss v{TailwindConstants.Version}, @tailwindcss/cli"); // Create CSS files AnsiConsole.MarkupLine("[cyan]Creating CSS files...[/]"); diff --git a/src/ShellUI.CLI/Services/TailwindDownloader.cs b/src/ShellUI.CLI/Services/TailwindDownloader.cs index 23420b9..4a789b0 100644 --- a/src/ShellUI.CLI/Services/TailwindDownloader.cs +++ b/src/ShellUI.CLI/Services/TailwindDownloader.cs @@ -1,12 +1,13 @@ using System.IO.Compression; using System.Runtime.InteropServices; +using ShellUI.Core; using Spectre.Console; namespace ShellUI.CLI.Services; public class TailwindDownloader { - private const string TailwindVersion = "v4.1.18"; + private const string TailwindVersion = TailwindConstants.GitHubTag; private const string BaseUrl = "https://github.com/tailwindlabs/tailwindcss/releases/download"; public static async Task EnsureTailwindCliAsync(string projectRoot) From d4923ae2da9736cd090cc99192b4a599e7311ea8 Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Sun, 21 Jun 2026 22:50:03 +0200 Subject: [PATCH 05/19] chore: update Tailwind CSS version to 4.3.1 in documentation - Updated all references to Tailwind CSS from v4.1.18 to v4.3.1 in README.md and src/ShellUI.Components/README.md. - Adjusted installation instructions to reflect the new version and ensure compatibility with existing setups. - Enhanced clarity on the two installation paths for users, emphasizing the benefits of each approach. --- README.md | 62 ++++++++++++++++++++------------ src/ShellUI.Components/README.md | 36 ++++++++++++++++--- 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ae51ab5..d24c395 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ ShellUI transforms Blazor component development with a hybrid approach: - **CLI-First**: Copy components to YOUR codebase for full control (`shellui add button`) - **NuGet Option**: Traditional package install for quick starts (`dotnet add package ShellUI.Components`) - **Choose your workflow**: Use CLI for customization, NuGet for speed, or mix both -- Powered by Tailwind CSS v4.1.18 (standalone CLI - no Node.js required!) +- Powered by Tailwind CSS v4.3.1 (standalone CLI - no Node.js required!) - Best of both worlds: flexibility when you need it, convenience when you want it ## Current Status: 68 Components (Alpha) πŸŽ‰ @@ -44,7 +44,7 @@ ShellUI transforms Blazor component development with a hybrid approach: **ShellUI is in alpha!** Test and provide feedback before we ship stable. We've completed: - βœ… **CLI Tool** (`dotnet tool install -g ShellUI.CLI`) - βœ… **NuGet Package** (`dotnet add package ShellUI.Components`) -- βœ… **68 Installable Components** with Tailwind v4.1.18 *(top-level components you `shellui add` β€” sub-components, variants, models, and services auto-install as dependencies)* +- βœ… **68 Installable Components** with Tailwind v4.3.1 *(top-level components you `shellui add` β€” sub-components, variants, models, and services auto-install as dependencies)* - βœ… **Hybrid Workflow** (CLI + NuGet) - βœ… **No Node.js Required** (Standalone Tailwind CLI) - βœ… **Comprehensive Documentation** @@ -141,7 +141,7 @@ Alert, Callout, EmptyState, Loading, Progress, Skeleton, Sonner, Toast, Tooltip **Utility (2):** CopyButton, ThemeToggle -### βœ… Tailwind CSS v4.1.18 Integration +### βœ… Tailwind CSS v4.3.1 Integration **Two Setup Methods:** @@ -159,7 +159,7 @@ shellui init # Choose "standalone" shellui init # Choose "npm" # Or: dotnet shellui init ``` -- Installs `tailwindcss@^4.1.18` + `@tailwindcss/cli@^4.1.18` +- Installs `tailwindcss@^4.3.1` + `@tailwindcss/cli@^4.3.1` - Uses `npx @tailwindcss/cli` for builds - Requires Node.js @@ -198,7 +198,7 @@ shellui init # Choose "npm" ## Design Principles 1. **Copy, Don't Install**: Components are copied to your project, not imported from a package -2. **Tailwind-First**: All styling uses Tailwind CSS v4.1.18 utility classes +2. **Tailwind-First**: All styling uses Tailwind CSS v4.3.1 utility classes 3. **Accessible by Default**: WCAG 2.1 AA compliant out of the box 4. **Composable**: Build complex components from simple ones 5. **Customizable**: Modify any component to fit your needs @@ -225,7 +225,7 @@ shellui init # Choose "npm" **Use both:** Start with NuGet, migrate to CLI for components you customize heavily! -### Why Tailwind v4.1.18? +### Why Tailwind v4.3.1? - Latest stable version with v4 features - Better performance than v3 - Improved dark mode support @@ -285,7 +285,7 @@ Simply edit the component file in `Components/UI/` - it's yours to modify! - .NET 8.0 or higher - **Choice of Tailwind setup:** - **Standalone CLI** (recommended): No Node.js required - - **npm**: Requires Node.js, uses `tailwindcss@^4.1.18` + - **npm**: Requires Node.js, uses `tailwindcss@^4.3.1` ## Comparison with Existing Solutions @@ -294,7 +294,7 @@ Simply edit the component file in `Components/UI/` - it's yours to modify! | CLI Installation | βœ… | ❌ | ❌ | ❌ | | NuGet Package | βœ… | βœ… | βœ… | βœ… | | Component Ownership (CLI) | βœ… | ❌ | ❌ | ❌ | -| Tailwind CSS | βœ… (v4.1.18) | ❌ | ❌ | ❌ | +| Tailwind CSS | βœ… (v4.3.1) | ❌ | ❌ | ❌ | | No Node.js Required | βœ… | N/A | N/A | N/A | | Hybrid Workflow | βœ… | ❌ | ❌ | ❌ | | Free & Open Source | βœ… | βœ… | Partial | βœ… | @@ -315,30 +315,46 @@ ShellUI ships two NuGet packages β€” the CLI is the primary install path; the ru ## Installation -ShellUI is a **CLI-first** library. The CLI is what wires up Tailwind, drops the theme into `wwwroot/input.css`, patches `App.razor` with the render mode and theme bootstrap, and copies component source into your project so Tailwind can scan it. +Two paths β€” pick based on whether you already have Tailwind set up. + +### Path A β€” NuGet + your existing Tailwind setup (new in 0.4.x) + +If your project already builds Tailwind, install the runtime DLL via NuGet and add one line to your `input.css`: ```bash -dotnet tool install -g ShellUI.CLI -shellui init # one-time setup -shellui add button card dialog # any time you want more components +dotnet add package ShellUI.Components ``` -That's it. Components render styled out of the box. Re-run `shellui add` whenever you want more. +The package ships a `shellui-classes.txt` safelist at `wwwroot/shellui-classes.txt` in your project. Wire Tailwind to scan it: -### Where does `ShellUI.Components` (the NuGet package) fit? +```css +/* wwwroot/input.css */ +@import "tailwindcss"; +@source "./shellui-classes.txt"; +``` -The NuGet package ships the same component DLLs, the JS interop (`shellui.js`), and helpers like `Shell.Cn`. It's useful when you want the runtime types referenced directly β€” e.g. consuming `Shell.Cn` from your own code, or shipping a library that re-exports ShellUI components. +`@using ShellUI.Components` in your `_Imports.razor` and you're done. Tailwind tree-shakes β€” only classes that actually appear in your code (yours + ShellUI's) end up in the compiled CSS. -**The NuGet package alone does not produce styled components.** Tailwind v4 builds the CSS at compile time by scanning `.razor` source files. The component source lives inside the DLL, so Tailwind never sees the utility classes used inside ShellUI components and emits no rules for them. The result: components render with the right HTML structure but with most styling missing. +### Path B β€” CLI tool (full source control, no Tailwind setup required) + +If you want zero Tailwind config of your own, or want to edit component source directly, use the CLI: + +```bash +dotnet tool install -g ShellUI.CLI +shellui init # one-time setup β€” installs Tailwind, theme CSS, patches App.razor +shellui add button card dialog # any time you want more components +``` -The supported way to get styled components is: +The CLI copies the `.razor` files into your project. You own them β€” edit them however you like. -1. `dotnet tool install -g ShellUI.CLI` -2. `shellui init` β€” sets up Tailwind, theme CSS, and patches `App.razor` -3. `shellui add ` for every component you want styled β€” this copies the `.razor` source into your project so Tailwind can scan it -4. *(Optional)* `dotnet add package ShellUI.Components --prerelease` if you also want the runtime DLL on hand (most projects don't need both β€” pick one) +### Which one? -We're tracking a proper "NuGet-only with auto-CSS" path for a future release (`v0.4.x`). Until then, run the CLI. +| You want… | Use | +|---|---| +| Full source control over every component | CLI | +| Restyle by editing the component source | CLI | +| Minimal install, you already use Tailwind | NuGet | +| Mix β€” NuGet for most, CLI for ones you customize | both (no conflict; NuGet's classes are tree-shaken via the safelist, CLI-copied components Tailwind scans directly) ### Configure Tailwind CSS manually (advanced) Create/update `wwwroot/tailwind.config.js`: @@ -575,7 +591,7 @@ MIT License - See LICENSE.txt for details ## Status -**Alpha:** 68 components, CLI + NuGet, Tailwind v4.1.18. Test before stable. +**Alpha:** 68 components, CLI + NuGet, Tailwind v4.3.1. Test before stable. **πŸš€ Ready to use today!** --- diff --git a/src/ShellUI.Components/README.md b/src/ShellUI.Components/README.md index a24e278..dd69470 100644 --- a/src/ShellUI.Components/README.md +++ b/src/ShellUI.Components/README.md @@ -11,11 +11,37 @@ Beautiful, accessible Blazor components inspired by shadcn/ui. A CLI-first compo - πŸ“± **Responsive design** - Mobile-first approach - πŸ”§ **Fully customizable** - Copy components to your project for full control -## ⚠️ Read this first +## Two install paths -This package ships the component DLLs, JS interop, and helpers (`Shell.Cn`). **It does not produce styled components on its own.** Tailwind v4 builds CSS by scanning `.razor` source files at compile time β€” the component source lives inside this DLL, so Tailwind never sees the utility classes used inside ShellUI components. +Pick one based on whether you have Tailwind set up in your project. -The supported way to get styled components is the **`ShellUI.CLI` global tool**: +### Path A β€” NuGet + your existing Tailwind setup (new in 0.4.x) + +If your project already uses Tailwind, install the NuGet package and add one `@source` directive to your input.css. The package ships a `shellui-classes.txt` safelist that Tailwind scans at build time so utility classes used inside ShellUI components end up in your compiled CSS β€” tree-shaken, only what's used: + +```bash +dotnet add package ShellUI.Components +``` + +After restore, the safelist appears at `wwwroot/shellui-classes.txt` in your project. In your `wwwroot/input.css`: + +```css +@import "tailwindcss"; +@source "./shellui-classes.txt"; + +/* ... your theme variables, custom layers, etc. ... */ +``` + +Then in your `App.razor` or `_Host.cshtml`: +```html +@using ShellUI.Components +``` + +That's it. `