icons: restore inline-SVG link/gear icons, share them across all three pages
Fixes a regression + a longer-standing inconsistency (mara: "agent
page link icons is different from swarm ui, settings icon looks weird
since component extract").
- The `SettingsMenu` shared-component extraction swapped swarm-ui's
original inline-SVG gear trigger for a plain `⚙` text glyph (matching
agent's `MetaNav`, which was itself still on the `🔗` emoji at the
time). An emoji/text glyph is rendered by the OS/browser's own font
at that font's fixed metrics — it can never match a neighbouring
icon in size or weight, and some codepoints (the gear included)
aren't even reliably covered by every font.
- New `@hive/shared/icons.js` (`GearIcon`, `LinkIcon`) — the exact SVG
markup that used to live only in swarm-ui's `SettingsMenu`/
`LinksMenu` as two separate inline copies, now the one shared source.
- `SettingsMenu` (shared) uses `GearIcon`; agent's `MetaNav` and
swarm-ui's `LinksMenu` both use `LinkIcon` — three consumers, one
rendering path, matching stroke/viewBox/size everywhere.
Verified with real screenshots on both agent and swarm-ui — both
trigger icons render as the same crisp line-icon style now.
This commit is contained in:
parent
350b4e9fb7
commit
4175ae86e3
5 changed files with 84 additions and 27 deletions
|
|
@ -1,5 +1,10 @@
|
|||
// <MetaNav> — the header's meta-nav trigger: a single fixed-size Badge
|
||||
// ("🔗") in the pills cluster that opens a popover listing
|
||||
// (`@hive/shared/icons.js`'s `LinkIcon` — an emoji glyph here can't
|
||||
// match a neighbouring icon's size/weight on any platform, see that
|
||||
// file's comment; mara: "agent page link icons is different from
|
||||
// swarm ui" was this trigger still on the old `🔗` emoji after
|
||||
// swarm-ui's own link trigger had already moved to the SVG) in the
|
||||
// pills cluster that opens a popover listing
|
||||
// stats/screen/forge/config + any `hyperhive.dashboardLinks` extras,
|
||||
// sourced from the backend's `agent_links()` (the single source of
|
||||
// truth — same list also feeds the dashboard card's icon strip) — plus
|
||||
|
|
@ -25,6 +30,7 @@
|
|||
// `LoginFlow`'s `.login-card` already made for the same reason.
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { Badge } from '@hive/shared/badge.js';
|
||||
import { LinkIcon } from '@hive/shared/icons.js';
|
||||
import type { AgentLink } from '../types.js';
|
||||
import './MetaNav.css';
|
||||
|
||||
|
|
@ -67,7 +73,7 @@ export function MetaNav({ links, forgePublicUrl, dashboardBase }: MetaNavProps)
|
|||
|
||||
return (
|
||||
<div class="meta-nav-anchor" ref={rootRef}>
|
||||
<Badge value="🔗" title="agent links" onClick={() => setOpen((o) => !o)} expanded={open} />
|
||||
<Badge value={<LinkIcon />} title="agent links" onClick={() => setOpen((o) => !o)} expanded={open} />
|
||||
{open ? (
|
||||
<div class="meta-nav-popover" role="menu" aria-label="agent links">
|
||||
<a
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
"./badge.css": "./src/badge/Badge.css",
|
||||
"./dropdown.js": "./src/dropdown/Dropdown.tsx",
|
||||
"./dropdown.css": "./src/dropdown/Dropdown.css",
|
||||
"./icons.js": "./src/icons.tsx",
|
||||
"./settings-storage.js": "./src/settings/settings-storage.ts",
|
||||
"./theme-apply.js": "./src/settings/theme-apply.ts",
|
||||
"./motion-apply.js": "./src/settings/motion-apply.ts",
|
||||
|
|
|
|||
58
frontend/packages/shared/src/icons.tsx
Normal file
58
frontend/packages/shared/src/icons.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Small inline-SVG icons shared across pages — deliberately NOT emoji
|
||||
// glyphs for a trigger button's own icon. mara, live, on swarm-ui's
|
||||
// original links/settings buttons: "links and settings icon styles
|
||||
// different / all different sizes" — an emoji glyph renders via the
|
||||
// OS/browser's colour-emoji font at that font's own fixed metrics,
|
||||
// ignoring `font-size`/`color`, so it can never match a neighbouring
|
||||
// icon in size or weight on any platform (and some codepoints, like the
|
||||
// gear `⚙`, aren't even reliably covered by every font — showing as a
|
||||
// missing-glyph box or an oddly-weighted fallback depending on what's
|
||||
// installed). Same `stroke`/`viewBox`/size shape for every icon here so
|
||||
// they read as one rendering path wherever they're mounted — Feather/
|
||||
// lucide-style line icons, `currentColor` stroke so they pick up
|
||||
// whatever text colour the surrounding `Badge`/button already has.
|
||||
//
|
||||
// Originated in swarm-ui's `shell/SettingsMenu.tsx` (gear) and
|
||||
// `shell/LinksMenu.tsx` (link chain) as separate inline copies; moved
|
||||
// here once the agent page's `MetaNav`/`SettingsMenu` needed the exact
|
||||
// same icons too (mara: the settings trigger went back to a text glyph
|
||||
// when `SettingsMenu` was extracted into `@hive/shared`, undoing this
|
||||
// fix — restoring the SVG here, in the shared component this time,
|
||||
// fixes it for both pages at once instead of just one).
|
||||
export function GearIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="1.3em"
|
||||
height="1.3em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function LinkIcon() {
|
||||
return (
|
||||
<svg
|
||||
width="1.3em"
|
||||
height="1.3em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,6 +14,14 @@
|
|||
// visual language for that package either), motion included
|
||||
// unconditionally rather than agent-only.
|
||||
//
|
||||
// That first merge swapped the trigger's icon from swarm-ui's original
|
||||
// inline SVG gear to a plain `⚙` text glyph (matching `MetaNav`'s own
|
||||
// `value="🔗"` emoji at the time) — mara caught it: "settings icon
|
||||
// looks weird since component extract". `../icons.js`'s `GearIcon` is
|
||||
// swarm-ui's original SVG, restored here so both pages get the crisp
|
||||
// version now instead of just one — see that file's comment for why a
|
||||
// text/emoji glyph is the wrong tool for a trigger's own icon.
|
||||
//
|
||||
// Storage keys are the caller's responsibility (`themeKey`/`motionKey`
|
||||
// props), not derived here — a page mounts `useApplyThemeOverride`/
|
||||
// `useApplyMotionOverride` (`./theme-apply.js`/`./motion-apply.js`)
|
||||
|
|
@ -22,6 +30,7 @@
|
|||
// page-specific naming decision.
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { Badge } from '../badge/Badge.js';
|
||||
import { GearIcon } from '../icons.js';
|
||||
import { useThemeOverride, type ThemeOverride } from './theme-apply.js';
|
||||
import { useMotionOverride, type MotionOverride } from './motion-apply.js';
|
||||
import './SettingsMenu.css';
|
||||
|
|
@ -59,7 +68,7 @@ export function SettingsMenu({ themeKey, motionKey }: SettingsMenuProps) {
|
|||
|
||||
return (
|
||||
<div class="settings-menu-anchor" ref={rootRef}>
|
||||
<Badge value="⚙" title="settings" onClick={() => setOpen((v) => !v)} expanded={open} />
|
||||
<Badge value={<GearIcon />} title="settings" onClick={() => setOpen((v) => !v)} expanded={open} />
|
||||
{open ? (
|
||||
<div class="settings-menu-popover" role="menu" aria-label="settings">
|
||||
<label class="settings-menu-row">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// render a dead affordance" rule the old dashboard's H0M3 tiles follow
|
||||
// for Forge/Matrix.
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { LinkIcon } from '@hive/shared/icons.js';
|
||||
import './LinksMenu.css';
|
||||
|
||||
interface ServiceLink {
|
||||
|
|
@ -62,30 +63,12 @@ export function LinksMenu() {
|
|||
aria-label="swarm services"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
>
|
||||
{/* Feather/lucide "link" glyph, not the 🔗 emoji this replaced —
|
||||
reported live by mara: "links and settings icon styles
|
||||
different / all different sizes". An emoji glyph is rendered
|
||||
by the
|
||||
OS/browser's colour-emoji font at that font's own fixed
|
||||
metrics, ignoring `font-size`/`color` — it can never match a
|
||||
neighbouring text-style icon (SettingsMenu's `⚙`) in size or
|
||||
weight, on any platform. Same inline-SVG shape as
|
||||
SettingsMenu's gear now uses, so both trigger buttons finally
|
||||
share one rendering path (stroke, viewBox, size). */}
|
||||
<svg
|
||||
width="1.3em"
|
||||
height="1.3em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
||||
</svg>
|
||||
{/* `@hive/shared/icons.js`'s `LinkIcon` — reported live by mara:
|
||||
"links and settings icon styles different / all different
|
||||
sizes". Now shared with `SettingsMenu`'s `GearIcon` and
|
||||
agent's own `MetaNav` trigger, one rendering path instead of
|
||||
three separate inline copies — see that file's comment. */}
|
||||
<LinkIcon />
|
||||
</button>
|
||||
{open ? (
|
||||
<div class="links-menu-popover" role="menu">
|
||||
|
|
|
|||
Loading…
Reference in a new issue