Browse Source

mol-plugin: collapse left panel

David Sehnal 5 years ago
parent
commit
a312c4ef1d

+ 1 - 1
src/apps/state-docs/pd-to-md.ts

@@ -38,7 +38,7 @@ function paramInfo(param: PD.Any, offset: number): string {
     }
 }
 
-function oToS(options: [string, string][]) {
+function oToS(options: (readonly [string, string])[]) {
     return options.map(o => `'${o[0]}'`).join(', ');
 }
 

+ 12 - 0
src/mol-plugin/layout.ts

@@ -10,10 +10,22 @@ import { PluginComponent } from './component';
 import { PluginContext } from './context';
 import { PluginCommands } from './command';
 
+const regionStateOptions = [
+    ['full', 'Full'] as const,
+    ['collapsed', 'Collapsed'] as const,
+    ['hidden', 'Hidden'] as const,
+];
 export type PluginLayoutControlsDisplay = 'outside' | 'portrait' | 'landscape' | 'reactive'
 export const PluginLayoutStateParams = {
     isExpanded: PD.Boolean(false),
     showControls: PD.Boolean(true),
+    regionState: PD.Group({
+        left: PD.Select('full', regionStateOptions),
+        // TODO: support other region states
+        // right: PD.Select('full', regionStateOptions),
+        // top: PD.Select('full', regionStateOptions),
+        // bottom: PD.Select('full', regionStateOptions),
+    }),
     controlsDisplay: PD.Value<PluginLayoutControlsDisplay>('outside', { isHidden: true })
 }
 export type PluginLayoutStateProps = PD.Values<typeof PluginLayoutStateParams>

+ 9 - 0
src/mol-plugin/skin/base/layout/controls-landscape.scss

@@ -62,6 +62,15 @@
     }    
 }
 
+.msp-layout-collapse-left {
+    .msp-layout-left {
+        width: $collapsed-left-width; 
+    }
+    .msp-layout-main, .msp-layout-top, .msp-layout-bottom {
+        left: $collapsed-left-width;
+    }    
+}
+
 .msp-layout-hide-bottom {
     .msp-layout-bottom {
         display: none;

+ 10 - 0
src/mol-plugin/skin/base/layout/controls-outside.scss

@@ -67,6 +67,16 @@
     }    
 }
 
+.msp-layout-collapse-left {
+    .msp-layout-left {
+        width: $collapsed-left-width; 
+    }
+    .msp-layout-right {
+        left: $collapsed-left-width;
+        width: auto;
+    }    
+}
+
 ///////////////////////////////////
 .msp-layout-hide-top {
     .msp-layout-top {

+ 10 - 0
src/mol-plugin/skin/base/layout/controls-portrait.scss

@@ -71,6 +71,16 @@
     }
 }
 
+.msp-layout-collapse-left {
+    .msp-layout-left {
+        width: $collapsed-left-width; 
+    }
+    .msp-layout-right {
+        left: $collapsed-left-width;
+        width: auto;
+    }    
+}
+
 ///////////////////////////////////
 .msp-layout-hide-top {
     .msp-layout-top {

+ 2 - 0
src/mol-plugin/skin/base/variables.scss

@@ -15,6 +15,8 @@ $expanded-bottom-height: 3 * $row-height + 2;
 $expanded-right-width:   300px;
 $expanded-left-width:    330px;
 
+$collapsed-left-width:   $row-height;
+
 $expanded-portrait-bottom-height: 10 * ($row-height + 1) + 3 * $control-spacing + 1;
 $expanded-portrait-top-height:    3 * $row-height + 1;
 

+ 19 - 7
src/mol-plugin/ui/left-panel.tsx

@@ -16,24 +16,36 @@ import { Canvas3DParams } from '../../mol-canvas3d/canvas3d';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { StateSnapshots } from './state/snapshots';
 
-type TabName = 'root' | 'data' | 'behavior' | 'states' | 'viewport-settings'
+type TabName = 'none' | 'root' | 'data' | 'behavior' | 'states' | 'viewport-settings'
 
-export class LeftPanelControls extends PluginUIComponent<{}, { currentTab: TabName }> {
-    state = { currentTab: 'data' as TabName };
+export class LeftPanelControls extends PluginUIComponent<{}, { tab: TabName }> {
+    state = { tab: 'data' as TabName };
 
     componentDidMount() {
         // this.subscribe(this.plugin.state.behavior.kind, () => this.forceUpdate());
     }
 
-    set(kind: TabName) {
-        switch (kind) {
+    set(tab: TabName) {
+        if (this.state.tab === tab) {
+            this.setState({ tab: 'none' });
+            PluginCommands.Layout.Update.dispatch(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'collapsed' } } });
+            return;
+        }
+
+
+        switch (tab) {
             case 'data': this.plugin.state.setKind('data'); break;
             case 'behavior': this.plugin.state.setKind('behavior'); break;
         }
-        this.setState({ currentTab: kind });
+
+        this.setState({ tab });
+        if (this.plugin.layout.state.regionState.left !== 'full') {
+            PluginCommands.Layout.Update.dispatch(this.plugin, { state: { regionState: { ...this.plugin.layout.state.regionState, left: 'full' } } });
+        }
     }
 
     tabs: { [K in TabName]: JSX.Element } = {
+        'none': <></>,
         'root': <>
             <SectionHeader icon='home' title='Home' />
             <StateObjectActions state={this.plugin.state.dataState} nodeRef={StateTransform.RootRef} hideHeader={true} initiallyCollapsed={true} alwaysExpandFirst={true} />
@@ -54,7 +66,7 @@ export class LeftPanelControls extends PluginUIComponent<{}, { currentTab: TabNa
     }
 
     render() {
-        const tab = this.state.currentTab;
+        const tab = this.state.tab;
 
         return <div className='msp-left-panel-controls'>
             <div className='msp-left-panel-controls-buttons'>

+ 7 - 1
src/mol-plugin/ui/plugin.tsx

@@ -72,9 +72,15 @@ class Layout extends PluginUIComponent {
         if (controls.top === 'none' || !layout.showControls) {
             classList.push('msp-layout-hide-top')
         }
-        if (controls.left === 'none' || !layout.showControls) {
+
+        if (controls.left === 'none' || !layout.showControls || layout.regionState.left === 'hidden') {
             classList.push('msp-layout-hide-left')
         }
+
+        if (layout.regionState.left === 'collapsed') {
+            classList.push('msp-layout-collapse-left')
+        }
+
         if (controls.right === 'none' || !layout.showControls) {
             classList.push('msp-layout-hide-right')
         }

+ 3 - 3
src/mol-util/param-definition.ts

@@ -65,9 +65,9 @@ export namespace ParamDefinition {
     export interface Select<T extends string | number> extends Base<T> {
         type: 'select'
         /** array of (value, label) tuples */
-        options: [T, string][]
+        options: (readonly [T, string])[]
     }
-    export function Select<T extends string | number>(defaultValue: T, options: [T, string][], info?: Info): Select<T> {
+    export function Select<T extends string | number>(defaultValue: T, options: (readonly [T, string])[], info?: Info): Select<T> {
         return setInfo<Select<T>>({ type: 'select', defaultValue: checkDefaultKey(defaultValue, options), options }, info)
     }
 
@@ -363,7 +363,7 @@ export namespace ParamDefinition {
         return false;
     }
 
-    function checkDefaultKey<T>(k: T, options: [T, string][]) {
+    function checkDefaultKey<T>(k: T, options: (readonly [T, string])[]) {
         for (const o of options) {
             if (o[0] === k) return k;
         }