diff --git a/packages/client/ui-settings-general/src/client/SettingsRoot.module.css b/packages/client/ui-settings-general/src/client/SettingsRoot.module.css index 060e8d115b..03e0f6372c 100644 --- a/packages/client/ui-settings-general/src/client/SettingsRoot.module.css +++ b/packages/client/ui-settings-general/src/client/SettingsRoot.module.css @@ -1,19 +1,19 @@ /* Settings shell (figma 501:29904 mask context / 501:29947 panel): sidebar foot trigger row + centered 1080x700 modal panel. The trigger uses the - sidebar's 34px compact row / 36px rail circle rhythm; the + sidebar foot's 42px row / 36px rail circle rhythm; the panel is a two-column layout — 188px nav rail + content column with a 54px header and the 24px-padded options area. */ -/* Trigger row: match the other wide sidebar controls' compact vertical rhythm. */ +/* Trigger row: the 42px foot-row box shared with the Cordis footer action. */ .trigger { flex: none; display: flex; align-items: center; gap: 8px; - width: calc(100% + 8px); - height: 34px; - margin: 4px -4px 4px; - padding: 6px 2px 6px 10px; + width: calc(100% + 4px); + height: 42px; + margin: 4px -2px; + padding: 0 10px 0 8px; box-sizing: border-box; border: none; border-radius: 12px; diff --git a/packages/extensions/ui-cordis/src/client/CordisPanel.module.css b/packages/extensions/ui-cordis/src/client/CordisPanel.module.css index bf72bfecec..1a10f07ee3 100644 --- a/packages/extensions/ui-cordis/src/client/CordisPanel.module.css +++ b/packages/extensions/ui-cordis/src/client/CordisPanel.module.css @@ -6,7 +6,7 @@ display: flex; align-items: center; width: 100%; - height: 49px; + height: 42px; margin: 8px 0 0; } @@ -20,9 +20,10 @@ display: inline-flex; align-items: center; gap: 8px; - width: 100%; - height: 49px; - padding: 0 8px 0 6px; + width: calc(100% + 4px); + height: 42px; + margin: 0 -2px; + padding: 0 10px 0 8px; border: none; border-radius: 12px; background: transparent; @@ -34,7 +35,7 @@ } .badge:hover { - background: var(--dsw-alias-interactive-bg-hover-solid); + background: var(--dsw-alias-interactive-bg-hover); } .badge[data-active] { @@ -77,10 +78,10 @@ gap: 2px; } +/* Fixed so the sidebar's overflow clip cannot cut the 420px surface; the + left/bottom offsets are measured from the trigger before paint. */ .panel { position: fixed; - left: 12px; - bottom: 128px; z-index: 30; display: flex; flex-direction: column; @@ -88,10 +89,10 @@ max-width: calc(100vw - 24px); max-height: 60vh; overflow: hidden; - border: 1px solid var(--dsw-alias-border-l1); + border: 1px solid var(--dsw-alias-border-inverted); border-radius: 12px; - background: var(--dsw-alias-bg-base); - box-shadow: var(--dsw-shadow-lv2); + background: var(--dsw-specific-menu); + box-shadow: var(--dsw-shadow-lv3); /* Only `.body` scrolls; the header remains fixed above it. */ --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2); --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2); @@ -105,19 +106,17 @@ min-height: 44px; padding: 10px 12px; box-sizing: border-box; - border-bottom: 1px solid var(--dsw-alias-border-l2); - background: var(--dsw-alias-bg-base); } .body { flex: 1; min-height: 0; overflow-y: auto; - padding: 4px 12px 12px; + padding: 0 12px 12px; } .title { - font-size: 13px; + font-size: 14px; font-weight: 500; line-height: 20px; color: var(--dsw-alias-label-primary); @@ -137,7 +136,7 @@ /* Session headings replace per-row ownership markers. */ .group { - margin: 8px 0 4px; + margin: 8px 0 8px; font-size: 11px; font-weight: 500; line-height: 16px; @@ -159,10 +158,9 @@ display: flex; flex-direction: column; gap: 8px; - padding: 10px 12px; + padding: 14px 12px 10px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; - background: var(--dsw-alias-bg-base); } .row[data-cordis-awaiting] { @@ -252,7 +250,7 @@ padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 7px; - background: var(--dsw-alias-bg-base); + background: transparent; color: var(--dsw-alias-label-secondary); font: inherit; } diff --git a/packages/extensions/ui-cordis/src/client/CordisPanel.tsx b/packages/extensions/ui-cordis/src/client/CordisPanel.tsx index 946e9d9dfa..42f1586dae 100644 --- a/packages/extensions/ui-cordis/src/client/CordisPanel.tsx +++ b/packages/extensions/ui-cordis/src/client/CordisPanel.tsx @@ -1,6 +1,6 @@ /** Frame-wide dynamic Plugin inventory, approvals, versions, and lifecycle actions. */ -import { useEffect, useRef, useState } from 'react' +import { useEffect, useLayoutEffect, useRef, useState } from 'react' import type { ButtonHTMLAttributes, ReactNode } from 'react' import { IconCheckOutline16, IconCloseOutline16, IconCordisPluginOutline14, IconPlayOutline16, @@ -119,6 +119,34 @@ export function CordisPanel({ const [pending, setPending] = useState>(new Set()) const [actionErrors, setActionErrors] = useState>(new Map()) const visibleRequests = useRef>(new Set()) + const rootRef = useRef(null) + const [anchor, setAnchor] = useState<{ left: number; bottom: number }>() + + // The panel is position: fixed (the sidebar clips overflow), so it hugs the + // trigger through a measured offset instead of document flow. + useLayoutEffect(() => { + if (!open) return + const place = (): void => { + const rect = rootRef.current?.getBoundingClientRect() + if (rect !== undefined) { + setAnchor({ left: rect.left, bottom: window.innerHeight - rect.top + 8 }) + } + } + place() + window.addEventListener('resize', place) + return () => { window.removeEventListener('resize', place) } + }, [open]) + + useEffect(() => { + if (!open) return + const closeOutside = (event: PointerEvent): void => { + if (event.target instanceof Node && !rootRef.current?.contains(event.target)) { + setOpen(false) + } + } + document.addEventListener('pointerdown', closeOutside) + return () => { document.removeEventListener('pointerdown', closeOutside) } + }, [open]) useEffect(() => { const now = new Set() @@ -420,9 +448,9 @@ export function CordisPanel({ } return ( -
- {open && ( -
+
+ {open && anchor !== undefined && ( +
{t('panel.title')}
@@ -458,7 +486,7 @@ export function CordisPanel({ aria-expanded={open} onClick={() => { setOpen(value => !value) }} > - + {wide && ( <> {t('panel.trigger')}