From 3f7145d69a4cbe8b1132fc48b30c32427fb75b22 Mon Sep 17 00:00:00 2001 From: Jokin Date: Fri, 9 Oct 2026 12:09:20 +0200 Subject: [PATCH] Draw the + on the pixel grid so it stays sharp on 1x screens On a 1x display TDesign's + smeared at every small size: its 24-grid strokes are centred on the box's middle, which at 12 or 14px is a pixel boundary, so each ~1px bar covered two pixels at half ink. A thinner stroke alone keeps the bar on the boundary. This is not Electrobun: headless Chrome renders the same. pixelAdd (icons.ts) redraws the + on the 14px grid with 1px bars at 7.5, so they fill whole pixels at 1x and 2x, half a pixel off-centre. It replaces tdesignAdd in the tab bar, the shortcut rows, the connection manager and the tab menu. Checked at 1x in the real tab-bar and shortcut-row markup: single-pixel bars at full ink. Co-Authored-By: Claude --- docs/architecture.md | 5 +++-- docs/gotchas.md | 8 ++++++++ ui/src/app/core/context-menu.service.ts | 2 +- ui/src/app/core/icons.ts | 10 ++++++++-- .../connection-manager/connection-manager.html | 2 +- .../shadlike/settings-window/settings-window.html | 2 +- ui/src/app/skins/shadlike/tab-bar/tab-bar.ts | 2 +- 7 files changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index cf8be50..801199c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -372,8 +372,9 @@ component; tokens → `ui/src/styles.css`. walker check the flag themselves. - `file-icons.ts` — extension → category map driving glyphs, colors (fixed `--icon-*` tokens from Oxide's hue scales) and the Kind column. -- `icons.ts` — the one icon registry (TDesign, `@ng-icons/tdesign-icons`), passed to - `provideIcons` in `app.config.ts`. Icon names are plain strings in templates and +- `icons.ts` — the one icon registry (TDesign, `@ng-icons/tdesign-icons`, plus one + redrawn glyph: `pixelAdd`, TDesign's + on the 14px pixel grid so it stays sharp + on 1x screens), passed to `provideIcons` in `app.config.ts`. Icon names are plain strings in templates and the build never checks them: an unregistered name renders nothing (console error only), so every name used anywhere must be listed here. - `platform.ts` — preload-global readers (`PLATFORM`, `APP_MODE`, diff --git a/docs/gotchas.md b/docs/gotchas.md index 6d69b03..9172509 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -82,6 +82,14 @@ touching the adjacent code. it. Per-template picks had drifted to 12 sizes, and neighbours stopped matching: a 14.4px cog beside a 12.8px +, and a 12px + beside 9.6px × in the shortcut chips. +- **On a 1x screen, a TDesign line through the icon's centre smears at any + small size.** At 12 or 14px the centre is a pixel boundary, so a ~1px bar + covers two pixels at half ink. A 1px stroke alone doesn't help, because the + bar stays centred on the boundary. This is geometry, not Electrobun: + headless Chrome renders the same. So the + is `pixelAdd` (`icons.ts`), + redrawn on the 14px grid with 1px bars at 7.5, which fill whole pixels at 1x + and at 2x. It's tuned for `--icon-size-sm` only. Arrow shafts (↑ →) have + the same issue if it ever shows. ## The interface scale (root font-size lever) diff --git a/ui/src/app/core/context-menu.service.ts b/ui/src/app/core/context-menu.service.ts index 303e72b..3d46d7e 100644 --- a/ui/src/app/core/context-menu.service.ts +++ b/ui/src/app/core/context-menu.service.ts @@ -180,7 +180,7 @@ export class ContextMenuService { const t = (key: string) => this.i18n.t(key); const last = ctx.tabCount <= 1; return [ - { label: t('ctx.tabNew'), action: 'tab:new', shortcut: 'new-tab', icon: 'tdesignAdd' }, + { label: t('ctx.tabNew'), action: 'tab:new', shortcut: 'new-tab', icon: 'pixelAdd' }, { type: 'separator' }, { label: t('ctx.tabClose'), diff --git a/ui/src/app/core/icons.ts b/ui/src/app/core/icons.ts index b658cd9..a84fa0e 100644 --- a/ui/src/app/core/icons.ts +++ b/ui/src/app/core/icons.ts @@ -3,7 +3,6 @@ // plain strings in templates — the build never checks them, so every name used // anywhere must be listed here (an unregistered one renders nothing). import { - tdesignAdd, tdesignArrowLeft, tdesignArrowRight, tdesignArrowUp, @@ -37,8 +36,15 @@ import { tdesignVideo, } from "@ng-icons/tdesign-icons"; +// TDesign's + redrawn on the pixel grid of --icon-size-sm (14px). Its own glyph +// centres 24-grid strokes on the box's middle, a pixel boundary at 14px, so on a +// 1x screen both bars smear over two pixels at half ink. These bars are 1px wide +// on a half pixel (7.5): whole pixels at 1x and 2x, half a pixel off-centre. +const pixelAdd = + ''; + export const APP_ICONS = { - tdesignAdd, + pixelAdd, tdesignArrowLeft, tdesignArrowRight, tdesignArrowUp, diff --git a/ui/src/app/skins/shadlike/connection-manager/connection-manager.html b/ui/src/app/skins/shadlike/connection-manager/connection-manager.html index b0a9d46..5f16ff0 100644 --- a/ui/src/app/skins/shadlike/connection-manager/connection-manager.html +++ b/ui/src/app/skins/shadlike/connection-manager/connection-manager.html @@ -36,7 +36,7 @@ [title]="shortcuts.tip(i18n.t('connMgr.newConnectionHint'), 'conn-new')" class="flex items-center gap-1 px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground" > - {{ i18n.t('connMgr.newConnection') }} + {{ i18n.t('connMgr.newConnection') }}