Skip to content

fix(ui): make toast notifications opaque instead of ~50% transparent - #484

Merged
schubydoo merged 4 commits into
mainfrom
fix/toast-opacity
Jun 19, 2026
Merged

fix(ui): make toast notifications opaque instead of ~50% transparent#484
schubydoo merged 4 commits into
mainfrom
fix/toast-opacity

Conversation

@schubydoo

Copy link
Copy Markdown
Owner

Reported: the toast/notification box is too transparent — dashboard content shows through it.

Root cause: toasts are Tabler .alert cards (.toast-stack.alert.alert-*). Tabler computes .alert background as color-mix(in srgb, var(--tblr-alert-bg), var(--tblr-bg-surface)) where --tblr-alert-bg is itself color-mix(… 10%, transparent) — so the fill lands ~50% opaque over the fixed-position toast and the page shows through.

Fix: one CSS rule scoped to .toast-stack .alert that re-mixes the per-type tint (var(--tblr-alert-color)) into the solid var(--tblr-bg-surface), so the toast is opaque while keeping its per-type colour. Theme-safe (both vars are theme-reactive).

.toast-stack .alert { background-color: color-mix(in srgb, var(--tblr-alert-color) 12%, var(--tblr-bg-surface)); }

Reviewed by clauster-frontend-reviewer: APPROVE — specificity (0,2,0) wins over Tabler .alert (0,1,0) without !important, scoped to only the toast region (no collateral on the ~15 other .alert uses), contrast-neutral (≤0.2 delta), holds in light + dark themes, zero XSS surface.

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes toast/notification transparency by adding one scoped CSS rule that overrides Tabler's default semi-transparent alert background with a solid color-mix of the per-type tint and the solid surface variable.

  • .toast-stack .alert gets background-color: color-mix(in srgb, var(--tblr-alert-color) 12%, var(--tblr-bg-surface)) — specificity 0-2-0 beats Tabler's 0-1-0, stays scoped to the toast region only, and is theme-reactive.
  • No other alert uses across the page are touched; --tblr-alert-color is already set per-type by Tabler's modifier classes (.alert-success, .alert-danger, etc.).

Confidence Score: 5/5

Minimal, well-scoped CSS change with no behavioural side-effects beyond the intended toast region.

The change is a single CSS rule touching only the toast overlay area. It uses only stable, already-required CSS features (color-mix() is already a Tabler baseline), and the rule is correctly scoped so it cannot affect the ~15 other .alert uses on the page. No logic, data, or template code is modified.

No files require special attention.

Important Files Changed

Filename Overview
src/clauster/templates/dashboard.html Adds a single scoped CSS rule to make .toast-stack .alert backgrounds opaque by re-mixing the per-type tint colour into the solid surface variable, overriding Tabler's default transparent computation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Toast rendered as .toast-stack .alert.alert-*] --> B{Which CSS selector wins?}
    B -->|Tabler default: specificity 0-1-0| C[".alert background-color\ncolor-mix(...tblr-alert-bg... tblr-bg-surface)\nwhere tblr-alert-bg itself uses transparent\n→ ~50% opacity"]
    B -->|New override: specificity 0-2-0| D[".toast-stack .alert background-color\ncolor-mix(in srgb, tblr-alert-color 12%, tblr-bg-surface)\n→ solid / opaque"]
    C --> E["❌ Dashboard content visible through toast"]
    D --> F["✅ Opaque toast, per-type tint preserved,\nworks in light + dark themes"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Toast rendered as .toast-stack .alert.alert-*] --> B{Which CSS selector wins?}
    B -->|Tabler default: specificity 0-1-0| C[".alert background-color\ncolor-mix(...tblr-alert-bg... tblr-bg-surface)\nwhere tblr-alert-bg itself uses transparent\n→ ~50% opacity"]
    B -->|New override: specificity 0-2-0| D[".toast-stack .alert background-color\ncolor-mix(in srgb, tblr-alert-color 12%, tblr-bg-surface)\n→ solid / opaque"]
    C --> E["❌ Dashboard content visible through toast"]
    D --> F["✅ Opaque toast, per-type tint preserved,\nworks in light + dark themes"]
Loading

Reviews (4): Last reviewed commit: "Merge main into fix/toast-opacity" | Re-trigger Greptile

@schubydoo
schubydoo enabled auto-merge (squash) June 19, 2026 23:28
@schubydoo
schubydoo merged commit 76f63af into main Jun 19, 2026
29 checks passed
@schubydoo
schubydoo deleted the fix/toast-opacity branch June 19, 2026 23:39
schubydoo added a commit that referenced this pull request Jun 20, 2026
## What

Migrates clauster's release pipeline from **release-please** to
**knope**, using a **changesets-only** model. This is the Phase-2
cutover from the proposal in `scratch/knope-migration-plan.md`,
authorized to land now.

Every user-facing change now ships a `.changeset/*.md` fragment that
drives **both** the version bump and the changelog
(`ignore_conventional_commits = true`), so release notes can carry the
captured "why" instead of terse commit subjects. knope replaces **only**
release-please's orchestration (version PR + changelog + draft-release
creation) — the build / Sigstore-sign / `actions/attest` / publish
supply chain and `release.yml` (PyPI + GHCR on the tag) are
**unchanged**.

## How it works now

- **`knope-prepare.yml`** (`push: main`) — when a `.changeset/*.md` is
pending, knope bumps `pyproject.toml` + `src/clauster/__init__.py` +
`CHANGELOG.md`, resyncs `uv.lock`, and opens/refreshes the `release` PR
(`chore: prepare release X.Y.Z`). Gated on changeset *presence*, so a
genuine knope failure fails the job **loudly** (no blanket
`continue-on-error`); an ordinary push is a clean no-op.
- **`knope-release.yml`** (the `release` PR merging) — builds the
5-target binaries, Sigstore-signs dists + binaries, attests SLSA
provenance, runs a **fail-closed gate** (aborts unless the full signed
set is present), then `knope release` natively does draft → upload
assets → publish. The tag is created at publish and pushed as the
clauster-ci App so it triggers `release.yml`. The immutability invariant
(tag only at publish, assets attached to the draft first) is preserved.
- **`changeset-check.yml`** — advisory, **non-blocking** nudge on `src/`
PRs without a changeset (opt out with the `no-changelog` label).

Triggered on `pull_request: closed` + `head_ref == 'release'` rather
than a commit-message marker — the repo squash-merges and a squash
subject is editable, so head_ref is the reliable signal. The release job
checks out `merge_commit_sha` (the squash commit on main) so knope tags
a commit that actually landed on main.

## Removed / updated

- Deleted `release-please-config.json`, `.release-please-manifest.json`,
`.github/workflows/release-please.yml`.
- Refreshed `CONTRIBUTING.md` (the changeset workflow), the PR template,
the `no-changelog` label, `.bestpractices.json`, and the now-stale
`release-please` comments across the workflows/config.
- Included a changeset for the pending toast-opacity fix
([#484](#484)) so knope's
**first** release ships it as **0.12.1**.

## Validation

- Reviewed adversarially by `clauster-ci-auditor` (twice — it caught a
real silent-never-publish path in an earlier trigger design, now fixed):
immutability / fail-closed gate, attest-before-sign ordering, App-token
tag trigger, SHA-pinning, fork-safe advisory check, and prepare/release
mutual-exclusion — all confirmed.
- `knope prepare-release --dry-run` against this branch computes
**0.12.1** with a correct `### Fixes` entry.
- `yamllint` + `ruff` + `markdownlint` green (pre-commit).

## Maintainer notes (release-path — HOLD-for-maintainer)

- **Cutover**: merging this opens knope's own `chore: prepare release
0.12.1` PR. The stale release-please PR
[#486](#486) is superseded and
being closed.
- **First knope release** will pause at the `pypi` protected-environment
approval (unchanged, in `release.yml`) — that's yours to approve.
- The `RELEASE_PLEASE_APP_*` secret names are intentionally **kept**
(renaming would require re-adding the repo secrets); the comments now
explain they are the clauster-ci App credentials.
- Local-only `.claude/rules/release-safety.md` still says "cut by
release-please" — gitignored, not in this PR; update at your
convenience.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Schuby <12485317+schubydoo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
schubydoo added a commit that referenced this pull request Jun 20, 2026
## What

Backfills `([#492])` into the `harden-untrusted-readers` changeset so
0.12.1's changelog entry is correctly linked — matching the toast
entry's `([#484])`. The harden fix + its changeset both shipped in
#492, but the changeset was
authored without a link (the number didn't exist yet), so without this
it would ship unlinked.

Dry-run confirms both pending 0.12.1 entries now render with their links
and no double-link.

## ⚠️ Merge order

- Merge this **before**
[#491](#491) (the 0.12.1
release) so it lands in 0.12.1.
- Then #491 (release), then
[#493](#493) (the
change_templates config — auto-links from 0.12.2 on, so no more manual
backfills).

Changeset-content only — no `src`, no new changeset needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Schuby <12485317+schubydoo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
schubydoo pushed a commit that referenced this pull request Jun 20, 2026
Merging this PR tags and publishes **v0.12.1**.

Generated by knope from the `.changeset/` fragments — don't edit it by
hand; add or amend a changeset on the source PR instead.

---

## Fixes

- Harden two untrusted-input readers against malformed input (both
surfaced by new fuzz harnesses): the CSRF/CORS origin check no longer
returns a 500 on an `Origin` header with an out-of-range or non-numeric
port, and project discovery no longer crashes on a non-dict
`~/.claude.json` — each now degrades safely
([#492](#492)).
- Toast notifications now render fully opaque instead of ~50%
transparent, so they stay readable over busy page content
([#484](#484)).

Co-authored-by: clauster-ci[bot] <289303168+clauster-ci[bot]@users.noreply.github.com>
schubydoo added a commit that referenced this pull request Jun 20, 2026
## What

Adds a `[release_notes] change_templates` config so knope **auto-appends
the PR number** to every changelog entry, resolving `$pr_number` (knope
0.23.0+) to the PR that introduced each changeset.

This closes the gap spotted on
[#491](#491): without it,
knope prints the changeset body verbatim, so an entry only had a PR link
if the author *typed* one (the toast entry had `([#484])` only because
it was added by hand; the harden-readers entry had none). Now:

- **Authors write a plain summary** — no PR number (you don't have it at
authoring time).
- **knope appends `([#NNN])`** at release time, tracing the changeset's
commit → PR.

The ordered template chain handles every shape: a headed/complex
changeset keeps its `### + body`, a one-liner renders as a bullet, and
either drops the `(#NNN)` suffix when a change isn't yet traceable to a
committed PR (e.g. a local `--dry-run`, where knope shows a `#1234`
placeholder).

## ⚠️ Best merged AFTER
[#491](#491) (the 0.12.1
release)

The **toast changeset is a backfill** — it was added in the cutover
(#487) while its fix was #484 — so `$pr_number` resolves to the
*cutover* PR, not the fix, and it would **double-link** with the manual
`([#484])` still in its body. Merging this after 0.12.1 ships means:

- 0.12.1 keeps the correct manual `([#484])` for the toast entry.
- This template applies cleanly from **0.12.2** onward, where every
changeset is authored in the same PR as its change, so `$pr_number` is
always correct.

If it lands first, the only effect is a one-time double-link on that
single toast entry, which I'll clean up.

## Validation

`knope prepare-release --dry-run` renders both pending 0.12.1 entries
with the `([#…])` suffix correctly (the real numbers resolve in CI; the
dry-run shows knope's `#1234` placeholder). Config + docs only — no
`src`, so no changeset is needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Schuby <12485317+schubydoo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: clauster-ci[bot] <289303168+clauster-ci[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant