From e075c4040b88d376f9e817780fd7a850dfe8b570 Mon Sep 17 00:00:00 2001 From: thepra Date: Sat, 3 Oct 2026 12:08:52 +0200 Subject: [PATCH] Delete the SCSS/Bulma pipeline and document the new one Nothing loads the old bundle any more, so it goes, along with everything that built it and the csproj entries that pointed at it: - SCSS/, including the vendored Bulma 0.9.4 sass; - compilerconfig.json and bundleconfig.json; - tailwind.config.js and terminal-script.txt; - wwwroot/css/style.min.css, main.css, main.min.css and tailwind-override.css; - wwwroot/vendor's bulma, tailwind and toggle-dark-light-mode CSS. The unused Font Awesome and Open Iconic assets stay. The deploy workflow now requires css/app.css and its .gz in the publish output. The .gz only exists when the generated file was registered as a static web asset, so the check catches a silent regression of that. It also checks for js/theme.js. CLAUDE.md, new on this branch, documents the repo: - the no-Node Tailwind/daisyUI build; - the theme runtime; - the neo layer, including the cascade-layer rule its overrides must follow; - the rules for the D components. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw --- .gitea/workflows/deploy.yml | 2 +- CLAUDE.md | 163 + SCSS/base.scss | 92 - SCSS/bulma/bulma.sass | 7 - SCSS/bulma/sass/base/_all.sass | 5 - SCSS/bulma/sass/base/animations.sass | 5 - SCSS/bulma/sass/base/generic.sass | 140 - SCSS/bulma/sass/components/_all.sass | 6 - SCSS/bulma/sass/components/dropdown.sass | 82 - SCSS/bulma/sass/components/message.sass | 101 - SCSS/bulma/sass/components/pagination.sass | 167 - SCSS/bulma/sass/elements/_all.sass | 12 - SCSS/bulma/sass/elements/button.sass | 337 -- SCSS/bulma/sass/elements/content.sass | 162 - SCSS/bulma/sass/elements/icon.sass | 46 - SCSS/bulma/sass/elements/image.sass | 73 - SCSS/bulma/sass/elements/notification.sass | 52 - SCSS/bulma/sass/elements/other.sass | 28 - SCSS/bulma/sass/elements/progress.sass | 73 - SCSS/bulma/sass/elements/tag.sass | 140 - SCSS/bulma/sass/form/_all.sass | 9 - SCSS/bulma/sass/form/checkbox-radio.sass | 22 - SCSS/bulma/sass/form/file.sass | 184 - SCSS/bulma/sass/form/input-textarea.sass | 66 - SCSS/bulma/sass/form/select.sass | 88 - SCSS/bulma/sass/form/shared.sass | 59 - SCSS/bulma/sass/form/tools.sass | 215 - SCSS/bulma/sass/utilities/_all.sass | 9 - SCSS/bulma/sass/utilities/controls.sass | 49 - .../sass/utilities/derived-variables.sass | 114 - SCSS/bulma/sass/utilities/extends.sass | 25 - SCSS/bulma/sass/utilities/functions.sass | 135 - .../sass/utilities/initial-variables.sass | 79 - SCSS/bulma/sass/utilities/mixins.sass | 303 - SCSS/main.scss | 4 - SCSS/mixins.scss | 33 - SCSS/neomorph.scss | 656 --- SCSS/variables.scss | 28 - bundleconfig.json | 22 - compilerconfig.json | 22 - compilerconfig.json.bindings | 1 - decePubClient.csproj | 14 - tailwind.config.js | 12 - terminal-script.txt | 2 - wwwroot/css/main.css | 566 -- wwwroot/css/main.min.css | 1 - wwwroot/css/style.min.css | 4910 ----------------- wwwroot/css/tailwind-override.css | 6 - wwwroot/vendor/bulma.css | 3706 ------------- wwwroot/vendor/bulma.min.css | 2 - wwwroot/vendor/tailwind-generator.css | 3 - wwwroot/vendor/tailwind.css | 1115 ---- wwwroot/vendor/toggle-dark-light-mode.css | 80 - 53 files changed, 164 insertions(+), 14069 deletions(-) create mode 100644 CLAUDE.md delete mode 100644 SCSS/base.scss delete mode 100644 SCSS/bulma/bulma.sass delete mode 100644 SCSS/bulma/sass/base/_all.sass delete mode 100644 SCSS/bulma/sass/base/animations.sass delete mode 100644 SCSS/bulma/sass/base/generic.sass delete mode 100644 SCSS/bulma/sass/components/_all.sass delete mode 100644 SCSS/bulma/sass/components/dropdown.sass delete mode 100644 SCSS/bulma/sass/components/message.sass delete mode 100644 SCSS/bulma/sass/components/pagination.sass delete mode 100644 SCSS/bulma/sass/elements/_all.sass delete mode 100644 SCSS/bulma/sass/elements/button.sass delete mode 100644 SCSS/bulma/sass/elements/content.sass delete mode 100644 SCSS/bulma/sass/elements/icon.sass delete mode 100644 SCSS/bulma/sass/elements/image.sass delete mode 100644 SCSS/bulma/sass/elements/notification.sass delete mode 100644 SCSS/bulma/sass/elements/other.sass delete mode 100644 SCSS/bulma/sass/elements/progress.sass delete mode 100644 SCSS/bulma/sass/elements/tag.sass delete mode 100644 SCSS/bulma/sass/form/_all.sass delete mode 100644 SCSS/bulma/sass/form/checkbox-radio.sass delete mode 100644 SCSS/bulma/sass/form/file.sass delete mode 100644 SCSS/bulma/sass/form/input-textarea.sass delete mode 100644 SCSS/bulma/sass/form/select.sass delete mode 100644 SCSS/bulma/sass/form/shared.sass delete mode 100644 SCSS/bulma/sass/form/tools.sass delete mode 100644 SCSS/bulma/sass/utilities/_all.sass delete mode 100644 SCSS/bulma/sass/utilities/controls.sass delete mode 100644 SCSS/bulma/sass/utilities/derived-variables.sass delete mode 100644 SCSS/bulma/sass/utilities/extends.sass delete mode 100644 SCSS/bulma/sass/utilities/functions.sass delete mode 100644 SCSS/bulma/sass/utilities/initial-variables.sass delete mode 100644 SCSS/bulma/sass/utilities/mixins.sass delete mode 100644 SCSS/main.scss delete mode 100644 SCSS/mixins.scss delete mode 100644 SCSS/neomorph.scss delete mode 100644 SCSS/variables.scss delete mode 100644 bundleconfig.json delete mode 100644 compilerconfig.json delete mode 100644 compilerconfig.json.bindings delete mode 100644 tailwind.config.js delete mode 100644 terminal-script.txt delete mode 100644 wwwroot/css/main.css delete mode 100644 wwwroot/css/main.min.css delete mode 100644 wwwroot/css/style.min.css delete mode 100644 wwwroot/css/tailwind-override.css delete mode 100644 wwwroot/vendor/bulma.css delete mode 100644 wwwroot/vendor/bulma.min.css delete mode 100644 wwwroot/vendor/tailwind-generator.css delete mode 100644 wwwroot/vendor/tailwind.css delete mode 100644 wwwroot/vendor/toggle-dark-light-mode.css diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index eb7f667..fc5e270 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -44,7 +44,7 @@ jobs: - name: Assert the publish actually produced a site run: | W="$GITHUB_WORKSPACE/publish/wwwroot" - for f in index.html appsettings.json build.json _framework/blazor.webassembly.js css/style.min.css; do + for f in index.html appsettings.json build.json _framework/blazor.webassembly.js css/app.css css/app.css.gz js/theme.js; do [ -e "$W/$f" ] || { echo "::error::publish output is missing $f"; exit 1; } done ls "$W/_framework" | grep -q '\.wasm$' || { echo "::error::no .wasm in _framework"; exit 1; } diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a1720cc --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,163 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +decePubClient is a Blazor WebAssembly PWA (.NET 10). It is meant as a Pleroma-FE-like client for **PrivaPub**, the +owner's ActivityPub server, whose repo is `thepra/SocialPub`. It is deployed as a static site at +https://decepub.thepra.dev, and its API base address is `https://privapub.thepra.dev` +(`AppConfiguration:ApiBaseAddress` in `wwwroot/appsettings.json`). + +**It is still a prototype and is not connected to the server:** +- The feed comes from `Helpers/Faker.cs`. `Storage.GetMessages()` (`Services/IStorage.cs`) and `Pages/ExpandMessage.razor` + create mock posts. +- Every method in `Services/MessagesService.cs` is a `//TODO` stub. +- `HttpService` (`Services/IHttpService.cs`) is written but not registered in DI. +- The nginx vhost sends `X-Robots-Tag: noindex` while the site shows mock posts. + +`Docs/Insomnia_APIs.json` is an old API collection for a localhost backend. Don't treat it as PrivaPub's API. + +## Sibling repo dependency + +The project references `../SocialPub/PrivaPub.ClientModels/PrivaPub.ClientModels.csproj`, so SocialPub must be +checked out next to this repo. CI clones it there. That project supplies: +- the shared DTOs; +- `Policies` (IsAdmin, IsUser, IsModerator); +- the `FieldsNameResource` and `ErrorsResource` localization resources. + +Before wiring anything to the API, read `../SocialPub/CLAUDE.md`. PrivaPub's route names (`/peasants/...`, `/mouth`, +`/anus`, ...) are deliberate. Never "correct" them. The intended API surface is the Mastodon client API plus PrivaPub's +private `/clientapi`. + +## Commands + +```sh +dotnet build decePubClient.csproj # what CI runs (-c Release) on every push to master and on PRs +dotnet run # dev server: https://localhost:7046 / http://localhost:5046 +dotnet publish decePubClient.csproj -c Release -o publish # static site lands in publish/wwwroot +``` + +`global.json` pins SDK 10.0.100 with `rollForward: latestFeature`. There are no tests and no linter. + +## CSS: Tailwind 4 + daisyUI 5, no Node + +`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. + +- `tools/tailwind.sh` downloads Tailwind 4.3.3 and daisyUI 5.7.47 into the gitignored `.tools/tailwind/`, checking each + against a pinned sha256. To upgrade, change the versions and hashes there. +- 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. +- `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`. + 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 + daisyUI's `llms.txt` (its component reference) into `.tools/tailwind/`. +- Tailwind scans every file `.gitignore` doesn't exclude, and only generates the classes it finds written out + **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. + +Ionicons 4.5 (`wwwroot/vendor/ionicons.min.css`, ``) is loaded as its own stylesheet. + +## Theme and neumorphism + +- `Styles/theme.css` holds two daisyUI themes, `neo-light` (default) and `neo-dark` (`prefersdark`). Every colour + is an `hsl()` of `--neo-hue-light` / `--neo-hue-dark` / `--neo-chroma` (0 for the grey themes). +- `wwwroot/js/theme.js` sets those variables and `data-theme` on `` from `PageSettings`. It runs in `` + 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, + and the OS decides. +- `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 + old `neomorph is-nxsmall` classes); + - `neo-gradient(-pressed)` and `neo-hue-track`; + - `@utility ` overrides that give btn, input, select, card, … the neo look. daisyUI puts its rules + in sublayers of `utilities`, so these overrides beat **every** daisyUI rule. Each override must exclude the + daisyUI variants it shouldn't touch, e.g. `:not(:where(.btn-ghost, .btn-link, ...))`, and call sites drop a neo + shadow with `shadow-none!`. +- Never write `@utility collapse`. It brings back Tailwind's own `collapse` utility (`visibility: collapse`), and + every collapse disappears. + +## daisyUI Blazor components (`Components/Daisy/`) + +Every daisyUI component has a `D`-prefixed wrapper (`DButton`, `DModal`, `DDropdown`, `DInput`, ...), grouped by +daisyUI's categories into folders whose namespaces are imported in `_Imports.razor`. `/styleguide` (not linked) renders +all of them in every theme. When you add or change one: +- Map each enum to its classes in a switch with whole literal class names. +- Value-holding fields derive from `DInputBase`, Blazor's `InputBase`, so `@bind-Value` and EditForm + 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 + classes. No JS interop. `DCalendar` is the one exception: it wraps the vendored Cally web component. +- 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. +- Components don't use `Localizer` or `CascadingState`; their user-visible strings are parameters. + +## Architecture + +**Startup (`Program.cs`).** +- DI registration happens here. +- The named `HttpClient` "default" uses `ApiBaseAddress` as its base address. It falls back to the host's base + address when that setting is empty. +- `SetDefaultCulture()` (`Extensions/ExtensionMethods.cs`) runs before the app starts. It picks the culture from the + saved `PublicCacheData` or from the browser language, and maps any `en*` to `en-GB`. + +**`LayerComponents/CascadingState.razor`** wraps the router in `App.razor`. It is the app-wide state object, and pages +take it as `[CascadingParameter] CascadingState`. It handles: +- `PublicCacheData` (page settings: theme colours, dark/light/system theming, language), persisted in localStorage; +- the theme, applied through `AppStatusService.ApplyTheme` (`wwwroot/js/theme.js`); +- an online check every 10 seconds; +- `ProcessError` / `ProcessWarning`, which components should call to report errors and warnings; +- `LogFromJs`, which JS calls back into through a `DotNetObjectReference`. + +**Components and pages** inherit `LocalizableComponentBase`, which supplies `Localizer`, an `IsLoading` flag and +`AfterRenderAsyncJobs`. `PagesBase` is an empty subclass of it, and only `Authentication.razor` uses it. + +**Localization (`Services/CoalescingStringLocalizer.cs`).** +- Lookup order: this repo's `Resources/AllStrings.resx`, then `FieldsNameResource`, then `ErrorsResource`. +- A missing key renders as the key itself, so a typo fails silently. +- The class lives in namespace `collAnon.Client.Services`, a leftover from another project. + +**Client storage** comes in two layers: +- **localStorage** (Blazored.LocalStorage, camelCase JSON) holds `AuthData` and `PublicCacheData`, keyed by + `nameof(Type)`. +- **IndexedDB** (DnetIndexedDb, database `data`) is reached through `IStorage`. Its schema is declared in + `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 + fail silently (they are wrapped in try/catch). + +**Auth.** +- `TokenAuthStateProvider` builds the auth state from the `AuthData` token in localStorage. +- `SetToken` is mostly commented out, so there is no real login flow yet. +- `AddApiAuthorization` and `Pages/Authentication.razor` are leftovers from the Blazor template. + +**JS interop.** +- `wwwroot/main.js` defines `window.*` helpers. `Services/AppStatusService.cs` calls them, mostly through the + synchronous `IJSInProcessRuntime`. +- Each helper reports its errors back through `window.logFromJs`. +- The other scripts (IndexedDB, HeadElement, auth, rxjs) are loaded by `