Skip to content

Release v0.51.242 — Release HJ (stage-q14): Graphite skin - #3500

Merged
nesquena-hermes merged 1 commit into
masterfrom
release/stage-q14
Jun 3, 2026
Merged

nesquena-hermes merged 1 commit into
masterfrom
release/stage-q14

Conversation

@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Release v0.51.242 — Release HJ (stage-q14)

UX-approved via Telegram (Nathan — dark/light/mobile screenshots).

Added

PR Author Feature
#3440 @t3chn0pr13st Graphite appearance skin — a quiet, neutral-gray "workbench" alternative to the default gold/cream. Selectable from Settings → Appearance and /theme skin graphite. Both light + dark palettes on the existing CSS-variable token system; tightened typography, shadows, active-sidebar spacing, code-block framing.

Why it's safe

  • Fully scoped + additive: every new CSS rule (and every !important) is under [data-skin="graphite"] — Codex verified zero bleed into the default appearance or other skins. api/config.py keeps the default skin as default and only adds graphite to the allowed set. No i18n keys dropped (only the /theme help string gains graphite).
  • Opt-in; a user has to select it. Default experience unchanged.

Test-robustness fix (absorbed)

The new graphite scoped selectors (e.g. :root[data-skin="graphite"] .session-item.active .session-time{…}) appear in style.css before the canonical unscoped rules, which broke 3 naive first-occurrence CSS-contract tests (test_issue677 scroll-btn-overlay, test_issue856_pinned_indicator_layout, test_workspace_panel_session_list). Fixed those 3 to anchor on the canonical unscoped rule (start-of-line regex) instead of the first .selector match — robust against this and future skins. Verified they still pass on clean master CSS (invariant preserved, not weakened).

Gate

  • Full pytest suite: 7517 passed, 9 skipped, 3 xpassed, 0 failed
  • ESLint runtime gate: CLEAN · ruff: CLEAN · browser-smoke: CLEAN
  • Codex (regression): SAFE TO SHIP (verified all CSS scoped, default skin unchanged, no i18n key loss)
  • Vision-verified dark + light + mobile; UX-approved by Nathan via Telegram

Co-authored-by: t3chn0pr13st t3chn0pr13st@users.noreply.github.com

Add the Graphite appearance skin (#3440).

- New neutral-gray "workbench" skin, alternative to the default gold/cream.
  All visual changes scoped to data-skin="graphite" (default appearance
  unchanged); both light + dark palettes on the existing CSS-variable token
  system, no new dependency. Registered in the skin picker + /theme help.
  De-olive-tinted light palette. (@t3chn0pr13st)

UX-approved via Telegram (Nathan, dark+light+mobile screenshots).

Co-authored-by: t3chn0pr13st <t3chn0pr13st@users.noreply.github.com>

Test-robustness fix (the new graphite scoped selectors precede the canonical
unscoped rules, breaking 3 naive first-occurrence CSS-contract tests):
test_issue677, test_issue856_pinned_indicator_layout, test_workspace_panel_session_list
now anchor on the canonical UNSCOPED rule (start-of-line regex) instead of the
first `.selector` match — robust against this and future skins. Verified the
3 tests still pass on clean master CSS (invariant preserved, not weakened).
@nesquena-hermes
nesquena-hermes merged commit c0d86db into master Jun 3, 2026
11 checks passed
@greptile-apps

greptile-apps Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR ships the Graphite appearance skin — a neutral-gray "workbench" alternative to the default gold/cream palette — as a fully opt-in, additive change. Every new CSS rule is scoped under [data-skin="graphite"], the backend allowlist in api/config.py and the boot-time whitelist in index.html are updated consistently, all 12 i18n locales have their /theme help strings updated, and three pre-existing CSS-contract tests are robustly fixed to anchor on the canonical unscoped selector rather than the first-occurrence match.

  • Adds light + dark palettes via CSS custom properties, with per-font-size overrides for session-item and msg-body, active-sidebar accent bar via ::before, and tightened composer/code-block framing — all under the graphite data-skin attribute scope.
  • Fixes test_issue677, test_issue856_pinned_indicator_layout, and test_workspace_panel_session_list to use a start-of-line regex anchor so skin-scoped selectors that precede the canonical rules no longer break first-occurrence slicing.

Confidence Score: 4/5

Safe to merge — the graphite skin is fully opt-in and every new CSS rule is correctly scoped under [data-skin="graphite"]; the default experience is unchanged.

The change is additive with no risk to the default skin. The only notable quirk is font-weight:430, which is valid CSS but only meaningful on variable fonts; Segoe UI on Windows and most Linux system fonts will silently render it as 400, so Windows users may not see the intended slightly-tighter weight. This is purely cosmetic and does not break functionality.

static/style.css — the font-weight:430 declarations are the only lines worth a second look from a cross-platform rendering perspective.

Important Files Changed

Filename Overview
static/style.css Adds ~130 lines of graphite skin CSS; all rules correctly scoped under [data-skin="graphite"] and :root.dark[data-skin="graphite"]. font-weight:430 silently falls back to 400 on non-variable fonts. color-mix() is already used extensively in the codebase, so the new occurrence is consistent with established patterns.
api/config.py Correctly adds "graphite" to both the _SETTINGS_DEFAULTS comment and _SETTINGS_SKIN_VALUES allowlist set.
static/boot.js Adds Graphite to the _SKINS array in the correct position (after Mono), consistent with the config.py allowlist ordering.
static/index.html Adds graphite:1 to the inline boot-script skins whitelist, enabling localStorage persistence and data-skin attribute application at page load.
static/i18n.js Updates cmd_theme help strings in all 12 locales (confirmed by grep: exactly 12 cmd_theme occurrences, all updated in the diff).
tests/test_graphite_skin.py New test file with 7 tests covering end-to-end registration, palette correctness, neutral accent enforcement, workbench chrome, code-block framing, and font stack presence.
tests/test_issue677.py Fixed test to use a start-of-line regex anchor instead of a naive first-occurrence find(), correctly skipping the skin-scoped grouped selector that now precedes the canonical rule.
tests/test_issue856_pinned_indicator_layout.py Fixed test to anchor on the canonical unscoped .session-time{ rule and tightened the slice to just the single rule's declaration block, also relaxing semicolon-exact assertions.
tests/test_workspace_panel_session_list.py Same regex fix applied — anchors on the unscoped .session-time{ rule to prevent matching the skin-scoped variant that appears earlier in the file.
tests/test_issue2462_theme_i18n.py Updates the expected skin-list fragment to include "graphite"; the 12 tested locales align exactly with the locales updated in i18n.js.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Page Load — index.html inline boot script] -->|reads localStorage hermes-skin| B{graphite in skins whitelist?}
    B -->|yes| C[dataset.skin = 'graphite']
    B -->|no / default| D[no data-skin attribute set]
    C --> E[CSS: :root data-skin=graphite rules activate]
    E --> F[Light palette tokens applied]
    E --> G[dark class? → Dark palette tokens applied]
    F & G --> H[Skin-scoped overrides: typography, shadows, sidebar, composer, code blocks]
    I[Settings UI / /theme skin graphite] -->|boot.js _SKINS array| J[Skin picker shows Graphite swatch]
    J -->|user selects| K[localStorage.setItem hermes-skin graphite]
    K --> A
    L[api/config.py _SETTINGS_SKIN_VALUES] -->|validates POST body| M{graphite allowed?}
    M -->|yes — added in this PR| N[Setting persisted server-side]
Loading

Reviews (1): Last reviewed commit: "Release v0.51.242 — Release HJ (stage-q1..." | Re-trigger Greptile

Comment thread static/style.css
:root[data-skin="graphite"] .session-jump-btn{box-shadow:0 1px 2px rgba(0,0,0,0.08)!important;background:var(--surface)!important;}
:root.dark[data-skin="graphite"] .workspace-panel-edge-toggle,
:root.dark[data-skin="graphite"] .scroll-to-bottom-btn,
:root.dark[data-skin="graphite"] .session-jump-btn{box-shadow:0 1px 2px rgba(0,0,0,0.28)!important;}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 font-weight:430 may silently fall back to 400 on non-variable fonts

430 is a valid numeric CSS weight, but it only has a visible effect on variable fonts. -apple-system (San Francisco) and ui-monospace are variable, so macOS/iOS users see the intended feel. On Windows, Segoe UI is not a variable font — the browser rounds to 400 (regular). The same applies to most Linux system fonts. The visual "tightened typography" goal of the skin will be inconsistently met depending on OS.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

SysAdminDoc pushed a commit to SysAdminDoc/hermes-webui that referenced this pull request Jun 26, 2026
## Release v0.51.242 — Release HJ (stage-q14)

UX-approved via Telegram (Nathan — dark/light/mobile screenshots).

### Added
| PR | Author | Feature |
|----|--------|---------|
| nesquena#3440 | @t3chn0pr13st | **Graphite appearance skin** — a quiet, neutral-gray "workbench" alternative to the default gold/cream. Selectable from Settings → Appearance and `/theme skin graphite`. Both light + dark palettes on the existing CSS-variable token system; tightened typography, shadows, active-sidebar spacing, code-block framing. |

### Why it's safe
- **Fully scoped + additive**: every new CSS rule (and every `!important`) is under `[data-skin="graphite"]` — Codex verified zero bleed into the default appearance or other skins. `api/config.py` keeps the default skin as `default` and only *adds* `graphite` to the allowed set. No i18n keys dropped (only the `/theme` help string gains `graphite`).
- Opt-in; a user has to select it. Default experience unchanged.

### Test-robustness fix (absorbed)
The new graphite scoped selectors (e.g. `:root[data-skin="graphite"] .session-item.active .session-time{…}`) appear in `style.css` *before* the canonical unscoped rules, which broke 3 naive first-occurrence CSS-contract tests (`test_issue677` scroll-btn-overlay, `test_issue856_pinned_indicator_layout`, `test_workspace_panel_session_list`). Fixed those 3 to anchor on the canonical **unscoped** rule (start-of-line regex) instead of the first `.selector` match — robust against this and future skins. Verified they still pass on clean master CSS (invariant preserved, not weakened).

### Gate
- Full pytest suite: **7517 passed, 9 skipped, 3 xpassed, 0 failed**
- ESLint runtime gate: CLEAN · ruff: CLEAN · browser-smoke: CLEAN
- Codex (regression): **SAFE TO SHIP** (verified all CSS scoped, default skin unchanged, no i18n key loss)
- Vision-verified dark + light + mobile; UX-approved by Nathan via Telegram

Co-authored-by: t3chn0pr13st <t3chn0pr13st@users.noreply.github.com>
@nesquena-hermes
nesquena-hermes deleted the release/stage-q14 branch June 28, 2026 06:10
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