From ed2e0640b48148b69eca00ad7dd06789506e12ac Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 15 Aug 2026 00:10:12 +0200 Subject: One stroked icon set, matching the Administration shield MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site drew its icons with colour emoji, which means a different drawing on every operating system and never the same line weight twice — except the Administration entry, whose shield is a text-default glyph and so rendered as a thin outline. That one was the odd one out and also the one that looked right. Fifteen inline SVG paths now replace it: menu, bell, shield, globe, gear, sun, moon, power, lock, envelope, door, clip, check, chevron, close. They are stroked in currentColor and sized in em, so an icon takes the colour and size of the text beside it and needs no rule of its own — the caret in the dark nav bar and the gear in a light dropdown are the same file. The explorer keeps its emoji. There the icon says what kind of file this is and the colour is doing real work; a wall of identical grey outlines would be a worse file list. One bug fell out of the change: .nav-notif was painted with --text, the page's text colour, on a nav bar that is nearly black. The emoji bell carried its own colours and showed anyway; a stroked one was invisible until it was given --nav-text. Checked by rendering the real stylesheet in headless Chrome, light and dark. Co-Authored-By: Claude Opus 5 --- packages/meshbay-hub/src/meshbay_hub/static/app.js | 88 +++++++++++++++++----- .../meshbay-hub/src/meshbay_hub/static/style.css | 29 +++++-- 2 files changed, 94 insertions(+), 23 deletions(-) (limited to 'packages') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index 3197c31..a5b74f0 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -223,6 +223,55 @@ function navigate(path) { const AuthContext = createContext(null); function useAuth() { return useContext(AuthContext); } +// ── Icons ──────────────────────────────────────────────────────────────────── +// +// One stroked set, drawn in currentColor and sized in em, so an icon takes the +// weight and colour of the text beside it. The Administration entry was already +// an outline shield while the rest of the site was colour emoji — a different +// drawing on every operating system, and never the same line weight twice. +// +// The explorer keeps its emoji on purpose. There the icon says what kind of file +// this is, and the colour is doing real work; a wall of identical grey outlines +// would be a worse file list. + +const ICON_PATHS = { + menu: ['M4 7h16M4 12h16M4 17h16'], + bell: ['M18 9a6 6 0 1 0-12 0c0 6-2.5 7.5-2.5 7.5h17S18 15 18 9', + 'M10.3 20a2 2 0 0 0 3.4 0'], + shield: ['M12 3l7.5 3v5.2c0 4.6-3.1 8.6-7.5 10.3-4.4-1.7-7.5-5.7-7.5-10.3V6z'], + globe: ['M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18', + 'M3.4 9.2h17.2M3.4 14.8h17.2', + 'M12 3c-2.6 2.4-4 5.6-4 9s1.4 6.6 4 9c2.6-2.4 4-5.6 4-9s-1.4-6.6-4-9'], + gear: ['M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6', + 'M19.2 14.4a1.7 1.7 0 0 0 .3 1.9 2 2 0 1 1-2.8 2.8 1.7 1.7 0 0 0-2.9 1.2 2 2 0 0 1-4 0 1.7 1.7 0 0 0-2.9-1.2 2 2 0 1 1-2.8-2.8 1.7 1.7 0 0 0-1.2-2.9 2 2 0 0 1 0-4 1.7 1.7 0 0 0 1.2-2.9 2 2 0 1 1 2.8-2.8 1.7 1.7 0 0 0 2.9-1.2 2 2 0 0 1 4 0 1.7 1.7 0 0 0 2.9 1.2 2 2 0 1 1 2.8 2.8 1.7 1.7 0 0 0 1.2 2.9 2 2 0 0 1 0 4 1.7 1.7 0 0 0-1.5 1.1z'], + sun: ['M12 8.2a3.8 3.8 0 1 0 0 7.6 3.8 3.8 0 0 0 0-7.6', + 'M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4'], + moon: ['M20.8 13.4A8.6 8.6 0 1 1 10.6 3.2a6.9 6.9 0 0 0 10.2 10.2z'], + power: ['M12 3.2v8.4', 'M6.9 6.6a7.6 7.6 0 1 0 10.2 0'], + lock: ['M5.5 11h13a1 1 0 0 1 1 1v7.5a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1V12a1 1 0 0 1 1-1z', + 'M8 11V7.4a4 4 0 0 1 8 0V11'], + envelope: ['M4 5.5h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-11a1 1 0 0 1 1-1z', + 'M3.4 6.6L12 13.4l8.6-6.8'], + door: ['M13.5 3.5H6a1 1 0 0 0-1 1v15a1 1 0 0 0 1 1h7.5', + 'M10.5 12H21', 'M17.8 8.8L21 12l-3.2 3.2'], + clip: ['M20.5 11.8l-8.4 8.4a5.4 5.4 0 0 1-7.6-7.6l8.8-8.8a3.6 3.6 0 0 1 5.1 5.1l-8.8 8.8a1.8 1.8 0 0 1-2.5-2.5l8.1-8.1'], + check: ['M4.5 12.5l5 5 10-11'], + chevron: ['M6 9.5l6 6 6-6'], + close: ['M6 6l12 12M18 6L6 18'], +}; + +function Icon({ name, cls = '' }) { + const paths = ICON_PATHS[name]; + if (!paths) return null; + return html` + + `; +} + // ── User Menu ──────────────────────────────────────────────────────────────── function UserMenu({ user, theme, onThemeChange, onLogout }) { @@ -246,7 +295,7 @@ function UserMenu({ user, theme, onThemeChange, onLogout }) { ${open && html`
@@ -259,28 +308,29 @@ function UserMenu({ user, theme, onThemeChange, onLogout }) {
${langOpen && LOCALES.map(l => html` `)}
`} @@ -296,14 +346,15 @@ function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount }