diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9857ab..22f45cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,12 +158,15 @@ jobs: print(" ".join(names)) PY ) - cd "$TMPDIR/app" - dotnet new blazor -o AllApp --no-restore - cd AllApp - shellui init --tailwind standalone --yes - shellui add $ALL - dotnet build -c Debug + # The CLI's source must build in .NET 8 and 9 projects too, and hyphenated names test the namespace sanitizing. + for fw in net10.0 net9.0 net8.0; do + cd "$TMPDIR/app" + dotnet new blazor -o "AllApp-$fw" -f "$fw" --no-restore + cd "AllApp-$fw" + shellui init --tailwind standalone --yes + shellui add $ALL + dotnet build -c Debug + done # Pure-NuGet install path — `dotnet add package ShellUI.Components` without # the CLI. Uses a one-off NuGet.config that whitelists ONLY the local feed, diff --git a/README.md b/README.md index 91716b1..db9db07 100644 --- a/README.md +++ b/README.md @@ -24,26 +24,28 @@ | Channel | Version | Notes | |---|---|---| -| Latest prerelease (recommended) | `0.3.0-rc.2` | .NET 10, Tailwind CSS `4.3.2` | -| Latest stable | `0.2.1` | Older release; superseded once `0.3.0` ships | +| Latest stable (recommended) | `0.3.0` | Tailwind CSS `4.3.2` | +| In development | `0.4.0` | This branch; not published yet | -Prereleases are not picked up by a plain install, so pass `--version 0.3.0-rc.2` explicitly. Projects still on .NET 9 can use `0.3.0-rc.1`, the last release that targets .NET 9. +The CLI needs the .NET 10 SDK and works in Blazor projects on .NET 8, 9 and 10. The `ShellUI.Components` NuGet package targets .NET 10 only; on .NET 8 or 9, use the CLI. -ShellUI is prerelease software. Validate it in your target Blazor and hosting environments before relying on it. +`main` is where 0.4 is being built, so this README and `docs/` include features that are not released yet, such as `shellui init --dashboard`. For the released version, read the [v0.3.0 docs](https://github.com/shellui-dev/shellui/tree/v0.3.0). Prereleases, when published, need `--version` to install. + +ShellUI is pre-1.0, so APIs and generated output can still change between minor versions. Validate it in your target Blazor and hosting environments before relying on it. ## Capabilities - The CLI commands are `init`, `add`, `list`, `remove`, and `update`, plus `theme init`, `theme apply`, and `theme update`. - The component registry has **194 entries**: **90 direct install targets** and **104 hidden dependency entries**. `list` shows direct targets; `add` resolves hidden dependencies. -- `0.3.0-rc.2` adds `typed-select`, `command-palette`, `data-picker`, `multi-select`, `tag-input`, `donut-chart`, `radar-chart`, and `radial-chart`. +- `0.3.0` added `typed-select`, `command-palette`, `data-picker`, `multi-select`, `tag-input`, `donut-chart`, `radar-chart`, and `radial-chart`. - `ShellUI.Components` supports a release-generated precompiled CSS bundle and a generated safelist for existing Tailwind builds. - The CLI can install source with Tailwind's standalone executable or an npm-based build. The current Tailwind baseline is `4.3.2`. - The repository and demo have migrated to .NET 10. The demo is `NET10/BlazorInteractiveServer`. ## Requirements -- .NET 10 SDK -- A .NET 10 Blazor project +- The .NET 10 SDK +- A Blazor project on .NET 8, 9 or 10 with the CLI, or on .NET 10 with the NuGet package - Tailwind CSS `4.3.2` via either: - the standalone CLI, which does not require Node.js; or - npm, which requires Node.js and npm @@ -53,7 +55,7 @@ ShellUI is prerelease software. Validate it in your target Blazor and hosting en The published global tool is named `shellui`: ```bash -dotnet tool install --global ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install --global ShellUI.CLI shellui --help ``` @@ -61,7 +63,7 @@ A local .NET tool is invoked as `dotnet shellui`: ```bash dotnet new tool-manifest -dotnet tool install --local ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install --local ShellUI.CLI dotnet shellui --help ``` @@ -92,7 +94,7 @@ New CLI sidebar installs use the host-loaded `shellui.js`; the legacy `sidebar-j | `theme apply ` | Apply a theme to `wwwroot/input.css` or emit override CSS | | `theme update` | Re-fetch the source recorded in `shellui.theme.lock` | -The targets added in `0.3.0-rc.2` can be installed together: +The targets added in `0.3.0` can be installed together: ```bash shellui add typed-select command-palette data-picker multi-select tag-input donut-chart radar-chart radial-chart @@ -101,7 +103,7 @@ shellui add typed-select command-palette data-picker multi-select tag-input donu ## Components package ```bash -dotnet add package ShellUI.Components --version 0.3.0-rc.2 +dotnet add package ShellUI.Components ``` `ShellUI.Core` and `ShellUI.Templates` are internal projects and must not be installed by consumers. diff --git a/ShellUI.Tests/InitBootstrapTests.cs b/ShellUI.Tests/InitBootstrapTests.cs index 4394e8e..5618cfd 100644 --- a/ShellUI.Tests/InitBootstrapTests.cs +++ b/ShellUI.Tests/InitBootstrapTests.cs @@ -191,3 +191,18 @@ public void BaseLayer_HidesFocusOutlineOnNavigatedHeading() Assert.Contains("h1:focus {\n outline: none;", ShellUI.Templates.CssTemplates.InputCss.Replace("\r\n", "\n")); } } + +public class RootNamespaceTests +{ + // Matches what the compiler and the .NET 10 template produce for the same project names. + [Theory] + [InlineData("my-app", "my_app")] + [InlineData("AllApp-net9.0", "AllApp_net9._0")] + [InlineData("Contoso.Shop", "Contoso.Shop")] + [InlineData("1app", "_1app")] + [InlineData("My App", "My_App")] + public void SanitizeNamespace_MakesAValidNamespace(string value, string expected) + { + Assert.Equal(expected, ProjectDetector.SanitizeNamespace(value)); + } +} diff --git a/ShellUI.Tests/TemplateCompileTests.cs b/ShellUI.Tests/TemplateCompileTests.cs index 227a011..3295137 100644 --- a/ShellUI.Tests/TemplateCompileTests.cs +++ b/ShellUI.Tests/TemplateCompileTests.cs @@ -2,6 +2,7 @@ using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using ShellUI.Core.Models; using ShellUI.Templates; using Xunit; @@ -142,6 +143,58 @@ public void EveryHiddenEntry_IsReachableFromAnInstallableTarget() Assert.True(orphans.Count == 0, "Hidden entries no installable target depends on:\n " + string.Join("\n ", orphans)); } + // `shellui add ` alone must compile: every project namespace a file imports has to be declared + // by a file the same install writes. The all-components CI sweep can't see this, since other files fill the gap. + [Fact] + public void EveryDirectTarget_ImportsOnlyNamespacesItInstalls() + { + var declaration = new Regex(@"^\s*@?namespace\s+YourProjectNamespace(\.[\w.]+)?", RegexOptions.Multiline); + var import = new Regex(@"^\s*@?using\s+YourProjectNamespace(\.[\w.]+)?\s*;?\s*$", RegexOptions.Multiline); + // Present in every project: init installs shell and shellui-js, and files without @namespace use folder namespaces. + var always = new[] { "", ".Components", ".Components.UI", ".Components.Layout" }; + + var failures = new List(); + foreach (var (name, metadata) in ComponentRegistry.Components.Where(c => c.Value.IsAvailable)) + { + var closure = new HashSet(); + var stack = new Stack(new[] { name, "shell", "shellui-js" }); + while (stack.Count > 0) + { + var current = stack.Pop(); + if (!closure.Add(current)) continue; + foreach (var dep in ComponentRegistry.Components[current].Dependencies ?? new List()) + stack.Push(dep); + } + + var contents = closure.Select(n => ComponentRegistry.GetComponentContent(n) ?? "").ToList(); + var declared = contents.SelectMany(c => declaration.Matches(c).Select(m => m.Groups[1].Value)).Concat(always).ToHashSet(); + var missing = contents.SelectMany(c => import.Matches(c).Select(m => m.Groups[1].Value)) + .Where(ns => !declared.Contains(ns)) + .Distinct() + .ToList(); + if (missing.Count > 0) + failures.Add($"{name}: {string.Join(", ", missing.Select(ns => "YourProjectNamespace" + ns))}"); + + var packages = closure.SelectMany(n => ComponentRegistry.Components[n].NuGetDependencies ?? new List()) + .Select(p => p.PackageId) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + foreach (var (ns, package) in ThirdPartyNamespaces) + { + var usesIt = new Regex($@"^\s*@?using\s+{Regex.Escape(ns)}\s*;?\s*$", RegexOptions.Multiline); + if (contents.Any(c => usesIt.IsMatch(c)) && !packages.Contains(package)) + failures.Add($"{name}: imports {ns} without the {package} package"); + } + } + + Assert.True(failures.Count == 0, "Targets whose imports are not installed with them:\n " + string.Join("\n ", failures)); + } + + private static readonly (string Namespace, string Package)[] ThirdPartyNamespaces = + { + ("ApexCharts", "Blazor-ApexCharts"), + ("System.Linq.Dynamic.Core", "System.Linq.Dynamic.Core") + }; + /// Strips Razor markup directives so the remaining text can be best-effort /// parsed as C#. Not a real Razor parser — just enough to surface useful /// diagnostics when ExtractCodeBlock fails. diff --git a/VERSIONING_STRATEGY.md b/VERSIONING_STRATEGY.md index 39259a2..21659ad 100644 --- a/VERSIONING_STRATEGY.md +++ b/VERSIONING_STRATEGY.md @@ -6,7 +6,7 @@ ShellUI uses one centralized version for the source templates, CLI tool, and pac | Scope | Value | |---|---| -| Version | `0.3.0-rc.2` | +| Version | `0.4.0-alpha.1` (in development; latest release `0.3.0`) | | Target framework | .NET 10 | | Tailwind version | `4.3.2` | @@ -18,15 +18,15 @@ The root `Directory.Build.props` supplies the version: ```xml - 0.3.0 - rc.2 + 0.4.0 + alpha.1 ``` `Directory.Build.props` composes the package and assembly metadata: -- `Version` becomes `0.3.0-rc.2` when a suffix is present. -- `AssemblyVersion` and `FileVersion` use the numeric base `0.3.0`. +- `Version` becomes `0.4.0-alpha.1` with the suffix above, and `0.4.0` without one. +- `AssemblyVersion` and `FileVersion` use the numeric base `0.4.0`. - `InformationalVersion` includes the prerelease suffix. - Component metadata reads the centralized properties when running from the repository. `VersionHelper` uses assembly metadata as a fallback when its repository search does not find the solution file. @@ -57,7 +57,7 @@ The CLI writes the computed version into `shellui.json` for each installed entry "InstalledComponents": [ { "Name": "button", - "Version": "0.3.0-rc.2", + "Version": "0.4.0", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } diff --git a/docs/CLI_INSTALLATION.md b/docs/CLI_INSTALLATION.md index 0883d51..f770229 100644 --- a/docs/CLI_INSTALLATION.md +++ b/docs/CLI_INSTALLATION.md @@ -4,25 +4,25 @@ | Context | Version | |---|---| -| Latest prerelease (recommended) | `0.3.0-rc.2`, needs the .NET 10 runtime | -| Latest stable | `0.2.1` | +| Latest stable (recommended) | `0.3.0`, needs the .NET 10 runtime | +| Previous stable | `0.2.1` | | Tailwind | `4.3.2` | -A plain tool install only selects stable releases, so pass `--version` for the prerelease. `0.3.0-rc.1` was the last release targeting .NET 9. +The tool needs the .NET 10 runtime. The projects it sets up can target .NET 8, 9 or 10. ## Global installation A global tool is available as `shellui`: ```bash -dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install -g ShellUI.CLI shellui --version ``` -If a global tool is already installed, update it to the same version: +If a global tool is already installed, update it: ```bash -dotnet tool update -g ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool update -g ShellUI.CLI ``` ## Local installation @@ -31,7 +31,7 @@ A local tool is recorded in the repository and invoked as `dotnet shellui` after ```bash dotnet new tool-manifest -dotnet tool install ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install ShellUI.CLI dotnet shellui --version ``` @@ -43,7 +43,7 @@ The manifest is `.config/dotnet-tools.json` and uses the installed package versi "isRoot": true, "tools": { "shellui.cli": { - "version": "0.3.0-rc.2", + "version": "0.3.0", "commands": ["shellui"] } } @@ -114,7 +114,7 @@ jobs: - uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - - run: dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.2 + - run: dotnet tool install -g ShellUI.CLI - run: dotnet new blazor -n App - working-directory: App run: shellui init --yes --tailwind standalone @@ -181,7 +181,7 @@ dotnet tool list -g shellui --version ``` -A plain install selects the latest stable release (`0.2.1`). Pass `--version 0.3.0-rc.2` for the prerelease. +A plain install or update selects the latest stable release. Pass `--version ` to pin a specific release. ## Related documentation diff --git a/docs/CLI_SYNTAX.md b/docs/CLI_SYNTAX.md index 70338df..fd858d8 100644 --- a/docs/CLI_SYNTAX.md +++ b/docs/CLI_SYNTAX.md @@ -1,6 +1,6 @@ # ShellUI CLI Syntax -This reference covers CLI `0.3.0-rc.2`: `net10.0`, Tailwind CSS `4.3.2`, and 90 direct component targets. Older versions, including the stable `0.2.1`, lack some of these commands. +This reference covers the CLI on `main` (0.4, in development): it runs on .NET 10, sets up Blazor projects on .NET 8, 9 and 10, uses Tailwind CSS `4.3.2`, and has 90 direct component targets. Some options, such as `--dashboard`, are not in the released 0.3.0; see the [v0.3.0 reference](https://github.com/shellui-dev/shellui/blob/v0.3.0/docs/CLI_SYNTAX.md) for that version. ## Command prefix @@ -63,7 +63,7 @@ Initialization creates or updates: `init` removes the template's local Bootstrap copy (`wwwroot/lib/bootstrap` or, on .NET 8, `wwwroot/bootstrap`) and its `` in `App.razor`; Bootstrap loaded from a CDN is left alone. The sample pages (`Home`, `Counter`, `Weather`, `Error`, `NotFound`, `Auth`) are restyled with Tailwind classes when they are unchanged from `dotnet new blazor`. Pages you have edited are kept, and `init` lists any that still use Bootstrap classes. Identity pages under `Account/` are counted but not restyled. -With `--dashboard`, `init` then runs `shellui add dashboard-0x`, including the layout wiring described under [Dashboard layouts](#dashboard-layouts). +With `--dashboard`, `init` then runs `shellui add dashboard-02` (or `dashboard-01`), including the layout wiring described under [Dashboard layouts](#dashboard-layouts). Standalone mode stores the Tailwind executable in `.shellui/bin/`. npm mode installs `tailwindcss@^4.3.2` and `@tailwindcss/cli@^4.3.2` and requires Node.js and npm. The current CLI invokes npm through `cmd`; use standalone mode on non-Windows systems or run npm manually. @@ -226,7 +226,7 @@ Representative fields look like this: "InstalledComponents": [ { "Name": "button", - "Version": "0.3.0-rc.2", + "Version": "0.4.0", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index dfb6890..399c7b9 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -52,7 +52,7 @@ Choose ShellUI when the project benefits from: - Direct ownership and editing of copied Blazor component source - Tailwind CSS as the styling foundation - A CLI workflow similar to copy-based component libraries -- A .NET 10 component source that can be adapted for a particular application +- Component source for .NET 8, 9 and 10 projects that can be adapted for a particular application - Explicit control over generated code and dependencies These are workflow and architecture characteristics, not a claim that ShellUI has more features, better performance, or broader compatibility than every packaged library. @@ -96,7 +96,7 @@ The CLI's copy-based model can avoid installing unused component source, but it Community size is not a stable, comparable metric. Stars, forum activity, Discord membership, and commercial support change over time, and no current comparable dataset is maintained here. Check the official project repositories and support channels directly. -ShellUI is prerelease software. Validate the specific release you plan to use. +ShellUI is pre-1.0. Validate the specific release you plan to use. ## Migration considerations diff --git a/docs/FAQ.md b/docs/FAQ.md index 6f8f531..5b95631 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -6,13 +6,13 @@ Answers for the current ShellUI source and the currently published packages. ### Which version should I use? -Use `0.3.0-rc.2`. It targets `net10.0`, uses Tailwind CSS `4.3.2`, and exposes 90 direct component targets. A plain install selects the older stable `0.2.1`, so select the prerelease explicitly: +Use the latest stable release, `0.3.0`. It uses Tailwind CSS `4.3.2`. The 0.4 work on `main`, with 90 direct component targets, is not published yet: ```bash -dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install -g ShellUI.CLI ``` -Projects still on .NET 9 can use `0.3.0-rc.1`, the last release targeting .NET 9. +The CLI needs the .NET 10 SDK and works in Blazor projects on .NET 8, 9 and 10. The `ShellUI.Components` NuGet package targets .NET 10 only; on .NET 8 or 9, use the CLI. ### Which command prefix should I use? @@ -145,7 +145,7 @@ A representative Tailwind and component record is: "InstalledComponents": [ { "Name": "button", - "Version": "0.3.0-rc.2", + "Version": "0.3.0", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } @@ -236,7 +236,7 @@ For standalone mode, check `.shellui/bin/`. For npm mode, run `npm install`. Pass the version explicitly: ```bash -dotnet add package ShellUI.Components --version 0.3.0-rc.2 +dotnet add package ShellUI.Components ``` Then restore and build the project. diff --git a/docs/PROJECT_STATUS.md b/docs/PROJECT_STATUS.md index 406311e..b2e50b0 100644 --- a/docs/PROJECT_STATUS.md +++ b/docs/PROJECT_STATUS.md @@ -67,7 +67,7 @@ CI restores `ShellUI.slnx`, regenerates the precompiled CSS bundle, builds the s ## Current Boundaries -- ShellUI is prerelease software and its APIs, templates, and generated output may change. +- ShellUI is pre-1.0, so its APIs, templates, and generated output may change between minor versions. - Only `ShellUI.CLI` and `ShellUI.Components` are packable in the current project configuration. - `ShellUI.Core` and `ShellUI.Templates` are internal; they are not consumer installation targets. - No stable release date, adoption target, or guaranteed delivery schedule is stated here. diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 8af7ab5..3563344 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -1,6 +1,6 @@ # ShellUI Quick Start -This quick start uses ShellUI `0.3.0-rc.2`: .NET 10, Tailwind CSS `4.3.2`, and 90 direct component targets. +This quick start uses ShellUI `0.3.0`: Tailwind CSS `4.3.2`. The CLI needs the .NET 10 SDK and works in Blazor projects on .NET 8, 9 and 10. ## Prerequisites @@ -20,12 +20,10 @@ dotnet --version A global tool is invoked as `shellui`: ```bash -dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install -g ShellUI.CLI shellui --version ``` -A plain install without `--version` selects the older stable `0.2.1`, which lacks several commands in this guide. - If the project has a .NET tool manifest, use `dotnet shellui` instead. See [CLI installation](CLI_INSTALLATION.md). ## Create and initialize a project diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index e0b25b6..e67adbd 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -1,5 +1,106 @@ # ShellUI Release Notes +# ShellUI v0.3.0 🎉 + +> The first stable release of the 0.3 line. It builds on .NET 10 and Tailwind CSS 4.3.2 and ships everything from the 0.3.0 alphas and release candidates. A plain `dotnet tool install` now picks it up, so `--version` is no longer needed. Report issues via [GitHub Issues](https://github.com/shellui-dev/shellui/issues). + +## Highlights since 0.2.1 + +- **Blazor on .NET 8, 9 and 10.** The CLI needs the .NET 10 SDK, and the components it installs build in projects on .NET 8, 9 and 10; CI now checks all three. The `ShellUI.Components` NuGet package targets .NET 10 only. +- **Tailwind CSS 4.3.2.** +- **`shellui init` produces an app that builds and runs.** It patches `App.razor` (render mode, theme bootstrap, `shellui.js`), writes the full theme to `input.css`, and wires Tailwind into the build. +- **`shellui add` resolves everything a component needs:** its sub-components, models and variants, NuGet packages (`Blazor-ApexCharts`, `System.Linq.Dynamic.Core`), and the `@using` lines in `_Imports.razor`. Typos get a "did you mean" suggestion. +- **76 components**, including `command-palette`, `data-picker`, `multi-select`, `tag-input`, `typed-select`, and the `donut-chart`, `radar-chart` and `radial-chart` charts. +- **Composable APIs** for Select, Dropdown, Popover, ContextMenu, NavigationMenu, Carousel, HoverCard, Accordion and Tabs, installed together with their parent. +- **Themes from [tweakcn](https://tweakcn.com):** `shellui theme init | apply | update`. +- **NuGet package** with a precompiled `shellui-all.css` bundle and a Tailwind safelist, so it works without a Tailwind build step. +- **Accessibility:** Dialog, Sheet and Drawer take focus on open, close on Escape, and set `role="dialog"`. +- `Class` is accepted everywhere; `ClassName` still works but is deprecated. + +See the release candidate sections below for the full list of changes. + +## 🐛 Fixes since rc.3 + +- Adding certain components on their own produced a project that did not build: + - `avatar`, `alert`, `badge`, `sonner`, `toggle`: `shellui add` wrote `@using ….Components.UI.Variants` to `_Imports.razor`, but those variants files declare `.Components.UI`. Imports now follow the namespace each installed file declares. + - `input`, `alert`, `badge`, `toggle`: the component files imported that same namespace themselves. The import is removed. + - `chart-series`: now installs `chart` and the `Blazor-ApexCharts` package. + + Every component was installed and built on its own in a fresh app for this release, and a new test checks that each component installs the namespaces and packages it imports. +- On .NET 8 and 9 projects whose name is not a valid namespace, such as `my-app`, installed files got `namespace my-app.Components.UI` and did not build. The template writes `my-app`, while the compiler uses `my_app`; the CLI now does the same. +- `shellui init` on .NET 8 left Bootstrap active: the template keeps it in `wwwroot/bootstrap/`, which was not removed. It is now, and the local Bootstrap `` is removed from `App.razor` (on .NET 9 and 10 it pointed at deleted files). Bootstrap loaded from a CDN is left alone. +- On Windows the CLI now writes UTF-8, so ✅ no longer prints as `?` and the spinner no longer falls back to ASCII. +- A failed `shellui init` now exits with code 1. + +## ⬆️ Upgrading + +- **From a 0.3.0 release candidate:** update the tool, then run `shellui update` to rewrite the installed components from the new templates. `update` overwrites the files, so commit or back up any components you customized first. +- **From 0.2.1:** install the .NET 10 SDK to run the CLI. Your project can stay on .NET 8 or 9 when you use the CLI; the NuGet package needs .NET 10. Read the rc.1 notes below for what changed in `init` and the templates. + +## 📦 Installation + +```bash +# CLI +dotnet tool install -g ShellUI.CLI +# or upgrade an existing install +dotnet tool update -g ShellUI.CLI +``` + +```bash +# NuGet package +dotnet add package ShellUI.Components +``` + +**Full Changelog**: https://github.com/shellui-dev/shellui/compare/v0.2.1...v0.3.0 + +--- + +# ShellUI v0.3.0-rc.3 🚦 + +> Third release candidate for v0.3.0. It contains only fixes, mostly to what `shellui add` installs. There are no new components and no breaking changes. If nothing critical comes up during testing, v0.3.0 ships from this code with the suffix dropped. Report issues via [GitHub Issues](https://github.com/shellui-dev/shellui/issues). + +## 🐛 Fixes + +### Components that installed incomplete or didn't compile +- **Composable parts are installed.** `SelectTrigger`, `SelectContent`, `SelectItem`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuOption`, `NavList`, `NavItem`, `NavTrigger`, `NavContent`, `CarouselList` and `CarouselSlide` were empty templates, so composable markup failed to compile after `shellui add`. They now ship with their parent component. +- The Dropdown, Popover, HoverCard and Accordion parts (`*Trigger`, `*Content`, `DropdownItem`) were never pulled in by their parent, and the Dropdown, Popover and HoverCard CLI templates didn't support composable use. The CLI templates now match the NuGet package. +- `Tabs` supports `Items` / `TabItems` and `ActiveTab` as in the package. Its `TabModels.cs` now installs to `Components/UI/Models/` instead of a nested `Components/UI/Components/Models/` folder. +- `command` no longer declares its own `CommandItem`, which clashed with `command-palette`. It now installs the shared `CommandModels.cs`. +- `alert-dialog` was missing its `Variants` using. +- `shellui add` adds the `@using` lines that installed components need (`.Components.UI.Variants` and `.Components.Models`) to `_Imports.razor`. + +### Behavior +- Compositional Dropdown, Popover, ContextMenu and NavigationMenu items now open and close without binding `IsOpen`. ContextMenu and Dropdown close on an outside click. +- A value-based `Carousel` (`CarouselSlide Value="..."`) shows its dots and the correct width on first render. +- `HoverCardContent` stays open while the pointer is over it. +- `SelectItem` marks the selected option (`data-selected`, `aria-selected`), and triggers expose `aria-expanded`. +- Dialog, Sheet and Drawer take focus when they open, close on Escape, and set `role="dialog"` and `aria-modal`. +- Keyboard shortcuts such as `Ctrl+K` accept Ctrl or Cmd, as intended. Before, they required both. +- `Loading` animations work in CLI projects. Their keyframes ship with the component, and the grid delays no longer depend on the server culture. +- Headings focused by Blazor navigation no longer show a focus outline. + +### Tooling +- CI runs on `release/**` branches and installs every component into a fresh app and builds it, so a template that doesn't compile or a missing dependency fails the build. +- New tests fail when a registry entry has empty content, when a hidden part isn't reachable from any installable component, or when a CLI template drifts from its package component. + +## 📦 Installation + +```bash +# CLI (prerelease: the version is required) +dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.3 +# or upgrade an existing install +dotnet tool update -g ShellUI.CLI --version 0.3.0-rc.3 +``` + +```bash +# NuGet package +dotnet add package ShellUI.Components --version 0.3.0-rc.3 +``` + +**Full Changelog**: https://github.com/shellui-dev/shellui/compare/v0.3.0-rc.2...v0.3.0-rc.3 + +--- + # ShellUI v0.3.0-rc.2 🚦 > Second release candidate for v0.3.0. It moves ShellUI to .NET 10, adds new components, and fixes bugs found in real projects using rc.1. If nothing critical comes up during testing, v0.3.0 ships from this code with the suffix dropped. Report issues via [GitHub Issues](https://github.com/shellui-dev/shellui/issues). diff --git a/docs/tailwind-setup.md b/docs/tailwind-setup.md index f0c0dd0..e9a6ea5 100644 --- a/docs/tailwind-setup.md +++ b/docs/tailwind-setup.md @@ -25,11 +25,9 @@ For a production Blazor application, use either the standalone or npm workflow a ### Install the CLI ```text -dotnet tool install -g ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install -g ShellUI.CLI ``` -A plain install without `--version` selects the older stable `0.2.1`. - ### Initialize a project Run this from the project directory: diff --git a/src/ShellUI.CLI/README.md b/src/ShellUI.CLI/README.md index cf30d11..ed35d9d 100644 --- a/src/ShellUI.CLI/README.md +++ b/src/ShellUI.CLI/README.md @@ -1,200 +1,79 @@ # ShellUI CLI -The ShellUI command-line tool initializes a .NET 10 Blazor project and copies ShellUI component templates into source files that the application owns. +`shellui` sets up Tailwind CSS in a Blazor project and copies ShellUI components into it as source you own, in the spirit of shadcn/ui. ## Install -The tool needs the .NET 10 runtime. Prereleases are not picked up by a plain install, so pass the version: +The tool needs the .NET 10 runtime. The projects it sets up can target .NET 8, 9 or 10: ```bash -dotnet tool install --global ShellUI.CLI --version 0.3.0-rc.2 +dotnet tool install --global ShellUI.CLI ``` -A global tool uses the `shellui` command: - -```bash -shellui --help -``` - -A local .NET tool uses `dotnet shellui`: +Or as a local tool, invoked as `dotnet shellui`: ```bash dotnet new tool-manifest -dotnet tool install --local ShellUI.CLI --version 0.3.0-rc.2 -dotnet shellui --help +dotnet tool install --local ShellUI.CLI ``` ## Quick start -Run these commands from the root of the target Blazor project: +From the root of a Blazor project: ```bash shellui init shellui add button card dialog -shellui list -shellui list --installed +dotnet watch ``` -For a local tool, prefix each command with `dotnet `, for example `dotnet shellui init`. +`init` sets up Tailwind CSS `4.3.2` (the standalone executable, or npm), writes the default theme to `wwwroot/input.css`, adds a build step that compiles it to `wwwroot/app.css`, and patches `App.razor` with an interactive render mode, a theme script, and `shellui.js`. It removes the template's local Bootstrap copy and its ``, and restyles the template's sample pages if you haven't edited them. -`init` detects the Blazor project, creates the ShellUI folder and configuration structure, selects the Tailwind method, writes the default theme, wires the host, and adds the Tailwind MSBuild integration. It can use the standalone Tailwind executable or npm. +`add` writes each component and everything it depends on to `Components/UI/`. It also adds the NuGet packages, stylesheet links, and `_Imports.razor` usings the components need. ## Commands -### `init` - -Initialize ShellUI in a Blazor project. - -```bash -shellui init -``` - -Options: - -- `--force` reinitialize a project that is already configured -- `--style ` select a component style -- `--tailwind ` select the Tailwind build method -- `--yes` accept the defaults without prompts - -### `add ` - -Install one or more direct component targets and their dependencies. - -```bash -shellui add button -shellui add input card dialog table -shellui add button,input,card -``` - -Options: - -- `--force` overwrite existing files - -Dependency-only registry entries are hidden from `list` but are installed recursively. Some templates also add required NuGet packages and stylesheet links. - -### `list` - -List direct component targets. - -```bash -shellui list -shellui list --installed -shellui list --available -``` - -### `remove ` - -Remove one or more named installed components. - -```bash -shellui remove button input -``` - -The command accepts one or more component names. Review local changes before removing source files. Layout blocks such as `dashboard-01` and `dashboard-02` currently require manual removal from `Components/Layout` because remove is not yet layout-aware. - -### `update [components...]` - -Reinstall named components from the current CLI templates. With no names, or with `--all`, it updates every installed component. - -```bash -shellui update button -shellui update card input -shellui update --all -``` - -`update` overwrites template files. Commit or otherwise preserve local customizations before running it. - -### `theme init ` - -Initialize a project and apply a public [tweakcn](https://tweakcn.com) theme in one operation. - -```bash -shellui theme init https://tweakcn.com/themes/THEME_ID -shellui theme init THEME_ID --yes -``` - -The URL argument also accepts a bare theme ID or a public `https://tweakcn.com/r/themes/THEME_ID` URL. Options match `init`: `--force`, `--style`, `--tailwind`, and `--yes`. - -### `theme apply ` - -Apply a theme to an initialized project. - -```bash -shellui theme apply https://tweakcn.com/themes/THEME_ID -shellui theme apply THEME_ID --emit-override wwwroot/theme.css -``` - -Without `--emit-override`, the command replaces the sentinel-marked region in `wwwroot/input.css` and leaves surrounding CSS intact. With `--emit-override`, it writes a standalone theme file that can be loaded after `shellui-all.css`. - -### `theme update` - -Re-fetch the theme recorded in `shellui.theme.lock` and apply it again. - -```bash -shellui theme update -``` - -The lock file stores the original source URL, theme name, timestamp, and SHA-256 of the fetched theme JSON. - -## Component inventory - -The registry contains **194 entries**: +| Command | Purpose | +|---|---| +| `init` | Set up ShellUI and Tailwind in the current project | +| `add ` | Install components and their dependencies | +| `list` | List the 90 components, with `--installed` or `--available` filters | +| `remove ` | Delete installed component files | +| `update [names...]` | Rewrite installed components from the current templates (`--all` for every one) | +| `theme init ` | Run `init`, then apply a [tweakcn](https://tweakcn.com) theme | +| `theme apply ` | Apply a tweakcn theme to `wwwroot/input.css`, or write an override file with `--emit-override ` | +| `theme update` | Re-apply the theme recorded in `shellui.theme.lock` | -- **90 direct install targets**, shown by `list` -- **104 hidden dependency entries**, resolved by `add` but omitted from the direct list +`init` options: -The targets added in `0.3.0-rc.2` are: +- `--tailwind standalone|npm` selects how Tailwind is installed. `standalone` needs no Node.js. npm mode runs npm through `cmd`, so it only works on Windows. +- `--yes` runs without prompts; Tailwind defaults to `standalone`. +- `--force` re-initializes a project that already has `shellui.json`. +- `--dashboard 02|01|none` sets up a dashboard layout (sticky or scrolling header) and makes it the default layout. Without the option, `init` asks; `--yes` alone means none. +- `--replace-layout` switches to the dashboard even when the app has a custom layout. +- `--style` is recorded in `shellui.json`. All styles currently install the same templates. -```bash -shellui add typed-select command-palette data-picker multi-select tag-input donut-chart radar-chart radial-chart -``` +`add` accepts names separated by spaces or commas, and `--force` overwrites existing files. `update` and `add --force` overwrite your copies, so commit customized components first. `add dashboard-01` or `add dashboard-02` also makes the dashboard the default layout and builds its sidebar links from your pages. `remove` does not handle dashboard layouts; delete those from `Components/Layout/` yourself. -Use `shellui list` for the complete direct-target inventory and descriptions. - -## Generated project structure - -A typical initialized project contains: +## Generated files | Path | Purpose | |---|---| -| `Components/UI/` | Installed component source | -| `Components/Layout/` | Dashboard layout blocks, when installed | -| `wwwroot/input.css` | Tailwind input and ShellUI theme variables | -| `wwwroot/app.css` | Compiled project CSS | -| `wwwroot/shellui.js` | JavaScript interop used by ShellUI components | -| `Build/ShellUI.targets` | MSBuild Tailwind integration | -| `shellui.json` | Installed component and Tailwind configuration | -| `shellui.theme.lock` | Theme source metadata, when a theme is applied | - -## Tailwind setup - -ShellUI uses Tailwind CSS `4.3.2`. - -- `shellui init --tailwind standalone` downloads the standalone executable and does not require Node.js. -- `shellui init --tailwind npm --yes` installs `tailwindcss@^4.3.2` and `@tailwindcss/cli@^4.3.2` and requires Node.js and npm. - -Both methods compile `wwwroot/input.css` to `wwwroot/app.css` through the generated MSBuild target. The current CLI invokes npm through `cmd`; use standalone mode on non-Windows systems or run npm manually. - -## Development - -From the repository root: - -```bash -dotnet restore ShellUI.slnx -dotnet build ShellUI.slnx -dotnet test ShellUI.slnx -``` - -The CLI project is `src/ShellUI.CLI/ShellUI.CLI.csproj`. `ShellUI.Core` and `ShellUI.Templates` are internal dependencies and are not packable. +| `Components/UI/` | Installed components | +| `Components/Layout/` | Dashboard layouts, when installed | +| `wwwroot/input.css` | Tailwind input and theme variables | +| `wwwroot/app.css` | Compiled CSS | +| `wwwroot/shellui.js` | JavaScript used by some components | +| `Build/ShellUI.targets` | Tailwind build step | +| `shellui.json` | ShellUI settings and installed components | +| `shellui.theme.lock` | Theme source, when a theme is applied | ## Documentation -- [Repository README](https://github.com/shellui-dev/shellui/blob/main/README.md) -- [Contributing guide](https://github.com/shellui-dev/shellui/blob/main/docs/CONTRIBUTING.md) +- [README](https://github.com/shellui-dev/shellui/blob/main/README.md) +- [CLI reference](https://github.com/shellui-dev/shellui/blob/main/docs/CLI_SYNTAX.md) - [Release notes](https://github.com/shellui-dev/shellui/blob/main/docs/RELEASE_NOTES.md) -The release notes are historical records for published versions and do not replace this source-version command reference. - ## License [MIT](https://github.com/shellui-dev/shellui/blob/main/LICENSE.txt) diff --git a/src/ShellUI.CLI/Services/ProjectDetector.cs b/src/ShellUI.CLI/Services/ProjectDetector.cs index 27a18e3..fc15eb1 100644 --- a/src/ShellUI.CLI/Services/ProjectDetector.cs +++ b/src/ShellUI.CLI/Services/ProjectDetector.cs @@ -66,8 +66,16 @@ private static string DetectRootNamespace(XDocument doc, string projectName) .Descendants("RootNamespace") .FirstOrDefault()?.Value; - return rootNamespace ?? projectName; + return SanitizeNamespace(string.IsNullOrWhiteSpace(rootNamespace) ? projectName : rootNamespace); } + + // The .NET 8/9 templates write e.g. my-app; the compiler and Razor use my_app. + internal static string SanitizeNamespace(string value) => + string.Join(".", value.Trim().Split('.', StringSplitOptions.RemoveEmptyEntries).Select(segment => + { + var identifier = new string(segment.Select(c => char.IsLetterOrDigit(c) || c == '_' ? c : '_').ToArray()); + return char.IsDigit(identifier[0]) ? "_" + identifier : identifier; + })); } public class ProjectInfo diff --git a/src/ShellUI.Components/README.md b/src/ShellUI.Components/README.md index a07aede..2c5f4f9 100644 --- a/src/ShellUI.Components/README.md +++ b/src/ShellUI.Components/README.md @@ -1,101 +1,85 @@ # ShellUI Components -`ShellUI.Components` is the .NET 10 Razor class library packaged as `ShellUI.Components`. It provides the component runtime, Tailwind classes, theme variables, JavaScript assets, and package build integration used by ShellUI. +Blazor components styled with Tailwind CSS, in the spirit of shadcn/ui, as a Razor class library. + +Prefer to own and edit the component source? Use the [ShellUI CLI](https://www.nuget.org/packages/ShellUI.CLI) instead; it copies the components into your project. ## Install -Requires a .NET 10 project. Prereleases are not picked up by a plain install, so pass the version: +Requires a .NET 10 project: ```bash -dotnet add package ShellUI.Components --version 0.3.0-rc.2 +dotnet add package ShellUI.Components ``` -Projects still on .NET 9 can use `0.3.0-rc.1`. Do not install `ShellUI.Core` or `ShellUI.Templates`; both are internal, non-packable projects. +On .NET 8 or 9, use the [ShellUI CLI](https://www.nuget.org/packages/ShellUI.CLI) instead. The source it installs builds on .NET 8, 9 and 10. -## CSS workflows +## Set up -After building the current package, consumers can choose one of two CSS workflows. +1. Import the namespace in `Components/_Imports.razor`: -### Precompiled bundle + ```razor + @using ShellUI.Components + ``` -The release pipeline runs `scripts/rebuild-precompiled-css.sh` before packing. For a local pack, run that script first; the generated `shellui-all.css` contains the ShellUI theme and safelisted utilities, so the consuming app does not need a Tailwind build for ShellUI styles. +2. Make the app interactive. Components with state or events (dialogs, dropdowns, tabs) need an interactive render mode, for example in `Components/App.razor`: -```razor - -``` - -```razor -@using ShellUI.Components -``` + ```razor + + ... + + ``` -`shellui-all.css` is generated and gitignored; it is not a checked-in source file. +3. Add the styles, in one of two ways: -### Safelist with an existing Tailwind build + - **Precompiled stylesheet.** No Tailwind build needed. Add it to the `` in `App.razor`: -For an app that already compiles Tailwind, the package build target writes `wwwroot/shellui-classes.txt` in the consuming project. Reference that file from the app's input stylesheet: + ```html + + ``` -```css -@import "tailwindcss"; -@source "./shellui-classes.txt"; -``` + - **Your own Tailwind build.** On build, the package writes the class names it uses to `wwwroot/shellui-classes.txt`. Add it as a source in your input stylesheet, and copy the theme variables from the package's `shellui-theme.css` into the same file: -Keep the theme variables used by ShellUI in the same Tailwind build. ShellUI uses Tailwind CSS `4.3.2`. + ```css + @import "tailwindcss"; + @source "./shellui-classes.txt"; + ``` -## Use a component + ShellUI uses Tailwind CSS `4.3.2`. -Add the package namespace to `Components/_Imports.razor`: +## Use ```razor -@using ShellUI.Components -``` - -Then use the components in a Razor file: - -```razor - + + ShellUI -

Component content

+

Card content

``` -The package also serves static assets, including `shellui.js`, from `_content/ShellUI.Components/` for components that use JavaScript interop. The package's own `SidebarProvider` retains `shellui-sidebar.js` for its runtime module; CLI-copied providers use the host-loaded `shellui.js` contract instead. - -## Component inventory - -The CLI registry contains **194 entries**: **90 direct install targets** and **104 hidden dependency entries**. The CLI displays the 90 direct targets and resolves hidden entries recursively. - -`0.3.0-rc.2` adds `typed-select`, `command-palette`, `data-picker`, `multi-select`, `tag-input`, `donut-chart`, `radar-chart`, and `radial-chart`. Use the CLI's `list` command for the complete direct-target inventory. - -## Theming with the CLI +## Themes -The CLI can apply a public [tweakcn](https://tweakcn.com) theme: +Themes come from [tweakcn](https://tweakcn.com). With the CLI, write a theme as a stylesheet and load it after `shellui-all.css`: ```bash -shellui theme apply https://tweakcn.com/themes/THEME_ID shellui theme apply https://tweakcn.com/themes/THEME_ID --emit-override wwwroot/theme.css -shellui theme update ``` -The first form updates the managed region in `wwwroot/input.css` for a Tailwind build. The override form writes standalone variables for an app using `shellui-all.css`; load that file after the precompiled stylesheet. The source URL and hash are stored in `shellui.theme.lock` for `theme update`. - -These commands require CLI `0.3.0-rc.2` or later. - -## Accessibility - -ShellUI components use Blazor and Tailwind patterns for semantics, focus, and keyboard interaction where implemented. Accessibility still depends on the component API, configuration, content, and host application; test each consuming app rather than assuming a blanket conformance level. +```html + +``` ## Documentation -- [Repository README](https://github.com/shellui-dev/shellui/blob/main/README.md) +- [README](https://github.com/shellui-dev/shellui/blob/main/README.md) - [Tailwind setup](https://github.com/shellui-dev/shellui/blob/main/docs/tailwind-setup.md) -- [Contributing guide](https://github.com/shellui-dev/shellui/blob/main/docs/CONTRIBUTING.md) -- [Historical release notes](https://github.com/shellui-dev/shellui/blob/main/docs/RELEASE_NOTES.md) +- [Release notes](https://github.com/shellui-dev/shellui/blob/main/docs/RELEASE_NOTES.md) ## License diff --git a/src/ShellUI.Templates/README.md b/src/ShellUI.Templates/README.md index d88b33d..fee70f4 100644 --- a/src/ShellUI.Templates/README.md +++ b/src/ShellUI.Templates/README.md @@ -39,7 +39,7 @@ The registry contains **194 entries**: Each entry provides content plus metadata used by the CLI, including its display name, category, description, target path, version, dependencies, and optional NuGet dependencies. The catalog also includes hidden subcomponents, variants, models, services, JavaScript, and stylesheet assets required by direct targets. -`0.3.0-rc.2` adds the direct targets `typed-select`, `command-palette`, `data-picker`, `multi-select`, `tag-input`, `donut-chart`, `radar-chart`, and `radial-chart`. +`0.3.0` added the direct targets `typed-select`, `command-palette`, `data-picker`, `multi-select`, `tag-input`, `donut-chart`, `radar-chart`, and `radial-chart`. ## Development diff --git a/src/ShellUI.Templates/Templates/AlertTemplate.cs b/src/ShellUI.Templates/Templates/AlertTemplate.cs index a297bbc..68644f2 100644 --- a/src/ShellUI.Templates/Templates/AlertTemplate.cs +++ b/src/ShellUI.Templates/Templates/AlertTemplate.cs @@ -16,7 +16,6 @@ public static class AlertTemplate }; public static string Content => @"@namespace YourProjectNamespace.Components.UI -@using YourProjectNamespace.Components.UI.Variants
@if (Icon != null) diff --git a/src/ShellUI.Templates/Templates/BadgeTemplate.cs b/src/ShellUI.Templates/Templates/BadgeTemplate.cs index 3f940b3..0e7b9ba 100644 --- a/src/ShellUI.Templates/Templates/BadgeTemplate.cs +++ b/src/ShellUI.Templates/Templates/BadgeTemplate.cs @@ -16,7 +16,6 @@ public static class BadgeTemplate }; public static string Content => @"@namespace YourProjectNamespace.Components.UI -@using YourProjectNamespace.Components.UI.Variants
@ChildContent diff --git a/src/ShellUI.Templates/Templates/ChartSeriesTemplate.cs b/src/ShellUI.Templates/Templates/ChartSeriesTemplate.cs index 674dbe8..1007518 100644 --- a/src/ShellUI.Templates/Templates/ChartSeriesTemplate.cs +++ b/src/ShellUI.Templates/Templates/ChartSeriesTemplate.cs @@ -11,7 +11,7 @@ public class ChartSeriesTemplate Description = "Individual chart series component for use in multi-series charts", Category = ComponentCategory.DataDisplay, FilePath = "ChartSeries.razor", - Dependencies = new List(), + Dependencies = new List { "chart" }, Variants = new List { "line", "bar", "area", "pie" }, Tags = new List { "chart", "series", "data", "visualization", "apexcharts" } }; diff --git a/src/ShellUI.Templates/Templates/InputTemplate.cs b/src/ShellUI.Templates/Templates/InputTemplate.cs index d2d634e..1003eb0 100644 --- a/src/ShellUI.Templates/Templates/InputTemplate.cs +++ b/src/ShellUI.Templates/Templates/InputTemplate.cs @@ -16,7 +16,6 @@ public static class InputTemplate }; public static string Content => @"@namespace YourProjectNamespace.Components.UI -@using YourProjectNamespace.Components.UI.Variants @"@namespace YourProjectNamespace.Components.UI -@using YourProjectNamespace.Components.UI.Variants