47 lines
3.6 KiB
TypeScript
47 lines
3.6 KiB
TypeScript
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
|
|
|
// Widths stay in effect while switching projects, tabs, and collapsed panels.
|
|
export function installSidebarResize(editor: monaco.editor.IStandaloneCodeEditor) {
|
|
const main = document.querySelector('main')!;
|
|
const left = main.querySelector('aside')!;
|
|
const right = document.getElementById('explanation-pane')!;
|
|
const handles: { side: 'left' | 'right'; panel: HTMLElement; handle: HTMLDivElement }[] = [];
|
|
function limits(side: 'left' | 'right') {
|
|
const overlay = window.innerWidth <= 1100 || right.classList.contains('graph-expanded');
|
|
const other = side === 'left' ? (right.hidden || overlay ? 0 : right.getBoundingClientRect().width) : (overlay ? 0 : left.getBoundingClientRect().width);
|
|
return { min: side === 'left' ? 180 : 300, max: Math.max(side === 'left' ? 180 : 300, Math.min(side === 'left' ? 650 : 1100, main.clientWidth - other - (overlay && side === 'right' ? 40 : 280))) };
|
|
}
|
|
function widthProperty(side: 'left' | 'right') { return side === 'right' && right.classList.contains('graph-expanded') ? '--expanded-sidebar-width' : `--${side}-sidebar-width`; }
|
|
function setWidth(side: 'left' | 'right', width: number) {
|
|
const {min,max} = limits(side);
|
|
document.documentElement.style.setProperty(widthProperty(side), `${Math.round(Math.max(min,Math.min(max,width)))}px`);
|
|
editor.layout(); update();
|
|
}
|
|
function update() {
|
|
for (const {side,panel,handle} of handles) {
|
|
const {min,max}=limits(side);
|
|
handle.setAttribute('aria-valuemin',String(min));handle.setAttribute('aria-valuemax',String(Math.round(max)));
|
|
handle.setAttribute('aria-valuenow',String(Math.round(panel.getBoundingClientRect().width)));
|
|
}
|
|
}
|
|
for (const [side,panel] of [['left',left],['right',right]] as const) {
|
|
const handle = document.createElement('div');handle.className=`sidebar-resizer ${side}-resizer`;handle.tabIndex=0;
|
|
handle.setAttribute('role','separator');handle.setAttribute('aria-orientation','vertical');
|
|
handle.setAttribute('aria-label',`Resize ${side} sidebar`);handle.title='Drag to resize · arrow keys adjust · double-click to reset';
|
|
panel.append(handle);handles.push({side,panel,handle});
|
|
let drag: {x:number;width:number} | null=null;
|
|
handle.onpointerdown=event=>{if(event.button)return;event.preventDefault();drag={x:event.clientX,width:panel.getBoundingClientRect().width};handle.setPointerCapture(event.pointerId);document.body.classList.add('resizing-sidebars');};
|
|
handle.onpointermove=event=>{if(drag)setWidth(side,drag.width+(event.clientX-drag.x)*(side==='left'?1:-1));};
|
|
const stop=()=>{drag=null;document.body.classList.remove('resizing-sidebars');};
|
|
handle.onpointerup=handle.onpointercancel=handle.onlostpointercapture=stop;
|
|
handle.ondblclick=()=>{document.documentElement.style.removeProperty(widthProperty(side));editor.layout();update();};
|
|
handle.onkeydown=event=>{
|
|
if(event.key==='ArrowLeft'||event.key==='ArrowRight') {event.preventDefault();const direction=(event.key==='ArrowRight'?1:-1)*(side==='left'?1:-1);setWidth(side,panel.getBoundingClientRect().width+direction*(event.shiftKey?50:10));}
|
|
else if(event.key==='Home'||event.key==='End') {event.preventDefault();const range=limits(side);setWidth(side,event.key==='Home'?range.min:range.max);}
|
|
};
|
|
}
|
|
const observer=new ResizeObserver(update);observer.observe(left);observer.observe(right);
|
|
window.addEventListener('resize',()=>{for(const {side,panel} of handles) if(!panel.hidden && document.documentElement.style.getPropertyValue(widthProperty(side))) setWidth(side,panel.getBoundingClientRect().width);});
|
|
update();
|
|
}
|