Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -53,15 +55,15 @@ 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
```

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
```

Expand Down Expand Up @@ -92,7 +94,7 @@ New CLI sidebar installs use the host-loaded `shellui.js`; the legacy `sidebar-j
| `theme apply <url-or-id>` | 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
Expand All @@ -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.
Expand Down
15 changes: 15 additions & 0 deletions ShellUI.Tests/InitBootstrapTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
53 changes: 53 additions & 0 deletions ShellUI.Tests/TemplateCompileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using ShellUI.Core.Models;
using ShellUI.Templates;
using Xunit;

Expand Down Expand Up @@ -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 <target>` 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<string>();
foreach (var (name, metadata) in ComponentRegistry.Components.Where(c => c.Value.IsAvailable))
{
var closure = new HashSet<string>();
var stack = new Stack<string>(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<string>())
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<NuGetDependency>())
.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.
Expand Down
12 changes: 6 additions & 6 deletions VERSIONING_STRATEGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |

Expand All @@ -18,15 +18,15 @@ The root `Directory.Build.props` supplies the version:

```xml
<PropertyGroup>
<ShellUIVersion>0.3.0</ShellUIVersion>
<ShellUIVersionSuffix>rc.2</ShellUIVersionSuffix>
<ShellUIVersion>0.4.0</ShellUIVersion>
<ShellUIVersionSuffix>alpha.1</ShellUIVersionSuffix>
</PropertyGroup>
```

`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.

Expand Down Expand Up @@ -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
}
Expand Down
20 changes: 10 additions & 10 deletions docs/CLI_INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
```

Expand All @@ -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"]
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 <version>` to pin a specific release.

## Related documentation

Expand Down
6 changes: 3 additions & 3 deletions docs/CLI_SYNTAX.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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 `<link>` 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.

Expand Down Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions docs/COMPARISON.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down
10 changes: 5 additions & 5 deletions docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion docs/PROJECT_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 2 additions & 4 deletions docs/QUICKSTART.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
Expand Down
Loading
Loading