Skip to content

Commit

Permalink
Add global toolbar extension (#10731)
Browse files Browse the repository at this point in the history
The commit introduces the `@theia/toolbar` extension which contributes a global toolbar to the application which applications and users can modify to add their favorite commands for easy access.
  • Loading branch information
kenneth-marut-work authored Feb 24, 2022
1 parent 9a02be6 commit 307b279
Show file tree
Hide file tree
Showing 38 changed files with 2,867 additions and 35 deletions.
3 changes: 3 additions & 0 deletions examples/api-samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
"description": "Theia - Example code to demonstrate Theia API",
"dependencies": {
"@theia/core": "1.22.1",
"@theia/file-search": "1.22.1",
"@theia/filesystem": "1.22.1",
"@theia/output": "1.22.1",
"@theia/search-in-workspace": "1.22.1",
"@theia/toolbar": "1.22.1",
"@theia/vsx-registry": "1.22.1",
"@theia/workspace": "1.22.1"
},
Expand Down
11 changes: 9 additions & 2 deletions examples/api-samples/src/browser/api-samples-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,30 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { ContainerModule } from '@theia/core/shared/inversify';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
import { bindDynamicLabelProvider } from './label/sample-dynamic-label-provider-command-contribution';
import { bindSampleFilteredCommandContribution } from './contribution-filter/sample-filtered-command-contribution';
import { bindSampleUnclosableView } from './view/sample-unclosable-view-contribution';
import { bindSampleOutputChannelWithSeverity } from './output/sample-output-channel-with-severity';
import { bindSampleMenu } from './menu/sample-menu-contribution';
import { bindSampleFileWatching } from './file-watching/sample-file-watching-contribution';
import { bindVSXCommand } from './vsx/sample-vsx-command-contribution';
import { bindSampleToolbarContribution } from './toolbar/sample-toolbar-contribution';

import '../../src/browser/style/branding.css';

export default new ContainerModule(bind => {
export default new ContainerModule((
bind: interfaces.Bind,
unbind: interfaces.Unbind,
isBound: interfaces.IsBound,
rebind: interfaces.Rebind,
) => {
bindDynamicLabelProvider(bind);
bindSampleUnclosableView(bind);
bindSampleOutputChannelWithSeverity(bind);
bindSampleMenu(bind);
bindSampleFileWatching(bind);
bindVSXCommand(bind);
bindSampleFilteredCommandContribution(bind);
bindSampleToolbarContribution(bind, rebind);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/********************************************************************************
* Copyright (C) 2022 Ericsson and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

#theia-sample-toolbar-contribution {
position: relative;
}

#theia-sample-toolbar-contribution .icon-wrapper {
cursor: pointer;
margin-left: 0;
}

#theia-sample-toolbar-contribution:focus,
#theia-sample-toolbar-contribution .icon-wrapper:focus,
#theia-sample-toolbar-contribution .codicon-search:focus {
outline: none;
}

#theia-sample-toolbar-contribution .icon-wrapper.action-item.item.enabled:hover {
background-color: var(--theia-toolbar-hoverBackground);
}

#theia-sample-toolbar-contribution #easy-search-item-icon.codicon-search {
position: relative;
}

#theia-sample-toolbar-contribution .icon-wrapper .codicon-triangle-down {
position: absolute;
font-size: 10px;
bottom: -7px;
right: -2px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/********************************************************************************
* Copyright (C) 2022 Ericsson and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { CommandContribution, CommandRegistry, CommandService, MenuContribution, MenuModelRegistry } from '@theia/core';
import { LabelProvider, quickCommand, QuickInputService, QuickPickItem } from '@theia/core/lib/browser';
import { inject, injectable, interfaces } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { quickFileOpen } from '@theia/file-search/lib/browser/quick-file-open';
import { SearchInWorkspaceCommands } from '@theia/search-in-workspace/lib/browser/search-in-workspace-frontend-contribution';
import { WorkspaceService } from '@theia/workspace/lib/browser';
import { AbstractToolbarContribution } from '@theia/toolbar/lib/browser/abstract-toolbar-contribution';
import { ToolbarMenus, ReactInteraction } from '@theia/toolbar/lib/browser/toolbar-constants';
import { ToolbarContribution } from '@theia/toolbar/lib/browser/toolbar-interfaces';
import { ToolbarDefaultsFactory } from '@theia/toolbar/lib/browser/toolbar-defaults';
import { SampleToolbarDefaultsOverride } from './sample-toolbar-defaults-override';
import '../../../src/browser/toolbar/sample-toolbar-contribution.css';

export const bindSampleToolbarContribution = (bind: interfaces.Bind, rebind: interfaces.Rebind) => {
bind(SampleToolbarContribution).toSelf().inSingletonScope();
bind(ToolbarContribution).to(SampleToolbarContribution);
bind(CommandContribution).to(SampleToolbarContribution);
bind(MenuContribution).to(SampleToolbarContribution);
bind(SearchInWorkspaceQuickInputService).toSelf().inSingletonScope();
rebind(ToolbarDefaultsFactory).toConstantValue(SampleToolbarDefaultsOverride);
};

export const FIND_IN_WORKSPACE_ROOT = {
id: 'easy.search.find.in.workspace.root',
category: 'Search',
label: 'Search Workspace Root for Text',
};

@injectable()
export class SearchInWorkspaceQuickInputService {
@inject(QuickInputService) protected readonly quickInputService: QuickInputService;
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;
@inject(LabelProvider) protected readonly labelProvider: LabelProvider;
@inject(CommandService) protected readonly commandService: CommandService;
protected quickPickItems: QuickPickItem[] = [];

open(): void {
this.quickPickItems = this.createWorkspaceList();
this.quickInputService.showQuickPick(this.quickPickItems, {
placeholder: 'Workspace root to search',
});
}

protected createWorkspaceList(): QuickPickItem[] {
const roots = this.workspaceService.tryGetRoots();
return roots.map(root => {
const uri = root.resource;
return {
label: this.labelProvider.getName(uri),
execute: (): Promise<void> => this.commandService.executeCommand(SearchInWorkspaceCommands.FIND_IN_FOLDER.id, [uri]),
};
});
}
}

@injectable()
export class SampleToolbarContribution extends AbstractToolbarContribution
implements CommandContribution,
MenuContribution {
@inject(SearchInWorkspaceQuickInputService) protected readonly searchPickService: SearchInWorkspaceQuickInputService;
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;

static ID = 'theia-sample-toolbar-contribution';
id = SampleToolbarContribution.ID;

protected handleOnClick = (e: ReactInteraction<HTMLSpanElement>): void => this.doHandleOnClick(e);
protected doHandleOnClick(e: ReactInteraction<HTMLSpanElement>): void {
e.stopPropagation();
const toolbar = document.querySelector<HTMLDivElement>('#main-toolbar');
if (toolbar) {
const { bottom } = toolbar.getBoundingClientRect();
const { left } = e.currentTarget.getBoundingClientRect();
this.contextMenuRenderer.render({
includeAnchorArg: false,
menuPath: ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU,
anchor: { x: left, y: bottom },
});
}
}

render(): React.ReactNode {
return (
<div
role='button'
tabIndex={0}
className='icon-wrapper action-item item enabled codicon codicon-search'
id='easy-search-item-icon'
onClick={this.handleOnClick}
title='Search for files, text, commands, and more...'
>
<div className='codicon codicon-triangle-down' />
</div>);
}

registerCommands(registry: CommandRegistry): void {
registry.registerCommand(FIND_IN_WORKSPACE_ROOT, {
execute: async () => {
const wsRoots = await this.workspaceService.roots;
if (!wsRoots.length) {
await this.commandService.executeCommand(SearchInWorkspaceCommands.FIND_IN_FOLDER.id);
} else if (wsRoots.length === 1) {
const { resource } = wsRoots[0];
await this.commandService.executeCommand(SearchInWorkspaceCommands.FIND_IN_FOLDER.id, [resource]);
} else {
this.searchPickService.open();
}
},
});
}

registerMenus(registry: MenuModelRegistry): void {
registry.registerMenuAction(ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU, {
commandId: quickCommand.id,
label: 'Find a Command',
order: 'a',
});
registry.registerMenuAction(ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU, {
commandId: quickFileOpen.id,
order: 'b',
label: 'Search for a file'
});
registry.registerMenuAction(ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU, {
commandId: SearchInWorkspaceCommands.OPEN_SIW_WIDGET.id,
label: 'Search Entire Workspace for Text',
order: 'c',
});
registry.registerMenuAction(ToolbarMenus.SEARCH_WIDGET_DROPDOWN_MENU, {
commandId: FIND_IN_WORKSPACE_ROOT.id,
order: 'd',
});
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/********************************************************************************
* Copyright (C) 2022 Ericsson and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { DeflatedToolbarTree, ToolbarAlignment } from '@theia/toolbar/lib/browser/toolbar-interfaces';

export const SampleToolbarDefaultsOverride: () => DeflatedToolbarTree = () => ({
items: {
[ToolbarAlignment.LEFT]: [
[
{
id: 'textEditor.commands.go.back',
command: 'textEditor.commands.go.back',
icon: 'codicon codicon-arrow-left',
},
{
id: 'textEditor.commands.go.forward',
command: 'textEditor.commands.go.forward',
icon: 'codicon codicon-arrow-right',
},
],
[
{
id: 'workbench.action.splitEditorRight',
command: 'workbench.action.splitEditor',
icon: 'codicon codicon-split-horizontal',
},
],
],
[ToolbarAlignment.CENTER]: [[
{
id: 'theia-sample-toolbar-contribution',
group: 'contributed'
}
]],
[ToolbarAlignment.RIGHT]: [
[
{
id: 'workbench.action.showCommands',
command: 'workbench.action.showCommands',
icon: 'codicon codicon-terminal',
tooltip: 'Command Palette',
},
]
]
},
});
9 changes: 9 additions & 0 deletions examples/api-samples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@
{
"path": "../../packages/core"
},
{
"path": "../../packages/file-search"
},
{
"path": "../../packages/filesystem"
},
{
"path": "../../packages/output"
},
{
"path": "../../packages/search-in-workspace"
},
{
"path": "../../packages/toolbar"
},
{
"path": "../../packages/vsx-registry"
},
Expand Down
1 change: 1 addition & 0 deletions examples/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@theia/task": "1.22.1",
"@theia/terminal": "1.22.1",
"@theia/timeline": "1.22.1",
"@theia/toolbar": "1.22.1",
"@theia/typehierarchy": "1.22.1",
"@theia/userstorage": "1.22.1",
"@theia/variable-resolver": "1.22.1",
Expand Down
3 changes: 3 additions & 0 deletions examples/browser/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@
{
"path": "../../packages/timeline"
},
{
"path": "../../packages/toolbar"
},
{
"path": "../../packages/typehierarchy"
},
Expand Down
1 change: 1 addition & 0 deletions examples/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@theia/task": "1.22.1",
"@theia/terminal": "1.22.1",
"@theia/timeline": "1.22.1",
"@theia/toolbar": "1.22.1",
"@theia/typehierarchy": "1.22.1",
"@theia/userstorage": "1.22.1",
"@theia/variable-resolver": "1.22.1",
Expand Down
3 changes: 3 additions & 0 deletions examples/electron/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@
{
"path": "../../packages/timeline"
},
{
"path": "../../packages/toolbar"
},
{
"path": "../../packages/typehierarchy"
},
Expand Down
24 changes: 23 additions & 1 deletion packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1761,6 +1761,12 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
hc: 'focusBorder'
}, description: "The color of the row's top and bottom border when the row is focused."
},
// Toolbar Action colors should be aligned with https://code.visualstudio.com/api/references/theme-color#action-colors
{
id: 'toolbar.hoverBackground', defaults: {
dark: '#5a5d5e50', light: '#b8b8b850', hc: undefined
}, description: 'Toolbar background when hovering over actions using the mouse.'
},

// Theia Variable colors
{
Expand Down Expand Up @@ -2042,7 +2048,23 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
hc: 'editorWidget.background',
},
description: 'Background color of breadcrumb item picker'
}
},
{
id: 'mainToolbar.background',
defaults: {
dark: Color.lighten('activityBar.background', 0.1),
light: Color.darken('activityBar.background', 0.1),
hc: Color.lighten('activityBar.background', 0.1),
},
description: 'Background color of shell\'s global toolbar'
},
{
id: 'mainToolbar.foreground', defaults: {
dark: Color.darken('activityBar.foreground', 0.1),
light: Color.lighten('activityBar.foreground', 0.1),
hc: Color.lighten('activityBar.foreground', 0.1),
}, description: 'Foreground color of active toolbar item',
},
);
}
}
Loading

0 comments on commit 307b279

Please sign in to comment.