@@ -21,6 +21,8 @@ type PaletteProps = {
2121 open : boolean ;
2222 onClose : ( ) => void ;
2323 anchorRef : RefObject < HTMLElement | null > ;
24+ /** Collapsed sidebar: center the palette instead of morphing from the slot. */
25+ collapsed : boolean ;
2426 dark : boolean ;
2527} ;
2628
@@ -118,10 +120,36 @@ const EXIT_MS = 150;
118120const PROTRUDE_PX = 60 ;
119121/** Sidebar content padding-right; included so width clears the sidebar edge. */
120122const SIDEBAR_PAD_RIGHT = 20 ;
123+ /** Centered (collapsed-sidebar) palette width and viewport insets. */
124+ const CENTERED_WIDTH = 560 ;
125+ const CENTERED_MARGIN = 16 ;
126+ /** Vertical placement as a fraction of viewport height (upper-center). */
127+ const CENTERED_TOP_RATIO = 0.22 ;
121128const CLOSED_HEIGHT = 40 ;
122129/** Wait out rapid ↑/↓ before kicking off a prefetch. */
123130const PREFETCH_DEBOUNCE_MS = 75 ;
124131
132+ type PaletteLayout = {
133+ top : number ;
134+ left : number ;
135+ width : number ;
136+ } ;
137+
138+ function getCenteredLayout (
139+ viewportWidth = window . innerWidth ,
140+ viewportHeight = window . innerHeight
141+ ) : PaletteLayout {
142+ const width = Math . min (
143+ CENTERED_WIDTH ,
144+ Math . max ( 0 , viewportWidth - CENTERED_MARGIN * 2 )
145+ ) ;
146+ return {
147+ width,
148+ left : Math . max ( CENTERED_MARGIN , Math . round ( ( viewportWidth - width ) / 2 ) ) ,
149+ top : Math . round ( viewportHeight * CENTERED_TOP_RATIO ) ,
150+ } ;
151+ }
152+
125153function getPaletteMount ( ) : HTMLElement | null {
126154 const layer = document . getElementById ( 'sep-plus-palette-layer' ) ;
127155 return layer ?. shadowRoot ?. getElementById ( 'sep-plus-palette-mount' ) ?? null ;
@@ -143,7 +171,13 @@ function measureAnchor(
143171 } ;
144172}
145173
146- export function Palette ( { open, onClose, anchorRef, dark } : PaletteProps ) {
174+ export function Palette ( {
175+ open,
176+ onClose,
177+ anchorRef,
178+ collapsed,
179+ dark,
180+ } : PaletteProps ) {
147181 const inputRef = useRef < HTMLInputElement > ( null ) ;
148182 const listRef = useRef < HTMLUListElement > ( null ) ;
149183 const [ query , setQuery ] = useState ( '' ) ;
@@ -157,14 +191,25 @@ export function Palette({ open, onClose, anchorRef, dark }: PaletteProps) {
157191 const [ mounted , setMounted ] = useState ( open ) ;
158192 const [ expanded , setExpanded ] = useState ( false ) ;
159193 const [ anchor , setAnchor ] = useState < AnchorRect | null > ( null ) ;
194+ const [ viewport , setViewport ] = useState ( ( ) => ( {
195+ width : window . innerWidth ,
196+ height : window . innerHeight ,
197+ } ) ) ;
160198
161199 const closing = mounted && ! open ;
200+ // Layout mode is captured when opening so a sidebar toggle mid-session
201+ // (or during close) doesn't jump between centered and anchored geometry.
202+ const collapsedRef = useRef ( collapsed ) ;
203+ collapsedRef . current = collapsed ;
204+ const [ centered , setCentered ] = useState ( collapsed ) ;
162205
163206 useEffect ( ( ) => {
164207 if ( ! open ) {
165208 return ;
166209 }
210+ setCentered ( collapsedRef . current ) ;
167211 setRelated ( collectRelatedEntries ( ) ) ;
212+ setViewport ( { width : window . innerWidth , height : window . innerHeight } ) ;
168213 const next = measureAnchor ( anchorRef ) ;
169214 setAnchor ( next ) ;
170215 setMounted ( true ) ;
@@ -208,6 +253,7 @@ export function Palette({ open, onClose, anchorRef, dark }: PaletteProps) {
208253 }
209254
210255 function onResize ( ) : void {
256+ setViewport ( { width : window . innerWidth , height : window . innerHeight } ) ;
211257 const next = measureAnchor ( anchorRef ) ;
212258 if ( next ) {
213259 setAnchor ( next ) ;
@@ -393,9 +439,15 @@ export function Palette({ open, onClose, anchorRef, dark }: PaletteProps) {
393439 return null ;
394440 }
395441
396- const width = expanded
397- ? anchor . width + SIDEBAR_PAD_RIGHT + PROTRUDE_PX
398- : anchor . width ;
442+ const layout : PaletteLayout = centered
443+ ? getCenteredLayout ( viewport . width , viewport . height )
444+ : {
445+ top : anchor . top ,
446+ left : anchor . left ,
447+ width : expanded
448+ ? anchor . width + SIDEBAR_PAD_RIGHT + PROTRUDE_PX
449+ : anchor . width ,
450+ } ;
399451
400452 return createPortal (
401453 < div
@@ -423,6 +475,7 @@ export function Palette({ open, onClose, anchorRef, dark }: PaletteProps) {
423475 < div
424476 className = { [
425477 'sep-palette-inline' ,
478+ centered ? 'is-centered' : '' ,
426479 expanded ? 'is-open' : '' ,
427480 closing ? 'is-closing' : '' ,
428481 ]
@@ -432,9 +485,9 @@ export function Palette({ open, onClose, anchorRef, dark }: PaletteProps) {
432485 aria-modal = { expanded ? true : undefined }
433486 aria-label = "Search"
434487 style = { {
435- top : anchor . top ,
436- left : anchor . left ,
437- width,
488+ top : layout . top ,
489+ left : layout . left ,
490+ width : layout . width ,
438491 } }
439492 >
440493 < div className = "sep-palette-input-row" >
0 commit comments