From 1f35f7686515e75659d8f7b1a805f54b23337a9c Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 3 Jul 2026 22:25:22 +0200 Subject: [PATCH 1/2] feat: add `theme init` command for streamlined ShellUI setup Introduces a new `theme init` command that initializes ShellUI in a fresh Blazor project while applying a tweakcn theme in a single step. The command accepts various options for customization, including URL, style, and Tailwind method, enhancing user experience and simplifying theme integration. This addition complements existing theme management commands, providing a more comprehensive CLI interface for users. --- src/ShellUI.CLI/Program.cs | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ShellUI.CLI/Program.cs b/src/ShellUI.CLI/Program.cs index a12de1a..8ff2db9 100644 --- a/src/ShellUI.CLI/Program.cs +++ b/src/ShellUI.CLI/Program.cs @@ -28,11 +28,51 @@ static async Task Main(string[] args) static Command CreateThemeCommand() { var theme = new Command("theme", "Fetch and apply themes from tweakcn.com at build time."); + theme.AddCommand(CreateThemeInitCommand()); theme.AddCommand(CreateThemeApplyCommand()); theme.AddCommand(CreateThemeUpdateCommand()); return theme; } + static Command CreateThemeInitCommand() + { + var command = new Command("init", "Initialize ShellUI in a fresh Blazor project and bake in a tweakcn theme in one shot."); + + var urlArg = new Argument("url", + "tweakcn URL or theme id. Accepts https://tweakcn.com/themes/, the raw , or the public https://tweakcn.com/r/themes/ endpoint."); + command.AddArgument(urlArg); + + var forceOpt = new Option("--force", "Reinitialize even if already initialized"); + var styleOpt = new Option("--style", getDefaultValue: () => "default", + "Component style: default, new-york, minimal"); + var tailwindOpt = new Option("--tailwind", getDefaultValue: () => "standalone", + "Tailwind method: standalone, npm"); + var yesOpt = new Option("--yes", "Non-interactive mode with default options"); + command.AddOption(forceOpt); + command.AddOption(styleOpt); + command.AddOption(tailwindOpt); + command.AddOption(yesOpt); + + command.SetHandler(async (url, force, style, tailwind, nonInteractive) => + { + try + { + AnsiConsole.MarkupLine("[cyan]Step 1/2:[/] initializing ShellUI…"); + await InitService.InitializeAsync(style, force, tailwind, nonInteractive); + AnsiConsole.MarkupLine(""); + AnsiConsole.MarkupLine("[cyan]Step 2/2:[/] applying tweakcn theme…"); + await ApplyThemeAsync(url, emitOverride: null); + } + catch (Exception ex) + { + AnsiConsole.MarkupLine($"[red]Error:[/] {ex.Message.Replace("[", "[[").Replace("]", "]]")}"); + Environment.Exit(1); + } + }, urlArg, forceOpt, styleOpt, tailwindOpt, yesOpt); + + return command; + } + static Command CreateThemeApplyCommand() { var command = new Command("apply", "Fetch a theme from tweakcn and bake it into wwwroot/input.css"); From 92fa68565bb308f51d276184ef6efa915a3d01ab Mon Sep 17 00:00:00 2001 From: Shephard Tseisi Date: Fri, 3 Jul 2026 22:25:52 +0200 Subject: [PATCH 2/2] feat: enhance README with detailed `theme` command usage and tweakcn integration Expanded the README files to include comprehensive instructions on using the `shellui theme` commands for integrating tweakcn themes. Added examples for initializing a project with a theme, applying themes to existing projects, and generating standalone override CSS. Clarified the idempotent nature of theme application and how themes are recorded in `shellui.theme.lock`, improving user guidance on theme management. --- README.md | 47 +++++++++++++++++++++++++++----- src/ShellUI.CLI/README.md | 28 ++++++++++++++++++- src/ShellUI.Components/README.md | 42 ++++++++++++++++++++++++---- 3 files changed, 103 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ec29254..0289c9f 100644 --- a/README.md +++ b/README.md @@ -482,18 +482,51 @@ Now write raw HTML with ShellUI's Tailwind classes: --- +### Using tweakcn themes with `shellui theme` (new in 0.4.x) + +[tweakcn.com](https://tweakcn.com) is a visual theme editor for shadcn-style CSS variables. ShellUI's `theme` subcommand fetches a theme by URL and bakes it into your project at **build time** — no runtime dep, works offline, exactly-what-you-see-is-what-ships. + +```bash +# One-shot: init a fresh project AND apply a theme (Path C setup) +shellui theme init https://tweakcn.com/themes/ + +# Existing project: apply a theme to your input.css (Path B/C) +shellui theme apply https://tweakcn.com/themes/ + +# Existing project: emit standalone override CSS (Path A/D) +shellui theme apply https://tweakcn.com/themes/ --emit-override wwwroot/theme.css + +# Re-fetch the theme recorded in shellui.theme.lock +shellui theme update +``` + +Each `apply` writes a `shellui.theme.lock` file recording the source URL + SHA-256, so `shellui theme update` refreshes from the same source without you having to remember the URL. + +**How it drops into each install path:** + +| Path | Command | Where the theme lands | +|---|---|---| +| **A** — precompiled bundle | `shellui theme apply --emit-override wwwroot/theme.css`, then `` it after `shellui-all.css` | Standalone override CSS; wins the cascade over the baked bundle | +| **B** — safelist | `shellui theme apply ` | Sentinel-marked region in your `wwwroot/input.css`; user content outside markers survives re-applies | +| **C** — CLI | `shellui theme init ` (fresh) or `shellui theme apply ` (existing) | Sentinel-marked region in the `input.css` `shellui init` created; Tailwind rebuilds on `dotnet build` | +| **D** — CDN | `shellui theme apply --emit-override theme.css`, then `` it after the CDN link | Same override pattern as Path A | + +The apply is **idempotent** — re-running with the same URL produces byte-identical output. Custom utilities, `@source` directives, and imports you added around the theme block are preserved verbatim. + +--- + ### Theming across paths All four paths use the same CSS variable system, so theming works uniformly — just with different edit surfaces: -| Path | Where the theme lives | How you edit it | -|---|---|---| -| A | Baked in `shellui-all.css` | Override CSS vars in a ` + ``` **Best for:** new projects, prototypes, teams without existing Tailwind, "just get me components" scenarios. @@ -93,6 +96,13 @@ The package copies `shellui-classes.txt` (auto-generated safelist of every Tailw } ``` +Or auto-import a tweakcn theme into the `:root` / `.dark` blocks (idempotent, preserves your custom utilities and imports around it): + +```bash +dotnet tool install -g ShellUI.CLI +dotnet shellui theme apply https://tweakcn.com/themes/ +``` + ```razor @* _Imports.razor *@ @using ShellUI.Components @@ -122,6 +132,9 @@ The package copies `shellui-classes.txt` (auto-generated safelist of every Tailw dotnet tool install -g ShellUI.CLI shellui init # one-time shellui add button card dialog # any time you want more components + +# Or one-shot: init + tweakcn theme +shellui theme init https://tweakcn.com/themes/ --yes ``` `shellui init` automatically: @@ -259,12 +272,29 @@ ShellUI components work alongside Bootstrap. You can: ### 🎨 Theme Customization -**Easily customize themes with [tweakcn](https://tweakcn.com/):** +**Easiest — auto-import a [tweakcn](https://tweakcn.com/) theme with the CLI:** + +```bash +dotnet tool install -g ShellUI.CLI + +# Path B / Path C — write into wwwroot/input.css between sentinel markers +dotnet shellui theme apply https://tweakcn.com/themes/ + +# Path A — emit standalone override CSS, link AFTER shellui-all.css +dotnet shellui theme apply https://tweakcn.com/themes/ --emit-override wwwroot/theme.css + +# Refresh later from the same URL (recorded in shellui.theme.lock) +dotnet shellui theme update +``` + +Re-runs are idempotent. Your custom utilities, `@source` directives, and imports outside the sentinel block are preserved verbatim. + +**Manual alternative:** 1. Design your perfect theme on tweakcn 2. Copy the generated CSS variables 3. Paste into `wwwroot/input.css` -4. All ShellUI components update automatically! +4. All ShellUI components update automatically **Custom Fonts:** Add Google Fonts links and update `--font-*` variables in your CSS.