Document the vendored tools, the theme helpers and the auth leftovers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
483ed271e0
commit
ca060f25fb
1 file changed
+37
-11
@@ -40,22 +40,30 @@ dotnet publish decePubClient.csproj -c Release -o publish # static site lands
|
|||||||
|
|
||||||
`global.json` pins SDK 10.0.100 with `rollForward: latestFeature`. There are no tests and no linter.
|
`global.json` pins SDK 10.0.100 with `rollForward: latestFeature`. There are no tests and no linter.
|
||||||
|
|
||||||
## CSS: Tailwind 4 + daisyUI 5, no Node
|
## CSS: Tailwind 4 + daisyUI 5, vendored, offline
|
||||||
|
|
||||||
`Styles/app.css` is compiled into `wwwroot/css/app.css` by the Tailwind CSS standalone binary with the daisyUI
|
`Styles/app.css` is compiled into `wwwroot/css/app.css` by the Tailwind CSS standalone binary with the daisyUI
|
||||||
plugin. `app.css` is gitignored and regenerated on every build.
|
plugin. `app.css` is gitignored and regenerated on every build.
|
||||||
|
|
||||||
- `tools/tailwind.sh` downloads Tailwind 4.3.3 and daisyUI 5.7.47 into the gitignored `.tools/tailwind/`, checking each
|
**Nothing in the build or the CI may download from github.com.** Tools live in the repo, and the CSS build runs
|
||||||
against a pinned sha256. To upgrade, change the versions and hashes there.
|
without network access. NuGet restore still uses nuget.org.
|
||||||
|
- `tools/tailwind/` holds the pinned tools:
|
||||||
|
- Tailwind 4.3.3 as `tailwindcss-linux-x64.xz`;
|
||||||
|
- daisyUI 5.7.47 (`daisyui.mjs`, `daisyui-theme.mjs`);
|
||||||
|
- daisyUI's component reference, `daisyui-llms.txt`.
|
||||||
|
- `.gitattributes` keeps these files byte-exact.
|
||||||
|
- `tools/tailwind.sh prepare` checks them against the sha256 values pinned in the script, and unpacks the binary into
|
||||||
|
the gitignored `.tools/tailwind/`. It needs `xz`.
|
||||||
|
- Only linux-x64 is vendored.
|
||||||
|
- The script's header explains how to upgrade or add a platform.
|
||||||
- The `TailwindCompile` target in the csproj runs it, so `dotnet build` / `publish` are enough, in CI as well. Debug
|
- The `TailwindCompile` target in the csproj runs it, so `dotnet build` / `publish` are enough, in CI as well. Debug
|
||||||
builds use `--optimize`, Release builds `--minify`. Pass `-p:SkipTailwind=true` to skip it.
|
builds use `--optimize`, Release builds `--minify`. Pass `-p:SkipTailwind=true` to skip it.
|
||||||
- `IncludeTailwindOutput` adds the generated file to `Content` before static web assets are resolved. Without that, a
|
- `IncludeTailwindOutput` adds the generated file to `Content` before static web assets are resolved. Without that, a
|
||||||
clean-clone publish would ship `app.css` without its `.gz`/`.br` copies and outside `service-worker-assets.js`.
|
clean-clone publish would ship `app.css` without its `.gz`/`.br` copies and outside `service-worker-assets.js`.
|
||||||
The deploy workflow checks for `css/app.css.gz`.
|
The deploy workflow checks for `css/app.css.gz`.
|
||||||
- `bash tools/tailwind.sh watch` rebuilds the CSS live next to `dotnet watch`. `bash tools/tailwind.sh docs` fetches
|
- `bash tools/tailwind.sh watch` rebuilds the CSS live next to `dotnet watch`.
|
||||||
daisyUI's `llms.txt` (its component reference) into `.tools/tailwind/`.
|
- Tailwind scans every file `.gitignore` doesn't exclude (minus `tools/`, `wwwroot/vendor/`, `Docs/`), and only
|
||||||
- Tailwind scans every file `.gitignore` doesn't exclude, and only generates the classes it finds written out
|
generates the classes it finds written out **whole**. Never build a class name by concatenation or interpolation (`"btn-" + size`, `$"btn-{size}"`). Write
|
||||||
**whole**. Never build a class name by concatenation or interpolation (`"btn-" + size`, `$"btn-{size}"`). Write
|
|
||||||
every variant as a literal, e.g. in a switch arm.
|
every variant as a literal, e.g. in a switch arm.
|
||||||
|
|
||||||
Ionicons 4.5 (`wwwroot/vendor/ionicons.min.css`, `<i class="ion-md-...">`) is loaded as its own stylesheet.
|
Ionicons 4.5 (`wwwroot/vendor/ionicons.min.css`, `<i class="ion-md-...">`) is loaded as its own stylesheet.
|
||||||
@@ -68,6 +76,12 @@ Ionicons 4.5 (`wwwroot/vendor/ionicons.min.css`, `<i class="ion-md-...">`) is lo
|
|||||||
from localStorage, so there is no flash before Blazor boots. After that, CascadingState calls it through
|
from localStorage, so there is no flash before Blazor boots. After that, CascadingState calls it through
|
||||||
`AppStatusService.ApplyTheme` whenever the settings change. With `PreferSystemTheming` it leaves `data-theme` off,
|
`AppStatusService.ApplyTheme` whenever the settings change. With `PreferSystemTheming` it leaves `data-theme` off,
|
||||||
and the OS decides.
|
and the OS decides.
|
||||||
|
- Change the theme flags through `PageSettings.SetDarkMode` / `SetGray` / `SetHue` and
|
||||||
|
`CascadingState.UpdatePageSettings`, which keep the flags consistent:
|
||||||
|
- choosing light or dark leaves system theming;
|
||||||
|
- picking a hue leaves grey.
|
||||||
|
- `AppStatusService.IsDarkTheme()` tells which variant is showing.
|
||||||
|
- Settings → General edits every theme setting. NavMenu's toggle and slider are shortcuts to the dark and hue ones.
|
||||||
- `Styles/neo.css` holds the neumorphic layer:
|
- `Styles/neo.css` holds the neumorphic layer:
|
||||||
- `neo-raised` / `neo-inset` / `neo-flat`, with sizes `neo-2xs` / `neo-xs` / `neo-sm` / `neo-md` (these replace the
|
- `neo-raised` / `neo-inset` / `neo-flat`, with sizes `neo-2xs` / `neo-xs` / `neo-sm` / `neo-md` (these replace the
|
||||||
old `neomorph is-nxsmall` classes);
|
old `neomorph is-nxsmall` classes);
|
||||||
@@ -88,7 +102,11 @@ all of them in every theme. When you add or change one:
|
|||||||
- Value-holding fields derive from `DInputBase<TValue>`, Blazor's `InputBase`, so `@bind-Value` and EditForm
|
- Value-holding fields derive from `DInputBase<TValue>`, Blazor's `InputBase`, so `@bind-Value` and EditForm
|
||||||
validation work. Everything else derives from `DComponentBase` (`Class`, pass-through attributes, `Cx(...)`).
|
validation work. Everything else derives from `DComponentBase` (`Class`, pass-through attributes, `Cx(...)`).
|
||||||
- Open/active state lives in C# (`@bind-IsOpen`, `@bind-Active`) and is rendered with daisyUI's `*-open` modifier
|
- Open/active state lives in C# (`@bind-IsOpen`, `@bind-Active`) and is rendered with daisyUI's `*-open` modifier
|
||||||
classes. No JS interop. `DCalendar` is the one exception: it wraps the vendored Cally web component.
|
classes. No JS interop.
|
||||||
|
- What daisyUI does with scripts has a script-free equivalent here: `DCheckbox.Indeterminate` renders
|
||||||
|
`aria-checked="mixed"`, and `DCarousel`'s navigation links to the slides' ids, which Blazor scrolls to.
|
||||||
|
- `DCalendar` is the one exception: it wraps the vendored Cally web component (`wwwroot/vendor/cally.js`).
|
||||||
|
- Images and links in `/styleguide` stay local (`wwwroot/imgs/styleguide/`).
|
||||||
- Don't name a parameter after an HTML attribute (`Title`, `Style`, `Id`, `Label`, ...). Blazor matches attributes
|
- Don't name a parameter after an HTML attribute (`Title`, `Style`, `Id`, `Label`, ...). Blazor matches attributes
|
||||||
to parameters without regard to case, so the parameter would swallow the attribute.
|
to parameters without regard to case, so the parameter would swallow the attribute.
|
||||||
- Components don't use `Localizer` or `CascadingState`; their user-visible strings are parameters.
|
- Components don't use `Localizer` or `CascadingState`; their user-visible strings are parameters.
|
||||||
@@ -123,13 +141,18 @@ take it as `[CascadingParameter] CascadingState`. It handles:
|
|||||||
`nameof(Type)`.
|
`nameof(Type)`.
|
||||||
- **IndexedDB** (DnetIndexedDb, database `data`) is reached through `IStorage`. Its schema is declared in
|
- **IndexedDB** (DnetIndexedDb, database `data`) is reached through `IStorage`. Its schema is declared in
|
||||||
`GenericExtensions.AddIndexedDb()`, and you must bump `WithVersion` when you change it.
|
`GenericExtensions.AddIndexedDb()`, and you must bump `WithVersion` when you change it.
|
||||||
- Known gap: `IStorage` reads and writes a `ClientLogs` store that the schema never declares, so the error log writes
|
- The schema is at version 2, which added the `ClientLogs` store that `IStorage.AddLog` writes. Before it, every log
|
||||||
fail silently (they are wrapped in try/catch).
|
write failed silently.
|
||||||
|
|
||||||
**Auth.**
|
**Auth.**
|
||||||
- `TokenAuthStateProvider` builds the auth state from the `AuthData` token in localStorage.
|
- `TokenAuthStateProvider` builds the auth state from the `AuthData` token in localStorage.
|
||||||
- `SetToken` is mostly commented out, so there is no real login flow yet.
|
- `SetToken` is mostly commented out, so there is no real login flow yet.
|
||||||
- `AddApiAuthorization` and `Pages/Authentication.razor` are leftovers from the Blazor template.
|
- `Pages/Logout.razor` signs out through `TokenAuthStateProvider.LogoutAsync`, which clears the token and the local
|
||||||
|
database.
|
||||||
|
- `AddApiAuthorization`, `Pages/Authentication.razor` (`/authentication/{action}`) and `RedirectToLogin` are leftovers
|
||||||
|
from the Blazor OIDC template. That route's `RemoteAuthenticatorView` throws `InvalidCastException`, because the
|
||||||
|
registered `AuthenticationStateProvider` is `TokenAuthStateProvider`. The Login links that point there need a real
|
||||||
|
login page first.
|
||||||
|
|
||||||
**JS interop.**
|
**JS interop.**
|
||||||
- `wwwroot/main.js` defines `window.*` helpers. `Services/AppStatusService.cs` calls them, mostly through the
|
- `wwwroot/main.js` defines `window.*` helpers. `Services/AppStatusService.cs` calls them, mostly through the
|
||||||
@@ -141,6 +164,9 @@ take it as `[CascadingParameter] CascadingState`. It handles:
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
|
Both workflows check the repo out with a plain `git fetch` from this Gitea, not `actions/checkout`, because the runner
|
||||||
|
would download that action from github.com. Never add a `uses:` step.
|
||||||
|
|
||||||
`.gitea/workflows/deploy.yml` runs on a `v*` tag or a manual dispatch, on a self-hosted runner that is also the web
|
`.gitea/workflows/deploy.yml` runs on a `v*` tag or a manual dispatch, on a self-hosted runner that is also the web
|
||||||
host. The steps:
|
host. The steps:
|
||||||
1. Publish the site.
|
1. Publish the site.
|
||||||
|
|||||||
Reference in new issue
Block a user