mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
cleanup Draggable into ResizingAnchor (#989)
* Rename `Draggable` as `ResizingAnchor` since that is what it is used for and shouldn't be mistaken as a general draggable item * Refactor `ResizingAnchor` to be much more smart about how it handles mouse movements. Allow it to know which direction the resizing should be in allowing it to produce exact resized values. * Add event handlers for the min and max extents so that actions can be triggered when those extents are passed (in either direction) * Add double click support Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
135282da91
commit
9ecfeb316c
11 files changed
+376
-209
No files matched your search
@@ -14,10 +14,6 @@
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
|
||||
> .resizer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,24 +61,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.resizer {
|
||||
$height: 12px;
|
||||
|
||||
position: absolute;
|
||||
top: -$height / 2;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
height: $height;
|
||||
cursor: row-resize;
|
||||
z-index: 10;
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.AceEditor {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ export class DockStore {
|
||||
];
|
||||
|
||||
protected storage = createStorage("dock", {}); // keep settings in localStorage
|
||||
public defaultTabId = this.initialTabs[0].id;
|
||||
public minHeight = 100;
|
||||
public readonly defaultTabId = this.initialTabs[0].id;
|
||||
public readonly minHeight = 100;
|
||||
|
||||
@observable isOpen = false;
|
||||
@observable fullSize = false;
|
||||
@@ -45,11 +45,12 @@ export class DockStore {
|
||||
}
|
||||
|
||||
get maxHeight() {
|
||||
const mainLayoutHeader = 40;
|
||||
const mainLayoutTabs = 33;
|
||||
const mainLayoutMargin = 16;
|
||||
const dockTabs = 33;
|
||||
return window.innerHeight - mainLayoutHeader - mainLayoutTabs - mainLayoutMargin - dockTabs;
|
||||
const mainLayoutHeader = 40
|
||||
const mainLayoutTabs = 33
|
||||
const mainLayoutMargin = 16
|
||||
const dockTabs = 33
|
||||
const preferedMax = window.innerHeight - mainLayoutHeader - mainLayoutTabs - mainLayoutMargin - dockTabs
|
||||
return Math.max(preferedMax, this.minHeight) // don't let max < min
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@@ -65,7 +66,6 @@ export class DockStore {
|
||||
});
|
||||
|
||||
// adjust terminal height if window size changes
|
||||
this.checkMaxHeight();
|
||||
window.addEventListener("resize", throttle(this.checkMaxHeight, 250));
|
||||
}
|
||||
|
||||
@@ -171,20 +171,19 @@ export class DockStore {
|
||||
|
||||
@action
|
||||
selectTab(tabId: TabId) {
|
||||
const tab = this.getTabById(tabId);
|
||||
this.selectedTabId = tab ? tab.id : null;
|
||||
this.selectedTabId = this.getTabById(tabId)?.id ?? null;
|
||||
}
|
||||
|
||||
@action
|
||||
setHeight(height: number) {
|
||||
this.height = Math.max(0, Math.min(height, this.maxHeight));
|
||||
setHeight(height?: number) {
|
||||
this.height = Math.max(this.minHeight, Math.min(height || this.minHeight, this.maxHeight));
|
||||
}
|
||||
|
||||
@action
|
||||
reset() {
|
||||
this.selectedTabId = this.defaultTabId;
|
||||
this.tabs.replace(this.initialTabs);
|
||||
this.height = this.defaultHeight;
|
||||
this.setHeight(this.defaultHeight);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { Fragment } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Trans } from "@lingui/macro";
|
||||
import { autobind, cssNames, prevDefault } from "../../utils";
|
||||
import { Draggable, DraggableState } from "../draggable";
|
||||
import { ResizingAnchor, ResizeDirection } from "../resizing-anchor";
|
||||
import { Icon } from "../icon";
|
||||
import { Tabs } from "../tabs/tabs";
|
||||
import { MenuItem } from "../menu";
|
||||
@@ -29,28 +29,8 @@ interface Props {
|
||||
|
||||
@observer
|
||||
export class Dock extends React.Component<Props> {
|
||||
onResizeStart = () => {
|
||||
const { isOpen, open, setHeight, minHeight } = dockStore;
|
||||
if (!isOpen) {
|
||||
open();
|
||||
setHeight(minHeight);
|
||||
}
|
||||
}
|
||||
|
||||
onResize = ({ offsetY }: DraggableState) => {
|
||||
const { isOpen, close, height, setHeight, minHeight, defaultHeight } = dockStore;
|
||||
const newHeight = height + offsetY;
|
||||
if (height > newHeight && newHeight < minHeight) {
|
||||
setHeight(defaultHeight);
|
||||
close();
|
||||
}
|
||||
else if (isOpen) {
|
||||
setHeight(newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
onKeydown = (evt: React.KeyboardEvent<HTMLElement>) => {
|
||||
const { close, closeTab, selectedTab, fullSize, toggleFillSize } = dockStore;
|
||||
const { close, closeTab, selectedTab } = dockStore;
|
||||
if (!selectedTab) return;
|
||||
const { code, ctrlKey, shiftKey } = evt.nativeEvent;
|
||||
if (shiftKey && code === "Escape") {
|
||||
@@ -71,13 +51,13 @@ export class Dock extends React.Component<Props> {
|
||||
@autobind()
|
||||
renderTab(tab: IDockTab) {
|
||||
if (isTerminalTab(tab)) {
|
||||
return <TerminalTab value={tab}/>
|
||||
return <TerminalTab value={tab} />
|
||||
}
|
||||
if (isCreateResourceTab(tab) || isEditResourceTab(tab)) {
|
||||
return <DockTab value={tab} icon="edit"/>
|
||||
return <DockTab value={tab} icon="edit" />
|
||||
}
|
||||
if (isInstallChartTab(tab) || isUpgradeChartTab(tab)) {
|
||||
return <DockTab value={tab} icon={<Icon svg="install"/>}/>
|
||||
return <DockTab value={tab} icon={<Icon svg="install" />} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +66,11 @@ export class Dock extends React.Component<Props> {
|
||||
if (!isOpen || !tab) return;
|
||||
return (
|
||||
<div className="tab-content" style={{ flexBasis: height }}>
|
||||
{isCreateResourceTab(tab) && <CreateResource tab={tab}/>}
|
||||
{isEditResourceTab(tab) && <EditResource tab={tab}/>}
|
||||
{isInstallChartTab(tab) && <InstallChart tab={tab}/>}
|
||||
{isUpgradeChartTab(tab) && <UpgradeChart tab={tab}/>}
|
||||
{isTerminalTab(tab) && <TerminalWindow tab={tab}/>}
|
||||
{isCreateResourceTab(tab) && <CreateResource tab={tab} />}
|
||||
{isEditResourceTab(tab) && <EditResource tab={tab} />}
|
||||
{isInstallChartTab(tab) && <InstallChart tab={tab} />}
|
||||
{isUpgradeChartTab(tab) && <UpgradeChart tab={tab} />}
|
||||
{isTerminalTab(tab) && <TerminalWindow tab={tab} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -104,11 +84,16 @@ export class Dock extends React.Component<Props> {
|
||||
onKeyDown={this.onKeydown}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<Draggable
|
||||
className={cssNames("resizer", { disabled: !hasTabs() })}
|
||||
horizontal={false}
|
||||
onStart={this.onResizeStart}
|
||||
onEnter={this.onResize}
|
||||
<ResizingAnchor
|
||||
disabled={!hasTabs()}
|
||||
getCurrentExtent={() => dockStore.height}
|
||||
minExtent={dockStore.minHeight}
|
||||
maxExtent={dockStore.maxHeight}
|
||||
direction={ResizeDirection.VERTICAL}
|
||||
onStart={dockStore.open}
|
||||
onMinExtentSubceed={dockStore.close}
|
||||
onMinExtentExceed={dockStore.open}
|
||||
onDrag={dockStore.setHeight}
|
||||
/>
|
||||
<div className="tabs-container flex align-center" onDoubleClick={prevDefault(toggle)}>
|
||||
<Tabs
|
||||
@@ -121,11 +106,11 @@ export class Dock extends React.Component<Props> {
|
||||
<div className="dock-menu box grow">
|
||||
<MenuActions usePortal triggerIcon={{ material: "add", className: "new-dock-tab", tooltip: <Trans>New tab</Trans> }} closeOnScroll={false}>
|
||||
<MenuItem className="create-terminal-tab" onClick={() => createTerminalTab()}>
|
||||
<Icon small svg="terminal" size={15}/>
|
||||
<Icon small svg="terminal" size={15} />
|
||||
<Trans>Terminal session</Trans>
|
||||
</MenuItem>
|
||||
<MenuItem className="create-resource-tab" onClick={() => createResourceTab()}>
|
||||
<Icon small material="create"/>
|
||||
<Icon small material="create" />
|
||||
<Trans>Create resource</Trans>
|
||||
</MenuItem>
|
||||
</MenuActions>
|
||||
@@ -133,7 +118,7 @@ export class Dock extends React.Component<Props> {
|
||||
{hasTabs() && (
|
||||
<>
|
||||
<Icon
|
||||
material={fullSize ? "fullscreen_exit": "fullscreen"}
|
||||
material={fullSize ? "fullscreen_exit" : "fullscreen"}
|
||||
tooltip={fullSize ? <Trans>Exit full size mode</Trans> : <Trans>Fit to window</Trans>}
|
||||
onClick={toggleFillSize}
|
||||
/>
|
||||
|
||||
@@ -121,6 +121,8 @@ export class Terminal {
|
||||
}
|
||||
|
||||
fit = () => {
|
||||
// Since this function is debounced we need to read this value as late as possible
|
||||
if (!this.isActive) return;
|
||||
this.fitAddon.fit();
|
||||
const { cols, rows } = this.xterm;
|
||||
this.api.sendTerminalSize(cols, rows);
|
||||
@@ -150,7 +152,6 @@ export class Terminal {
|
||||
}
|
||||
|
||||
onResize = () => {
|
||||
if (!this.isActive) return;
|
||||
this.fitLazy();
|
||||
this.focus();
|
||||
}
|
||||
@@ -176,8 +177,8 @@ export class Terminal {
|
||||
if (this.xterm.hasSelection()) return false;
|
||||
break;
|
||||
|
||||
// Ctrl+W: prevent unexpected terminal tab closing, e.g. editing file in vim
|
||||
// https://github.com/kontena/lens-app/issues/156#issuecomment-534906480
|
||||
// Ctrl+W: prevent unexpected terminal tab closing, e.g. editing file in vim
|
||||
// https://github.com/kontena/lens-app/issues/156#issuecomment-534906480
|
||||
case "KeyW":
|
||||
evt.preventDefault();
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user