From 203472d0551c3a36791fc9238698a68d82cea224 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Tue, 13 Jul 2021 16:01:10 +0800 Subject: [PATCH 1/4] refactor: rename update actions and create a new update actions function --- src/services/workbench/editorService.ts | 43 ++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/services/workbench/editorService.ts b/src/services/workbench/editorService.ts index d71e62860..c3d297b2d 100644 --- a/src/services/workbench/editorService.ts +++ b/src/services/workbench/editorService.ts @@ -10,6 +10,7 @@ import { IEditorTab, EditorEvent, getEditorInitialActions, + EditorActionsProps, } from 'mo/model'; import { searchById } from '../helper'; import { editor as monacoEditor, Uri } from 'mo/monaco'; @@ -71,9 +72,13 @@ export interface IEditorService extends Component { setActive(groupId: number, tabId: string); updateGroup(groupId, groupValues: IEditorGroup): void; /** - * Update actions in group + * Set default actions when create a new group */ - updateGroupActions(actions: IMenuItemProps[]): void; + setDefaultActions(actions: EditorActionsProps[]): void; + /** + * Update actions in specific group + */ + updateActions(actions: IMenuItemProps[], groupId?: number): void; updateCurrentGroup(currentValues): void; /** * The Instance of Editor @@ -85,11 +90,11 @@ export class EditorService extends Component implements IEditorService { protected state: IEditor; - protected groupActions: IMenuItemProps[]; + protected defaultActions: EditorActionsProps[]; constructor() { super(); this.state = container.resolve(EditorModel); - this.groupActions = getEditorInitialActions(); + this.defaultActions = getEditorInitialActions(); } private disposeModel(tabs: IEditorTab | IEditorTab[]) { @@ -108,12 +113,40 @@ export class EditorService this.groupActions = actions; } + public setDefaultActions(actions: EditorActionsProps[]): void { + this.defaultActions = actions; + } + public setEntry(component: React.ReactNode) { this.setState({ entry: component, }); } + public updateActions = (actions: IMenuItemProps[], groupId?: number) => { + const { current, groups: rawGroups } = this.getState(); + if (!current) return; + + const groups = rawGroups?.concat() || []; + const targetGroup = groups.find(searchById(groupId || current.id)); + + if (targetGroup) { + const newActions = targetGroup.actions?.concat() || []; + newActions.forEach((action) => { + const target = actions.find((item) => item.id === action.id); + if (target) { + Object.assign(action, target); + } + }); + targetGroup.actions = newActions; + + this.setState({ + current: targetGroup.id === current.id ? targetGroup : current, + groups, + }); + } + }; + public getTabById( tabId: string, group: IEditorGroup @@ -378,7 +411,7 @@ export class EditorService groups.length + 1, tab, [tab], - this.groupActions + this.defaultActions ); groups.push(group); } From a225911fa74e4880988abd13568f900b0f30b15d Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Tue, 13 Jul 2021 16:01:43 +0800 Subject: [PATCH 2/4] fix: improve editor actions --- src/controller/editor.tsx | 30 ++++- .../theme-defaults/themes/dark_defaults.json | 1 + .../theme-defaults/themes/light_defaults.json | 1 + src/model/workbench/editor.ts | 25 +++- src/workbench/editor/action.tsx | 110 ++++++++++++------ src/workbench/editor/base.ts | 11 +- src/workbench/editor/editor.tsx | 4 +- src/workbench/editor/group.tsx | 5 +- src/workbench/editor/style.scss | 10 ++ 9 files changed, 145 insertions(+), 52 deletions(-) diff --git a/src/controller/editor.tsx b/src/controller/editor.tsx index b4c8450e3..accd9bab1 100644 --- a/src/controller/editor.tsx +++ b/src/controller/editor.tsx @@ -9,6 +9,9 @@ import { EDITOR_MENU_CLOSE_TO_RIGHT, EDITOR_MENU_CLOSE_TO_LEFT, EDITOR_MENU_CLOSE_ALL, + EditorActionsProps, + EDITOR_MENU_SHOW_OPENEDITORS, + EDITOR_MENU_SPILIT, } from 'mo/model/workbench/editor'; import { undoRedoMenu } from 'mo/model/workbench/menuBar'; import { Controller } from 'mo/react/controller'; @@ -47,7 +50,7 @@ export interface IEditorController { ) => void; onMoveTab?: (updateTabs: IEditorTab[], group: number) => void; onSelectTab?: (tabId: string, group: number) => void; - onSplitEditorRight?: () => void; + onClickActions: (action: EditorActionsProps) => void; onUpdateEditorIns?: (editorInstance: any, groupId: number) => void; onPaneSizeChange?: (newSize: number) => void; } @@ -190,9 +193,28 @@ export class EditorController extends Controller implements IEditorController { }); }; - public onSplitEditorRight = () => { - this.editorService.cloneGroup(); - this.emit(EditorEvent.OnSplitEditorRight); + public onClickActions = (action: EditorActionsProps) => { + const { current } = this.editorService.getState(); + if (!current) return; + + switch (action.id) { + case EDITOR_MENU_CLOSE_ALL: { + this.onCloseAll(current.id!); + break; + } + case EDITOR_MENU_SHOW_OPENEDITORS: { + // TODO + break; + } + case EDITOR_MENU_SPILIT: { + this.editorService.cloneGroup(); + this.emit(EditorEvent.OnSplitEditorRight); + break; + } + default: { + this.emit(EditorEvent.onActionsClick, action.id, current); + } + } }; public onPaneSizeChange = (newSize) => { diff --git a/src/extensions/theme-defaults/themes/dark_defaults.json b/src/extensions/theme-defaults/themes/dark_defaults.json index b60d370c0..ac49d4615 100644 --- a/src/extensions/theme-defaults/themes/dark_defaults.json +++ b/src/extensions/theme-defaults/themes/dark_defaults.json @@ -26,6 +26,7 @@ "inputValidation.warningBorder": "#B89500", "inputValidation.errorBackground": "#5A1D1D", "inputValidation.errorBorder": "#BE1100", + "icon.foreground": "#C5C5C5", "settings.textInputBackground": "#292929", "settings.numberInputBackground": "#292929", "menu.background": "#252526", diff --git a/src/extensions/theme-defaults/themes/light_defaults.json b/src/extensions/theme-defaults/themes/light_defaults.json index 4b4744326..8e712645f 100644 --- a/src/extensions/theme-defaults/themes/light_defaults.json +++ b/src/extensions/theme-defaults/themes/light_defaults.json @@ -26,6 +26,7 @@ "inputValidation.warningBorder": "#B89500", "inputValidation.errorBackground": "#F2DEDE", "inputValidation.errorBorder": "#BE1100", + "icon.foreground": "#424242", "searchEditor.textInputBorder": "#CECECE", "diffEditor.insertedTextBackground": "#9bb95533", "diffEditor.removedTextBackground": "#ff000033", diff --git a/src/model/workbench/editor.ts b/src/model/workbench/editor.ts index 195f22d84..1aaaacdd5 100644 --- a/src/model/workbench/editor.ts +++ b/src/model/workbench/editor.ts @@ -24,11 +24,19 @@ interface BuiltInEditorTabDataType { modified?: boolean; } +export interface EditorActionsProps extends IMenuItemProps { + id: string; + /** + * Mark the action placed in More menus or outer + */ + place?: 'outer'; +} + export interface IEditorTab extends ITabProps { breadcrumb?: IBreadcrumbItemProps[]; } export interface IEditorAction { - actions?: IMenuItemProps[]; + actions?: EditorActionsProps[]; menu?: IMenuItemProps[]; } export interface IEditorGroup extends ITabsProps { @@ -37,7 +45,7 @@ export interface IEditorGroup extends ITabsProps { * Current editor group tab */ tab?: IEditorTab; - actions?: IMenuItemProps[]; + actions?: EditorActionsProps[]; menu?: IMenuItemProps[]; editorInstance?: E; } @@ -57,6 +65,7 @@ export const EDITOR_MENU_CLOSE_OTHERS = 'editor.closeOthers'; export const EDITOR_MENU_CLOSE_SAVED = 'editor.closeSaved'; export const EDITOR_MENU_CLOSE = 'editor.close'; export const EDITOR_MENU_SHOW_OPENEDITORS = 'editor.showOpenEditors'; +export const EDITOR_MENU_SPILIT = 'editor.split'; export function getBaseMenu() { return [ @@ -67,8 +76,14 @@ export function getBaseMenu() { ]; } -export function getEditorInitialActions(): IMenuItemProps[] { +export function getEditorInitialActions(): EditorActionsProps[] { return [ + { + id: EDITOR_MENU_SPILIT, + name: 'Split Editor Right', + icon: 'split-horizontal', + place: 'outer', + }, { id: EDITOR_MENU_SHOW_OPENEDITORS, name: 'Show Opened Editors', @@ -103,7 +118,7 @@ export class EditorGroupModel implements IEditorGroup { id: number; tab: IEditorTab; data: IEditorTab[]; - actions: IMenuItemProps[]; + actions: EditorActionsProps[]; menu: IMenuItemProps[]; editorInstance: E | undefined; @@ -111,7 +126,7 @@ export class EditorGroupModel implements IEditorGroup { id: number, tab: IEditorTab, data: IEditorTab[], - actions: IMenuItemProps[] = getEditorInitialActions(), + actions: EditorActionsProps[] = getEditorInitialActions(), menu: IMenuItemProps[] = getEditorInitialMenu(), editorInstance?: E ) { diff --git a/src/workbench/editor/action.tsx b/src/workbench/editor/action.tsx index ed5f33245..3a0662b5f 100644 --- a/src/workbench/editor/action.tsx +++ b/src/workbench/editor/action.tsx @@ -1,36 +1,67 @@ import * as React from 'react'; -import { memo, useCallback } from 'react'; +import { memo } from 'react'; import { Icon } from 'mo/components/icon'; import { Menu } from 'mo/components/menu'; import { DropDown, DropDownRef } from 'mo/components/dropdown'; -import { IEditorAction } from 'mo/model'; -import { groupActionsClassName, groupActionsItemClassName } from './base'; +import { EditorActionsProps, IEditorAction } from 'mo/model'; +import { + groupActionItemDisabledClassName, + groupActionsClassName, + groupActionsItemClassName, +} from './base'; import { IEditorController } from 'mo/controller/editor'; +import { classNames } from 'mo/common/className'; export interface IEditorActionProps extends IEditorAction { isActiveGroup: boolean; } +const MAX_ACTIONS_LENGTH = 6; + +function splitActions(actions: EditorActionsProps[]) { + const outerActions: EditorActionsProps[] = []; + const ellipsisActions: EditorActionsProps[] = []; + + actions.forEach((action) => { + if (action.place === 'outer') { + outerActions.push(action); + } else { + ellipsisActions.push(action); + } + }); + + if (outerActions.length > MAX_ACTIONS_LENGTH) { + const surplusActions = outerActions.splice( + 0, + MAX_ACTIONS_LENGTH - outerActions.length + ); + + ellipsisActions.concat(surplusActions); + } + + return [outerActions, ellipsisActions]; +} + function EditorAction(props: IEditorActionProps & IEditorController) { - const { - actions = [], - isActiveGroup = false, - onClickContextMenu, - onSplitEditorRight, - } = props; + const { actions = [], isActiveGroup = false, onClickActions } = props; + const [outer, ellipsis] = splitActions(actions); const childRef = React.useRef(null); - const handleOnMenuClick = (e: React.MouseEvent, item) => { - onClickContextMenu?.(e, item); - (childRef.current as any)!.dispose(); + const handleOnMenuClick = (_, item) => { + onClickActions(item); + childRef.current?.dispose(); + }; + + const handleActionsClick = (action) => { + onClickActions(action); }; const overlay = - actions.length > 0 ? ( + ellipsis.length > 0 ? ( ) : ( @@ -44,33 +75,38 @@ function EditorAction(props: IEditorActionProps & IEditorController) { ); - const handleSplitEditor = useCallback( - (e: React.MouseEvent) => { - onSplitEditorRight?.(); - }, - [actions] - ); return (
- {isActiveGroup ? ( -
( +
handleActionsClick(action)} + className={classNames( + groupActionsItemClassName, + action.disabled && groupActionItemDisabledClassName + )} + title={action.name?.toString()} + > + {action.icon ? ( + + ) : ( + action.name + )} +
+ ))} + {Boolean(ellipsis.length) && ( + - -
- ) : null} - - - + + + )}
); } diff --git a/src/workbench/editor/base.ts b/src/workbench/editor/base.ts index ff9e4a761..a9faa859f 100644 --- a/src/workbench/editor/base.ts +++ b/src/workbench/editor/base.ts @@ -1,4 +1,8 @@ -import { getBEMElement, prefixClaName } from 'mo/common/className'; +import { + getBEMElement, + getBEMModifier, + prefixClaName, +} from 'mo/common/className'; export const defaultEditorClassName = prefixClaName('editor'); export const groupClassName = getBEMElement(defaultEditorClassName, 'group'); @@ -23,6 +27,11 @@ export const groupActionsItemClassName = getBEMElement( 'group-actions-item' ); +export const groupActionItemDisabledClassName = getBEMModifier( + groupActionsItemClassName, + 'disabled' +); + export const groupBreadcrumbClassName = getBEMElement( defaultEditorClassName, 'group-breadcrumb' diff --git a/src/workbench/editor/editor.tsx b/src/workbench/editor/editor.tsx index 99ca9932d..329b8f0b3 100644 --- a/src/workbench/editor/editor.tsx +++ b/src/workbench/editor/editor.tsx @@ -20,7 +20,7 @@ export function Editor(props: IEditor & IEditorController) { onSelectTab, groupSplitPos = [], onChangeEditorProps, - onSplitEditorRight, + onClickActions, onUpdateEditorIns, onPaneSizeChange, } = props; @@ -30,7 +30,7 @@ export function Editor(props: IEditor & IEditorController) { onMoveTab: (tabs) => onMoveTab?.(tabs, groupId), onCloseTab: (tabKey) => onCloseTab?.(tabKey, groupId), onSelectTab: (tabKey) => onSelectTab?.(tabKey, groupId), - onSplitEditorRight, + onClickActions, onUpdateEditorIns, onChangeEditorProps, onClickContextMenu, diff --git a/src/workbench/editor/group.tsx b/src/workbench/editor/group.tsx index a5c77d0d7..661f11438 100644 --- a/src/workbench/editor/group.tsx +++ b/src/workbench/editor/group.tsx @@ -34,7 +34,7 @@ export function EditorGroup(props: IEditorGroupProps & IEditorController) { onClickContextMenu, onChangeEditorProps, onSelectTab, - onSplitEditorRight, + onClickActions, onUpdateEditorIns, } = props; @@ -79,8 +79,7 @@ export function EditorGroup(props: IEditorGroupProps & IEditorController) { isActiveGroup={isActiveGroup} actions={actions} menu={menu} - onSplitEditorRight={onSplitEditorRight} - onClickContextMenu={onClickContextMenu} + onClickActions={onClickActions} /> diff --git a/src/workbench/editor/style.scss b/src/workbench/editor/style.scss index ee005955f..56c495e30 100644 --- a/src/workbench/editor/style.scss +++ b/src/workbench/editor/style.scss @@ -35,11 +35,21 @@ &-item { align-items: center; + color: var(--icon-foreground); cursor: pointer; display: flex; height: 35px; justify-content: center; padding: 0 8px 0 4px; + + &:not(#{$editor}__group-actions-item--disabled):hover { + color: var(--activityBar-activeBorder); + } + + &--disabled { + cursor: default; + opacity: 0.4; + } } } From 0f6058a5dafef2fecce706c0a796075ac8ca902d Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Thu, 15 Jul 2021 15:39:32 +0800 Subject: [PATCH 3/4] fix: improve interface name --- src/controller/editor.tsx | 6 +++--- src/model/workbench/editor.ts | 12 ++++++------ src/services/workbench/editorService.ts | 12 ++++-------- src/workbench/editor/action.tsx | 8 ++++---- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/controller/editor.tsx b/src/controller/editor.tsx index accd9bab1..6f24ad06f 100644 --- a/src/controller/editor.tsx +++ b/src/controller/editor.tsx @@ -9,7 +9,7 @@ import { EDITOR_MENU_CLOSE_TO_RIGHT, EDITOR_MENU_CLOSE_TO_LEFT, EDITOR_MENU_CLOSE_ALL, - EditorActionsProps, + IEditorActionsProps, EDITOR_MENU_SHOW_OPENEDITORS, EDITOR_MENU_SPILIT, } from 'mo/model/workbench/editor'; @@ -50,7 +50,7 @@ export interface IEditorController { ) => void; onMoveTab?: (updateTabs: IEditorTab[], group: number) => void; onSelectTab?: (tabId: string, group: number) => void; - onClickActions: (action: EditorActionsProps) => void; + onClickActions: (action: IEditorActionsProps) => void; onUpdateEditorIns?: (editorInstance: any, groupId: number) => void; onPaneSizeChange?: (newSize: number) => void; } @@ -193,7 +193,7 @@ export class EditorController extends Controller implements IEditorController { }); }; - public onClickActions = (action: EditorActionsProps) => { + public onClickActions = (action: IEditorActionsProps) => { const { current } = this.editorService.getState(); if (!current) return; diff --git a/src/model/workbench/editor.ts b/src/model/workbench/editor.ts index 1aaaacdd5..015e94077 100644 --- a/src/model/workbench/editor.ts +++ b/src/model/workbench/editor.ts @@ -24,7 +24,7 @@ interface BuiltInEditorTabDataType { modified?: boolean; } -export interface EditorActionsProps extends IMenuItemProps { +export interface IEditorActionsProps extends IMenuItemProps { id: string; /** * Mark the action placed in More menus or outer @@ -36,7 +36,7 @@ export interface IEditorTab extends ITabProps { breadcrumb?: IBreadcrumbItemProps[]; } export interface IEditorAction { - actions?: EditorActionsProps[]; + actions?: IEditorActionsProps[]; menu?: IMenuItemProps[]; } export interface IEditorGroup extends ITabsProps { @@ -45,7 +45,7 @@ export interface IEditorGroup extends ITabsProps { * Current editor group tab */ tab?: IEditorTab; - actions?: EditorActionsProps[]; + actions?: IEditorActionsProps[]; menu?: IMenuItemProps[]; editorInstance?: E; } @@ -76,7 +76,7 @@ export function getBaseMenu() { ]; } -export function getEditorInitialActions(): EditorActionsProps[] { +export function getEditorInitialActions(): IEditorActionsProps[] { return [ { id: EDITOR_MENU_SPILIT, @@ -118,7 +118,7 @@ export class EditorGroupModel implements IEditorGroup { id: number; tab: IEditorTab; data: IEditorTab[]; - actions: EditorActionsProps[]; + actions: IEditorActionsProps[]; menu: IMenuItemProps[]; editorInstance: E | undefined; @@ -126,7 +126,7 @@ export class EditorGroupModel implements IEditorGroup { id: number, tab: IEditorTab, data: IEditorTab[], - actions: EditorActionsProps[] = getEditorInitialActions(), + actions: IEditorActionsProps[] = getEditorInitialActions(), menu: IMenuItemProps[] = getEditorInitialMenu(), editorInstance?: E ) { diff --git a/src/services/workbench/editorService.ts b/src/services/workbench/editorService.ts index c3d297b2d..13be0f3b8 100644 --- a/src/services/workbench/editorService.ts +++ b/src/services/workbench/editorService.ts @@ -10,7 +10,7 @@ import { IEditorTab, EditorEvent, getEditorInitialActions, - EditorActionsProps, + IEditorActionsProps, } from 'mo/model'; import { searchById } from '../helper'; import { editor as monacoEditor, Uri } from 'mo/monaco'; @@ -74,7 +74,7 @@ export interface IEditorService extends Component { /** * Set default actions when create a new group */ - setDefaultActions(actions: EditorActionsProps[]): void; + setDefaultActions(actions: IEditorActionsProps[]): void; /** * Update actions in specific group */ @@ -90,7 +90,7 @@ export class EditorService extends Component implements IEditorService { protected state: IEditor; - protected defaultActions: EditorActionsProps[]; + protected defaultActions: IEditorActionsProps[]; constructor() { super(); this.state = container.resolve(EditorModel); @@ -109,11 +109,7 @@ export class EditorService return groups.some((group) => this.getTabById(tabId, group)); } - public updateGroupActions(actions: IMenuItemProps[]): void { - this.groupActions = actions; - } - - public setDefaultActions(actions: EditorActionsProps[]): void { + public setDefaultActions(actions: IEditorActionsProps[]): void { this.defaultActions = actions; } diff --git a/src/workbench/editor/action.tsx b/src/workbench/editor/action.tsx index 3a0662b5f..d6a18c9d0 100644 --- a/src/workbench/editor/action.tsx +++ b/src/workbench/editor/action.tsx @@ -3,7 +3,7 @@ import { memo } from 'react'; import { Icon } from 'mo/components/icon'; import { Menu } from 'mo/components/menu'; import { DropDown, DropDownRef } from 'mo/components/dropdown'; -import { EditorActionsProps, IEditorAction } from 'mo/model'; +import { IEditorActionsProps, IEditorAction } from 'mo/model'; import { groupActionItemDisabledClassName, groupActionsClassName, @@ -18,9 +18,9 @@ export interface IEditorActionProps extends IEditorAction { const MAX_ACTIONS_LENGTH = 6; -function splitActions(actions: EditorActionsProps[]) { - const outerActions: EditorActionsProps[] = []; - const ellipsisActions: EditorActionsProps[] = []; +function splitActions(actions: IEditorActionsProps[]) { + const outerActions: IEditorActionsProps[] = []; + const ellipsisActions: IEditorActionsProps[] = []; actions.forEach((action) => { if (action.place === 'outer') { From d67e205b2a2f5fd1cda32e9ddd322e897e5aa995 Mon Sep 17 00:00:00 2001 From: mortalYoung Date: Thu, 15 Jul 2021 17:30:25 +0800 Subject: [PATCH 4/4] fix: rename ellipsisActions --- src/workbench/editor/action.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/workbench/editor/action.tsx b/src/workbench/editor/action.tsx index d6a18c9d0..de1aadfee 100644 --- a/src/workbench/editor/action.tsx +++ b/src/workbench/editor/action.tsx @@ -20,13 +20,13 @@ const MAX_ACTIONS_LENGTH = 6; function splitActions(actions: IEditorActionsProps[]) { const outerActions: IEditorActionsProps[] = []; - const ellipsisActions: IEditorActionsProps[] = []; + const innerActions: IEditorActionsProps[] = []; actions.forEach((action) => { if (action.place === 'outer') { outerActions.push(action); } else { - ellipsisActions.push(action); + innerActions.push(action); } }); @@ -36,15 +36,15 @@ function splitActions(actions: IEditorActionsProps[]) { MAX_ACTIONS_LENGTH - outerActions.length ); - ellipsisActions.concat(surplusActions); + innerActions.concat(surplusActions); } - return [outerActions, ellipsisActions]; + return [outerActions, innerActions]; } function EditorAction(props: IEditorActionProps & IEditorController) { const { actions = [], isActiveGroup = false, onClickActions } = props; - const [outer, ellipsis] = splitActions(actions); + const [outer, inner] = splitActions(actions); const childRef = React.useRef(null); @@ -58,10 +58,10 @@ function EditorAction(props: IEditorActionProps & IEditorController) { }; const overlay = - ellipsis.length > 0 ? ( + inner.length > 0 ? ( ) : ( @@ -95,7 +95,7 @@ function EditorAction(props: IEditorActionProps & IEditorController) { )} ))} - {Boolean(ellipsis.length) && ( + {Boolean(inner.length) && (