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
28 changes: 26 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,32 @@ jobs:
- name: Run tests
run: dotnet test ShellUI.sln --no-restore --no-build --configuration Release --verbosity normal

- name: Pack NuGet packages
run: dotnet pack ShellUI.sln --no-build --configuration Release -p:ContinuousIntegrationBuild=true
# Guards against the template-escape bug class from shellui-fixes-for-lib.md
# (Fixes 2, 9, 10). TemplateCompileTests verifies generated content parses;
# this end-to-end build catches anything the syntactic check misses
# (e.g. missing using directives).
- name: Smoke-test CLI scaffolding
shell: bash
run: |
set -euxo pipefail
TMPDIR=$(mktemp -d)
dotnet pack src/ShellUI.CLI/ShellUI.CLI.csproj -c Release -o "$TMPDIR/nupkgs" --no-build
dotnet tool install --tool-path "$TMPDIR/tools" --add-source "$TMPDIR/nupkgs" ShellUI.CLI --prerelease
export PATH="$TMPDIR/tools:$PATH"

mkdir -p "$TMPDIR/app" && cd "$TMPDIR/app"
dotnet new blazor -o SmokeApp --no-restore
cd SmokeApp
shellui init --tailwind standalone --yes
# Hit the three components that regressed last time:
shellui add chart pie-chart dashboard-02 --force || true
# Chart components reference ApexCharts.* types — `shellui add chart`
# does NOT auto-install Blazor-ApexCharts today (tracked as Fix 12.3:
# `nugetDependencies` field on component manifests). Add it explicitly
# here so the smoke test isolates THIS PR's bug class (template escapes)
# from that one. When Fix 12.3 lands, remove this line.
dotnet add package Blazor-ApexCharts --version 6.0.2
dotnet build -c Debug

- name: Upload build artifacts
uses: actions/upload-artifact@v4
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/preview-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ jobs:

- name: Setup Pages
uses: actions/configure-pages@v4
with:
# Auto-enable Pages on first run so this workflow can deploy without
# someone clicking through Settings → Pages first. Requires the
# GITHUB_TOKEN to have `pages: write` (already set above).
enablement: true

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
Expand Down
43 changes: 24 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ ShellUI transforms Blazor component development with a hybrid approach:
- Powered by Tailwind CSS v4.1.18 (standalone CLI - no Node.js required!)
- Best of both worlds: flexibility when you need it, convenience when you want it

## Current Status: 100 Components (Alpha) 🎉
## Current Status: 68 Components (Alpha) 🎉

**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`)
- ✅ **100 Components** with Tailwind v4.1.18 *(actual components only; *-variants, *-service auto-installed)*
- ✅ **68 Installable Components** with Tailwind v4.1.18 *(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**
Expand Down Expand Up @@ -96,7 +96,7 @@ To update ShellUI version across all components:

This single file change updates:
- ✅ All NuGet packages (`ShellUI.CLI`, `ShellUI.Components`)
- ✅ All component templates (~100 installable components)
- ✅ All component templates (68 installable components)
- ✅ Build configurations and metadata

**Example for pre-release:**
Expand All @@ -116,25 +116,30 @@ Results in version: `0.3.0-alpha.2`

**For Advanced Users:** Future versions may support component-specific versioning for power users who need granular control.

### ✅ 100 Production-Ready Components
### ✅ 68 Production-Ready Components

**Form Components (14):**
Button, Input, Textarea, Select, Checkbox, RadioGroup, RadioGroupItem, Switch, Toggle, Label, Slider, Form, InputOTP
Counts below are top-level components you can `shellui add` directly. Sub-components (e.g. `SidebarTrigger`, `DialogContent`, `TableRow`), variants (`ButtonVariants`, `AlertVariants`, …), models, and services auto-install as dependencies and are not counted.

**Layout Components (15):**
Card, Dialog, Sheet, Drawer, Popover, Tooltip, Separator, ScrollArea, Resizable, Collapsible, Accordion, Breadcrumb, BreadcrumbItem, Sonner, Toast
**Form (17):**
Button, Checkbox, Combobox, DatePicker, DateRangePicker, FileUpload, Form, Input, InputOTP, Label, RadioGroup, Select, Slider, Switch, Textarea, TimePicker, Toggle

**Navigation Components (12):**
Navbar, Sidebar, NavigationMenu, NavigationMenuItem, Menubar, MenubarItem, Pagination, Tabs, Stepper
**Layout (12):**
Accordion, Breadcrumb, Card, Collapsible, DashboardLayout01, DashboardLayout02, LinkCard, Navbar, Resizable, ScrollArea, Separator, Sidebar

**Data Display (14):**
Table, TableHeader, TableBody, TableRow, TableHead, TableCell, DataTable, Badge, Avatar, Alert, Toast, Sonner, Skeleton, Progress, Loading
**Navigation (7):**
ContextMenu, Menubar, NavigationMenu, Pagination, PrevNextNav, Stepper, Tabs

**Interactive Components (8):**
Dropdown, Command, ContextMenu, HoverCard, ThemeToggle, EmptyState, FileUpload
**Overlay (8):**
AlertDialog, Command, Dialog, Drawer, Dropdown, HoverCard, Popover, Sheet

**Advanced Components (18):**
Calendar, DatePicker, DateRangePicker, TimePicker, Combobox, AlertDialog, Carousel, Charts (Chart, BarChart, LineChart, PieChart, AreaChart, MultiSeriesChart), CarouselItem, CarouselContent, CarouselPrevious, CarouselNext, CarouselDots
**Data Display (13):**
AreaChart, Avatar, Badge, BarChart, Calendar, Carousel, Chart, ChartSeries, DataTable, LineChart, MultiSeriesChart, PieChart, Table

**Feedback (9):**
Alert, Callout, EmptyState, Loading, Progress, Skeleton, Sonner, Toast, Tooltip

**Utility (2):**
CopyButton, ThemeToggle

### ✅ Tailwind CSS v4.1.18 Integration

Expand Down Expand Up @@ -252,7 +257,7 @@ shellui init
shellui add button input card dialog
# Or: dotnet shellui add button input card dialog

shellui list # See all 100 available components
shellui list # See all 68 available components
# Or: dotnet shellui list
```

Expand Down Expand Up @@ -294,7 +299,7 @@ Simply edit the component file in `Components/UI/` - it's yours to modify!
| Hybrid Workflow | ✅ | ❌ | ❌ | ❌ |
| Free & Open Source | ✅ | ✅ | Partial | ✅ |
| Customization | Full | Limited | Limited | Limited |
| Components | 100+ | 70+ | 50+ | 80+ |
| Components | 68 | 70+ | 50+ | 80+ |
| Current Status | Production Ready | Mature | Commercial | Mature |

## 📦 Package Overview
Expand Down Expand Up @@ -606,7 +611,7 @@ MIT License - See LICENSE.txt for details

## Status

**Alpha:** 100 components, CLI + NuGet, Tailwind v4.1.18. Test before stable.
**Alpha:** 68 components, CLI + NuGet, Tailwind v4.1.18. Test before stable.
**🚀 Ready to use today!**

---
Expand Down
1 change: 1 addition & 0 deletions ShellUI.Tests/ShellUI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
Expand Down
154 changes: 154 additions & 0 deletions ShellUI.Tests/TemplateCompileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using ShellUI.Templates;
using Xunit;

namespace ShellUI.Tests;

/// Verifies that the *generated* content of each template parses as valid C#.
/// For pure-.cs templates (variants), parse the whole content.
/// For .razor templates, extract the @code { ... } block and parse its body.
/// This catches the exact class of bug from shellui-fixes-for-lib.md (Fixes 2, 9, 10):
/// unescaped quotes inside C# verbatim strings that ship as compile errors to consumers.
public class TemplateCompileTests
{
[Theory]
[InlineData("chart-variants")]
[InlineData("alert-variants")]
[InlineData("badge-variants")]
[InlineData("button-variants")]
public void CsharpTemplate_GeneratedContentParses(string componentName)
{
var content = ComponentRegistry.GetComponentContent(componentName);
Assert.False(string.IsNullOrWhiteSpace(content), $"{componentName} template has no content");

var tree = CSharpSyntaxTree.ParseText(content!);
var errors = tree.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
.ToList();

Assert.True(errors.Count == 0,
$"{componentName} generated content has {errors.Count} parse error(s):\n" +
string.Join("\n", errors.Select(e => $" {e.Location.GetLineSpan().StartLinePosition}: {e.GetMessage()}")));
}

[Theory]
[InlineData("pie-chart")]
[InlineData("dashboard-02")]
[InlineData("button")]
[InlineData("dialog")]
public void RazorTemplate_CodeBlockParses(string componentName)
{
var content = ComponentRegistry.GetComponentContent(componentName);
Assert.False(string.IsNullOrWhiteSpace(content), $"{componentName} template has no content");

var codeBlock = ExtractCodeBlock(content!);
if (string.IsNullOrWhiteSpace(codeBlock))
{
// Brace extraction failed — almost always because an unterminated string
// swallowed the closing brace. Surface a real diagnostic by parsing the
// raw @code-onward suffix as if it were C#; the line/column points at
// the actual offending escape.
var raw = StripRazorDirectives(content!);
var rawTree = CSharpSyntaxTree.ParseText($"class __Probe {{ {raw} }}");
var rawErrors = rawTree.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
// The only diagnostics that matter for this bug class are unterminated literals.
.Where(d => d.Id is "CS1010" or "CS1002" or "CS1003" or "CS1026" or "CS1513" or "CS1525" or "CS1056")
.Take(5)
.ToList();
Assert.Fail(
$"{componentName} @code block could not be extracted — likely an unterminated " +
$"string literal in the template. Diagnostics:\n" +
string.Join("\n", rawErrors.Select(e => $" {e.Id} at {e.Location.GetLineSpan().StartLinePosition}: {e.GetMessage()}")));
}

// Wrap in a synthetic class so the code block parses standalone.
var wrapped = $"class __Probe {{ {codeBlock} }}";
var tree = CSharpSyntaxTree.ParseText(wrapped);
var errors = tree.GetDiagnostics()
.Where(d => d.Severity == DiagnosticSeverity.Error)
.ToList();

Assert.True(errors.Count == 0,
$"{componentName} @code block has {errors.Count} parse error(s):\n" +
string.Join("\n", errors.Select(e => $" {e.Location.GetLineSpan().StartLinePosition}: {e.GetMessage()}")));
}

/// 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.
private static string StripRazorDirectives(string razor)
{
// Drop everything before the first @code keyword if present, else return as-is.
var codeIdx = razor.IndexOf("@code", System.StringComparison.Ordinal);
return codeIdx >= 0 ? razor.Substring(codeIdx + 5) : razor;
}

/// Extracts the body of the first `@code { ... }` block, balancing braces.
/// Returns null if no `@code` block is found.
private static string? ExtractCodeBlock(string razor)
{
var match = Regex.Match(razor, @"@code\s*\{");
if (!match.Success) return null;

var start = match.Index + match.Length;
var depth = 1;
var inString = false;
var inVerbatimString = false;
var inCharLiteral = false;
var inLineComment = false;
var inBlockComment = false;

for (var i = start; i < razor.Length; i++)
{
var c = razor[i];
var next = i + 1 < razor.Length ? razor[i + 1] : '\0';

if (inLineComment)
{
if (c == '\n') inLineComment = false;
continue;
}
if (inBlockComment)
{
if (c == '*' && next == '/') { inBlockComment = false; i++; }
continue;
}
if (inVerbatimString)
{
if (c == '"' && next == '"') { i++; continue; } // escaped ""
if (c == '"') inVerbatimString = false;
continue;
}
if (inString)
{
if (c == '\\' && next != '\0') { i++; continue; }
if (c == '"') inString = false;
continue;
}
if (inCharLiteral)
{
if (c == '\\' && next != '\0') { i++; continue; }
if (c == '\'') inCharLiteral = false;
continue;
}

if (c == '/' && next == '/') { inLineComment = true; i++; continue; }
if (c == '/' && next == '*') { inBlockComment = true; i++; continue; }
if (c == '@' && next == '"') { inVerbatimString = true; i++; continue; }
if (c == '"') { inString = true; continue; }
if (c == '\'') { inCharLiteral = true; continue; }

if (c == '{') depth++;
else if (c == '}')
{
depth--;
if (depth == 0) return razor.Substring(start, i - start);
}
}
return null;
}
}
6 changes: 3 additions & 3 deletions VERSIONING_STRATEGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ ShellUI follows a **unified versioning approach** where all components, CLI, and

## Version Number: v0.3.0-alpha.2 ✅

**Current Release:** v0.3.0-alpha.2
- ✅ 100 production-ready components
**Current Release:** v0.3.0-alpha.3
- ✅ 68 installable production-ready components
- ✅ CLI tool + NuGet packages
- ✅ Full Blazor WebAssembly + Server support
- ✅ Tailwind CSS v4.1.17 integration
Expand All @@ -25,7 +25,7 @@ ShellUI follows a **unified versioning approach** where all components, CLI, and

**Automatically Applied To:**
- ✅ All NuGet packages (`ShellUI.CLI`, `ShellUI.Components`, `ShellUI.Core`)
- ✅ All ~100 component templates
- ✅ All 68 installable component templates (167 templates total including dependencies)
- ✅ Build configurations
- ✅ Component metadata

Expand Down
27 changes: 13 additions & 14 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ShellUI is a CLI-first Blazor component library that copies components directly
- ComponentInstaller (add, update – resolves dependencies, writes files)
- ComponentManager (list, remove)

**ShellUI.Templates** (embedded in CLI) provides ComponentRegistry with 139 templates. `GetComponentContent(name)` returns Razor/C# source.
**ShellUI.Templates** (embedded in CLI) provides ComponentRegistry with 167 templates total (68 installable top-level components + sub-components, variants, models, services that auto-install as dependencies). `GetComponentContent(name)` returns Razor/C# source.

**Packages:** ShellUI.Core (models/config), ShellUI.Components (NuGet – components, variants, services, theme CSS).

Expand All @@ -30,19 +30,18 @@ ShellUI is a CLI-first Blazor component library that copies components directly

## Component Counts (Actual Components Only)

When you run `shellui add button`, that counts as **1 component**. Dependencies (button-variants, etc.) are auto-installed and **not** counted.

| Category | Installable | Description |
|----------|-------------|-------------|
| Form | 14 | Button, Input, Select, Checkbox, Switch, etc. |
| Layout | 15 | Card, Dialog, Sheet, Drawer, Popover, etc. |
| Navigation | 12 | Navbar, Sidebar, Tabs, Breadcrumb, etc. |
| Data Display | 14 | Table, Badge, Avatar, Alert, Toast, Sonner, etc. |
| Feedback | 8 | Toast, Sonner, Loading, Skeleton, Progress, etc. |
| Overlay | 10 | Dialog, Sheet, Drawer, Tooltip, Popover, etc. |
| Charts | 9 | Chart, BarChart, LineChart, PieChart, etc. |
| Utility | 18 | ThemeToggle, CopyButton, ScrollArea, etc. |
| **Total** | **~100** | *Actual components only; *-variants, *-service excluded* |
When you run `shellui add button`, that counts as **1 component**. Dependencies (button-variants, etc.) are auto-installed and **not** counted. Counts derived from `ComponentRegistry` where `IsAvailable = true`.

| Category | Installable | Examples |
|----------|-------------|----------|
| Form | 17 | Button, Input, Select, Checkbox, Switch, Combobox, DatePicker, … |
| Layout | 12 | Card, Sidebar, Navbar, Accordion, Resizable, DashboardLayout01/02, … |
| Navigation | 7 | Tabs, Menubar, NavigationMenu, Pagination, Stepper, … |
| Overlay | 8 | Dialog, Sheet, Drawer, Popover, Dropdown, Command, … |
| Data Display | 13 | Table, DataTable, Badge, Avatar, Calendar, Carousel, Chart family, … |
| Feedback | 9 | Alert, Callout, Toast, Sonner, Loading, Progress, Tooltip, … |
| Utility | 2 | CopyButton, ThemeToggle |
| **Total** | **68** | *Top-level components only; sub-components, variants, models, services excluded* |

## Project Structure

Expand Down
2 changes: 1 addition & 1 deletion docs/CLI_SYNTAX.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Examples:
dotnet shellui list --json
```

**Output:** A table with columns: Component, Status (installed/available), Version, Category, Description. Run `dotnet shellui list` to see all ~100 available components.
**Output:** A table with columns: Component, Status (installed/available), Version, Category, Description. Run `dotnet shellui list` to see all 68 installable components.

## update - Update Components

Expand Down
2 changes: 1 addition & 1 deletion docs/COMPARISON.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A comprehensive comparison of ShellUI with other popular Blazor component librar
| **Distribution** | CLI (Copy) | NuGet | NuGet | NuGet | NuGet | NuGet |
| **Customization** | Full Source | Limited | Limited | Limited | Limited | Limited |
| **CSS Framework** | Tailwind v4 | Custom | Bootstrap | Bootstrap/Custom | Ant Design | Custom |
| **Component Count** | 100+ | 50+ | 90+ | 80+ | 60+ | 60+ |
| **Component Count** | 68 | 50+ | 90+ | 80+ | 60+ | 60+ |
| **Open Source** | Yes (MIT) | Yes (MIT) | Partial | Yes (MIT) | Yes (MIT) | Yes (MIT) |
| **Commercial License** | Free | Free | Paid Plans | Free | Free | Free |
| **Dark Mode** | Built-in | Built-in | Built-in | Built-in | Built-in | Built-in |
Expand Down
Loading
Loading