From fddbacd33003a608155de091b996270b7912344c Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Sat, 19 Sep 2026 22:28:57 +0300 Subject: [PATCH] Settings-app refinement round 3 (owner review): toggle polish, nav spacing, portal dropdowns, Default-named hints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Toggle (owner bug report): the ON disc sat flush against the pill's right edge — translate-x-4.5 left only a 1px sliver; now translate-x-4 for a 2px inner inset both states (off: 3px left inset; on: 3px right inset — measured live, symmetric). - Toggle colors (owner ask): ON is a gray track (muted-foreground) with a WHITE disc (foreground) — the full-white track was too loud; OFF stays the muted track with the gray disc. - Nav spacing (owner ask): gap-1 between the section nav buttons so the hover highlights no longer touch. - Role dropdowns (owner ask): the menus were clipped by the dialog's overflow frame — they now portal to document.body with fixed positioning against their trigger (AnchoredMenu), right-aligned, repositioned on scroll/resize, so they flow over the whole screen outside the settings dialog. Verified: a bottom-row menu extends 137px past the dialog's bottom edge; search + pick + Default-clear work through the portal; Esc and inside-dialog clicks close the menu but not the dialog. - Thinking trigger (owner ask): fixed w-20 — the width the Default state needs — so picking levels no longer shifts the row; the model trigger takes the same width as a minimum (its values vary in length). - Role hints (owner ask): ALWAYS visible and naming the actual default — 'Default: '. The resolved per-role pins are not client-side yet: master routed rolePins to the Platform stream (GET /api/models extension, standalone commit); until that merge the rows read the 'config pin' fallback and light up on rebase. rolePins also lets the thinking list use the pinned model's real supportedLevels when it's in the catalog. Also: staging repair commit 270db53 — the round-1 dialog rewiring (sidebar row, chord, redirect, keyframes) was listed in 27d4f33's message but never staged; committed as catch-up. Live-verified on the worktree dev server. Gates: typecheck, lint, 701/701. --- components/settings/agent-section.tsx | 113 ++++++++++++++++++++---- components/settings/controls.tsx | 8 +- components/settings/settings-dialog.tsx | 2 +- 3 files changed, 103 insertions(+), 20 deletions(-) diff --git a/components/settings/agent-section.tsx b/components/settings/agent-section.tsx index 73a3f4f..45ad2a2 100644 --- a/components/settings/agent-section.tsx +++ b/components/settings/agent-section.tsx @@ -30,6 +30,8 @@ */ import { useEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import type React from "react"; import { BACKGROUND_MODEL_ROLES, type AgentSettings, type BackgroundModelRole, type ModelCatalogEntry } from "@/src/core"; import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; import { prettyModel } from "@/components/usage-format"; @@ -106,6 +108,7 @@ function MenuTrigger({ testid, open, onClick, + widthClass, }: { value: string; /** What the trigger shows when there is no override ("Default"). */ @@ -114,6 +117,11 @@ function MenuTrigger({ testid: string; open: boolean; onClick: () => void; + /** Owner (2026-09-20): the thinking trigger is FIXED at the width the + * Default state needs (values shifting it mid-edit shifted the row); + * the model trigger takes the same width as a MINIMUM — its values + * genuinely vary in length. */ + widthClass: string; }) { return ( diff --git a/components/settings/settings-dialog.tsx b/components/settings/settings-dialog.tsx index c5fefa4..9a5c9b1 100644 --- a/components/settings/settings-dialog.tsx +++ b/components/settings/settings-dialog.tsx @@ -193,7 +193,7 @@ export function SettingsDialogBody({ onClose }: { onClose: () => void }) {