diff --git a/Directory.Build.props b/Directory.Build.props index d87b4bc..03e8e89 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ - 0.3.5 + 0.3.6 @@ -24,5 +24,10 @@ blazor;ui;components;tailwindcss;shadcn https://github.com/shellui-dev/shellui git + icon.png + + + + \ No newline at end of file diff --git a/README.md b/README.md index bf0c27a..c609f1f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ | Channel | Version | Notes | |---|---|---| -| Latest stable (recommended) | `0.3.5` | Tailwind CSS `4.3.2` | +| Latest stable (recommended) | `0.3.6` | Tailwind CSS `4.3.2` | | Previous stable | `0.2.1` | Superseded by `0.3.0` | 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. diff --git a/ShellUI.Tests/SafelistDriftTests.cs b/ShellUI.Tests/SafelistDriftTests.cs index 3f3ae50..f55f69c 100644 --- a/ShellUI.Tests/SafelistDriftTests.cs +++ b/ShellUI.Tests/SafelistDriftTests.cs @@ -39,6 +39,28 @@ public void Safelist_MatchesGeneratedFromCurrentSources() BuildDiffMessage(addedSinceCommit, removedSinceCommit)); } + [Fact] + public void Generator_HarvestsClassesInRazorExpressions() + { + var file = Path.Combine(Path.GetTempPath(), $"safelist-{Guid.NewGuid():N}.razor"); + File.WriteAllLines(file, new[] + { + "
", + "", + "@code { string Tone(string v) => v switch { \"ok\" => \"bg-green-500/20\", _ => \"bg-background\" }; }", + }); + try + { + var classes = Program.GenerateSafelist(new[] { file }); + foreach (var expected in new[] { "translate-y-[-50%]", "sm:rounded-lg", "text-destructive", "text-muted-foreground", "bg-green-500/20", "bg-background" }) + Assert.Contains(expected, classes); + } + finally + { + File.Delete(file); + } + } + [Fact] public void GeneratedTargetsFile_IsValidXml() { diff --git a/VERSIONING_STRATEGY.md b/VERSIONING_STRATEGY.md index e24b6c8..f1cdc40 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.5` | +| Version | `0.3.6` | | Target framework | .NET 10 | | Tailwind version | `4.3.2` | @@ -18,15 +18,15 @@ The root `Directory.Build.props` supplies the version: ```xml - 0.3.5 + 0.3.6 ``` `Directory.Build.props` composes the package and assembly metadata: -- `Version` is `0.3.5`; with a suffix such as `rc.1` it becomes `0.3.5-rc.1`. -- `AssemblyVersion` and `FileVersion` use the numeric base `0.3.5`. +- `Version` is `0.3.6`; with a suffix such as `rc.1` it becomes `0.3.6-rc.1`. +- `AssemblyVersion` and `FileVersion` use the numeric base `0.3.6`. - `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.5", + "Version": "0.3.6", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..322ff62 Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/icon.svg b/assets/icon.svg new file mode 100644 index 0000000..dae45b4 --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1 @@ + diff --git a/docs/CLI_INSTALLATION.md b/docs/CLI_INSTALLATION.md index 777cfc2..4768cac 100644 --- a/docs/CLI_INSTALLATION.md +++ b/docs/CLI_INSTALLATION.md @@ -4,7 +4,7 @@ | Context | Version | |---|---| -| Latest stable (recommended) | `0.3.5`, needs the .NET 10 runtime | +| Latest stable (recommended) | `0.3.6`, needs the .NET 10 runtime | | Previous stable | `0.2.1` | | Tailwind | `4.3.2` | @@ -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.5", + "version": "0.3.6", "commands": ["shellui"] } } diff --git a/docs/CLI_SYNTAX.md b/docs/CLI_SYNTAX.md index 6942145..64f4507 100644 --- a/docs/CLI_SYNTAX.md +++ b/docs/CLI_SYNTAX.md @@ -1,6 +1,6 @@ # ShellUI CLI Syntax -This reference covers CLI `0.3.5`: it runs on .NET 10, sets up Blazor projects on .NET 8, 9 and 10, uses Tailwind CSS `4.3.2`, and has 76 direct component targets. Older versions, such as `0.2.1`, lack some of these commands. +This reference covers CLI `0.3.6`: it runs on .NET 10, sets up Blazor projects on .NET 8, 9 and 10, uses Tailwind CSS `4.3.2`, and has 76 direct component targets. Older versions, such as `0.2.1`, lack some of these commands. ## Command prefix @@ -213,7 +213,7 @@ Representative fields look like this: "InstalledComponents": [ { "Name": "button", - "Version": "0.3.5", + "Version": "0.3.6", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } diff --git a/docs/FAQ.md b/docs/FAQ.md index 2ef4216..b03df97 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -6,7 +6,7 @@ Answers for the current ShellUI source and the currently published packages. ### Which version should I use? -Use `0.3.5`. It uses Tailwind CSS `4.3.2` and has 76 direct component targets: +Use `0.3.6`. It uses Tailwind CSS `4.3.2` and has 76 direct component targets: ```bash dotnet tool install -g ShellUI.CLI @@ -145,7 +145,7 @@ A representative Tailwind and component record is: "InstalledComponents": [ { "Name": "button", - "Version": "0.3.5", + "Version": "0.3.6", "InstalledAt": "2026-01-01T00:00:00Z", "IsCustomized": false } diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 42af6db..05b4b7d 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -1,6 +1,6 @@ # ShellUI Quick Start -This quick start uses ShellUI `0.3.5`: Tailwind CSS `4.3.2` and 76 direct component targets. The CLI needs the .NET 10 SDK and works in Blazor projects on .NET 8, 9 and 10. +This quick start uses ShellUI `0.3.6`: Tailwind CSS `4.3.2` and 76 direct component targets. The CLI needs the .NET 10 SDK and works in Blazor projects on .NET 8, 9 and 10. ## Prerequisites diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index eb8ae65..074fa31 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -1,5 +1,33 @@ # ShellUI Release Notes +# ShellUI v0.3.6 + +> A small patch: both packages now show the ShellUI logo on nuget.org, and the `ShellUI.Components` safelist includes the classes it was missing. + +## 🐛 Fixes + +- **Safelist:** `shellui-classes.txt`, which apps building their own Tailwind CSS from the package use, was missing 181 classes the components render: every class passed to `Shell.Cn("...")` inside a `class` attribute, plus those in conditional expressions. Among them were the dialog's centring (`translate-x-[-50%]`, `translate-y-[-50%]`), `sm:rounded-lg` and the Sonner variant colours, so in those apps dialogs weren't centred. The precompiled `shellui-all.css` wasn't affected. +- **Package icon:** `ShellUI.CLI` and `ShellUI.Components` showed nuget.org's default icon. They now use the ShellUI logo. + +## ⬆️ Upgrading + +- **NuGet package:** update `ShellUI.Components` to `0.3.6`. If you build your own Tailwind CSS from `shellui-classes.txt`, rebuild it afterwards. +- **CLI:** update the tool to `0.3.6`. Nothing changes in projects it set up. + +## 📦 Installation + +```bash +dotnet tool install -g ShellUI.CLI --version 0.3.6 +# or upgrade an existing install +dotnet tool update -g ShellUI.CLI --version 0.3.6 +``` + +```bash +dotnet add package ShellUI.Components --version 0.3.6 +``` + +**Full Changelog**: https://github.com/shellui-dev/shellui/compare/v0.3.5...v0.3.6 + # ShellUI v0.3.5 > A patch release that brings the 0.4 prerelease fixes to the stable line. `init` no longer downloads the Tailwind CLI into every project, `update` keeps your changes, `add` never downgrades a NuGet package, a component's `Class` overrides its own classes, overlays keep keyboard focus inside, and several component bugs are fixed. It also adds Razor class library support. diff --git a/src/ShellUI.CLI/README.md b/src/ShellUI.CLI/README.md index 15ab087..1424702 100644 --- a/src/ShellUI.CLI/README.md +++ b/src/ShellUI.CLI/README.md @@ -68,10 +68,10 @@ dotnet watch ## Documentation -- [README](https://github.com/shellui-dev/shellui/blob/v0.3.5/README.md) -- [CLI reference](https://github.com/shellui-dev/shellui/blob/v0.3.5/docs/CLI_SYNTAX.md) -- [Release notes](https://github.com/shellui-dev/shellui/blob/v0.3.5/docs/RELEASE_NOTES.md) +- [README](https://github.com/shellui-dev/shellui/blob/v0.3.6/README.md) +- [CLI reference](https://github.com/shellui-dev/shellui/blob/v0.3.6/docs/CLI_SYNTAX.md) +- [Release notes](https://github.com/shellui-dev/shellui/blob/v0.3.6/docs/RELEASE_NOTES.md) ## License -[MIT](https://github.com/shellui-dev/shellui/blob/v0.3.5/LICENSE.txt) +[MIT](https://github.com/shellui-dev/shellui/blob/v0.3.6/LICENSE.txt) diff --git a/src/ShellUI.Components/README.md b/src/ShellUI.Components/README.md index 899f0eb..497bb34 100644 --- a/src/ShellUI.Components/README.md +++ b/src/ShellUI.Components/README.md @@ -77,10 +77,10 @@ shellui theme apply https://tweakcn.com/themes/THEME_ID --emit-override wwwroot/ ## Documentation -- [README](https://github.com/shellui-dev/shellui/blob/v0.3.5/README.md) -- [Tailwind setup](https://github.com/shellui-dev/shellui/blob/v0.3.5/docs/tailwind-setup.md) -- [Release notes](https://github.com/shellui-dev/shellui/blob/v0.3.5/docs/RELEASE_NOTES.md) +- [README](https://github.com/shellui-dev/shellui/blob/v0.3.6/README.md) +- [Tailwind setup](https://github.com/shellui-dev/shellui/blob/v0.3.6/docs/tailwind-setup.md) +- [Release notes](https://github.com/shellui-dev/shellui/blob/v0.3.6/docs/RELEASE_NOTES.md) ## License -[MIT](https://github.com/shellui-dev/shellui/blob/v0.3.5/LICENSE.txt) +[MIT](https://github.com/shellui-dev/shellui/blob/v0.3.6/LICENSE.txt) diff --git a/src/ShellUI.Components/build/ShellUI.Components.targets b/src/ShellUI.Components/build/ShellUI.Components.targets index 4552cf9..05668ce 100644 --- a/src/ShellUI.Components/build/ShellUI.Components.targets +++ b/src/ShellUI.Components/build/ShellUI.Components.targets @@ -1,62 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -64,12 +112,22 @@ + + + + + + + + + + @@ -99,14 +157,21 @@ + + + + + + + @@ -120,19 +185,36 @@ + + + + + + + + + + + + + + + + + @@ -146,11 +228,15 @@ + + + + @@ -158,16 +244,21 @@ + + + + + @@ -181,29 +272,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -212,11 +328,14 @@ + + + @@ -231,27 +350,38 @@ + + + + + + + + + + + @@ -263,6 +393,7 @@ + @@ -270,12 +401,21 @@ + + + + + + + + + @@ -297,25 +437,39 @@ + + + + + + + + + + + + + + @@ -324,6 +478,7 @@ + @@ -331,42 +486,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ShellUI.Components/icon.svg b/src/ShellUI.Components/icon.svg deleted file mode 100644 index 19e1eaf..0000000 --- a/src/ShellUI.Components/icon.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/ShellUI.Components/wwwroot/shellui-classes.txt b/src/ShellUI.Components/wwwroot/shellui-classes.txt index a610327..b557c9c 100644 --- a/src/ShellUI.Components/wwwroot/shellui-classes.txt +++ b/src/ShellUI.Components/wwwroot/shellui-classes.txt @@ -1,59 +1,107 @@ +active:scale-[0.98] +after:-inset-2 +after:absolute +after:md:hidden align-middle +animate-bounce animate-in animate-pulse animate-spin appearance-none aspect-square +backdrop-blur backdrop-blur-md backdrop-blur-sm +bars-pulse +bars-vertical bg-accent +bg-accent/30 +bg-accent/50 bg-background bg-background/80 bg-background/95 bg-black/80 bg-blue-500 +bg-blue-500/20 bg-border bg-card bg-destructive +bg-green-50 bg-green-500 +bg-green-500/20 +bg-input bg-muted bg-muted/30 bg-popover bg-primary +bg-primary/10 bg-secondary bg-sidebar +bg-sidebar-accent +bg-sidebar-border bg-sidebar-primary bg-transparent bg-yellow-500 +bg-yellow-500/20 border-0 border-2 +border-4 border-b border-border border-border/40 +border-dashed border-destructive +border-green-500 border-input border-l +border-muted +border-primary border-primary/20 border-r +border-r-primary/50 +border-ring +border-sidebar-border border-t +border-t-primary border-transparent bottom-0 bottom-4 bottom-full +bottom-left +bottom-right +break-words caption-bottom cursor-default +cursor-not-allowed cursor-pointer +dark:bg-blue-900/30 +dark:bg-green-900/20 +dark:bg-green-900/30 +dark:bg-yellow-900/30 +dark:text-blue-100 +dark:text-green-100 +dark:text-yellow-100 +data-[disabled]:opacity-50 +data-[disabled]:pointer-events-none data-[selected]:bg-accent data-[selected]:text-accent-foreground data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=closed]:fade-out-0 +data-[state=closed]:slide-out-to-left-1/2 +data-[state=closed]:slide-out-to-top-[48%] +data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:bg-accent data-[state=open]:duration-500 data-[state=open]:fade-in-0 data-[state=open]:grid-rows-[1fr] +data-[state=open]:opacity-100 +data-[state=open]:slide-in-from-left-1/2 +data-[state=open]:slide-in-from-top-[48%] data-[state=open]:text-muted-foreground +data-[state=open]:zoom-in-95 +data-[state=selected]:bg-muted disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none @@ -61,12 +109,22 @@ duration-200 duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ease-in-out +ease-linear fa-bell +fa-book +fa-bullhorn fa-chevron-right fa-circle-check fa-circle-plus +fa-code fa-credit-card fa-ellipsis +fa-gear +fa-life-ring +fa-location-dot +fa-microchip +fa-paper-plane +fa-pen-ruler fa-right-from-bracket fa-solid fa-sort @@ -96,14 +154,21 @@ focus-visible:ring-1 focus-visible:ring-2 focus-visible:ring-destructive focus-visible:ring-offset-2 +focus-visible:ring-offset-background focus-visible:ring-ring +focus-within:ring-2 +focus-within:ring-offset-2 +focus-within:ring-ring focus:bg-accent +focus:bg-primary +focus:border-ring focus:outline-none focus:ring-1 focus:ring-2 focus:ring-offset-2 focus:ring-ring focus:text-accent-foreground +focus:text-primary-foreground font-bold font-medium font-mono @@ -117,19 +182,36 @@ gap-2 gap-3 gap-4 grid-cols-2 +grid-cols-3 grid-cols-7 grid-rows-[0fr] +group-content +group-data-[collapsible=icon]:!bg-sidebar-primary 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]:-mt-8 group-data-[collapsible=icon]:hidden +group-data-[collapsible=icon]:opacity-0 +group-data-[collapsible=icon]:overflow-hidden +group-data-[collapsible=icon]:text-sidebar-primary-foreground +group-data-[collapsible=offcanvas]:after:left-full +group-data-[collapsible=offcanvas]:hover:bg-sidebar +group-data-[collapsible=offcanvas]:translate-x-0 +group-data-[side=right]:group-data-[collapsible=offcanvas]:-translate-x-full group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:shadow +group-focus-within/menu-item:opacity-100 +group-hover/menu-item:opacity-100 +group-label +group/menu-item +group/sidebar-wrapper +h-1.5 h-1/2 h-10 h-11 @@ -143,11 +225,15 @@ h-3 h-3.5 h-4 h-5 +h-6 h-7 h-8 h-9 +h-[1px] h-full h-px +h-svh +has-[[data-variant=inset]]:bg-sidebar hover:bg-accent hover:bg-accent/50 hover:bg-blue-600 @@ -155,16 +241,21 @@ hover:bg-destructive/80 hover:bg-destructive/90 hover:bg-green-600 hover:bg-muted +hover:bg-muted/50 +hover:bg-primary hover:bg-primary/80 hover:bg-primary/90 hover:bg-secondary/80 hover:bg-sidebar-accent hover:bg-yellow-600 +hover:border-border +hover:border-primary/50 hover:opacity-100 hover:text-accent-foreground hover:text-destructive hover:text-foreground hover:text-muted-foreground +hover:text-primary-foreground hover:text-sidebar-accent-foreground hover:underline inline-block @@ -178,29 +269,54 @@ items-start justify-between justify-center justify-end +last:border-b-0 leading-none leading-tight left-0 left-1/2 left-2 +left-[50%] +left-full lg:space-x-8 list-none max-h-60 max-h-[300px] +max-h-screen +max-w-lg +max-w-max max-w-sm mb-1 mb-2 mb-4 mb-6 md:block +md:flex +md:max-w-[420px] +md:opacity-0 +md:peer-data-[variant=inset]:m-2 +md:peer-data-[variant=inset]:ml-0 +md:peer-data-[variant=inset]:rounded-xl +md:peer-data-[variant=inset]:shadow +menu-action +menu-badge +menu-button +menu-item +menu-sub +menu-sub-button +menu-sub-item min-h-0 +min-h-10 min-h-8 min-h-[80px] +min-h-svh min-w-0 min-w-24 +min-w-5 min-w-8 min-w-[640px] min-w-[8rem] +ml-1 +ml-2 ml-3 ml-auto motion-reduce:animate-none @@ -209,11 +325,14 @@ mr-2 mr-3 mt-0.5 mt-1 +mt-10 mt-2 mt-4 mt-6 mt-8 mt-auto +mx-2 +mx-3.5 mx-auto my-1 object-cover @@ -228,27 +347,38 @@ overflow-auto overflow-hidden overflow-x-auto overflow-y-auto +p-0 p-0.5 p-1 p-2 p-3 p-4 p-6 +p-8 p-[3px] pb-4 +peer-data-[active=true]/menu-button:text-sidebar-accent-foreground +peer-data-[variant=inset]:min-h-[calc(100svh-1rem)] peer-disabled:cursor-not-allowed peer-disabled:opacity-70 +peer-hover/menu-button:text-sidebar-accent-foreground peer/menu-button pl-2 +pl-2.5 +pl-3 pl-4 +pl-8 placeholder:text-muted-foreground pointer-events-auto pointer-events-none pr-2 +pr-2.5 pr-3 pr-6 pr-8 +pr-9 pt-0 +pt-6 px-1 px-1.5 px-2 @@ -260,6 +390,7 @@ px-8 py-0.5 py-1 py-1.5 +py-12 py-2 py-4 py-6 @@ -267,12 +398,21 @@ right-0 right-1 right-2 right-4 +right-full +ring-0 +ring-2 +ring-offset-2 ring-offset-background +ring-primary/20 +ring-ring ring-sidebar-ring +rotate-180 +rotate-90 rounded-full rounded-lg rounded-md rounded-sm +scale-[1.02] select-none shadow-lg shadow-md @@ -294,25 +434,39 @@ slide-in-from-left slide-in-from-right slide-in-from-top slide-in-from-top-2 +sm:flex-col sm:flex-row +sm:gap-2.5 sm:items-center sm:justify-between +sm:justify-end sm:max-w-sm +sm:rounded-lg +sm:space-x-2 sm:space-x-6 sm:text-left space-x-1 space-x-2 +space-x-4 +space-y-1.5 space-y-2 space-y-4 +space-y-6 sr-only +supports-[backdrop-filter]:bg-background/60 +tabular-nums +text-2xl text-[10px] text-[8px] text-accent-foreground +text-blue-700 text-card-foreground text-center text-destructive-foreground text-foreground text-foreground/70 +text-green-700 +text-green-900 text-left text-lg text-muted-foreground @@ -321,6 +475,7 @@ text-primary text-primary-foreground text-right text-secondary-foreground +text-sidebar-accent-foreground text-sidebar-foreground text-sidebar-foreground/70 text-sidebar-primary-foreground @@ -328,42 +483,68 @@ text-sm text-white text-xl text-xs +text-yellow-800 top-0 top-2 top-4 top-8 +top-[1px] +top-[50%] top-full +top-right +touch-none tracking-tight transition-[grid-template-rows] +transition-[left,right,width] transition-[width,height,padding] +transition-[width] transition-all transition-colors transition-opacity transition-transform +translate-x-0 +translate-x-5 +translate-x-[-50%] +translate-x-px +translate-y-[-50%] underline-offset-4 var(--border var(--muted +var(--sidebar-width +var(--sidebar-width-icon +w-1 +w-1.5 w-1/2 w-10 +w-11 w-12 w-16 +w-2 w-2.5 +w-20 +w-24 w-3 w-3.5 w-3/4 w-4 w-5 w-56 +w-6 w-64 w-7 +w-72 w-8 w-9 w-[100px] +w-[1px] w-[70px] +w-auto w-fit w-full w-max whitespace-nowrap +width: +z-10 z-40 z-50 zoom-in-95 diff --git a/src/ShellUI.Core/Models/ComponentMetadata.cs b/src/ShellUI.Core/Models/ComponentMetadata.cs index 38f0d4a..1be9bb8 100644 --- a/src/ShellUI.Core/Models/ComponentMetadata.cs +++ b/src/ShellUI.Core/Models/ComponentMetadata.cs @@ -66,7 +66,7 @@ private static string GetCurrentVersion() if (assemblyVersion != null) return assemblyVersion.InformationalVersion.Split('+')[0]; - return "0.3.5"; + return "0.3.6"; } } diff --git a/src/ShellUI.Templates/VersionHelper.cs b/src/ShellUI.Templates/VersionHelper.cs index 52e14d2..4cebe3d 100644 --- a/src/ShellUI.Templates/VersionHelper.cs +++ b/src/ShellUI.Templates/VersionHelper.cs @@ -51,7 +51,7 @@ public static string GetCurrentVersion() return _cachedVersion; } - return "0.3.5"; + return "0.3.6"; } private static string? FindSolutionRoot() diff --git a/tools/ShellUI.SafelistGenerator/Program.cs b/tools/ShellUI.SafelistGenerator/Program.cs index 1ad88ea..c19d33c 100644 --- a/tools/ShellUI.SafelistGenerator/Program.cs +++ b/tools/ShellUI.SafelistGenerator/Program.cs @@ -64,6 +64,7 @@ public static SortedSet GenerateSafelist(IEnumerable sourceFileP if (file.EndsWith(".razor", StringComparison.OrdinalIgnoreCase)) { ExtractClasses(text, classes); + ExtractFromRazorExpressions(text, classes); } else if (file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) { @@ -86,7 +87,7 @@ private static void ExtractFromCSharp(string content, SortedSet sink) private static bool LooksLikeClassList(string s) { - if (s.Length == 0 || s.Length > 500) return false; + if (s.Length == 0 || s.Length > 2000) return false; // `=` outside `[…]` implies key=value pairs, not class strings. if (s.Contains("://") || s.Contains('<') || s.Contains('>') || s.Contains('{') || s.Contains(';') || s.Contains('=') && !s.Contains('[') @@ -151,6 +152,20 @@ private static string XmlEscape(string s) "class\\s*=\\s*\"(?[^\"]*)\"", RegexOptions.Compiled); + // Shell.Cn arguments, ternaries and switch arms, which the class attribute regex cuts off at their first quote. + private static readonly Regex RazorExpressionLiteralRegex = new( + "(?<=[(,?:=>]\\s*)\"(?[^\"@]*)\"", + RegexOptions.Compiled); + + private static void ExtractFromRazorExpressions(string content, SortedSet sink) + { + foreach (Match lit in RazorExpressionLiteralRegex.Matches(content)) + { + var value = lit.Groups["lit"].Value; + if (LooksLikeClassList(value)) HarvestTokens(value, sink); + } + } + private static readonly Regex StringLiteralRegex = new( "\"(?[^\"]*)\"", RegexOptions.Compiled);