deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
packages/toolbar/.eslintrc.js
Normal file
10
packages/toolbar/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
2
packages/toolbar/.gitignore
vendored
Normal file
2
packages/toolbar/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
font-awesome.json
|
||||
codicon.json
|
||||
40
packages/toolbar/README.md
Normal file
40
packages/toolbar/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
<div align='center'>
|
||||
|
||||
<br />
|
||||
|
||||
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
||||
|
||||
<h2>ECLIPSE THEIA - TOOLBAR EXTENSION</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
The `@theia/toolbar` extension contributes a global toolbar to the application shell. The toolbar supplements the `Command Palette` and allows users to easily add, remove, and rearrange toolbar items to their liking. The toolbar is hidden by default and ships with a default layout which can be overridden by downstream applications. Extenders can also contribute custom widgets to the toolbar through a contribution point.
|
||||
|
||||
### Icon Management
|
||||
|
||||
When a new item is added to the toolbar, a dialog appears showing all installed icons. This feature allows users to easily select a suitable icon for their toolbar item without needing to know the icon names in advance. The dialog visually displays available icons from both the FontAwesome and Codicons libraries.
|
||||
|
||||
The `update-icons.js` script collects the icon strings for FontAwesome and Codicons from the currently installed dependencies and saves them to temporary JSON files. The content is then copied to `codicon.ts` and `font-awesome-icons.ts` to update the icon lists.
|
||||
A util npm script is available: `npm run update:icons`.
|
||||
|
||||
## Additional Information
|
||||
|
||||
An example toolbar custom widget and layout override can be found in [here](https://github.com/eclipse-theia/theia/tree/master/examples/api-samples/src/browser/toolbar).
|
||||
|
||||
- [API documentation for `@theia/toolbar`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_toolbar.html)
|
||||
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
||||
- [Theia - Website](https://theia-ide.org/)
|
||||
|
||||
## License
|
||||
|
||||
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
||||
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
||||
|
||||
## Trademark
|
||||
|
||||
"Theia" is a trademark of the Eclipse Foundation
|
||||
<https://www.eclipse.org/theia>
|
||||
55
packages/toolbar/package.json
Normal file
55
packages/toolbar/package.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "@theia/toolbar",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia - Toolbar",
|
||||
"keywords": [
|
||||
"theia-extension"
|
||||
],
|
||||
"homepage": "https://github.com/eclipse-theia/theia",
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eclipse-theia/theia.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/eclipse-theia/theia/issues"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "theiaext build",
|
||||
"clean": "theiaext clean",
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"test": "theiaext test",
|
||||
"watch": "theiaext watch",
|
||||
"update:icons": "node ./update-icons.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@theia/core": "1.68.0",
|
||||
"@theia/editor": "1.68.0",
|
||||
"@theia/file-search": "1.68.0",
|
||||
"@theia/filesystem": "1.68.0",
|
||||
"@theia/monaco": "1.68.0",
|
||||
"@theia/monaco-editor-core": "1.96.302",
|
||||
"@theia/search-in-workspace": "1.68.0",
|
||||
"@theia/userstorage": "1.68.0",
|
||||
"@theia/workspace": "1.68.0",
|
||||
"ajv": "^6.5.3",
|
||||
"jsonc-parser": "^2.2.0",
|
||||
"perfect-scrollbar": "1.5.5",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"frontend": "lib/browser/toolbar-frontend-module",
|
||||
"backend": "lib/node/toolbar-backend-module"
|
||||
}
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "21358137e41342742707f660b8e222f940a27652"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import * as React from '@theia/core/shared/react';
|
||||
import { CommandService, Emitter } from '@theia/core';
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import { ContextMenuRenderer, KeybindingRegistry } from '@theia/core/lib/browser';
|
||||
import { DeflatedContributedToolbarItem, ToolbarContribution } from './toolbar-interfaces';
|
||||
|
||||
@injectable()
|
||||
export abstract class AbstractToolbarContribution implements ToolbarContribution {
|
||||
@inject(KeybindingRegistry) protected readonly keybindingRegistry: KeybindingRegistry;
|
||||
@inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer;
|
||||
@inject(CommandService) protected readonly commandService: CommandService;
|
||||
|
||||
abstract id: string;
|
||||
|
||||
protected didChangeEmitter = new Emitter<void>();
|
||||
readonly onDidChange = this.didChangeEmitter.event;
|
||||
|
||||
abstract render(): React.ReactNode;
|
||||
|
||||
toJSON(): DeflatedContributedToolbarItem {
|
||||
return { id: this.id, group: 'contributed' };
|
||||
}
|
||||
|
||||
protected resolveKeybindingForCommand(commandID: string | undefined): string {
|
||||
if (!commandID) {
|
||||
return '';
|
||||
}
|
||||
const keybindings = this.keybindingRegistry.getKeybindingsForCommand(commandID);
|
||||
if (keybindings.length > 0) {
|
||||
const binding = keybindings[0];
|
||||
const bindingKeySequence = this.keybindingRegistry.resolveKeybinding(binding);
|
||||
const keyCode = bindingKeySequence[0];
|
||||
return ` (${this.keybindingRegistry.acceleratorForKeyCode(keyCode, '+')})`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import {
|
||||
ApplicationShell,
|
||||
Layout,
|
||||
MAXIMIZED_CLASS,
|
||||
TheiaSplitPanel,
|
||||
} from '@theia/core/lib/browser';
|
||||
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { Toolbar, ToolbarFactory } from './toolbar-interfaces';
|
||||
import { ToolbarPreferences, TOOLBAR_ENABLE_PREFERENCE_ID } from '../common/toolbar-preference-contribution';
|
||||
import { PreferenceService } from '@theia/core';
|
||||
|
||||
@injectable()
|
||||
export class ApplicationShellWithToolbarOverride extends ApplicationShell {
|
||||
@inject(ToolbarPreferences) protected toolbarPreferences: ToolbarPreferences;
|
||||
@inject(PreferenceService) protected readonly preferenceService: PreferenceService;
|
||||
@inject(ToolbarFactory) protected readonly toolbarFactory: () => Toolbar;
|
||||
|
||||
protected toolbar: Toolbar;
|
||||
|
||||
@postConstruct()
|
||||
protected override init(): void {
|
||||
this.doInit();
|
||||
}
|
||||
|
||||
protected async doInit(): Promise<void> {
|
||||
this.toolbar = this.toolbarFactory();
|
||||
this.toolbar.id = 'main-toolbar';
|
||||
super.init();
|
||||
await this.toolbarPreferences.ready;
|
||||
this.tryShowToolbar();
|
||||
this.onDidToggleMaximized(() => {
|
||||
this.tryShowToolbar();
|
||||
});
|
||||
|
||||
this.preferenceService.onPreferenceChanged(event => {
|
||||
if (event.preferenceName === TOOLBAR_ENABLE_PREFERENCE_ID) {
|
||||
this.tryShowToolbar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected tryShowToolbar(): boolean {
|
||||
const doShowToolbarFromPreference = this.toolbarPreferences[TOOLBAR_ENABLE_PREFERENCE_ID];
|
||||
const isShellMaximized = this.mainPanel.hasClass(MAXIMIZED_CLASS) || this.bottomPanel.hasClass(MAXIMIZED_CLASS);
|
||||
if (doShowToolbarFromPreference && !isShellMaximized) {
|
||||
this.toolbar.show();
|
||||
return true;
|
||||
}
|
||||
this.toolbar.hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override createLayout(): Layout {
|
||||
const bottomSplitLayout = this.createSplitLayout(
|
||||
[this.mainPanel, this.bottomPanel],
|
||||
[1, 0],
|
||||
{ orientation: 'vertical', spacing: 0 },
|
||||
);
|
||||
const panelForBottomArea = new TheiaSplitPanel({ layout: bottomSplitLayout });
|
||||
panelForBottomArea.id = 'theia-bottom-split-panel';
|
||||
|
||||
const leftRightSplitLayout = this.createSplitLayout(
|
||||
[this.leftPanelHandler.container, panelForBottomArea, this.rightPanelHandler.container],
|
||||
[0, 1, 0],
|
||||
{ orientation: 'horizontal', spacing: 0 },
|
||||
);
|
||||
const panelForSideAreas = new TheiaSplitPanel({ layout: leftRightSplitLayout });
|
||||
panelForSideAreas.id = 'theia-left-right-split-panel';
|
||||
return this.createBoxLayout(
|
||||
[this.topPanel, this.toolbar, panelForSideAreas, this.statusBar],
|
||||
[0, 0, 1, 0],
|
||||
{ direction: 'top-to-bottom', spacing: 0 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const bindToolbarApplicationShell = (bind: interfaces.Bind, rebind: interfaces.Rebind, unbind: interfaces.Unbind): void => {
|
||||
bind(ApplicationShellWithToolbarOverride).toSelf().inSingletonScope();
|
||||
rebind(ApplicationShell).toService(ApplicationShellWithToolbarOverride);
|
||||
};
|
||||
647
packages/toolbar/src/browser/icons/codicons.ts
Normal file
647
packages/toolbar/src/browser/icons/codicons.ts
Normal file
@@ -0,0 +1,647 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export const codiconsMapping = {
|
||||
'codicon-add': 60000,
|
||||
'codicon-plus': 60000,
|
||||
'codicon-gist-new': 60000,
|
||||
'codicon-repo-create': 60000,
|
||||
'codicon-lightbulb': 60001,
|
||||
'codicon-light-bulb': 60001,
|
||||
'codicon-repo': 60002,
|
||||
'codicon-repo-delete': 60002,
|
||||
'codicon-gist-fork': 60003,
|
||||
'codicon-repo-forked': 60003,
|
||||
'codicon-git-pull-request': 60004,
|
||||
'codicon-git-pull-request-abandoned': 60004,
|
||||
'codicon-record-keys': 60005,
|
||||
'codicon-keyboard': 60005,
|
||||
'codicon-tag': 60006,
|
||||
'codicon-git-pull-request-label': 60006,
|
||||
'codicon-tag-add': 60006,
|
||||
'codicon-tag-remove': 60006,
|
||||
'codicon-person': 60007,
|
||||
'codicon-person-follow': 60007,
|
||||
'codicon-person-outline': 60007,
|
||||
'codicon-person-filled': 60007,
|
||||
'codicon-source-control': 60008,
|
||||
'codicon-mirror': 60009,
|
||||
'codicon-mirror-public': 60009,
|
||||
'codicon-star': 60010,
|
||||
'codicon-star-add': 60010,
|
||||
'codicon-star-delete': 60010,
|
||||
'codicon-star-empty': 60010,
|
||||
'codicon-comment': 60011,
|
||||
'codicon-comment-add': 60011,
|
||||
'codicon-alert': 60012,
|
||||
'codicon-warning': 60012,
|
||||
'codicon-search': 60013,
|
||||
'codicon-search-save': 60013,
|
||||
'codicon-log-out': 60014,
|
||||
'codicon-sign-out': 60014,
|
||||
'codicon-log-in': 60015,
|
||||
'codicon-sign-in': 60015,
|
||||
'codicon-eye': 60016,
|
||||
'codicon-eye-unwatch': 60016,
|
||||
'codicon-eye-watch': 60016,
|
||||
'codicon-circle-filled': 60017,
|
||||
'codicon-primitive-dot': 60017,
|
||||
'codicon-close-dirty': 60017,
|
||||
'codicon-debug-breakpoint': 60017,
|
||||
'codicon-debug-breakpoint-disabled': 60017,
|
||||
'codicon-debug-hint': 60017,
|
||||
'codicon-terminal-decoration-success': 60017,
|
||||
'codicon-primitive-square': 60018,
|
||||
'codicon-edit': 60019,
|
||||
'codicon-pencil': 60019,
|
||||
'codicon-info': 60020,
|
||||
'codicon-issue-opened': 60020,
|
||||
'codicon-gist-private': 60021,
|
||||
'codicon-git-fork-private': 60021,
|
||||
'codicon-lock': 60021,
|
||||
'codicon-mirror-private': 60021,
|
||||
'codicon-close': 60022,
|
||||
'codicon-remove-close': 60022,
|
||||
'codicon-x': 60022,
|
||||
'codicon-repo-sync': 60023,
|
||||
'codicon-sync': 60023,
|
||||
'codicon-clone': 60024,
|
||||
'codicon-desktop-download': 60024,
|
||||
'codicon-beaker': 60025,
|
||||
'codicon-microscope': 60025,
|
||||
'codicon-vm': 60026,
|
||||
'codicon-device-desktop': 60026,
|
||||
'codicon-file': 60027,
|
||||
'codicon-more': 60028,
|
||||
'codicon-ellipsis': 60028,
|
||||
'codicon-kebab-horizontal': 60028,
|
||||
'codicon-mail-reply': 60029,
|
||||
'codicon-reply': 60029,
|
||||
'codicon-organization': 60030,
|
||||
'codicon-organization-filled': 60030,
|
||||
'codicon-organization-outline': 60030,
|
||||
'codicon-new-file': 60031,
|
||||
'codicon-file-add': 60031,
|
||||
'codicon-new-folder': 60032,
|
||||
'codicon-file-directory-create': 60032,
|
||||
'codicon-trash': 60033,
|
||||
'codicon-trashcan': 60033,
|
||||
'codicon-history': 60034,
|
||||
'codicon-clock': 60034,
|
||||
'codicon-folder': 60035,
|
||||
'codicon-file-directory': 60035,
|
||||
'codicon-symbol-folder': 60035,
|
||||
'codicon-logo-github': 60036,
|
||||
'codicon-mark-github': 60036,
|
||||
'codicon-github': 60036,
|
||||
'codicon-terminal': 60037,
|
||||
'codicon-console': 60037,
|
||||
'codicon-repl': 60037,
|
||||
'codicon-zap': 60038,
|
||||
'codicon-symbol-event': 60038,
|
||||
'codicon-error': 60039,
|
||||
'codicon-stop': 60039,
|
||||
'codicon-variable': 60040,
|
||||
'codicon-symbol-variable': 60040,
|
||||
'codicon-array': 60042,
|
||||
'codicon-symbol-array': 60042,
|
||||
'codicon-symbol-module': 60043,
|
||||
'codicon-symbol-package': 60043,
|
||||
'codicon-symbol-namespace': 60043,
|
||||
'codicon-symbol-object': 60043,
|
||||
'codicon-symbol-method': 60044,
|
||||
'codicon-symbol-function': 60044,
|
||||
'codicon-symbol-constructor': 60044,
|
||||
'codicon-symbol-boolean': 60047,
|
||||
'codicon-symbol-null': 60047,
|
||||
'codicon-symbol-numeric': 60048,
|
||||
'codicon-symbol-number': 60048,
|
||||
'codicon-symbol-structure': 60049,
|
||||
'codicon-symbol-struct': 60049,
|
||||
'codicon-symbol-parameter': 60050,
|
||||
'codicon-symbol-type-parameter': 60050,
|
||||
'codicon-symbol-key': 60051,
|
||||
'codicon-symbol-text': 60051,
|
||||
'codicon-symbol-reference': 60052,
|
||||
'codicon-go-to-file': 60052,
|
||||
'codicon-symbol-enum': 60053,
|
||||
'codicon-symbol-value': 60053,
|
||||
'codicon-symbol-ruler': 60054,
|
||||
'codicon-symbol-unit': 60054,
|
||||
'codicon-activate-breakpoints': 60055,
|
||||
'codicon-archive': 60056,
|
||||
'codicon-arrow-both': 60057,
|
||||
'codicon-arrow-down': 60058,
|
||||
'codicon-arrow-left': 60059,
|
||||
'codicon-arrow-right': 60060,
|
||||
'codicon-arrow-small-down': 60061,
|
||||
'codicon-arrow-small-left': 60062,
|
||||
'codicon-arrow-small-right': 60063,
|
||||
'codicon-arrow-small-up': 60064,
|
||||
'codicon-arrow-up': 60065,
|
||||
'codicon-bell': 60066,
|
||||
'codicon-bold': 60067,
|
||||
'codicon-book': 60068,
|
||||
'codicon-bookmark': 60069,
|
||||
'codicon-debug-breakpoint-conditional-unverified': 60070,
|
||||
'codicon-debug-breakpoint-conditional': 60071,
|
||||
'codicon-debug-breakpoint-conditional-disabled': 60071,
|
||||
'codicon-debug-breakpoint-data-unverified': 60072,
|
||||
'codicon-debug-breakpoint-data': 60073,
|
||||
'codicon-debug-breakpoint-data-disabled': 60073,
|
||||
'codicon-debug-breakpoint-log-unverified': 60074,
|
||||
'codicon-debug-breakpoint-log': 60075,
|
||||
'codicon-debug-breakpoint-log-disabled': 60075,
|
||||
'codicon-briefcase': 60076,
|
||||
'codicon-broadcast': 60077,
|
||||
'codicon-browser': 60078,
|
||||
'codicon-bug': 60079,
|
||||
'codicon-calendar': 60080,
|
||||
'codicon-case-sensitive': 60081,
|
||||
'codicon-check': 60082,
|
||||
'codicon-checklist': 60083,
|
||||
'codicon-chevron-down': 60084,
|
||||
'codicon-chevron-left': 60085,
|
||||
'codicon-chevron-right': 60086,
|
||||
'codicon-chevron-up': 60087,
|
||||
'codicon-chrome-close': 60088,
|
||||
'codicon-chrome-maximize': 60089,
|
||||
'codicon-chrome-minimize': 60090,
|
||||
'codicon-chrome-restore': 60091,
|
||||
'codicon-circle-outline': 60092,
|
||||
'codicon-circle': 60092,
|
||||
'codicon-debug-breakpoint-unverified': 60092,
|
||||
'codicon-terminal-decoration-incomplete': 60092,
|
||||
'codicon-circle-slash': 60093,
|
||||
'codicon-circuit-board': 60094,
|
||||
'codicon-clear-all': 60095,
|
||||
'codicon-clippy': 60096,
|
||||
'codicon-close-all': 60097,
|
||||
'codicon-cloud-download': 60098,
|
||||
'codicon-cloud-upload': 60099,
|
||||
'codicon-code': 60100,
|
||||
'codicon-collapse-all': 60101,
|
||||
'codicon-color-mode': 60102,
|
||||
'codicon-comment-discussion': 60103,
|
||||
'codicon-credit-card': 60105,
|
||||
'codicon-dash': 60108,
|
||||
'codicon-dashboard': 60109,
|
||||
'codicon-database': 60110,
|
||||
'codicon-debug-continue': 60111,
|
||||
'codicon-debug-disconnect': 60112,
|
||||
'codicon-debug-pause': 60113,
|
||||
'codicon-debug-restart': 60114,
|
||||
'codicon-debug-start': 60115,
|
||||
'codicon-debug-step-into': 60116,
|
||||
'codicon-debug-step-out': 60117,
|
||||
'codicon-debug-step-over': 60118,
|
||||
'codicon-debug-stop': 60119,
|
||||
'codicon-debug': 60120,
|
||||
'codicon-device-camera-video': 60121,
|
||||
'codicon-device-camera': 60122,
|
||||
'codicon-device-mobile': 60123,
|
||||
'codicon-diff-added': 60124,
|
||||
'codicon-diff-ignored': 60125,
|
||||
'codicon-diff-modified': 60126,
|
||||
'codicon-diff-removed': 60127,
|
||||
'codicon-diff-renamed': 60128,
|
||||
'codicon-diff': 60129,
|
||||
'codicon-diff-sidebyside': 60129,
|
||||
'codicon-discard': 60130,
|
||||
'codicon-editor-layout': 60131,
|
||||
'codicon-empty-window': 60132,
|
||||
'codicon-exclude': 60133,
|
||||
'codicon-extensions': 60134,
|
||||
'codicon-eye-closed': 60135,
|
||||
'codicon-file-binary': 60136,
|
||||
'codicon-file-code': 60137,
|
||||
'codicon-file-media': 60138,
|
||||
'codicon-file-pdf': 60139,
|
||||
'codicon-file-submodule': 60140,
|
||||
'codicon-file-symlink-directory': 60141,
|
||||
'codicon-file-symlink-file': 60142,
|
||||
'codicon-file-zip': 60143,
|
||||
'codicon-files': 60144,
|
||||
'codicon-filter': 60145,
|
||||
'codicon-flame': 60146,
|
||||
'codicon-fold-down': 60147,
|
||||
'codicon-fold-up': 60148,
|
||||
'codicon-fold': 60149,
|
||||
'codicon-folder-active': 60150,
|
||||
'codicon-folder-opened': 60151,
|
||||
'codicon-gear': 60152,
|
||||
'codicon-gift': 60153,
|
||||
'codicon-gist-secret': 60154,
|
||||
'codicon-gist': 60155,
|
||||
'codicon-git-commit': 60156,
|
||||
'codicon-git-compare': 60157,
|
||||
'codicon-compare-changes': 60157,
|
||||
'codicon-git-merge': 60158,
|
||||
'codicon-github-action': 60159,
|
||||
'codicon-github-alt': 60160,
|
||||
'codicon-globe': 60161,
|
||||
'codicon-grabber': 60162,
|
||||
'codicon-graph': 60163,
|
||||
'codicon-gripper': 60164,
|
||||
'codicon-heart': 60165,
|
||||
'codicon-home': 60166,
|
||||
'codicon-horizontal-rule': 60167,
|
||||
'codicon-hubot': 60168,
|
||||
'codicon-inbox': 60169,
|
||||
'codicon-issue-reopened': 60171,
|
||||
'codicon-issues': 60172,
|
||||
'codicon-italic': 60173,
|
||||
'codicon-jersey': 60174,
|
||||
'codicon-json': 60175,
|
||||
'codicon-kebab-vertical': 60176,
|
||||
'codicon-key': 60177,
|
||||
'codicon-law': 60178,
|
||||
'codicon-lightbulb-autofix': 60179,
|
||||
'codicon-link-external': 60180,
|
||||
'codicon-link': 60181,
|
||||
'codicon-list-ordered': 60182,
|
||||
'codicon-list-unordered': 60183,
|
||||
'codicon-live-share': 60184,
|
||||
'codicon-loading': 60185,
|
||||
'codicon-location': 60186,
|
||||
'codicon-mail-read': 60187,
|
||||
'codicon-mail': 60188,
|
||||
'codicon-markdown': 60189,
|
||||
'codicon-megaphone': 60190,
|
||||
'codicon-mention': 60191,
|
||||
'codicon-milestone': 60192,
|
||||
'codicon-git-pull-request-milestone': 60192,
|
||||
'codicon-mortar-board': 60193,
|
||||
'codicon-move': 60194,
|
||||
'codicon-multiple-windows': 60195,
|
||||
'codicon-mute': 60196,
|
||||
'codicon-no-newline': 60197,
|
||||
'codicon-note': 60198,
|
||||
'codicon-octoface': 60199,
|
||||
'codicon-open-preview': 60200,
|
||||
'codicon-package': 60201,
|
||||
'codicon-paintcan': 60202,
|
||||
'codicon-pin': 60203,
|
||||
'codicon-play': 60204,
|
||||
'codicon-run': 60204,
|
||||
'codicon-plug': 60205,
|
||||
'codicon-preserve-case': 60206,
|
||||
'codicon-preview': 60207,
|
||||
'codicon-project': 60208,
|
||||
'codicon-pulse': 60209,
|
||||
'codicon-question': 60210,
|
||||
'codicon-quote': 60211,
|
||||
'codicon-radio-tower': 60212,
|
||||
'codicon-reactions': 60213,
|
||||
'codicon-references': 60214,
|
||||
'codicon-refresh': 60215,
|
||||
'codicon-regex': 60216,
|
||||
'codicon-remote-explorer': 60217,
|
||||
'codicon-remote': 60218,
|
||||
'codicon-remove': 60219,
|
||||
'codicon-replace-all': 60220,
|
||||
'codicon-replace': 60221,
|
||||
'codicon-repo-clone': 60222,
|
||||
'codicon-repo-force-push': 60223,
|
||||
'codicon-repo-pull': 60224,
|
||||
'codicon-repo-push': 60225,
|
||||
'codicon-report': 60226,
|
||||
'codicon-request-changes': 60227,
|
||||
'codicon-rocket': 60228,
|
||||
'codicon-root-folder-opened': 60229,
|
||||
'codicon-root-folder': 60230,
|
||||
'codicon-rss': 60231,
|
||||
'codicon-ruby': 60232,
|
||||
'codicon-save-all': 60233,
|
||||
'codicon-save-as': 60234,
|
||||
'codicon-save': 60235,
|
||||
'codicon-screen-full': 60236,
|
||||
'codicon-screen-normal': 60237,
|
||||
'codicon-search-stop': 60238,
|
||||
'codicon-server': 60240,
|
||||
'codicon-settings-gear': 60241,
|
||||
'codicon-settings': 60242,
|
||||
'codicon-shield': 60243,
|
||||
'codicon-smiley': 60244,
|
||||
'codicon-sort-precedence': 60245,
|
||||
'codicon-split-horizontal': 60246,
|
||||
'codicon-split-vertical': 60247,
|
||||
'codicon-squirrel': 60248,
|
||||
'codicon-star-full': 60249,
|
||||
'codicon-star-half': 60250,
|
||||
'codicon-symbol-class': 60251,
|
||||
'codicon-symbol-color': 60252,
|
||||
'codicon-symbol-constant': 60253,
|
||||
'codicon-symbol-enum-member': 60254,
|
||||
'codicon-symbol-field': 60255,
|
||||
'codicon-symbol-file': 60256,
|
||||
'codicon-symbol-interface': 60257,
|
||||
'codicon-symbol-keyword': 60258,
|
||||
'codicon-symbol-misc': 60259,
|
||||
'codicon-symbol-operator': 60260,
|
||||
'codicon-symbol-property': 60261,
|
||||
'codicon-wrench': 60261,
|
||||
'codicon-wrench-subaction': 60261,
|
||||
'codicon-symbol-snippet': 60262,
|
||||
'codicon-tasklist': 60263,
|
||||
'codicon-telescope': 60264,
|
||||
'codicon-text-size': 60265,
|
||||
'codicon-three-bars': 60266,
|
||||
'codicon-thumbsdown': 60267,
|
||||
'codicon-thumbsup': 60268,
|
||||
'codicon-tools': 60269,
|
||||
'codicon-triangle-down': 60270,
|
||||
'codicon-triangle-left': 60271,
|
||||
'codicon-triangle-right': 60272,
|
||||
'codicon-triangle-up': 60273,
|
||||
'codicon-twitter': 60274,
|
||||
'codicon-unfold': 60275,
|
||||
'codicon-unlock': 60276,
|
||||
'codicon-unmute': 60277,
|
||||
'codicon-unverified': 60278,
|
||||
'codicon-verified': 60279,
|
||||
'codicon-versions': 60280,
|
||||
'codicon-vm-active': 60281,
|
||||
'codicon-vm-outline': 60282,
|
||||
'codicon-vm-running': 60283,
|
||||
'codicon-watch': 60284,
|
||||
'codicon-whitespace': 60285,
|
||||
'codicon-whole-word': 60286,
|
||||
'codicon-window': 60287,
|
||||
'codicon-word-wrap': 60288,
|
||||
'codicon-zoom-in': 60289,
|
||||
'codicon-zoom-out': 60290,
|
||||
'codicon-list-filter': 60291,
|
||||
'codicon-list-flat': 60292,
|
||||
'codicon-list-selection': 60293,
|
||||
'codicon-selection': 60293,
|
||||
'codicon-list-tree': 60294,
|
||||
'codicon-debug-breakpoint-function-unverified': 60295,
|
||||
'codicon-debug-breakpoint-function': 60296,
|
||||
'codicon-debug-breakpoint-function-disabled': 60296,
|
||||
'codicon-debug-stackframe-active': 60297,
|
||||
'codicon-circle-small-filled': 60298,
|
||||
'codicon-debug-stackframe-dot': 60298,
|
||||
'codicon-terminal-decoration-mark': 60298,
|
||||
'codicon-debug-stackframe': 60299,
|
||||
'codicon-debug-stackframe-focused': 60299,
|
||||
'codicon-debug-breakpoint-unsupported': 60300,
|
||||
'codicon-symbol-string': 60301,
|
||||
'codicon-debug-reverse-continue': 60302,
|
||||
'codicon-debug-step-back': 60303,
|
||||
'codicon-debug-restart-frame': 60304,
|
||||
'codicon-debug-alt': 60305,
|
||||
'codicon-call-incoming': 60306,
|
||||
'codicon-call-outgoing': 60307,
|
||||
'codicon-menu': 60308,
|
||||
'codicon-expand-all': 60309,
|
||||
'codicon-feedback': 60310,
|
||||
'codicon-git-pull-request-reviewer': 60310,
|
||||
'codicon-group-by-ref-type': 60311,
|
||||
'codicon-ungroup-by-ref-type': 60312,
|
||||
'codicon-account': 60313,
|
||||
'codicon-git-pull-request-assignee': 60313,
|
||||
'codicon-bell-dot': 60314,
|
||||
'codicon-debug-console': 60315,
|
||||
'codicon-library': 60316,
|
||||
'codicon-output': 60317,
|
||||
'codicon-run-all': 60318,
|
||||
'codicon-sync-ignored': 60319,
|
||||
'codicon-pinned': 60320,
|
||||
'codicon-github-inverted': 60321,
|
||||
'codicon-server-process': 60322,
|
||||
'codicon-server-environment': 60323,
|
||||
'codicon-pass': 60324,
|
||||
'codicon-issue-closed': 60324,
|
||||
'codicon-stop-circle': 60325,
|
||||
'codicon-play-circle': 60326,
|
||||
'codicon-record': 60327,
|
||||
'codicon-debug-alt-small': 60328,
|
||||
'codicon-vm-connect': 60329,
|
||||
'codicon-cloud': 60330,
|
||||
'codicon-merge': 60331,
|
||||
'codicon-export': 60332,
|
||||
'codicon-graph-left': 60333,
|
||||
'codicon-magnet': 60334,
|
||||
'codicon-notebook': 60335,
|
||||
'codicon-redo': 60336,
|
||||
'codicon-check-all': 60337,
|
||||
'codicon-pinned-dirty': 60338,
|
||||
'codicon-pass-filled': 60339,
|
||||
'codicon-circle-large-filled': 60340,
|
||||
'codicon-circle-large': 60341,
|
||||
'codicon-circle-large-outline': 60341,
|
||||
'codicon-combine': 60342,
|
||||
'codicon-gather': 60342,
|
||||
'codicon-table': 60343,
|
||||
'codicon-variable-group': 60344,
|
||||
'codicon-type-hierarchy': 60345,
|
||||
'codicon-type-hierarchy-sub': 60346,
|
||||
'codicon-type-hierarchy-super': 60347,
|
||||
'codicon-git-pull-request-create': 60348,
|
||||
'codicon-run-above': 60349,
|
||||
'codicon-run-below': 60350,
|
||||
'codicon-notebook-template': 60351,
|
||||
'codicon-debug-rerun': 60352,
|
||||
'codicon-workspace-trusted': 60353,
|
||||
'codicon-workspace-untrusted': 60354,
|
||||
'codicon-workspace-unknown': 60355,
|
||||
'codicon-terminal-cmd': 60356,
|
||||
'codicon-terminal-debian': 60357,
|
||||
'codicon-terminal-linux': 60358,
|
||||
'codicon-terminal-powershell': 60359,
|
||||
'codicon-terminal-tmux': 60360,
|
||||
'codicon-terminal-ubuntu': 60361,
|
||||
'codicon-terminal-bash': 60362,
|
||||
'codicon-arrow-swap': 60363,
|
||||
'codicon-copy': 60364,
|
||||
'codicon-person-add': 60365,
|
||||
'codicon-filter-filled': 60366,
|
||||
'codicon-wand': 60367,
|
||||
'codicon-debug-line-by-line': 60368,
|
||||
'codicon-inspect': 60369,
|
||||
'codicon-layers': 60370,
|
||||
'codicon-layers-dot': 60371,
|
||||
'codicon-layers-active': 60372,
|
||||
'codicon-compass': 60373,
|
||||
'codicon-compass-dot': 60374,
|
||||
'codicon-compass-active': 60375,
|
||||
'codicon-azure': 60376,
|
||||
'codicon-issue-draft': 60377,
|
||||
'codicon-git-pull-request-closed': 60378,
|
||||
'codicon-git-pull-request-draft': 60379,
|
||||
'codicon-debug-all': 60380,
|
||||
'codicon-debug-coverage': 60381,
|
||||
'codicon-run-errors': 60382,
|
||||
'codicon-folder-library': 60383,
|
||||
'codicon-debug-continue-small': 60384,
|
||||
'codicon-beaker-stop': 60385,
|
||||
'codicon-graph-line': 60386,
|
||||
'codicon-graph-scatter': 60387,
|
||||
'codicon-pie-chart': 60388,
|
||||
'codicon-bracket': 60175,
|
||||
'codicon-bracket-dot': 60389,
|
||||
'codicon-bracket-error': 60390,
|
||||
'codicon-lock-small': 60391,
|
||||
'codicon-azure-devops': 60392,
|
||||
'codicon-verified-filled': 60393,
|
||||
'codicon-newline': 60394,
|
||||
'codicon-layout': 60395,
|
||||
'codicon-layout-activitybar-left': 60396,
|
||||
'codicon-layout-activitybar-right': 60397,
|
||||
'codicon-layout-panel-left': 60398,
|
||||
'codicon-layout-panel-center': 60399,
|
||||
'codicon-layout-panel-justify': 60400,
|
||||
'codicon-layout-panel-right': 60401,
|
||||
'codicon-layout-panel': 60402,
|
||||
'codicon-layout-sidebar-left': 60403,
|
||||
'codicon-layout-sidebar-right': 60404,
|
||||
'codicon-layout-statusbar': 60405,
|
||||
'codicon-layout-menubar': 60406,
|
||||
'codicon-layout-centered': 60407,
|
||||
'codicon-target': 60408,
|
||||
'codicon-indent': 60409,
|
||||
'codicon-record-small': 60410,
|
||||
'codicon-error-small': 60411,
|
||||
'codicon-terminal-decoration-error': 60411,
|
||||
'codicon-arrow-circle-down': 60412,
|
||||
'codicon-arrow-circle-left': 60413,
|
||||
'codicon-arrow-circle-right': 60414,
|
||||
'codicon-arrow-circle-up': 60415,
|
||||
'codicon-layout-sidebar-right-off': 60416,
|
||||
'codicon-layout-panel-off': 60417,
|
||||
'codicon-layout-sidebar-left-off': 60418,
|
||||
'codicon-blank': 60419,
|
||||
'codicon-heart-filled': 60420,
|
||||
'codicon-map': 60421,
|
||||
'codicon-map-horizontal': 60421,
|
||||
'codicon-fold-horizontal': 60421,
|
||||
'codicon-map-filled': 60422,
|
||||
'codicon-map-horizontal-filled': 60422,
|
||||
'codicon-fold-horizontal-filled': 60422,
|
||||
'codicon-circle-small': 60423,
|
||||
'codicon-bell-slash': 60424,
|
||||
'codicon-bell-slash-dot': 60425,
|
||||
'codicon-comment-unresolved': 60426,
|
||||
'codicon-git-pull-request-go-to-changes': 60427,
|
||||
'codicon-git-pull-request-new-changes': 60428,
|
||||
'codicon-search-fuzzy': 60429,
|
||||
'codicon-comment-draft': 60430,
|
||||
'codicon-send': 60431,
|
||||
'codicon-sparkle': 60432,
|
||||
'codicon-insert': 60433,
|
||||
'codicon-mic': 60434,
|
||||
'codicon-thumbsdown-filled': 60435,
|
||||
'codicon-thumbsup-filled': 60436,
|
||||
'codicon-coffee': 60437,
|
||||
'codicon-snake': 60438,
|
||||
'codicon-game': 60439,
|
||||
'codicon-vr': 60440,
|
||||
'codicon-chip': 60441,
|
||||
'codicon-piano': 60442,
|
||||
'codicon-music': 60443,
|
||||
'codicon-mic-filled': 60444,
|
||||
'codicon-repo-fetch': 60445,
|
||||
'codicon-copilot': 60446,
|
||||
'codicon-lightbulb-sparkle': 60447,
|
||||
'codicon-robot': 60448,
|
||||
'codicon-sparkle-filled': 60449,
|
||||
'codicon-diff-single': 60450,
|
||||
'codicon-diff-multiple': 60451,
|
||||
'codicon-surround-with': 60452,
|
||||
'codicon-share': 60453,
|
||||
'codicon-git-stash': 60454,
|
||||
'codicon-git-stash-apply': 60455,
|
||||
'codicon-git-stash-pop': 60456,
|
||||
'codicon-vscode': 60457,
|
||||
'codicon-vscode-insiders': 60458,
|
||||
'codicon-code-oss': 60459,
|
||||
'codicon-run-coverage': 60460,
|
||||
'codicon-run-all-coverage': 60461,
|
||||
'codicon-coverage': 60462,
|
||||
'codicon-github-project': 60463,
|
||||
'codicon-map-vertical': 60464,
|
||||
'codicon-fold-vertical': 60464,
|
||||
'codicon-map-vertical-filled': 60465,
|
||||
'codicon-fold-vertical-filled': 60465,
|
||||
'codicon-go-to-search': 60466,
|
||||
'codicon-percentage': 60467,
|
||||
'codicon-sort-percentage': 60467,
|
||||
'codicon-attach': 60468,
|
||||
'codicon-go-to-editing-session': 60469,
|
||||
'codicon-edit-session': 60470,
|
||||
'codicon-code-review': 60471,
|
||||
'codicon-copilot-warning': 60472,
|
||||
'codicon-python': 60473,
|
||||
'codicon-copilot-large': 60474,
|
||||
'codicon-copilot-warning-large': 60475,
|
||||
'codicon-keyboard-tab': 60476,
|
||||
'codicon-copilot-blocked': 60477,
|
||||
'codicon-copilot-not-connected': 60478,
|
||||
'codicon-flag': 60479,
|
||||
'codicon-lightbulb-empty': 60480,
|
||||
'codicon-symbol-method-arrow': 60481,
|
||||
'codicon-copilot-unavailable': 60482,
|
||||
'codicon-repo-pinned': 60483,
|
||||
'codicon-keyboard-tab-above': 60484,
|
||||
'codicon-keyboard-tab-below': 60485,
|
||||
'codicon-git-pull-request-done': 60486,
|
||||
'codicon-mcp': 60487,
|
||||
'codicon-extensions-large': 60488,
|
||||
'codicon-layout-panel-dock': 60489,
|
||||
'codicon-layout-sidebar-left-dock': 60490,
|
||||
'codicon-layout-sidebar-right-dock': 60491,
|
||||
'codicon-copilot-in-progress': 60492,
|
||||
'codicon-copilot-error': 60493,
|
||||
'codicon-copilot-success': 60494,
|
||||
'codicon-chat-sparkle': 60495,
|
||||
'codicon-search-sparkle': 60496,
|
||||
'codicon-edit-sparkle': 60497,
|
||||
'codicon-copilot-snooze': 60498,
|
||||
'codicon-send-to-remote-agent': 60499,
|
||||
'codicon-comment-discussion-sparkle': 60500,
|
||||
'codicon-chat-sparkle-warning': 60501,
|
||||
'codicon-chat-sparkle-error': 60502,
|
||||
'codicon-collection': 60503,
|
||||
'codicon-new-collection': 60504,
|
||||
'codicon-thinking': 60505,
|
||||
'codicon-build': 60506,
|
||||
'codicon-comment-discussion-quote': 60507,
|
||||
'codicon-cursor': 60508,
|
||||
'codicon-eraser': 60509,
|
||||
'codicon-file-text': 60510,
|
||||
'codicon-git-lens': 60511,
|
||||
'codicon-quotes': 60512,
|
||||
'codicon-rename': 60513,
|
||||
'codicon-run-with-deps': 60514,
|
||||
'codicon-debug-connected': 60515,
|
||||
'codicon-strikethrough': 60516,
|
||||
'codicon-open-in-product': 60517,
|
||||
'codicon-index-zero': 60518,
|
||||
'codicon-agent': 60519,
|
||||
'codicon-edit-code': 60520,
|
||||
'codicon-repo-selected': 60521,
|
||||
'codicon-skip': 60522,
|
||||
'codicon-merge-into': 60523,
|
||||
'codicon-git-branch-changes': 60524,
|
||||
'codicon-git-branch-staged-changes': 60525,
|
||||
'codicon-git-branch-conflicts': 60526,
|
||||
'codicon-git-branch': 60527,
|
||||
'codicon-git-branch-create': 60527,
|
||||
'codicon-git-branch-delete': 60527,
|
||||
'codicon-search-large': 60528,
|
||||
'codicon-terminal-git-bash': 60529
|
||||
};
|
||||
804
packages/toolbar/src/browser/icons/font-awesome-icons.ts
Normal file
804
packages/toolbar/src/browser/icons/font-awesome-icons.ts
Normal file
@@ -0,0 +1,804 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export const fontAwesomeMapping = {
|
||||
'fa-glass': 'f000',
|
||||
'fa-music': 'f001',
|
||||
'fa-search': 'f002',
|
||||
'fa-envelope-o': 'f003',
|
||||
'fa-heart': 'f004',
|
||||
'fa-star': 'f005',
|
||||
'fa-star-o': 'f006',
|
||||
'fa-user': 'f007',
|
||||
'fa-film': 'f008',
|
||||
'fa-th-large': 'f009',
|
||||
'fa-th': 'f00a',
|
||||
'fa-th-list': 'f00b',
|
||||
'fa-check': 'f00c',
|
||||
'fa-remove': 'f00d',
|
||||
'fa-close': 'f00d',
|
||||
'fa-times': 'f00d',
|
||||
'fa-search-plus': 'f00e',
|
||||
'fa-search-minus': 'f010',
|
||||
'fa-power-off': 'f011',
|
||||
'fa-signal': 'f012',
|
||||
'fa-gear': 'f013',
|
||||
'fa-cog': 'f013',
|
||||
'fa-trash-o': 'f014',
|
||||
'fa-home': 'f015',
|
||||
'fa-file-o': 'f016',
|
||||
'fa-clock-o': 'f017',
|
||||
'fa-road': 'f018',
|
||||
'fa-download': 'f019',
|
||||
'fa-arrow-circle-o-down': 'f01a',
|
||||
'fa-arrow-circle-o-up': 'f01b',
|
||||
'fa-inbox': 'f01c',
|
||||
'fa-play-circle-o': 'f01d',
|
||||
'fa-rotate-right': 'f01e',
|
||||
'fa-repeat': 'f01e',
|
||||
'fa-refresh': 'f021',
|
||||
'fa-list-alt': 'f022',
|
||||
'fa-lock': 'f023',
|
||||
'fa-flag': 'f024',
|
||||
'fa-headphones': 'f025',
|
||||
'fa-volume-off': 'f026',
|
||||
'fa-volume-down': 'f027',
|
||||
'fa-volume-up': 'f028',
|
||||
'fa-qrcode': 'f029',
|
||||
'fa-barcode': 'f02a',
|
||||
'fa-tag': 'f02b',
|
||||
'fa-tags': 'f02c',
|
||||
'fa-book': 'f02d',
|
||||
'fa-bookmark': 'f02e',
|
||||
'fa-print': 'f02f',
|
||||
'fa-camera': 'f030',
|
||||
'fa-font': 'f031',
|
||||
'fa-bold': 'f032',
|
||||
'fa-italic': 'f033',
|
||||
'fa-text-height': 'f034',
|
||||
'fa-text-width': 'f035',
|
||||
'fa-align-left': 'f036',
|
||||
'fa-align-center': 'f037',
|
||||
'fa-align-right': 'f038',
|
||||
'fa-align-justify': 'f039',
|
||||
'fa-list': 'f03a',
|
||||
'fa-dedent': 'f03b',
|
||||
'fa-outdent': 'f03b',
|
||||
'fa-indent': 'f03c',
|
||||
'fa-video-camera': 'f03d',
|
||||
'fa-photo': 'f03e',
|
||||
'fa-image': 'f03e',
|
||||
'fa-picture-o': 'f03e',
|
||||
'fa-pencil': 'f040',
|
||||
'fa-map-marker': 'f041',
|
||||
'fa-adjust': 'f042',
|
||||
'fa-tint': 'f043',
|
||||
'fa-edit': 'f044',
|
||||
'fa-pencil-square-o': 'f044',
|
||||
'fa-share-square-o': 'f045',
|
||||
'fa-check-square-o': 'f046',
|
||||
'fa-arrows': 'f047',
|
||||
'fa-step-backward': 'f048',
|
||||
'fa-fast-backward': 'f049',
|
||||
'fa-backward': 'f04a',
|
||||
'fa-play': 'f04b',
|
||||
'fa-pause': 'f04c',
|
||||
'fa-stop': 'f04d',
|
||||
'fa-forward': 'f04e',
|
||||
'fa-fast-forward': 'f050',
|
||||
'fa-step-forward': 'f051',
|
||||
'fa-eject': 'f052',
|
||||
'fa-chevron-left': 'f053',
|
||||
'fa-chevron-right': 'f054',
|
||||
'fa-plus-circle': 'f055',
|
||||
'fa-minus-circle': 'f056',
|
||||
'fa-times-circle': 'f057',
|
||||
'fa-check-circle': 'f058',
|
||||
'fa-question-circle': 'f059',
|
||||
'fa-info-circle': 'f05a',
|
||||
'fa-crosshairs': 'f05b',
|
||||
'fa-times-circle-o': 'f05c',
|
||||
'fa-check-circle-o': 'f05d',
|
||||
'fa-ban': 'f05e',
|
||||
'fa-arrow-left': 'f060',
|
||||
'fa-arrow-right': 'f061',
|
||||
'fa-arrow-up': 'f062',
|
||||
'fa-arrow-down': 'f063',
|
||||
'fa-mail-forward': 'f064',
|
||||
'fa-share': 'f064',
|
||||
'fa-expand': 'f065',
|
||||
'fa-compress': 'f066',
|
||||
'fa-plus': 'f067',
|
||||
'fa-minus': 'f068',
|
||||
'fa-asterisk': 'f069',
|
||||
'fa-exclamation-circle': 'f06a',
|
||||
'fa-gift': 'f06b',
|
||||
'fa-leaf': 'f06c',
|
||||
'fa-fire': 'f06d',
|
||||
'fa-eye': 'f06e',
|
||||
'fa-eye-slash': 'f070',
|
||||
'fa-warning': 'f071',
|
||||
'fa-exclamation-triangle': 'f071',
|
||||
'fa-plane': 'f072',
|
||||
'fa-calendar': 'f073',
|
||||
'fa-random': 'f074',
|
||||
'fa-comment': 'f075',
|
||||
'fa-magnet': 'f076',
|
||||
'fa-chevron-up': 'f077',
|
||||
'fa-chevron-down': 'f078',
|
||||
'fa-retweet': 'f079',
|
||||
'fa-shopping-cart': 'f07a',
|
||||
'fa-folder': 'f07b',
|
||||
'fa-folder-open': 'f07c',
|
||||
'fa-arrows-v': 'f07d',
|
||||
'fa-arrows-h': 'f07e',
|
||||
'fa-bar-chart-o': 'f080',
|
||||
'fa-bar-chart': 'f080',
|
||||
'fa-twitter-square': 'f081',
|
||||
'fa-facebook-square': 'f082',
|
||||
'fa-camera-retro': 'f083',
|
||||
'fa-key': 'f084',
|
||||
'fa-gears': 'f085',
|
||||
'fa-cogs': 'f085',
|
||||
'fa-comments': 'f086',
|
||||
'fa-thumbs-o-up': 'f087',
|
||||
'fa-thumbs-o-down': 'f088',
|
||||
'fa-star-half': 'f089',
|
||||
'fa-heart-o': 'f08a',
|
||||
'fa-sign-out': 'f08b',
|
||||
'fa-linkedin-square': 'f08c',
|
||||
'fa-thumb-tack': 'f08d',
|
||||
'fa-external-link': 'f08e',
|
||||
'fa-sign-in': 'f090',
|
||||
'fa-trophy': 'f091',
|
||||
'fa-github-square': 'f092',
|
||||
'fa-upload': 'f093',
|
||||
'fa-lemon-o': 'f094',
|
||||
'fa-phone': 'f095',
|
||||
'fa-square-o': 'f096',
|
||||
'fa-bookmark-o': 'f097',
|
||||
'fa-phone-square': 'f098',
|
||||
'fa-twitter': 'f099',
|
||||
'fa-facebook-f': 'f09a',
|
||||
'fa-facebook': 'f09a',
|
||||
'fa-github': 'f09b',
|
||||
'fa-unlock': 'f09c',
|
||||
'fa-credit-card': 'f09d',
|
||||
'fa-feed': 'f09e',
|
||||
'fa-rss': 'f09e',
|
||||
'fa-hdd-o': 'f0a0',
|
||||
'fa-bullhorn': 'f0a1',
|
||||
'fa-bell': 'f0f3',
|
||||
'fa-certificate': 'f0a3',
|
||||
'fa-hand-o-right': 'f0a4',
|
||||
'fa-hand-o-left': 'f0a5',
|
||||
'fa-hand-o-up': 'f0a6',
|
||||
'fa-hand-o-down': 'f0a7',
|
||||
'fa-arrow-circle-left': 'f0a8',
|
||||
'fa-arrow-circle-right': 'f0a9',
|
||||
'fa-arrow-circle-up': 'f0aa',
|
||||
'fa-arrow-circle-down': 'f0ab',
|
||||
'fa-globe': 'f0ac',
|
||||
'fa-wrench': 'f0ad',
|
||||
'fa-tasks': 'f0ae',
|
||||
'fa-filter': 'f0b0',
|
||||
'fa-briefcase': 'f0b1',
|
||||
'fa-arrows-alt': 'f0b2',
|
||||
'fa-group': 'f0c0',
|
||||
'fa-users': 'f0c0',
|
||||
'fa-chain': 'f0c1',
|
||||
'fa-link': 'f0c1',
|
||||
'fa-cloud': 'f0c2',
|
||||
'fa-flask': 'f0c3',
|
||||
'fa-cut': 'f0c4',
|
||||
'fa-scissors': 'f0c4',
|
||||
'fa-copy': 'f0c5',
|
||||
'fa-files-o': 'f0c5',
|
||||
'fa-paperclip': 'f0c6',
|
||||
'fa-save': 'f0c7',
|
||||
'fa-floppy-o': 'f0c7',
|
||||
'fa-square': 'f0c8',
|
||||
'fa-navicon': 'f0c9',
|
||||
'fa-reorder': 'f0c9',
|
||||
'fa-bars': 'f0c9',
|
||||
'fa-list-ul': 'f0ca',
|
||||
'fa-list-ol': 'f0cb',
|
||||
'fa-strikethrough': 'f0cc',
|
||||
'fa-underline': 'f0cd',
|
||||
'fa-table': 'f0ce',
|
||||
'fa-magic': 'f0d0',
|
||||
'fa-truck': 'f0d1',
|
||||
'fa-pinterest': 'f0d2',
|
||||
'fa-pinterest-square': 'f0d3',
|
||||
'fa-google-plus-square': 'f0d4',
|
||||
'fa-google-plus': 'f0d5',
|
||||
'fa-money': 'f0d6',
|
||||
'fa-caret-down': 'f0d7',
|
||||
'fa-caret-up': 'f0d8',
|
||||
'fa-caret-left': 'f0d9',
|
||||
'fa-caret-right': 'f0da',
|
||||
'fa-columns': 'f0db',
|
||||
'fa-unsorted': 'f0dc',
|
||||
'fa-sort': 'f0dc',
|
||||
'fa-sort-down': 'f0dd',
|
||||
'fa-sort-desc': 'f0dd',
|
||||
'fa-sort-up': 'f0de',
|
||||
'fa-sort-asc': 'f0de',
|
||||
'fa-envelope': 'f0e0',
|
||||
'fa-linkedin': 'f0e1',
|
||||
'fa-rotate-left': 'f0e2',
|
||||
'fa-undo': 'f0e2',
|
||||
'fa-legal': 'f0e3',
|
||||
'fa-gavel': 'f0e3',
|
||||
'fa-dashboard': 'f0e4',
|
||||
'fa-tachometer': 'f0e4',
|
||||
'fa-comment-o': 'f0e5',
|
||||
'fa-comments-o': 'f0e6',
|
||||
'fa-flash': 'f0e7',
|
||||
'fa-bolt': 'f0e7',
|
||||
'fa-sitemap': 'f0e8',
|
||||
'fa-umbrella': 'f0e9',
|
||||
'fa-paste': 'f0ea',
|
||||
'fa-clipboard': 'f0ea',
|
||||
'fa-lightbulb-o': 'f0eb',
|
||||
'fa-exchange': 'f0ec',
|
||||
'fa-cloud-download': 'f0ed',
|
||||
'fa-cloud-upload': 'f0ee',
|
||||
'fa-user-md': 'f0f0',
|
||||
'fa-stethoscope': 'f0f1',
|
||||
'fa-suitcase': 'f0f2',
|
||||
'fa-bell-o': 'f0a2',
|
||||
'fa-coffee': 'f0f4',
|
||||
'fa-cutlery': 'f0f5',
|
||||
'fa-file-text-o': 'f0f6',
|
||||
'fa-building-o': 'f0f7',
|
||||
'fa-hospital-o': 'f0f8',
|
||||
'fa-ambulance': 'f0f9',
|
||||
'fa-medkit': 'f0fa',
|
||||
'fa-fighter-jet': 'f0fb',
|
||||
'fa-beer': 'f0fc',
|
||||
'fa-h-square': 'f0fd',
|
||||
'fa-plus-square': 'f0fe',
|
||||
'fa-angle-double-left': 'f100',
|
||||
'fa-angle-double-right': 'f101',
|
||||
'fa-angle-double-up': 'f102',
|
||||
'fa-angle-double-down': 'f103',
|
||||
'fa-angle-left': 'f104',
|
||||
'fa-angle-right': 'f105',
|
||||
'fa-angle-up': 'f106',
|
||||
'fa-angle-down': 'f107',
|
||||
'fa-desktop': 'f108',
|
||||
'fa-laptop': 'f109',
|
||||
'fa-tablet': 'f10a',
|
||||
'fa-mobile-phone': 'f10b',
|
||||
'fa-mobile': 'f10b',
|
||||
'fa-circle-o': 'f10c',
|
||||
'fa-quote-left': 'f10d',
|
||||
'fa-quote-right': 'f10e',
|
||||
'fa-spinner': 'f110',
|
||||
'fa-circle': 'f111',
|
||||
'fa-mail-reply': 'f112',
|
||||
'fa-reply': 'f112',
|
||||
'fa-github-alt': 'f113',
|
||||
'fa-folder-o': 'f114',
|
||||
'fa-folder-open-o': 'f115',
|
||||
'fa-smile-o': 'f118',
|
||||
'fa-frown-o': 'f119',
|
||||
'fa-meh-o': 'f11a',
|
||||
'fa-gamepad': 'f11b',
|
||||
'fa-keyboard-o': 'f11c',
|
||||
'fa-flag-o': 'f11d',
|
||||
'fa-flag-checkered': 'f11e',
|
||||
'fa-terminal': 'f120',
|
||||
'fa-code': 'f121',
|
||||
'fa-mail-reply-all': 'f122',
|
||||
'fa-reply-all': 'f122',
|
||||
'fa-star-half-empty': 'f123',
|
||||
'fa-star-half-full': 'f123',
|
||||
'fa-star-half-o': 'f123',
|
||||
'fa-location-arrow': 'f124',
|
||||
'fa-crop': 'f125',
|
||||
'fa-code-fork': 'f126',
|
||||
'fa-unlink': 'f127',
|
||||
'fa-chain-broken': 'f127',
|
||||
'fa-question': 'f128',
|
||||
'fa-info': 'f129',
|
||||
'fa-exclamation': 'f12a',
|
||||
'fa-superscript': 'f12b',
|
||||
'fa-subscript': 'f12c',
|
||||
'fa-eraser': 'f12d',
|
||||
'fa-puzzle-piece': 'f12e',
|
||||
'fa-microphone': 'f130',
|
||||
'fa-microphone-slash': 'f131',
|
||||
'fa-shield': 'f132',
|
||||
'fa-calendar-o': 'f133',
|
||||
'fa-fire-extinguisher': 'f134',
|
||||
'fa-rocket': 'f135',
|
||||
'fa-maxcdn': 'f136',
|
||||
'fa-chevron-circle-left': 'f137',
|
||||
'fa-chevron-circle-right': 'f138',
|
||||
'fa-chevron-circle-up': 'f139',
|
||||
'fa-chevron-circle-down': 'f13a',
|
||||
'fa-html5': 'f13b',
|
||||
'fa-css3': 'f13c',
|
||||
'fa-anchor': 'f13d',
|
||||
'fa-unlock-alt': 'f13e',
|
||||
'fa-bullseye': 'f140',
|
||||
'fa-ellipsis-h': 'f141',
|
||||
'fa-ellipsis-v': 'f142',
|
||||
'fa-rss-square': 'f143',
|
||||
'fa-play-circle': 'f144',
|
||||
'fa-ticket': 'f145',
|
||||
'fa-minus-square': 'f146',
|
||||
'fa-minus-square-o': 'f147',
|
||||
'fa-level-up': 'f148',
|
||||
'fa-level-down': 'f149',
|
||||
'fa-check-square': 'f14a',
|
||||
'fa-pencil-square': 'f14b',
|
||||
'fa-external-link-square': 'f14c',
|
||||
'fa-share-square': 'f14d',
|
||||
'fa-compass': 'f14e',
|
||||
'fa-toggle-down': 'f150',
|
||||
'fa-caret-square-o-down': 'f150',
|
||||
'fa-toggle-up': 'f151',
|
||||
'fa-caret-square-o-up': 'f151',
|
||||
'fa-toggle-right': 'f152',
|
||||
'fa-caret-square-o-right': 'f152',
|
||||
'fa-euro': 'f153',
|
||||
'fa-eur': 'f153',
|
||||
'fa-gbp': 'f154',
|
||||
'fa-dollar': 'f155',
|
||||
'fa-usd': 'f155',
|
||||
'fa-rupee': 'f156',
|
||||
'fa-inr': 'f156',
|
||||
'fa-cny': 'f157',
|
||||
'fa-rmb': 'f157',
|
||||
'fa-yen': 'f157',
|
||||
'fa-jpy': 'f157',
|
||||
'fa-ruble': 'f158',
|
||||
'fa-rouble': 'f158',
|
||||
'fa-rub': 'f158',
|
||||
'fa-won': 'f159',
|
||||
'fa-krw': 'f159',
|
||||
'fa-bitcoin': 'f15a',
|
||||
'fa-btc': 'f15a',
|
||||
'fa-file': 'f15b',
|
||||
'fa-file-text': 'f15c',
|
||||
'fa-sort-alpha-asc': 'f15d',
|
||||
'fa-sort-alpha-desc': 'f15e',
|
||||
'fa-sort-amount-asc': 'f160',
|
||||
'fa-sort-amount-desc': 'f161',
|
||||
'fa-sort-numeric-asc': 'f162',
|
||||
'fa-sort-numeric-desc': 'f163',
|
||||
'fa-thumbs-up': 'f164',
|
||||
'fa-thumbs-down': 'f165',
|
||||
'fa-youtube-square': 'f166',
|
||||
'fa-youtube': 'f167',
|
||||
'fa-xing': 'f168',
|
||||
'fa-xing-square': 'f169',
|
||||
'fa-youtube-play': 'f16a',
|
||||
'fa-dropbox': 'f16b',
|
||||
'fa-stack-overflow': 'f16c',
|
||||
'fa-instagram': 'f16d',
|
||||
'fa-flickr': 'f16e',
|
||||
'fa-adn': 'f170',
|
||||
'fa-bitbucket': 'f171',
|
||||
'fa-bitbucket-square': 'f172',
|
||||
'fa-tumblr': 'f173',
|
||||
'fa-tumblr-square': 'f174',
|
||||
'fa-long-arrow-down': 'f175',
|
||||
'fa-long-arrow-up': 'f176',
|
||||
'fa-long-arrow-left': 'f177',
|
||||
'fa-long-arrow-right': 'f178',
|
||||
'fa-apple': 'f179',
|
||||
'fa-windows': 'f17a',
|
||||
'fa-android': 'f17b',
|
||||
'fa-linux': 'f17c',
|
||||
'fa-dribbble': 'f17d',
|
||||
'fa-skype': 'f17e',
|
||||
'fa-foursquare': 'f180',
|
||||
'fa-trello': 'f181',
|
||||
'fa-female': 'f182',
|
||||
'fa-male': 'f183',
|
||||
'fa-gittip': 'f184',
|
||||
'fa-gratipay': 'f184',
|
||||
'fa-sun-o': 'f185',
|
||||
'fa-moon-o': 'f186',
|
||||
'fa-archive': 'f187',
|
||||
'fa-bug': 'f188',
|
||||
'fa-vk': 'f189',
|
||||
'fa-weibo': 'f18a',
|
||||
'fa-renren': 'f18b',
|
||||
'fa-pagelines': 'f18c',
|
||||
'fa-stack-exchange': 'f18d',
|
||||
'fa-arrow-circle-o-right': 'f18e',
|
||||
'fa-arrow-circle-o-left': 'f190',
|
||||
'fa-toggle-left': 'f191',
|
||||
'fa-caret-square-o-left': 'f191',
|
||||
'fa-dot-circle-o': 'f192',
|
||||
'fa-wheelchair': 'f193',
|
||||
'fa-vimeo-square': 'f194',
|
||||
'fa-turkish-lira': 'f195',
|
||||
'fa-try': 'f195',
|
||||
'fa-plus-square-o': 'f196',
|
||||
'fa-space-shuttle': 'f197',
|
||||
'fa-slack': 'f198',
|
||||
'fa-envelope-square': 'f199',
|
||||
'fa-wordpress': 'f19a',
|
||||
'fa-openid': 'f19b',
|
||||
'fa-institution': 'f19c',
|
||||
'fa-bank': 'f19c',
|
||||
'fa-university': 'f19c',
|
||||
'fa-mortar-board': 'f19d',
|
||||
'fa-graduation-cap': 'f19d',
|
||||
'fa-yahoo': 'f19e',
|
||||
'fa-google': 'f1a0',
|
||||
'fa-reddit': 'f1a1',
|
||||
'fa-reddit-square': 'f1a2',
|
||||
'fa-stumbleupon-circle': 'f1a3',
|
||||
'fa-stumbleupon': 'f1a4',
|
||||
'fa-delicious': 'f1a5',
|
||||
'fa-digg': 'f1a6',
|
||||
'fa-pied-piper-pp': 'f1a7',
|
||||
'fa-pied-piper-alt': 'f1a8',
|
||||
'fa-drupal': 'f1a9',
|
||||
'fa-joomla': 'f1aa',
|
||||
'fa-language': 'f1ab',
|
||||
'fa-fax': 'f1ac',
|
||||
'fa-building': 'f1ad',
|
||||
'fa-child': 'f1ae',
|
||||
'fa-paw': 'f1b0',
|
||||
'fa-spoon': 'f1b1',
|
||||
'fa-cube': 'f1b2',
|
||||
'fa-cubes': 'f1b3',
|
||||
'fa-behance': 'f1b4',
|
||||
'fa-behance-square': 'f1b5',
|
||||
'fa-steam': 'f1b6',
|
||||
'fa-steam-square': 'f1b7',
|
||||
'fa-recycle': 'f1b8',
|
||||
'fa-automobile': 'f1b9',
|
||||
'fa-car': 'f1b9',
|
||||
'fa-cab': 'f1ba',
|
||||
'fa-taxi': 'f1ba',
|
||||
'fa-tree': 'f1bb',
|
||||
'fa-spotify': 'f1bc',
|
||||
'fa-deviantart': 'f1bd',
|
||||
'fa-soundcloud': 'f1be',
|
||||
'fa-database': 'f1c0',
|
||||
'fa-file-pdf-o': 'f1c1',
|
||||
'fa-file-word-o': 'f1c2',
|
||||
'fa-file-excel-o': 'f1c3',
|
||||
'fa-file-powerpoint-o': 'f1c4',
|
||||
'fa-file-photo-o': 'f1c5',
|
||||
'fa-file-picture-o': 'f1c5',
|
||||
'fa-file-image-o': 'f1c5',
|
||||
'fa-file-zip-o': 'f1c6',
|
||||
'fa-file-archive-o': 'f1c6',
|
||||
'fa-file-sound-o': 'f1c7',
|
||||
'fa-file-audio-o': 'f1c7',
|
||||
'fa-file-movie-o': 'f1c8',
|
||||
'fa-file-video-o': 'f1c8',
|
||||
'fa-file-code-o': 'f1c9',
|
||||
'fa-vine': 'f1ca',
|
||||
'fa-codepen': 'f1cb',
|
||||
'fa-jsfiddle': 'f1cc',
|
||||
'fa-life-bouy': 'f1cd',
|
||||
'fa-life-buoy': 'f1cd',
|
||||
'fa-life-saver': 'f1cd',
|
||||
'fa-support': 'f1cd',
|
||||
'fa-life-ring': 'f1cd',
|
||||
'fa-circle-o-notch': 'f1ce',
|
||||
'fa-ra': 'f1d0',
|
||||
'fa-resistance': 'f1d0',
|
||||
'fa-rebel': 'f1d0',
|
||||
'fa-ge': 'f1d1',
|
||||
'fa-empire': 'f1d1',
|
||||
'fa-git-square': 'f1d2',
|
||||
'fa-git': 'f1d3',
|
||||
'fa-y-combinator-square': 'f1d4',
|
||||
'fa-yc-square': 'f1d4',
|
||||
'fa-hacker-news': 'f1d4',
|
||||
'fa-tencent-weibo': 'f1d5',
|
||||
'fa-qq': 'f1d6',
|
||||
'fa-wechat': 'f1d7',
|
||||
'fa-weixin': 'f1d7',
|
||||
'fa-send': 'f1d8',
|
||||
'fa-paper-plane': 'f1d8',
|
||||
'fa-send-o': 'f1d9',
|
||||
'fa-paper-plane-o': 'f1d9',
|
||||
'fa-history': 'f1da',
|
||||
'fa-circle-thin': 'f1db',
|
||||
'fa-header': 'f1dc',
|
||||
'fa-paragraph': 'f1dd',
|
||||
'fa-sliders': 'f1de',
|
||||
'fa-share-alt': 'f1e0',
|
||||
'fa-share-alt-square': 'f1e1',
|
||||
'fa-bomb': 'f1e2',
|
||||
'fa-soccer-ball-o': 'f1e3',
|
||||
'fa-futbol-o': 'f1e3',
|
||||
'fa-tty': 'f1e4',
|
||||
'fa-binoculars': 'f1e5',
|
||||
'fa-plug': 'f1e6',
|
||||
'fa-slideshare': 'f1e7',
|
||||
'fa-twitch': 'f1e8',
|
||||
'fa-yelp': 'f1e9',
|
||||
'fa-newspaper-o': 'f1ea',
|
||||
'fa-wifi': 'f1eb',
|
||||
'fa-calculator': 'f1ec',
|
||||
'fa-paypal': 'f1ed',
|
||||
'fa-google-wallet': 'f1ee',
|
||||
'fa-cc-visa': 'f1f0',
|
||||
'fa-cc-mastercard': 'f1f1',
|
||||
'fa-cc-discover': 'f1f2',
|
||||
'fa-cc-amex': 'f1f3',
|
||||
'fa-cc-paypal': 'f1f4',
|
||||
'fa-cc-stripe': 'f1f5',
|
||||
'fa-bell-slash': 'f1f6',
|
||||
'fa-bell-slash-o': 'f1f7',
|
||||
'fa-trash': 'f1f8',
|
||||
'fa-copyright': 'f1f9',
|
||||
'fa-at': 'f1fa',
|
||||
'fa-eyedropper': 'f1fb',
|
||||
'fa-paint-brush': 'f1fc',
|
||||
'fa-birthday-cake': 'f1fd',
|
||||
'fa-area-chart': 'f1fe',
|
||||
'fa-pie-chart': 'f200',
|
||||
'fa-line-chart': 'f201',
|
||||
'fa-lastfm': 'f202',
|
||||
'fa-lastfm-square': 'f203',
|
||||
'fa-toggle-off': 'f204',
|
||||
'fa-toggle-on': 'f205',
|
||||
'fa-bicycle': 'f206',
|
||||
'fa-bus': 'f207',
|
||||
'fa-ioxhost': 'f208',
|
||||
'fa-angellist': 'f209',
|
||||
'fa-cc': 'f20a',
|
||||
'fa-shekel': 'f20b',
|
||||
'fa-sheqel': 'f20b',
|
||||
'fa-ils': 'f20b',
|
||||
'fa-meanpath': 'f20c',
|
||||
'fa-buysellads': 'f20d',
|
||||
'fa-connectdevelop': 'f20e',
|
||||
'fa-dashcube': 'f210',
|
||||
'fa-forumbee': 'f211',
|
||||
'fa-leanpub': 'f212',
|
||||
'fa-sellsy': 'f213',
|
||||
'fa-shirtsinbulk': 'f214',
|
||||
'fa-simplybuilt': 'f215',
|
||||
'fa-skyatlas': 'f216',
|
||||
'fa-cart-plus': 'f217',
|
||||
'fa-cart-arrow-down': 'f218',
|
||||
'fa-diamond': 'f219',
|
||||
'fa-ship': 'f21a',
|
||||
'fa-user-secret': 'f21b',
|
||||
'fa-motorcycle': 'f21c',
|
||||
'fa-street-view': 'f21d',
|
||||
'fa-heartbeat': 'f21e',
|
||||
'fa-venus': 'f221',
|
||||
'fa-mars': 'f222',
|
||||
'fa-mercury': 'f223',
|
||||
'fa-intersex': 'f224',
|
||||
'fa-transgender': 'f224',
|
||||
'fa-transgender-alt': 'f225',
|
||||
'fa-venus-double': 'f226',
|
||||
'fa-mars-double': 'f227',
|
||||
'fa-venus-mars': 'f228',
|
||||
'fa-mars-stroke': 'f229',
|
||||
'fa-mars-stroke-v': 'f22a',
|
||||
'fa-mars-stroke-h': 'f22b',
|
||||
'fa-neuter': 'f22c',
|
||||
'fa-genderless': 'f22d',
|
||||
'fa-facebook-official': 'f230',
|
||||
'fa-pinterest-p': 'f231',
|
||||
'fa-whatsapp': 'f232',
|
||||
'fa-server': 'f233',
|
||||
'fa-user-plus': 'f234',
|
||||
'fa-user-times': 'f235',
|
||||
'fa-hotel': 'f236',
|
||||
'fa-bed': 'f236',
|
||||
'fa-viacoin': 'f237',
|
||||
'fa-train': 'f238',
|
||||
'fa-subway': 'f239',
|
||||
'fa-medium': 'f23a',
|
||||
'fa-yc': 'f23b',
|
||||
'fa-y-combinator': 'f23b',
|
||||
'fa-optin-monster': 'f23c',
|
||||
'fa-opencart': 'f23d',
|
||||
'fa-expeditedssl': 'f23e',
|
||||
'fa-battery-4': 'f240',
|
||||
'fa-battery': 'f240',
|
||||
'fa-battery-full': 'f240',
|
||||
'fa-battery-3': 'f241',
|
||||
'fa-battery-three-quarters': 'f241',
|
||||
'fa-battery-2': 'f242',
|
||||
'fa-battery-half': 'f242',
|
||||
'fa-battery-1': 'f243',
|
||||
'fa-battery-quarter': 'f243',
|
||||
'fa-battery-0': 'f244',
|
||||
'fa-battery-empty': 'f244',
|
||||
'fa-mouse-pointer': 'f245',
|
||||
'fa-i-cursor': 'f246',
|
||||
'fa-object-group': 'f247',
|
||||
'fa-object-ungroup': 'f248',
|
||||
'fa-sticky-note': 'f249',
|
||||
'fa-sticky-note-o': 'f24a',
|
||||
'fa-cc-jcb': 'f24b',
|
||||
'fa-cc-diners-club': 'f24c',
|
||||
'fa-clone': 'f24d',
|
||||
'fa-balance-scale': 'f24e',
|
||||
'fa-hourglass-o': 'f250',
|
||||
'fa-hourglass-1': 'f251',
|
||||
'fa-hourglass-start': 'f251',
|
||||
'fa-hourglass-2': 'f252',
|
||||
'fa-hourglass-half': 'f252',
|
||||
'fa-hourglass-3': 'f253',
|
||||
'fa-hourglass-end': 'f253',
|
||||
'fa-hourglass': 'f254',
|
||||
'fa-hand-grab-o': 'f255',
|
||||
'fa-hand-rock-o': 'f255',
|
||||
'fa-hand-stop-o': 'f256',
|
||||
'fa-hand-paper-o': 'f256',
|
||||
'fa-hand-scissors-o': 'f257',
|
||||
'fa-hand-lizard-o': 'f258',
|
||||
'fa-hand-spock-o': 'f259',
|
||||
'fa-hand-pointer-o': 'f25a',
|
||||
'fa-hand-peace-o': 'f25b',
|
||||
'fa-trademark': 'f25c',
|
||||
'fa-registered': 'f25d',
|
||||
'fa-creative-commons': 'f25e',
|
||||
'fa-gg': 'f260',
|
||||
'fa-gg-circle': 'f261',
|
||||
'fa-tripadvisor': 'f262',
|
||||
'fa-odnoklassniki': 'f263',
|
||||
'fa-odnoklassniki-square': 'f264',
|
||||
'fa-get-pocket': 'f265',
|
||||
'fa-wikipedia-w': 'f266',
|
||||
'fa-safari': 'f267',
|
||||
'fa-chrome': 'f268',
|
||||
'fa-firefox': 'f269',
|
||||
'fa-opera': 'f26a',
|
||||
'fa-internet-explorer': 'f26b',
|
||||
'fa-tv': 'f26c',
|
||||
'fa-television': 'f26c',
|
||||
'fa-contao': 'f26d',
|
||||
'fa-500px': 'f26e',
|
||||
'fa-amazon': 'f270',
|
||||
'fa-calendar-plus-o': 'f271',
|
||||
'fa-calendar-minus-o': 'f272',
|
||||
'fa-calendar-times-o': 'f273',
|
||||
'fa-calendar-check-o': 'f274',
|
||||
'fa-industry': 'f275',
|
||||
'fa-map-pin': 'f276',
|
||||
'fa-map-signs': 'f277',
|
||||
'fa-map-o': 'f278',
|
||||
'fa-map': 'f279',
|
||||
'fa-commenting': 'f27a',
|
||||
'fa-commenting-o': 'f27b',
|
||||
'fa-houzz': 'f27c',
|
||||
'fa-vimeo': 'f27d',
|
||||
'fa-black-tie': 'f27e',
|
||||
'fa-fonticons': 'f280',
|
||||
'fa-reddit-alien': 'f281',
|
||||
'fa-edge': 'f282',
|
||||
'fa-credit-card-alt': 'f283',
|
||||
'fa-codiepie': 'f284',
|
||||
'fa-modx': 'f285',
|
||||
'fa-fort-awesome': 'f286',
|
||||
'fa-usb': 'f287',
|
||||
'fa-product-hunt': 'f288',
|
||||
'fa-mixcloud': 'f289',
|
||||
'fa-scribd': 'f28a',
|
||||
'fa-pause-circle': 'f28b',
|
||||
'fa-pause-circle-o': 'f28c',
|
||||
'fa-stop-circle': 'f28d',
|
||||
'fa-stop-circle-o': 'f28e',
|
||||
'fa-shopping-bag': 'f290',
|
||||
'fa-shopping-basket': 'f291',
|
||||
'fa-hashtag': 'f292',
|
||||
'fa-bluetooth': 'f293',
|
||||
'fa-bluetooth-b': 'f294',
|
||||
'fa-percent': 'f295',
|
||||
'fa-gitlab': 'f296',
|
||||
'fa-wpbeginner': 'f297',
|
||||
'fa-wpforms': 'f298',
|
||||
'fa-envira': 'f299',
|
||||
'fa-universal-access': 'f29a',
|
||||
'fa-wheelchair-alt': 'f29b',
|
||||
'fa-question-circle-o': 'f29c',
|
||||
'fa-blind': 'f29d',
|
||||
'fa-audio-description': 'f29e',
|
||||
'fa-volume-control-phone': 'f2a0',
|
||||
'fa-braille': 'f2a1',
|
||||
'fa-assistive-listening-systems': 'f2a2',
|
||||
'fa-asl-interpreting': 'f2a3',
|
||||
'fa-american-sign-language-interpreting': 'f2a3',
|
||||
'fa-deafness': 'f2a4',
|
||||
'fa-hard-of-hearing': 'f2a4',
|
||||
'fa-deaf': 'f2a4',
|
||||
'fa-glide': 'f2a5',
|
||||
'fa-glide-g': 'f2a6',
|
||||
'fa-signing': 'f2a7',
|
||||
'fa-sign-language': 'f2a7',
|
||||
'fa-low-vision': 'f2a8',
|
||||
'fa-viadeo': 'f2a9',
|
||||
'fa-viadeo-square': 'f2aa',
|
||||
'fa-snapchat': 'f2ab',
|
||||
'fa-snapchat-ghost': 'f2ac',
|
||||
'fa-snapchat-square': 'f2ad',
|
||||
'fa-pied-piper': 'f2ae',
|
||||
'fa-first-order': 'f2b0',
|
||||
'fa-yoast': 'f2b1',
|
||||
'fa-themeisle': 'f2b2',
|
||||
'fa-google-plus-circle': 'f2b3',
|
||||
'fa-google-plus-official': 'f2b3',
|
||||
'fa-fa': 'f2b4',
|
||||
'fa-font-awesome': 'f2b4',
|
||||
'fa-handshake-o': 'f2b5',
|
||||
'fa-envelope-open': 'f2b6',
|
||||
'fa-envelope-open-o': 'f2b7',
|
||||
'fa-linode': 'f2b8',
|
||||
'fa-address-book': 'f2b9',
|
||||
'fa-address-book-o': 'f2ba',
|
||||
'fa-vcard': 'f2bb',
|
||||
'fa-address-card': 'f2bb',
|
||||
'fa-vcard-o': 'f2bc',
|
||||
'fa-address-card-o': 'f2bc',
|
||||
'fa-user-circle': 'f2bd',
|
||||
'fa-user-circle-o': 'f2be',
|
||||
'fa-user-o': 'f2c0',
|
||||
'fa-id-badge': 'f2c1',
|
||||
'fa-drivers-license': 'f2c2',
|
||||
'fa-id-card': 'f2c2',
|
||||
'fa-drivers-license-o': 'f2c3',
|
||||
'fa-id-card-o': 'f2c3',
|
||||
'fa-quora': 'f2c4',
|
||||
'fa-free-code-camp': 'f2c5',
|
||||
'fa-telegram': 'f2c6',
|
||||
'fa-thermometer-4': 'f2c7',
|
||||
'fa-thermometer': 'f2c7',
|
||||
'fa-thermometer-full': 'f2c7',
|
||||
'fa-thermometer-3': 'f2c8',
|
||||
'fa-thermometer-three-quarters': 'f2c8',
|
||||
'fa-thermometer-2': 'f2c9',
|
||||
'fa-thermometer-half': 'f2c9',
|
||||
'fa-thermometer-1': 'f2ca',
|
||||
'fa-thermometer-quarter': 'f2ca',
|
||||
'fa-thermometer-0': 'f2cb',
|
||||
'fa-thermometer-empty': 'f2cb',
|
||||
'fa-shower': 'f2cc',
|
||||
'fa-bathtub': 'f2cd',
|
||||
'fa-s15': 'f2cd',
|
||||
'fa-bath': 'f2cd',
|
||||
'fa-podcast': 'f2ce',
|
||||
'fa-window-maximize': 'f2d0',
|
||||
'fa-window-minimize': 'f2d1',
|
||||
'fa-window-restore': 'f2d2',
|
||||
'fa-times-rectangle': 'f2d3',
|
||||
'fa-window-close': 'f2d3',
|
||||
'fa-times-rectangle-o': 'f2d4',
|
||||
'fa-window-close-o': 'f2d4',
|
||||
'fa-bandcamp': 'f2d5',
|
||||
'fa-grav': 'f2d6',
|
||||
'fa-etsy': 'f2d7',
|
||||
'fa-imdb': 'f2d8',
|
||||
'fa-ravelry': 'f2d9',
|
||||
'fa-eercast': 'f2da',
|
||||
'fa-microchip': 'f2db',
|
||||
'fa-snowflake-o': 'f2dc',
|
||||
'fa-superpowers': 'f2dd',
|
||||
'fa-wpexplorer': 'f2de',
|
||||
'fa-meetup': 'f2e0'
|
||||
};
|
||||
135
packages/toolbar/src/browser/icons/icon-set-provider.ts
Normal file
135
packages/toolbar/src/browser/icons/icon-set-provider.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2025 EclipseSource GmbH.
|
||||
//
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { IconSet } from '../toolbar-interfaces';
|
||||
import { fontAwesomeMapping } from './font-awesome-icons';
|
||||
import { codiconsMapping } from './codicons';
|
||||
|
||||
/**
|
||||
* Provider for icon set information including:
|
||||
* - List of unique icon IDs to avoid duplicate icons due to different keywords
|
||||
* - Metadata about each icon (main keyword and all associated keywords)
|
||||
*/
|
||||
@injectable()
|
||||
export class IconSetProvider {
|
||||
|
||||
private readonly iconSetMappings = new Map<IconSet, Record<string, string | number>>();
|
||||
private readonly iconsBySet = new Map<IconSet, string[]>();
|
||||
private readonly infoMapBySet = new Map<IconSet, Map<string, { mainKeyword: string; allKeywords: string }>>();
|
||||
|
||||
/**
|
||||
* Initializes all available icon sets
|
||||
*/
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
// Register built-in icon sets
|
||||
this.registerIconSet(IconSet.FA, fontAwesomeMapping);
|
||||
this.registerIconSet(IconSet.CODICON, codiconsMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new icon set with its mapping
|
||||
*
|
||||
* @param iconSet The icon set identifier
|
||||
* @param mapping The mapping object that maps icon names to their values
|
||||
*/
|
||||
registerIconSet(iconSet: IconSet, mapping: Record<string, string | number>): void {
|
||||
// Store the mapping
|
||||
this.iconSetMappings.set(iconSet, mapping);
|
||||
|
||||
// Initialize the icons array and infoMap for this set
|
||||
const icons: string[] = [];
|
||||
const infoMap = new Map<string, { mainKeyword: string; allKeywords: string }>();
|
||||
const iconValueToKeywords = new Map<string | number, string[]>();
|
||||
|
||||
// Process all mappings to group keywords by their icon value
|
||||
Object.entries(mapping).forEach(([keyword, value]) => {
|
||||
if (!iconValueToKeywords.has(value)) {
|
||||
iconValueToKeywords.set(value, [keyword]);
|
||||
} else {
|
||||
iconValueToKeywords.get(value)?.push(keyword);
|
||||
}
|
||||
});
|
||||
|
||||
// For each unique icon value, create an entry with the first keyword and store all keywords
|
||||
iconValueToKeywords.forEach((keywords, value) => {
|
||||
keywords.sort();
|
||||
const mainKeyword = keywords[0];
|
||||
const allKeywords = keywords.join(', ');
|
||||
|
||||
const iconId = mainKeyword;
|
||||
icons.push(iconId);
|
||||
|
||||
infoMap.set(iconId, {
|
||||
mainKeyword,
|
||||
allKeywords
|
||||
});
|
||||
});
|
||||
|
||||
// Store the processed data for this icon set
|
||||
this.iconsBySet.set(iconSet, icons);
|
||||
this.infoMapBySet.set(iconSet, infoMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all icon IDs for a specific icon set
|
||||
*
|
||||
* @param iconSet The icon set to get icons for
|
||||
* @returns Array of icon IDs in the specified set
|
||||
*/
|
||||
getIcons(iconSet: IconSet): string[] {
|
||||
return this.iconsBySet.get(iconSet) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keywords associated with the given icon ID in a specific icon set
|
||||
*
|
||||
* @param iconSet The icon set to get keywords from
|
||||
* @param iconId The icon ID to get keywords for
|
||||
* @returns A comma-separated string of keywords
|
||||
*/
|
||||
getKeywords(iconSet: IconSet, iconId: string): string {
|
||||
const infoMap = this.infoMapBySet.get(iconSet);
|
||||
if (infoMap) {
|
||||
const info = infoMap.get(iconId);
|
||||
if (info) {
|
||||
return info.allKeywords;
|
||||
}
|
||||
}
|
||||
return iconId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapping for a specific icon set
|
||||
*
|
||||
* @param iconSet The icon set to get the mapping for
|
||||
* @returns The mapping object for the specified icon set
|
||||
*/
|
||||
getMapping(iconSet: IconSet): Record<string, string | number> {
|
||||
return this.iconSetMappings.get(iconSet) || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an icon set is registered
|
||||
*
|
||||
* @param iconSet The icon set to check
|
||||
* @returns True if the icon set is registered
|
||||
*/
|
||||
hasIconSet(iconSet: IconSet): boolean {
|
||||
return this.iconSetMappings.has(iconSet);
|
||||
}
|
||||
}
|
||||
19
packages/toolbar/src/browser/package.spec.ts
Normal file
19
packages/toolbar/src/browser/package.spec.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
describe('timeline package', () => {
|
||||
it('supports code coverage statistics', () => true);
|
||||
});
|
||||
244
packages/toolbar/src/browser/style/toolbar.css
Normal file
244
packages/toolbar/src/browser/style/toolbar.css
Normal file
@@ -0,0 +1,244 @@
|
||||
/********************************************************************************
|
||||
* 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-only WITH Classpath-exception-2.0
|
||||
********************************************************************************/
|
||||
|
||||
#main-toolbar {
|
||||
--theia-toolbar-height: calc(var(--theia-private-menubar-height) - 2px);
|
||||
--theia-toolbar-item-padding: 5px;
|
||||
--theia-toolbar-icon-size: 20px;
|
||||
|
||||
min-height: var(--theia-toolbar-height);
|
||||
color: var(--theia-mainToolbar-foreground);
|
||||
background: var(--theia-mainToolbar-background);
|
||||
padding: 2px 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
border-bottom: 1px solid var(--theia-titleBar-border);
|
||||
}
|
||||
|
||||
#main-toolbar .theia-progress-bar-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.toolbar-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toolbar-wrapper .toolbar-column {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toolbar-wrapper .left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.toolbar-wrapper .center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.toolbar-wrapper .right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.toolbar-wrapper:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item {
|
||||
padding: 2px;
|
||||
margin: 0 2px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
background: unset;
|
||||
}
|
||||
|
||||
#main-toolbar .empty-column-space {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .codicon,
|
||||
#main-toolbar .toolbar-item .fa {
|
||||
font-size: var(--theia-toolbar-icon-size);
|
||||
width: unset;
|
||||
min-width: var(--theia-toolbar-icon-size);
|
||||
height: var(--theia-toolbar-icon-size);
|
||||
line-height: var(--theia-toolbar-icon-size);
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .item:not(.enabled) .action-label {
|
||||
cursor: default;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .hover-overlay {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .hover-overlay.drag-over {
|
||||
background-color: var(--theia-activityBar-foreground);
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .hover-overlay.location-left {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item .hover-overlay.location-right {
|
||||
width: 25%;
|
||||
left: 75%;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item.dragging {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#main-toolbar .toolbar-item:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#main-toolbar .item:focus,
|
||||
#main-toolbar .item div:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#main-toolbar .separator {
|
||||
width: 1px;
|
||||
background-color: var(--theia-activityBar-foreground);
|
||||
opacity: var(--theia-mod-disabled-opacity);
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.toolbar-column {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.toolbar-column.left {
|
||||
margin-right: var(--theia-toolbar-item-padding);
|
||||
}
|
||||
|
||||
.toolbar-column.right {
|
||||
margin-left: var(--theia-toolbar-item-padding);
|
||||
}
|
||||
|
||||
.toolbar-column.empty {
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.empty-column-space.drag-over {
|
||||
background-color: var(--theia-activityBar-foreground);
|
||||
opacity: 0.3;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog {
|
||||
--theia-icon-dialog-icon-size: 20px;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogBlock {
|
||||
max-height: 75%;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogContent {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogContent .icon-selector-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogContent .icon-selector-options .icon-set-selector-wrapper {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: var(--theia-ui-padding);
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogContent .icon-selector-options .icon-set-selector-wrapper .theia-select-component {
|
||||
width: 125px
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .dialogControl {
|
||||
padding-top: var(--theia-ui-padding);
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-dialog-content.grid {
|
||||
--grid-size: 28px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(20, var(--grid-size));
|
||||
grid-template-rows: var(--grid-size);
|
||||
grid-auto-rows: var(--grid-size);
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-dialog-content .icon-wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-dialog-content .search-placeholder {
|
||||
text-align: center;
|
||||
margin-top: var(--theia-ui-padding);
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-controls {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-controls .default-button {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-controls .toolbar-default-icon {
|
||||
margin-left: var(--theia-ui-padding);
|
||||
font-size: var(--theia-icon-dialog-icon-size);
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .icon-selector-options {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-dialog-content .fa,
|
||||
#toolbar-icon-selector-dialog .toolbar-icon-dialog-content .codicon {
|
||||
font-size: var(--theia-icon-dialog-icon-size);
|
||||
}
|
||||
|
||||
#toolbar-icon-selector-dialog .toolbar-scroll-container {
|
||||
height: 365px;
|
||||
position: relative;
|
||||
padding: 0 var(--theia-ui-padding);
|
||||
margin-top: calc(var(--theia-ui-padding) * 2);
|
||||
/* border: 1px solid var(--theia-editorWidget-border); FUNNY - this interefers and allows endless scrolling */
|
||||
background-color: var(--theia-dropdown-background);
|
||||
}
|
||||
204
packages/toolbar/src/browser/toolbar-command-contribution.ts
Normal file
204
packages/toolbar/src/browser/toolbar-command-contribution.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import {
|
||||
bindContributionProvider,
|
||||
CommandContribution,
|
||||
CommandRegistry,
|
||||
createPreferenceProxy,
|
||||
MenuContribution,
|
||||
MenuModelRegistry,
|
||||
PreferenceScope,
|
||||
PreferenceService,
|
||||
} from '@theia/core';
|
||||
import {
|
||||
CommonMenus,
|
||||
KeybindingContribution,
|
||||
KeybindingRegistry,
|
||||
Widget,
|
||||
} from '@theia/core/lib/browser';
|
||||
import { injectable, inject, interfaces, Container } from '@theia/core/shared/inversify';
|
||||
import { ToolbarImpl } from './toolbar';
|
||||
import { bindToolbarIconDialog } from './toolbar-icon-selector-dialog';
|
||||
import {
|
||||
ToolbarContribution,
|
||||
ToolbarItemPosition,
|
||||
ToolbarFactory,
|
||||
Toolbar,
|
||||
LateInjector,
|
||||
lateInjector,
|
||||
} from './toolbar-interfaces';
|
||||
import { ToolbarCommandQuickInputService } from './toolbar-command-quick-input-service';
|
||||
import { ToolbarStorageProvider } from './toolbar-storage-provider';
|
||||
import { ToolbarController } from './toolbar-controller';
|
||||
import { ToolbarPreferencesSchema, ToolbarPreferences, TOOLBAR_ENABLE_PREFERENCE_ID } from '../common/toolbar-preference-contribution';
|
||||
import { ToolbarDefaults, ToolbarDefaultsFactory } from './toolbar-defaults';
|
||||
import { ToolbarCommands, ToolbarMenus, UserToolbarURI, USER_TOOLBAR_URI } from './toolbar-constants';
|
||||
import { JsonSchemaContribution, JsonSchemaDataStore, JsonSchemaRegisterContext } from '@theia/core/lib/browser/json-schema-store';
|
||||
import { toolbarConfigurationSchema, toolbarSchemaId } from './toolbar-preference-schema';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { PreferenceContribution } from '@theia/core/lib/common/preferences/preference-schema';
|
||||
|
||||
@injectable()
|
||||
export class ToolbarCommandContribution implements CommandContribution, KeybindingContribution, MenuContribution, JsonSchemaContribution {
|
||||
@inject(ToolbarController) protected readonly controller: ToolbarController;
|
||||
@inject(ToolbarCommandQuickInputService) protected toolbarCommandPickService: ToolbarCommandQuickInputService;
|
||||
@inject(PreferenceService) protected readonly preferenceService: PreferenceService;
|
||||
@inject(JsonSchemaDataStore) protected readonly schemaStore: JsonSchemaDataStore;
|
||||
|
||||
protected readonly schemaURI = new URI(toolbarSchemaId);
|
||||
|
||||
registerSchemas(context: JsonSchemaRegisterContext): void {
|
||||
this.schemaStore.setSchema(this.schemaURI, toolbarConfigurationSchema);
|
||||
context.registerSchema({
|
||||
fileMatch: ['toolbar.json'],
|
||||
url: this.schemaURI.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(ToolbarCommands.CUSTOMIZE_TOOLBAR, {
|
||||
execute: () => this.controller.openOrCreateJSONFile(true),
|
||||
});
|
||||
registry.registerCommand(ToolbarCommands.RESET_TOOLBAR, {
|
||||
execute: () => this.controller.restoreToolbarDefaults(),
|
||||
});
|
||||
registry.registerCommand(ToolbarCommands.TOGGLE_TOOLBAR, {
|
||||
execute: () => {
|
||||
const isVisible = this.preferenceService.get<boolean>(TOOLBAR_ENABLE_PREFERENCE_ID);
|
||||
this.preferenceService.set(TOOLBAR_ENABLE_PREFERENCE_ID, !isVisible, PreferenceScope.User);
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerCommand(ToolbarCommands.REMOVE_COMMAND_FROM_TOOLBAR, {
|
||||
execute: async (_widget, position: ToolbarItemPosition | undefined, id?: string) => position && this.controller.removeItem(position, id),
|
||||
isVisible: (...args) => this.isToolbarWidget(args[0]),
|
||||
});
|
||||
registry.registerCommand(ToolbarCommands.INSERT_GROUP_LEFT, {
|
||||
execute: async (_widget: Widget, position: ToolbarItemPosition | undefined) => position && this.controller.insertGroup(position, 'left'),
|
||||
isVisible: (widget: Widget, position: ToolbarItemPosition | undefined) => {
|
||||
if (position) {
|
||||
const { alignment, groupIndex, itemIndex } = position;
|
||||
const owningGroupLength = this.controller.toolbarItems.items[alignment][groupIndex].length;
|
||||
return this.isToolbarWidget(widget) && (owningGroupLength > 1) && (itemIndex > 0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
registry.registerCommand(ToolbarCommands.INSERT_GROUP_RIGHT, {
|
||||
execute: async (_widget: Widget, position: ToolbarItemPosition | undefined) => position && this.controller.insertGroup(position, 'right'),
|
||||
isVisible: (widget: Widget, position: ToolbarItemPosition | undefined) => {
|
||||
if (position) {
|
||||
const { alignment, groupIndex, itemIndex } = position;
|
||||
const owningGroupLength = this.controller.toolbarItems.items[alignment][groupIndex].length;
|
||||
const isNotLastItem = itemIndex < (owningGroupLength - 1);
|
||||
return this.isToolbarWidget(widget) && owningGroupLength > 1 && isNotLastItem;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
registry.registerCommand(ToolbarCommands.ADD_COMMAND_TO_TOOLBAR, {
|
||||
execute: () => this.toolbarCommandPickService.openIconDialog(),
|
||||
});
|
||||
}
|
||||
|
||||
protected isToolbarWidget(arg: unknown): boolean {
|
||||
return arg instanceof ToolbarImpl;
|
||||
}
|
||||
|
||||
registerKeybindings(keys: KeybindingRegistry): void {
|
||||
keys.registerKeybinding({
|
||||
command: ToolbarCommands.TOGGLE_TOOLBAR.id,
|
||||
keybinding: 'alt+t',
|
||||
});
|
||||
}
|
||||
|
||||
registerMenus(registry: MenuModelRegistry): void {
|
||||
registry.registerMenuAction(CommonMenus.VIEW_LAYOUT, {
|
||||
commandId: ToolbarCommands.TOGGLE_TOOLBAR.id,
|
||||
order: 'z',
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_ITEM_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.ADD_COMMAND_TO_TOOLBAR.id,
|
||||
order: 'a',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_ITEM_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.INSERT_GROUP_LEFT.id,
|
||||
order: 'b',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_ITEM_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.INSERT_GROUP_RIGHT.id,
|
||||
order: 'c',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_ITEM_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.REMOVE_COMMAND_FROM_TOOLBAR.id,
|
||||
order: 'd',
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_BACKGROUND_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.ADD_COMMAND_TO_TOOLBAR.id,
|
||||
order: 'a',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_BACKGROUND_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.CUSTOMIZE_TOOLBAR.id,
|
||||
order: 'b',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_BACKGROUND_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.TOGGLE_TOOLBAR.id,
|
||||
order: 'c',
|
||||
});
|
||||
registry.registerMenuAction(ToolbarMenus.TOOLBAR_BACKGROUND_CONTEXT_MENU, {
|
||||
commandId: ToolbarCommands.RESET_TOOLBAR.id,
|
||||
order: 'd',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function bindToolbar(bind: interfaces.Bind): void {
|
||||
bind(ToolbarFactory).toFactory(({ container }) => (): Toolbar => {
|
||||
const child = new Container({ defaultScope: 'Singleton' });
|
||||
child.parent = container;
|
||||
child.bind(Toolbar).to(ToolbarImpl);
|
||||
return child.get(Toolbar);
|
||||
});
|
||||
bind(ToolbarCommandContribution).toSelf().inSingletonScope();
|
||||
bind(CommandContribution).to(ToolbarCommandContribution);
|
||||
bind(MenuContribution).toService(ToolbarCommandContribution);
|
||||
bind(KeybindingContribution).toService(ToolbarCommandContribution);
|
||||
bind(JsonSchemaContribution).toService(ToolbarCommandContribution);
|
||||
|
||||
bind(ToolbarCommandQuickInputService).toSelf().inSingletonScope();
|
||||
|
||||
bindToolbarIconDialog(bind);
|
||||
bind(ToolbarDefaultsFactory).toConstantValue(ToolbarDefaults);
|
||||
bind(ToolbarPreferences).toDynamicValue(({ container }) => {
|
||||
const preferences = container.get<PreferenceService>(PreferenceService);
|
||||
return createPreferenceProxy(preferences, ToolbarPreferencesSchema);
|
||||
}).inSingletonScope();
|
||||
bind(PreferenceContribution).toConstantValue({
|
||||
schema: ToolbarPreferencesSchema,
|
||||
});
|
||||
|
||||
bind(UserToolbarURI).toConstantValue(USER_TOOLBAR_URI);
|
||||
|
||||
bind(ToolbarController).toSelf().inSingletonScope();
|
||||
bind(ToolbarStorageProvider).toSelf().inSingletonScope();
|
||||
bindContributionProvider(bind, ToolbarContribution);
|
||||
bind(LateInjector).toFactory(
|
||||
<T>(context: interfaces.Context) => (id: interfaces.ServiceIdentifier<T>): T => lateInjector(context.container, id),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { Command, CommandRegistry, CommandService, nls } from '@theia/core';
|
||||
import { QuickCommandService, QuickInputService, QuickPickItem } from '@theia/core/lib/browser';
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import { ToolbarIconDialogFactory } from './toolbar-icon-selector-dialog';
|
||||
import { ToolbarAlignment, ToolbarAlignmentString } from './toolbar-interfaces';
|
||||
import { ToolbarController } from './toolbar-controller';
|
||||
|
||||
@injectable()
|
||||
export class ToolbarCommandQuickInputService {
|
||||
@inject(CommandService) protected readonly commandService: CommandService;
|
||||
@inject(QuickInputService) protected readonly quickInputService: QuickInputService;
|
||||
@inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry;
|
||||
@inject(QuickCommandService) protected readonly quickCommandService: QuickCommandService;
|
||||
@inject(ToolbarController) protected readonly model: ToolbarController;
|
||||
@inject(ToolbarIconDialogFactory) protected readonly iconDialogFactory: ToolbarIconDialogFactory;
|
||||
|
||||
protected quickPickItems: QuickPickItem[] = [];
|
||||
|
||||
protected iconClass: string | undefined;
|
||||
protected commandToAdd: Command | undefined;
|
||||
|
||||
protected columnQuickPickItems: QuickPickItem[] = [
|
||||
{
|
||||
label: nls.localize('theia/toolbar/leftColumn', 'Left Column'),
|
||||
id: ToolbarAlignment.LEFT,
|
||||
},
|
||||
{
|
||||
label: nls.localize('theia/toolbar/centerColumn', 'Center Column'),
|
||||
id: ToolbarAlignment.CENTER,
|
||||
},
|
||||
{
|
||||
label: nls.localize('theia/toolbar/rightColumn', 'Right Column'),
|
||||
id: ToolbarAlignment.RIGHT
|
||||
},
|
||||
];
|
||||
|
||||
openIconDialog(): void {
|
||||
this.quickPickItems = this.generateCommandsList();
|
||||
this.quickInputService.showQuickPick(this.quickPickItems, {
|
||||
placeholder: nls.localize('theia/toolbar/addCommandPlaceholder', 'Find a command to add to the toolbar'),
|
||||
});
|
||||
}
|
||||
|
||||
protected openColumnQP(): Promise<QuickPickItem | undefined> {
|
||||
return this.quickInputService.showQuickPick(this.columnQuickPickItems, {
|
||||
placeholder: nls.localize('theia/toolbar/toolbarLocationPlaceholder', 'Where would you like the command added?')
|
||||
});
|
||||
}
|
||||
|
||||
protected generateCommandsList(): QuickPickItem[] {
|
||||
const { recent, other } = this.quickCommandService.getCommands();
|
||||
return [...recent, ...other].map(command => {
|
||||
const formattedItem = this.quickCommandService.toItem(command) as QuickPickItem;
|
||||
return {
|
||||
...formattedItem,
|
||||
alwaysShow: true,
|
||||
execute: async (): Promise<void> => {
|
||||
const iconDialog = this.iconDialogFactory(command);
|
||||
const iconClass = await iconDialog.open();
|
||||
if (iconClass) {
|
||||
const { id } = await this.openColumnQP() ?? {};
|
||||
if (ToolbarAlignmentString.is(id)) {
|
||||
this.model.addItem({ ...command, iconClass }, id);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
79
packages/toolbar/src/browser/toolbar-constants.ts
Normal file
79
packages/toolbar/src/browser/toolbar-constants.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { Command, isObject, MenuPath, nls } from '@theia/core';
|
||||
import { CommonCommands } from '@theia/core/lib/browser';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { UserStorageUri } from '@theia/userstorage/lib/browser';
|
||||
|
||||
export namespace ToolbarCommands {
|
||||
export const TOGGLE_TOOLBAR = Command.toLocalizedCommand({
|
||||
id: 'toolbar.view.toggle',
|
||||
category: CommonCommands.VIEW_CATEGORY,
|
||||
label: 'Toggle Toolbar',
|
||||
}, 'theia/toolbar/toggleToolbar', nls.getDefaultKey(CommonCommands.VIEW_CATEGORY));
|
||||
|
||||
export const REMOVE_COMMAND_FROM_TOOLBAR = Command.toLocalizedCommand({
|
||||
id: 'toolbar.remove.command',
|
||||
category: 'Toolbar',
|
||||
label: 'Remove Command From Toolbar',
|
||||
}, 'theia/toolbar/removeCommand');
|
||||
|
||||
export const INSERT_GROUP_LEFT = Command.toLocalizedCommand({
|
||||
id: 'toolbar.insert.group.left',
|
||||
category: 'Toolbar',
|
||||
label: 'Insert Group Separator (Left)',
|
||||
}, 'theia/toolbar/insertGroupLeft');
|
||||
|
||||
export const INSERT_GROUP_RIGHT = Command.toLocalizedCommand({
|
||||
id: 'toolbar.insert.group.right',
|
||||
category: 'Toolbar',
|
||||
label: 'Insert Group Separator (Right)',
|
||||
}, 'theia/toolbar/insertGroupRight');
|
||||
|
||||
export const ADD_COMMAND_TO_TOOLBAR = Command.toLocalizedCommand({
|
||||
id: 'toolbar.add.command',
|
||||
category: 'Toolbar',
|
||||
label: 'Add Command to Toolbar',
|
||||
}, 'theia/toolbar/addCommand');
|
||||
|
||||
export const RESET_TOOLBAR = Command.toLocalizedCommand({
|
||||
id: 'toolbar.restore.defaults',
|
||||
category: 'Toolbar',
|
||||
label: 'Restore Toolbar Defaults',
|
||||
}, 'theia/toolbar/restoreDefaults');
|
||||
|
||||
export const CUSTOMIZE_TOOLBAR = Command.toLocalizedCommand({
|
||||
id: 'toolbar.customize',
|
||||
category: 'Toolbar',
|
||||
label: 'Customize Toolbar (Open JSON)',
|
||||
}, 'theia/toolbar/openJSON');
|
||||
}
|
||||
|
||||
export const UserToolbarURI = Symbol('UserToolbarURI');
|
||||
export const USER_TOOLBAR_URI = new URI().withScheme(UserStorageUri.scheme).withPath('/user/toolbar.json');
|
||||
export namespace ToolbarMenus {
|
||||
export const TOOLBAR_ITEM_CONTEXT_MENU: MenuPath = ['toolbar:toolbarItemContextMenu'];
|
||||
export const TOOLBAR_BACKGROUND_CONTEXT_MENU: MenuPath = ['toolbar:backgroundContextMenu'];
|
||||
export const SEARCH_WIDGET_DROPDOWN_MENU: MenuPath = ['searchToolbar:dropdown'];
|
||||
}
|
||||
|
||||
export type ReactInteraction<T = Element, U = MouseEvent> = React.MouseEvent<T, U> | React.KeyboardEvent<T>;
|
||||
export namespace ReactKeyboardEvent {
|
||||
export function is(obj: unknown): obj is React.KeyboardEvent {
|
||||
return isObject(obj) && 'key' in obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2025 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { ApplicationShell, FrontendApplication } from '@theia/core/lib/browser';
|
||||
import { injectable, interfaces } from '@theia/core/shared/inversify';
|
||||
import { DefaultContentHoverWidgetPatcher } from '@theia/monaco/lib/browser/default-content-hover-widget-patcher';
|
||||
import { ApplicationShellWithToolbarOverride } from './application-shell-with-toolbar-override';
|
||||
|
||||
@injectable()
|
||||
export class ToolbarContentHoverWidgetPatcher extends DefaultContentHoverWidgetPatcher {
|
||||
|
||||
override onStart(app: FrontendApplication): void {
|
||||
super.onStart(app);
|
||||
const shell = app.shell;
|
||||
if (shell instanceof ApplicationShellWithToolbarOverride) {
|
||||
shell['toolbar'].onDidChangeVisibility(() => {
|
||||
this.updateContentHoverWidgetHeight({
|
||||
topHeight: this.getTopPanelHeight(shell)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override getTopPanelHeight(shell: ApplicationShell): number {
|
||||
const defaultHeight = shell.topPanel.node.getBoundingClientRect().height;
|
||||
if (shell instanceof ApplicationShellWithToolbarOverride) {
|
||||
const toolbarHeight = shell['toolbar'].node.getBoundingClientRect().height;
|
||||
return defaultHeight + toolbarHeight;
|
||||
}
|
||||
return defaultHeight;
|
||||
}
|
||||
}
|
||||
|
||||
export const bindToolbarContentHoverWidgetPatcher = (bind: interfaces.Bind, rebind: interfaces.Rebind, unbind: interfaces.Unbind): void => {
|
||||
bind(ToolbarContentHoverWidgetPatcher).toSelf().inSingletonScope();
|
||||
rebind(DefaultContentHoverWidgetPatcher).toService(ToolbarContentHoverWidgetPatcher);
|
||||
};
|
||||
|
||||
196
packages/toolbar/src/browser/toolbar-controller.ts
Normal file
196
packages/toolbar/src/browser/toolbar-controller.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { Command, CommandRegistry, ContributionProvider, Emitter, MaybePromise, MessageService, nls } from '@theia/core';
|
||||
import { KeybindingRegistry, Widget } from '@theia/core/lib/browser';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { injectable, inject, postConstruct, named } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
DeflatedToolbarTree,
|
||||
ToolbarContribution,
|
||||
ToolbarTreeSchema,
|
||||
ToolbarAlignment,
|
||||
ToolbarItemPosition,
|
||||
} from './toolbar-interfaces';
|
||||
import { ToolbarStorageProvider, TOOLBAR_BAD_JSON_ERROR_MESSAGE } from './toolbar-storage-provider';
|
||||
import { ReactToolbarItemImpl, RenderedToolbarItemImpl, TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item';
|
||||
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
|
||||
import { LabelParser } from '@theia/core/lib/browser/label-parser';
|
||||
import { ToolbarCommands } from './toolbar-constants';
|
||||
|
||||
@injectable()
|
||||
export class ToolbarController {
|
||||
@inject(ToolbarStorageProvider) protected readonly storageProvider: ToolbarStorageProvider;
|
||||
@inject(FrontendApplicationStateService) protected readonly appState: FrontendApplicationStateService;
|
||||
@inject(MessageService) protected readonly messageService: MessageService;
|
||||
@inject(CommandRegistry) commandRegistry: CommandRegistry;
|
||||
@inject(ContextKeyService) contextKeyService: ContextKeyService;
|
||||
@inject(KeybindingRegistry) keybindingRegistry: KeybindingRegistry;
|
||||
@inject(LabelParser) labelParser: LabelParser;
|
||||
|
||||
@inject(ContributionProvider) @named(ToolbarContribution)
|
||||
protected widgetContributions: ContributionProvider<ToolbarContribution>;
|
||||
|
||||
protected toolbarModelDidUpdateEmitter = new Emitter<void>();
|
||||
readonly onToolbarModelDidUpdate = this.toolbarModelDidUpdateEmitter.event;
|
||||
|
||||
protected toolbarProviderBusyEmitter = new Emitter<boolean>();
|
||||
readonly onToolbarDidChangeBusyState = this.toolbarProviderBusyEmitter.event;
|
||||
|
||||
readonly ready = new Deferred<void>();
|
||||
|
||||
protected _toolbarItems: ToolbarTreeSchema;
|
||||
get toolbarItems(): ToolbarTreeSchema {
|
||||
return this._toolbarItems;
|
||||
}
|
||||
|
||||
set toolbarItems(newTree: ToolbarTreeSchema) {
|
||||
this._toolbarItems = newTree;
|
||||
this.toolbarModelDidUpdateEmitter.fire();
|
||||
}
|
||||
|
||||
protected inflateItems(schema?: DeflatedToolbarTree): ToolbarTreeSchema {
|
||||
const newTree: ToolbarTreeSchema = {
|
||||
items: {
|
||||
[ToolbarAlignment.LEFT]: [],
|
||||
[ToolbarAlignment.CENTER]: [],
|
||||
[ToolbarAlignment.RIGHT]: [],
|
||||
},
|
||||
};
|
||||
if (schema) {
|
||||
for (const column of Object.keys(schema.items)) {
|
||||
const currentColumn = schema.items[column as ToolbarAlignment];
|
||||
for (const group of currentColumn) {
|
||||
const newGroup: TabBarToolbarItem[] = [];
|
||||
for (const item of group) {
|
||||
if (item.group === 'contributed') {
|
||||
const contribution = this.getContributionByID(item.id);
|
||||
if (contribution) {
|
||||
newGroup.push(new ReactToolbarItemImpl(this.commandRegistry, this.contextKeyService, contribution));
|
||||
}
|
||||
} else {
|
||||
newGroup.push(new RenderedToolbarItemImpl(this.commandRegistry, this.contextKeyService, this.keybindingRegistry, this.labelParser, item));
|
||||
}
|
||||
}
|
||||
if (newGroup.length) {
|
||||
newTree.items[column as ToolbarAlignment].push(newGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newTree;
|
||||
}
|
||||
|
||||
getContributionByID(id: string): ToolbarContribution | undefined {
|
||||
return this.widgetContributions.getContributions().find(contribution => contribution.id === id);
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.doInit();
|
||||
}
|
||||
|
||||
protected async doInit(): Promise<void> {
|
||||
await this.appState.reachedState('ready');
|
||||
await this.storageProvider.ready;
|
||||
this.toolbarItems = await this.resolveToolbarItems();
|
||||
this.storageProvider.onToolbarItemsChanged(async () => {
|
||||
this.toolbarItems = await this.resolveToolbarItems(true);
|
||||
});
|
||||
this.ready.resolve();
|
||||
this.widgetContributions.getContributions().forEach(contribution => {
|
||||
if (contribution.onDidChange) {
|
||||
contribution.onDidChange(() => this.toolbarModelDidUpdateEmitter.fire());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected async resolveToolbarItems(promptUserOnInvalidConfig = false): Promise<ToolbarTreeSchema> {
|
||||
await this.storageProvider.ready;
|
||||
|
||||
if (!this.storageProvider.toolbarItems) {
|
||||
let restoreDefaults = true;
|
||||
if (promptUserOnInvalidConfig) {
|
||||
const resetLabel = ToolbarCommands.RESET_TOOLBAR.label!;
|
||||
const answer = await this.messageService.error(nls.localize('theia/toolbar/jsonError', TOOLBAR_BAD_JSON_ERROR_MESSAGE), resetLabel);
|
||||
restoreDefaults = answer === resetLabel;
|
||||
}
|
||||
if (restoreDefaults) {
|
||||
await this.restoreToolbarDefaults();
|
||||
}
|
||||
}
|
||||
return this.inflateItems(this.storageProvider.toolbarItems);
|
||||
}
|
||||
|
||||
async swapValues(
|
||||
oldPosition: ToolbarItemPosition,
|
||||
newPosition: ToolbarItemPosition,
|
||||
direction: 'location-left' | 'location-right',
|
||||
): Promise<boolean> {
|
||||
return this.withBusy<boolean>(async () => {
|
||||
await this.openOrCreateJSONFile(false);
|
||||
return this.storageProvider.swapValues(oldPosition, newPosition, direction);
|
||||
});
|
||||
}
|
||||
|
||||
async restoreToolbarDefaults(): Promise<boolean> {
|
||||
return this.withBusy<boolean>(() => this.storageProvider.restoreToolbarDefaults());
|
||||
}
|
||||
|
||||
async openOrCreateJSONFile(doOpen = false): Promise<Widget | undefined> {
|
||||
return this.storageProvider.openOrCreateJSONFile(this.toolbarItems, doOpen);
|
||||
}
|
||||
|
||||
async addItem(command: Command, area: ToolbarAlignment): Promise<boolean> {
|
||||
return this.withBusy<boolean>(async () => {
|
||||
await this.openOrCreateJSONFile(false);
|
||||
return this.storageProvider.addItem(command, area);
|
||||
});
|
||||
}
|
||||
|
||||
async removeItem(position: ToolbarItemPosition, id?: string): Promise<boolean> {
|
||||
return this.withBusy<boolean>(async () => {
|
||||
await this.openOrCreateJSONFile(false);
|
||||
return this.storageProvider.removeItem(position);
|
||||
});
|
||||
}
|
||||
|
||||
async moveItemToEmptySpace(
|
||||
draggedItemPosition: ToolbarItemPosition,
|
||||
column: ToolbarAlignment,
|
||||
centerPosition?: 'left' | 'right',
|
||||
): Promise<boolean> {
|
||||
return this.withBusy<boolean>(async () => {
|
||||
await this.openOrCreateJSONFile(false);
|
||||
return this.storageProvider.moveItemToEmptySpace(draggedItemPosition, column, centerPosition);
|
||||
});
|
||||
}
|
||||
|
||||
async insertGroup(position: ToolbarItemPosition, insertDirection: 'left' | 'right'): Promise<boolean> {
|
||||
return this.withBusy<boolean>(async () => {
|
||||
await this.openOrCreateJSONFile(false);
|
||||
return this.storageProvider.insertGroup(position, insertDirection);
|
||||
});
|
||||
}
|
||||
|
||||
async withBusy<T = unknown>(action: () => MaybePromise<T>): Promise<T> {
|
||||
this.toolbarProviderBusyEmitter.fire(true);
|
||||
const toReturn = await action();
|
||||
this.toolbarProviderBusyEmitter.fire(false);
|
||||
return toReturn;
|
||||
}
|
||||
}
|
||||
58
packages/toolbar/src/browser/toolbar-defaults.ts
Normal file
58
packages/toolbar/src/browser/toolbar-defaults.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { nls } from '@theia/core';
|
||||
import { DeflatedToolbarTree, ToolbarAlignment } from './toolbar-interfaces';
|
||||
|
||||
// This file specifies the default layout of the toolbar. This binding should be overridden for extenders.
|
||||
// Both Toolbar Command Items and Toolbar Contributions can be specified here.
|
||||
export const ToolbarDefaultsFactory = Symbol('ToolbarDefaultsFactory');
|
||||
export const ToolbarDefaults: () => 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.splitEditorRight',
|
||||
icon: 'codicon codicon-split-horizontal',
|
||||
},
|
||||
],
|
||||
],
|
||||
[ToolbarAlignment.CENTER]: [[]],
|
||||
[ToolbarAlignment.RIGHT]: [
|
||||
[
|
||||
{
|
||||
id: 'workbench.action.showCommands',
|
||||
command: 'workbench.action.showCommands',
|
||||
icon: 'codicon codicon-terminal',
|
||||
tooltip: nls.localizeByDefault('Command Palette'),
|
||||
},
|
||||
]
|
||||
]
|
||||
},
|
||||
});
|
||||
32
packages/toolbar/src/browser/toolbar-frontend-module.ts
Normal file
32
packages/toolbar/src/browser/toolbar-frontend-module.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import '../../src/browser/style/toolbar.css';
|
||||
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
||||
import { bindToolbarApplicationShell } from './application-shell-with-toolbar-override';
|
||||
import { bindToolbar } from './toolbar-command-contribution';
|
||||
import { bindToolbarContentHoverWidgetPatcher } from './toolbar-content-hover-widget-patcher';
|
||||
|
||||
export default new ContainerModule((
|
||||
bind: interfaces.Bind,
|
||||
unbind: interfaces.Unbind,
|
||||
_isBound: interfaces.IsBound,
|
||||
rebind: interfaces.Rebind,
|
||||
) => {
|
||||
bindToolbarApplicationShell(bind, rebind, unbind);
|
||||
bindToolbar(bind);
|
||||
bindToolbarContentHoverWidgetPatcher(bind, rebind, unbind);
|
||||
});
|
||||
303
packages/toolbar/src/browser/toolbar-icon-selector-dialog.tsx
Normal file
303
packages/toolbar/src/browser/toolbar-icon-selector-dialog.tsx
Normal file
@@ -0,0 +1,303 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { Command, Disposable, nls } from '@theia/core';
|
||||
import { DEFAULT_SCROLL_OPTIONS, Dialog, DialogProps, Message } from '@theia/core/lib/browser';
|
||||
import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog';
|
||||
import { FuzzySearch } from '@theia/core/lib/browser/tree/fuzzy-search';
|
||||
import { SelectComponent, SelectOption } from '@theia/core/lib/browser/widgets/select-component';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
||||
import * as React from '@theia/core/shared/react';
|
||||
import { createRoot, Root } from '@theia/core/shared/react-dom/client';
|
||||
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
import { IconSetProvider } from './icons/icon-set-provider';
|
||||
import { ReactInteraction, ReactKeyboardEvent } from './toolbar-constants';
|
||||
import { IconSet } from './toolbar-interfaces';
|
||||
import debounce = require('@theia/core/shared/lodash.debounce');
|
||||
|
||||
export interface ToolbarIconDialogFactory {
|
||||
(command: Command): ToolbarIconSelectorDialog;
|
||||
}
|
||||
|
||||
export const ToolbarIconDialogFactory = Symbol('ToolbarIconDialogFactory');
|
||||
export const ToolbarCommand = Symbol('ToolbarCommand');
|
||||
|
||||
const FIFTY_MS = 50;
|
||||
|
||||
@injectable()
|
||||
export class ToolbarIconSelectorDialog extends ReactDialog<string | undefined> {
|
||||
@inject(ToolbarCommand) protected readonly toolbarCommand: Command;
|
||||
@inject(FileService) protected readonly fileService: FileService;
|
||||
@inject(IconSetProvider) protected readonly iconSetProvider: IconSetProvider;
|
||||
@inject(FuzzySearch) protected readonly fuzzySearch: FuzzySearch;
|
||||
|
||||
static ID = 'toolbar-icon-selector-dialog';
|
||||
protected deferredScrollContainer = new Deferred<HTMLDivElement>();
|
||||
override scrollOptions: PerfectScrollbar.Options = { ...DEFAULT_SCROLL_OPTIONS };
|
||||
protected filterRef: HTMLInputElement;
|
||||
|
||||
protected selectedIcon: string | undefined;
|
||||
protected activeIconPrefix: IconSet = IconSet.CODICON;
|
||||
protected iconSets = new Map<IconSet, string[]>();
|
||||
protected filteredIcons: string[] = [];
|
||||
protected doShowFilterPlaceholder = false;
|
||||
protected debounceHandleSearch = debounce(this.doHandleSearch.bind(this), FIFTY_MS, { trailing: true });
|
||||
protected controlPanelRoot: Root;
|
||||
|
||||
constructor(
|
||||
@inject(DialogProps) protected override readonly props: DialogProps,
|
||||
) {
|
||||
super(props);
|
||||
this.controlPanelRoot = createRoot(this.controlPanel);
|
||||
this.toDispose.push(Disposable.create(() => this.controlPanelRoot.unmount()));
|
||||
}
|
||||
|
||||
protected override onUpdateRequest(msg: Message): void {
|
||||
super.onUpdateRequest(msg);
|
||||
this.controlPanelRoot.render(this.renderControls());
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.node.id = ToolbarIconSelectorDialog.ID;
|
||||
|
||||
// Initialize icon sets from the provider
|
||||
for (const iconSet of [IconSet.FA, IconSet.CODICON]) {
|
||||
if (this.iconSetProvider.hasIconSet(iconSet)) {
|
||||
this.iconSets.set(iconSet, this.iconSetProvider.getIcons(iconSet));
|
||||
}
|
||||
}
|
||||
|
||||
this.activeIconPrefix = IconSet.CODICON;
|
||||
const initialIcons = this.iconSets.get(this.activeIconPrefix);
|
||||
if (initialIcons) {
|
||||
this.filteredIcons = initialIcons;
|
||||
}
|
||||
}
|
||||
|
||||
override async getScrollContainer(): Promise<HTMLElement> {
|
||||
return this.deferredScrollContainer.promise;
|
||||
}
|
||||
|
||||
protected assignScrollContainerRef = (element: HTMLDivElement): void => this.doAssignScrollContainerRef(element);
|
||||
protected doAssignScrollContainerRef(element: HTMLDivElement): void {
|
||||
this.deferredScrollContainer.resolve(element);
|
||||
}
|
||||
|
||||
protected assignFilterRef = (element: HTMLInputElement): void => this.doAssignFilterRef(element);
|
||||
protected doAssignFilterRef(element: HTMLInputElement): void {
|
||||
this.filterRef = element;
|
||||
}
|
||||
|
||||
get value(): string | undefined {
|
||||
return this.selectedIcon;
|
||||
}
|
||||
|
||||
protected handleSelectOnChange = async (option: SelectOption): Promise<void> => this.doHandleSelectOnChange(option);
|
||||
protected async doHandleSelectOnChange(option: SelectOption): Promise<void> {
|
||||
this.activeIconPrefix = option.value as IconSet;
|
||||
this.filteredIcons = [];
|
||||
await this.doHandleSearch();
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected renderIconSelectorOptions(): React.ReactNode {
|
||||
return (
|
||||
<div className='icon-selector-options'>
|
||||
<div className='icon-set-selector-wrapper'>
|
||||
<span>{nls.localize('theia/toolbar/iconSet', 'Icon Set')}{': '}</span>
|
||||
<SelectComponent
|
||||
key='iconSetSelector'
|
||||
options={[
|
||||
{ value: IconSet.CODICON, label: 'Codicon' },
|
||||
{ value: IconSet.FA, label: 'Font Awesome' }
|
||||
]}
|
||||
onChange={this.handleSelectOnChange}
|
||||
defaultValue={this.activeIconPrefix} />
|
||||
</div>
|
||||
<div className='icon-fuzzy-filter'>
|
||||
<input
|
||||
ref={this.assignFilterRef}
|
||||
placeholder={nls.localize('theia/toolbar/filterIcons', 'Filter Icons')}
|
||||
type='text'
|
||||
className='icon-filter-input theia-input'
|
||||
onChange={this.debounceHandleSearch}
|
||||
spellCheck={false}
|
||||
/>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
protected renderIconGrid(): React.ReactNode {
|
||||
return (
|
||||
<div
|
||||
className='toolbar-scroll-container'
|
||||
ref={this.assignScrollContainerRef}
|
||||
>
|
||||
<div
|
||||
className={`toolbar-icon-dialog-content ${this.doShowFilterPlaceholder ? '' : 'grid'}`}
|
||||
>
|
||||
{!this.doShowFilterPlaceholder ? this.filteredIcons?.map(icon => (
|
||||
<div
|
||||
className='icon-wrapper'
|
||||
key={icon}
|
||||
role='button'
|
||||
onClick={this.handleOnIconClick}
|
||||
onDoubleClick={e => this.doAccept(e)}
|
||||
onBlur={this.handleOnIconBlur}
|
||||
tabIndex={0}
|
||||
data-id={`${this.activeIconPrefix} ${icon}`}
|
||||
title={this.iconSetProvider.getKeywords(this.activeIconPrefix, icon)}
|
||||
onKeyDown={this.handleOnIconClick}
|
||||
>
|
||||
<div className={`${this.activeIconPrefix} ${icon}`} />
|
||||
</div>
|
||||
))
|
||||
: <div className='search-placeholder'>{nls.localizeByDefault('No results found')}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
protected render(): React.ReactNode {
|
||||
return (
|
||||
<>
|
||||
{this.renderIconSelectorOptions()}
|
||||
{this.renderIconGrid()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
protected async doHandleSearch(): Promise<void> {
|
||||
const query = this.filterRef.value;
|
||||
const pattern = query;
|
||||
const items = this.iconSets.get(this.activeIconPrefix);
|
||||
if (items) {
|
||||
if (pattern.length) {
|
||||
// Transform the item to include all related keywords for search
|
||||
const transform = (item: string): string =>
|
||||
this.iconSetProvider.getKeywords(this.activeIconPrefix, item);
|
||||
|
||||
const filterResults = await this.fuzzySearch.filter({ pattern, items, transform });
|
||||
this.filteredIcons = filterResults.map(result => result.item);
|
||||
|
||||
if (!this.filteredIcons.length) {
|
||||
this.doShowFilterPlaceholder = true;
|
||||
} else {
|
||||
this.doShowFilterPlaceholder = false;
|
||||
}
|
||||
} else {
|
||||
this.doShowFilterPlaceholder = false;
|
||||
this.filteredIcons = items;
|
||||
}
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
protected handleOnIconClick = (e: ReactInteraction<HTMLDivElement>): void => this.doHandleOnIconClick(e);
|
||||
protected doHandleOnIconClick(e: ReactInteraction<HTMLDivElement>): void {
|
||||
e.currentTarget.classList.add('selected');
|
||||
if (ReactKeyboardEvent.is(e) && e.key !== 'Enter') {
|
||||
return;
|
||||
}
|
||||
const iconId = e.currentTarget.getAttribute('data-id');
|
||||
if (iconId) {
|
||||
this.selectedIcon = iconId;
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
protected handleOnIconBlur = (e: React.FocusEvent<HTMLDivElement>): void => this.doHandleOnIconBlur(e);
|
||||
protected doHandleOnIconBlur(e: React.FocusEvent<HTMLDivElement>): void {
|
||||
e.currentTarget.classList.remove('selected');
|
||||
}
|
||||
|
||||
protected doAccept = (e: React.MouseEvent<HTMLButtonElement | HTMLDivElement>): void => {
|
||||
const dataId = e.currentTarget.getAttribute('data-id');
|
||||
if (dataId === 'default-accept') {
|
||||
this.selectedIcon = this.toolbarCommand.iconClass;
|
||||
}
|
||||
this.accept();
|
||||
};
|
||||
|
||||
protected doClose = (): void => {
|
||||
this.selectedIcon = undefined;
|
||||
this.close();
|
||||
};
|
||||
|
||||
protected renderControls(): React.ReactElement {
|
||||
return (
|
||||
<div className='toolbar-icon-controls'>
|
||||
<div>
|
||||
{this.toolbarCommand.iconClass
|
||||
&& (
|
||||
<button
|
||||
type='button'
|
||||
className='theia-button main default-button'
|
||||
data-id='default-accept'
|
||||
onClick={this.doAccept}
|
||||
>
|
||||
<span>
|
||||
{`${nls.localize('theia/toolbar/useDefaultIcon', 'Use Default Icon')}:`}
|
||||
</span>
|
||||
<div className={`toolbar-default-icon ${this.toolbarCommand.iconClass}`} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type='button'
|
||||
disabled={!this.selectedIcon}
|
||||
className='theia-button main'
|
||||
onClick={this.doAccept}
|
||||
>
|
||||
{nls.localize('theia/toolbar/selectIcon', 'Select Icon')}
|
||||
</button>
|
||||
<button
|
||||
type='button'
|
||||
className='theia-button secondary'
|
||||
onClick={this.doClose}
|
||||
>
|
||||
{Dialog.CANCEL}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const ICON_DIALOG_WIDTH = 600;
|
||||
export const ICON_DIALOG_PADDING = 24;
|
||||
|
||||
export const bindToolbarIconDialog = (bind: interfaces.Bind): void => {
|
||||
bind(IconSetProvider).toSelf().inSingletonScope();
|
||||
|
||||
bind(ToolbarIconDialogFactory).toFactory(ctx => (command: Command): ToolbarIconSelectorDialog => {
|
||||
const child = ctx.container.createChild();
|
||||
child.bind(DialogProps).toConstantValue({
|
||||
title: nls.localize('theia/toolbar/iconSelectDialog', "Select an Icon for '{0}'", command.label),
|
||||
maxWidth: ICON_DIALOG_WIDTH + ICON_DIALOG_PADDING,
|
||||
});
|
||||
child.bind(ToolbarCommand).toConstantValue(command);
|
||||
child.bind(FuzzySearch).toSelf().inSingletonScope();
|
||||
child.bind(ToolbarIconSelectorDialog).toSelf().inSingletonScope();
|
||||
return child.get(ToolbarIconSelectorDialog);
|
||||
});
|
||||
};
|
||||
77
packages/toolbar/src/browser/toolbar-interfaces.ts
Normal file
77
packages/toolbar/src/browser/toolbar-interfaces.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { interfaces } from '@theia/core/shared/inversify';
|
||||
import { ReactTabBarToolbarAction, RenderedToolbarAction, TabBarToolbar } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item';
|
||||
|
||||
export enum ToolbarAlignment {
|
||||
LEFT = 'left',
|
||||
CENTER = 'center',
|
||||
RIGHT = 'right'
|
||||
}
|
||||
|
||||
export interface ToolbarTreeSchema {
|
||||
items: {
|
||||
[key in ToolbarAlignment]: TabBarToolbarItem[][];
|
||||
};
|
||||
}
|
||||
|
||||
export interface DeflatedToolbarTree {
|
||||
items: {
|
||||
[key in ToolbarAlignment]: ToolbarItemDeflated[][];
|
||||
};
|
||||
}
|
||||
export namespace ToolbarAlignmentString {
|
||||
export const is = (obj: unknown): obj is ToolbarAlignment => obj === ToolbarAlignment.LEFT
|
||||
|| obj === ToolbarAlignment.CENTER
|
||||
|| obj === ToolbarAlignment.RIGHT;
|
||||
}
|
||||
|
||||
export interface ToolbarContributionProperties {
|
||||
toJSON(): DeflatedContributedToolbarItem;
|
||||
}
|
||||
|
||||
export type ToolbarContribution = ReactTabBarToolbarAction & ToolbarContributionProperties;
|
||||
|
||||
export const ToolbarContribution = Symbol('ToolbarContribution');
|
||||
|
||||
export const Toolbar = Symbol('Toolbar');
|
||||
export const ToolbarFactory = Symbol('ToolbarFactory');
|
||||
export type Toolbar = TabBarToolbar;
|
||||
|
||||
export type ToolbarItem = ToolbarContribution | RenderedToolbarAction;
|
||||
export interface DeflatedContributedToolbarItem { id: string; group: 'contributed' };
|
||||
export type ToolbarItemDeflated = DeflatedContributedToolbarItem | RenderedToolbarAction;
|
||||
|
||||
export const LateInjector = Symbol('LateInjector');
|
||||
|
||||
export const lateInjector = <T>(
|
||||
context: interfaces.Container,
|
||||
serviceIdentifier: interfaces.ServiceIdentifier<T>,
|
||||
): T => context.get<T>(serviceIdentifier);
|
||||
|
||||
export interface ToolbarItemPosition {
|
||||
alignment: ToolbarAlignment;
|
||||
groupIndex: number;
|
||||
itemIndex: number;
|
||||
}
|
||||
|
||||
export enum IconSet {
|
||||
FA = 'fa',
|
||||
CODICON = 'codicon'
|
||||
}
|
||||
|
||||
75
packages/toolbar/src/browser/toolbar-preference-schema.ts
Normal file
75
packages/toolbar/src/browser/toolbar-preference-schema.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { IJSONSchema } from '@theia/core/lib/common/json-schema';
|
||||
import * as Ajv from '@theia/core/shared/ajv';
|
||||
import { DeflatedToolbarTree } from './toolbar-interfaces';
|
||||
|
||||
const toolbarColumnGroup: IJSONSchema = {
|
||||
'type': 'array',
|
||||
'description': 'Array of subgroups for right toolbar column',
|
||||
'items': {
|
||||
'type': 'array',
|
||||
'description': 'Grouping',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': { 'type': 'string' },
|
||||
'command': { 'type': 'string' },
|
||||
'icon': { 'type': 'string' },
|
||||
'tooltip': { 'type': 'string' },
|
||||
'group': { 'enum': ['contributed'] },
|
||||
'when': { 'type': 'string' },
|
||||
},
|
||||
'required': [
|
||||
'id',
|
||||
],
|
||||
'additionalProperties': false,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const toolbarSchemaId = 'vscode://schemas/toolbar';
|
||||
export const toolbarConfigurationSchema: IJSONSchema = {
|
||||
// '$schema': 'https://json-schema.org/draft/2019-09/schema',
|
||||
'$id': 'vscode://schemas/indexing-grid',
|
||||
'type': 'object',
|
||||
'title': 'Toolbar',
|
||||
'properties': {
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'left': toolbarColumnGroup,
|
||||
'center': toolbarColumnGroup,
|
||||
'right': toolbarColumnGroup,
|
||||
},
|
||||
'required': [
|
||||
'left',
|
||||
'center',
|
||||
'right'
|
||||
],
|
||||
'additionalProperties': false,
|
||||
}
|
||||
},
|
||||
'required': [
|
||||
'items'
|
||||
]
|
||||
};
|
||||
|
||||
const validator = new Ajv().compile(toolbarConfigurationSchema);
|
||||
export function isToolbarPreferences(candidate: unknown): candidate is DeflatedToolbarTree {
|
||||
return Boolean(validator(candidate));
|
||||
}
|
||||
349
packages/toolbar/src/browser/toolbar-storage-provider.ts
Normal file
349
packages/toolbar/src/browser/toolbar-storage-provider.ts
Normal file
@@ -0,0 +1,349 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
import { Command, deepClone, Disposable, DisposableCollection, Emitter, MessageService, nls } from '@theia/core';
|
||||
import { injectable, postConstruct, inject, interfaces } from '@theia/core/shared/inversify';
|
||||
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
||||
import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
|
||||
import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace';
|
||||
import * as monaco from '@theia/monaco-editor-core';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { Widget } from '@theia/core/lib/browser';
|
||||
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import {
|
||||
DeflatedToolbarTree,
|
||||
ToolbarTreeSchema,
|
||||
ToolbarItem,
|
||||
ToolbarItemDeflated,
|
||||
ToolbarAlignment,
|
||||
ToolbarItemPosition,
|
||||
LateInjector,
|
||||
} from './toolbar-interfaces';
|
||||
import { UserToolbarURI } from './toolbar-constants';
|
||||
import { isToolbarPreferences } from './toolbar-preference-schema';
|
||||
import { ToolbarDefaultsFactory } from './toolbar-defaults';
|
||||
|
||||
export const TOOLBAR_BAD_JSON_ERROR_MESSAGE = 'There was an error reading your toolbar.json file. Please check if it is corrupt'
|
||||
+ ' by right-clicking the toolbar and selecting "Customize Toolbar". You can also reset it to its defaults by selecting'
|
||||
+ ' "Restore Toolbar Defaults"';
|
||||
|
||||
@injectable()
|
||||
export class ToolbarStorageProvider implements Disposable {
|
||||
@inject(FrontendApplicationStateService) protected readonly appState: FrontendApplicationStateService;
|
||||
@inject(MonacoTextModelService) protected readonly textModelService: MonacoTextModelService;
|
||||
@inject(FileService) protected readonly fileService: FileService;
|
||||
@inject(MessageService) protected readonly messageService: MessageService;
|
||||
@inject(LateInjector) protected lateInjector: <T>(id: interfaces.ServiceIdentifier<T>) => T;
|
||||
@inject(UserToolbarURI) protected readonly USER_TOOLBAR_URI: URI;
|
||||
@inject(ToolbarDefaultsFactory) protected readonly defaultsFactory: () => DeflatedToolbarTree;
|
||||
|
||||
get ready(): Promise<void> {
|
||||
return this._ready.promise;
|
||||
}
|
||||
|
||||
protected readonly _ready = new Deferred<void>();
|
||||
|
||||
// Injecting this directly causes a circular dependency, so we're using a custom utility
|
||||
// to inject this after the application has started up
|
||||
protected monacoWorkspace: MonacoWorkspace;
|
||||
protected editorManager: EditorManager;
|
||||
protected model: MonacoEditorModel | undefined;
|
||||
protected toDispose = new DisposableCollection();
|
||||
protected toolbarItemsUpdatedEmitter = new Emitter<void>();
|
||||
readonly onToolbarItemsChanged = this.toolbarItemsUpdatedEmitter.event;
|
||||
|
||||
protected _toolbarItems: DeflatedToolbarTree | undefined;
|
||||
|
||||
get toolbarItems(): DeflatedToolbarTree | undefined {
|
||||
return this._toolbarItems;
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.doInit();
|
||||
}
|
||||
|
||||
protected async doInit(): Promise<void> {
|
||||
const reference = await this.textModelService.createModelReference(this.USER_TOOLBAR_URI);
|
||||
this.model = reference.object;
|
||||
this.toDispose.push(reference);
|
||||
this.toDispose.push(Disposable.create(() => this.model = undefined));
|
||||
this.readConfiguration();
|
||||
if (this.model) {
|
||||
this.toDispose.push(this.model.onDidChangeContent(() => this.readConfiguration()));
|
||||
this.toDispose.push(this.model.onDirtyChanged(() => this.readConfiguration()));
|
||||
this.toDispose.push(this.model.onDidChangeValid(() => this.readConfiguration()));
|
||||
}
|
||||
this.toDispose.push(this.toolbarItemsUpdatedEmitter);
|
||||
await this.appState.reachedState('ready');
|
||||
this.monacoWorkspace = this.lateInjector(MonacoWorkspace);
|
||||
this.editorManager = this.lateInjector(EditorManager);
|
||||
this._ready.resolve();
|
||||
}
|
||||
|
||||
protected readConfiguration(): void {
|
||||
if (!this.model || this.model.dirty) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (this.model.valid) {
|
||||
const content = this.model.getText();
|
||||
this._toolbarItems = this.parseContent(content);
|
||||
} else {
|
||||
this._toolbarItems = undefined;
|
||||
}
|
||||
this.toolbarItemsUpdatedEmitter.fire();
|
||||
} catch (e) {
|
||||
console.error(`Failed to load toolbar config from '${this.USER_TOOLBAR_URI}'.`, e);
|
||||
}
|
||||
}
|
||||
|
||||
async removeItem(position: ToolbarItemPosition): Promise<boolean> {
|
||||
if (this.toolbarItems) {
|
||||
const { alignment, groupIndex, itemIndex } = position;
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
modifiedConfiguration.items[alignment][groupIndex].splice(itemIndex, 1);
|
||||
const sanitizedConfiguration = this.removeEmptyGroupsFromToolbar(modifiedConfiguration);
|
||||
return this.writeToFile([], sanitizedConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async addItem(command: Command, alignment: ToolbarAlignment): Promise<boolean> {
|
||||
if (this.toolbarItems) {
|
||||
const itemFromCommand: ToolbarItem = {
|
||||
id: command.id,
|
||||
command: command.id,
|
||||
icon: command.iconClass,
|
||||
};
|
||||
const groupIndex = this.toolbarItems?.items[alignment].length;
|
||||
if (groupIndex) {
|
||||
const lastItemIndex = this.toolbarItems?.items[alignment][groupIndex - 1].length;
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
modifiedConfiguration.items[alignment][groupIndex - 1].push(itemFromCommand);
|
||||
return !!lastItemIndex && this.writeToFile([], modifiedConfiguration);
|
||||
}
|
||||
return this.addItemToEmptyColumn(itemFromCommand, alignment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async swapValues(
|
||||
oldPosition: ToolbarItemPosition,
|
||||
newPosition: ToolbarItemPosition,
|
||||
direction: 'location-left' | 'location-right',
|
||||
): Promise<boolean> {
|
||||
if (this.toolbarItems) {
|
||||
const { alignment, groupIndex, itemIndex } = oldPosition;
|
||||
const draggedItem = this.toolbarItems?.items[alignment][groupIndex][itemIndex];
|
||||
const newItemIndex = direction === 'location-right' ? newPosition.itemIndex + 1 : newPosition.itemIndex;
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
if (newPosition.alignment === oldPosition.alignment && newPosition.groupIndex === oldPosition.groupIndex) {
|
||||
modifiedConfiguration.items[newPosition.alignment][newPosition.groupIndex].splice(newItemIndex, 0, draggedItem);
|
||||
if (newPosition.itemIndex > oldPosition.itemIndex) {
|
||||
modifiedConfiguration.items[oldPosition.alignment][oldPosition.groupIndex].splice(oldPosition.itemIndex, 1);
|
||||
} else {
|
||||
modifiedConfiguration.items[oldPosition.alignment][oldPosition.groupIndex].splice(oldPosition.itemIndex + 1, 1);
|
||||
}
|
||||
} else {
|
||||
modifiedConfiguration.items[oldPosition.alignment][oldPosition.groupIndex].splice(oldPosition.itemIndex, 1);
|
||||
modifiedConfiguration.items[newPosition.alignment][newPosition.groupIndex].splice(newItemIndex, 0, draggedItem);
|
||||
}
|
||||
const sanitizedConfiguration = this.removeEmptyGroupsFromToolbar(modifiedConfiguration);
|
||||
return this.writeToFile([], sanitizedConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async addItemToEmptyColumn(item: ToolbarItemDeflated, alignment: ToolbarAlignment): Promise<boolean> {
|
||||
if (this.toolbarItems) {
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
modifiedConfiguration.items[alignment].push([item]);
|
||||
return this.writeToFile([], modifiedConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async moveItemToEmptySpace(
|
||||
oldPosition: ToolbarItemPosition,
|
||||
newAlignment: ToolbarAlignment,
|
||||
centerPosition?: 'left' | 'right',
|
||||
): Promise<boolean> {
|
||||
const { alignment: oldAlignment, itemIndex: oldItemIndex } = oldPosition;
|
||||
let oldGroupIndex = oldPosition.groupIndex;
|
||||
if (this.toolbarItems) {
|
||||
const draggedItem = this.toolbarItems.items[oldAlignment][oldGroupIndex][oldItemIndex];
|
||||
const newGroupIndex = this.toolbarItems.items[oldAlignment].length;
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
if (newAlignment === ToolbarAlignment.LEFT) {
|
||||
modifiedConfiguration.items[newAlignment].push([draggedItem]);
|
||||
} else if (newAlignment === ToolbarAlignment.CENTER) {
|
||||
if (centerPosition === 'left') {
|
||||
modifiedConfiguration.items[newAlignment].unshift([draggedItem]);
|
||||
if (newAlignment === oldAlignment) {
|
||||
oldGroupIndex = oldGroupIndex + 1;
|
||||
}
|
||||
} else if (centerPosition === 'right') {
|
||||
modifiedConfiguration.items[newAlignment].splice(newGroupIndex + 1, 0, [draggedItem]);
|
||||
}
|
||||
} else if (newAlignment === ToolbarAlignment.RIGHT) {
|
||||
modifiedConfiguration.items[newAlignment].unshift([draggedItem]);
|
||||
if (newAlignment === oldAlignment) {
|
||||
oldGroupIndex = oldGroupIndex + 1;
|
||||
}
|
||||
}
|
||||
modifiedConfiguration.items[oldAlignment][oldGroupIndex].splice(oldItemIndex, 1);
|
||||
const sanitizedConfiguration = this.removeEmptyGroupsFromToolbar(modifiedConfiguration);
|
||||
return this.writeToFile([], sanitizedConfiguration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async insertGroup(position: ToolbarItemPosition, insertDirection: 'left' | 'right'): Promise<boolean> {
|
||||
if (this.toolbarItems) {
|
||||
const { alignment, groupIndex, itemIndex } = position;
|
||||
const modifiedConfiguration = deepClone(this.toolbarItems);
|
||||
const originalColumn = modifiedConfiguration.items[alignment];
|
||||
if (originalColumn) {
|
||||
const existingGroup = originalColumn[groupIndex];
|
||||
const existingGroupLength = existingGroup.length;
|
||||
let poppedGroup: ToolbarItemDeflated[] = [];
|
||||
let numItemsToRemove: number;
|
||||
if (insertDirection === 'left' && itemIndex !== 0) {
|
||||
numItemsToRemove = existingGroupLength - itemIndex;
|
||||
poppedGroup = existingGroup.splice(itemIndex, numItemsToRemove);
|
||||
originalColumn.splice(groupIndex, 1, existingGroup, poppedGroup);
|
||||
} else if (insertDirection === 'right' && itemIndex !== existingGroupLength - 1) {
|
||||
numItemsToRemove = itemIndex + 1;
|
||||
poppedGroup = existingGroup.splice(0, numItemsToRemove);
|
||||
originalColumn.splice(groupIndex, 1, poppedGroup, existingGroup);
|
||||
}
|
||||
const sanitizedConfiguration = this.removeEmptyGroupsFromToolbar(modifiedConfiguration);
|
||||
return this.writeToFile([], sanitizedConfiguration);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected removeEmptyGroupsFromToolbar(
|
||||
toolbarItems: DeflatedToolbarTree | undefined,
|
||||
): DeflatedToolbarTree | undefined {
|
||||
if (toolbarItems) {
|
||||
const modifiedConfiguration = deepClone(toolbarItems);
|
||||
const columns = [ToolbarAlignment.LEFT, ToolbarAlignment.CENTER, ToolbarAlignment.RIGHT];
|
||||
columns.forEach(column => {
|
||||
const groups = toolbarItems.items[column];
|
||||
groups.forEach((group, index) => {
|
||||
if (group.length === 0) {
|
||||
modifiedConfiguration.items[column].splice(index, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
return modifiedConfiguration;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async restoreToolbarDefaults(): Promise<boolean> {
|
||||
this._toolbarItems = this.defaultsFactory();
|
||||
return this.writeToFile([], this._toolbarItems);
|
||||
}
|
||||
|
||||
protected async writeToFile(path: jsoncParser.JSONPath, value: unknown, insertion = false): Promise<boolean> {
|
||||
if (this.model) {
|
||||
try {
|
||||
const content = this.model.getText().trim();
|
||||
const textModel = this.model.textEditorModel;
|
||||
const editOperations: monaco.editor.IIdentifiedSingleEditOperation[] = [];
|
||||
const { insertSpaces, tabSize, defaultEOL } = textModel.getOptions();
|
||||
for (const edit of jsoncParser.modify(content, path, value, {
|
||||
isArrayInsertion: insertion,
|
||||
formattingOptions: {
|
||||
insertSpaces,
|
||||
tabSize,
|
||||
eol: defaultEOL === monaco.editor.DefaultEndOfLine.LF ? '\n' : '\r\n',
|
||||
},
|
||||
})) {
|
||||
const start = textModel.getPositionAt(edit.offset);
|
||||
const end = textModel.getPositionAt(edit.offset + edit.length);
|
||||
editOperations.push({
|
||||
range: monaco.Range.fromPositions(start, end),
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
text: edit.content || null,
|
||||
forceMoveMarkers: false,
|
||||
});
|
||||
}
|
||||
await this.monacoWorkspace.applyBackgroundEdit(this.model, editOperations, false);
|
||||
await this.model.save();
|
||||
return true;
|
||||
} catch (e) {
|
||||
const message = nls.localize('theia/toolbar/failedUpdate', "Failed to update the value of '{0}' in '{1}'.", path.join('.'), this.USER_TOOLBAR_URI.path.toString());
|
||||
this.messageService.error(nls.localize('theia/toolbar/jsonError', TOOLBAR_BAD_JSON_ERROR_MESSAGE));
|
||||
console.error(`${message}`, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected parseContent(fileContent: string): DeflatedToolbarTree | undefined {
|
||||
const rawConfig = this.parse(fileContent);
|
||||
if (!isToolbarPreferences(rawConfig)) {
|
||||
return undefined;
|
||||
}
|
||||
return rawConfig;
|
||||
}
|
||||
|
||||
protected parse(fileContent: string): DeflatedToolbarTree | undefined {
|
||||
let strippedContent = fileContent.trim();
|
||||
if (!strippedContent) {
|
||||
return undefined;
|
||||
}
|
||||
strippedContent = jsoncParser.stripComments(strippedContent);
|
||||
return jsoncParser.parse(strippedContent);
|
||||
}
|
||||
|
||||
async openOrCreateJSONFile(state: ToolbarTreeSchema, doOpen = false): Promise<Widget | undefined> {
|
||||
const fileExists = await this.fileService.exists(this.USER_TOOLBAR_URI);
|
||||
let doWriteStateToFile = false;
|
||||
if (fileExists) {
|
||||
const fileContent = await this.fileService.read(this.USER_TOOLBAR_URI);
|
||||
if (fileContent.value.trim() === '') {
|
||||
doWriteStateToFile = true;
|
||||
}
|
||||
} else {
|
||||
await this.fileService.create(this.USER_TOOLBAR_URI);
|
||||
doWriteStateToFile = true;
|
||||
}
|
||||
if (doWriteStateToFile) {
|
||||
await this.writeToFile([], state);
|
||||
}
|
||||
this.readConfiguration();
|
||||
if (doOpen) {
|
||||
const widget = await this.editorManager.open(this.USER_TOOLBAR_URI);
|
||||
return widget;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
}
|
||||
371
packages/toolbar/src/browser/toolbar.tsx
Normal file
371
packages/toolbar/src/browser/toolbar.tsx
Normal file
@@ -0,0 +1,371 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import * as React from '@theia/core/shared/react';
|
||||
import { Anchor, ContextMenuAccess, KeybindingRegistry, Widget, WidgetManager } from '@theia/core/lib/browser';
|
||||
import { TabBarToolbar, TabBarToolbarFactory } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { DisposableCollection, MenuPath, PreferenceService, ProgressService } from '@theia/core';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { ProgressBarFactory } from '@theia/core/lib/browser/progress-bar-factory';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import {
|
||||
ToolbarAlignment,
|
||||
ToolbarAlignmentString,
|
||||
ToolbarItemPosition,
|
||||
} from './toolbar-interfaces';
|
||||
import { ToolbarController } from './toolbar-controller';
|
||||
import { ToolbarMenus } from './toolbar-constants';
|
||||
import { TabBarToolbarItem } from '@theia/core/lib/browser/shell/tab-bar-toolbar/tab-toolbar-item';
|
||||
|
||||
const TOOLBAR_BACKGROUND_DATA_ID = 'toolbar-wrapper';
|
||||
export const TOOLBAR_PROGRESSBAR_ID = 'main-toolbar-progress';
|
||||
@injectable()
|
||||
export class ToolbarImpl extends TabBarToolbar {
|
||||
@inject(TabBarToolbarFactory) protected readonly tabbarToolbarFactory: TabBarToolbarFactory;
|
||||
@inject(WidgetManager) protected readonly widgetManager: WidgetManager;
|
||||
@inject(FrontendApplicationStateService) protected readonly appState: FrontendApplicationStateService;
|
||||
@inject(ToolbarController) protected readonly model: ToolbarController;
|
||||
@inject(PreferenceService) protected readonly preferenceService: PreferenceService;
|
||||
@inject(KeybindingRegistry) protected readonly keybindingRegistry: KeybindingRegistry;
|
||||
@inject(ProgressBarFactory) protected readonly progressFactory: ProgressBarFactory;
|
||||
@inject(ProgressService) protected readonly progressService: ProgressService;
|
||||
|
||||
protected currentlyDraggedItem: HTMLDivElement | undefined;
|
||||
protected draggedStartingPosition: ToolbarItemPosition | undefined;
|
||||
protected deferredRef = new Deferred<HTMLDivElement>();
|
||||
protected isBusyDeferred = new Deferred<void>();
|
||||
|
||||
@postConstruct()
|
||||
protected override init(): void {
|
||||
super.init();
|
||||
this.doInit();
|
||||
}
|
||||
|
||||
protected async doInit(): Promise<void> {
|
||||
this.hide();
|
||||
await this.model.ready.promise;
|
||||
|
||||
this.updateInlineItems();
|
||||
this.update();
|
||||
this.model.onToolbarModelDidUpdate(() => {
|
||||
this.updateInlineItems();
|
||||
this.update();
|
||||
});
|
||||
this.model.onToolbarDidChangeBusyState(isBusy => {
|
||||
if (isBusy) {
|
||||
this.isBusyDeferred = new Deferred<void>();
|
||||
this.progressService.withProgress('', TOOLBAR_PROGRESSBAR_ID, async () => this.isBusyDeferred.promise);
|
||||
} else {
|
||||
this.isBusyDeferred.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
await this.deferredRef.promise;
|
||||
this.progressFactory({ container: this.node, insertMode: 'append', locationId: TOOLBAR_PROGRESSBAR_ID });
|
||||
}
|
||||
|
||||
protected updateInlineItems(): void {
|
||||
this.toDisposeOnUpdateItems.dispose();
|
||||
this.toDisposeOnUpdateItems = new DisposableCollection();
|
||||
this.inline.clear();
|
||||
const { items } = this.model.toolbarItems;
|
||||
|
||||
for (const column of Object.keys(items)) {
|
||||
for (const group of items[column as ToolbarAlignment]) {
|
||||
for (const item of group) {
|
||||
this.inline.set(item.id, item);
|
||||
if (item.onDidChange) {
|
||||
this.toDisposeOnUpdateItems.push(item.onDidChange(() => this.maybeUpdate()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected handleContextMenu = (e: React.MouseEvent<HTMLDivElement>): ContextMenuAccess => this.doHandleContextMenu(e);
|
||||
protected doHandleContextMenu(event: React.MouseEvent<HTMLDivElement>): ContextMenuAccess {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const contextMenuArgs = this.getContextMenuArgs(event);
|
||||
const { menuPath, anchor } = this.getMenuDetailsForClick(event);
|
||||
return this.contextMenuRenderer.render({
|
||||
args: contextMenuArgs,
|
||||
context: event.currentTarget,
|
||||
menuPath,
|
||||
anchor,
|
||||
});
|
||||
}
|
||||
|
||||
protected getMenuDetailsForClick(event: React.MouseEvent<HTMLDivElement>): { menuPath: MenuPath; anchor: Anchor } {
|
||||
const clickId = event.currentTarget.getAttribute('data-id');
|
||||
let menuPath: MenuPath;
|
||||
let anchor: Anchor;
|
||||
if (clickId === TOOLBAR_BACKGROUND_DATA_ID) {
|
||||
menuPath = ToolbarMenus.TOOLBAR_BACKGROUND_CONTEXT_MENU;
|
||||
const { clientX, clientY } = event;
|
||||
anchor = { x: clientX, y: clientY };
|
||||
} else {
|
||||
menuPath = ToolbarMenus.TOOLBAR_ITEM_CONTEXT_MENU;
|
||||
const { left, bottom } = event.currentTarget.getBoundingClientRect();
|
||||
anchor = { x: left, y: bottom };
|
||||
}
|
||||
return { menuPath, anchor };
|
||||
}
|
||||
|
||||
protected getContextMenuArgs(event: React.MouseEvent): Array<string | Widget> {
|
||||
const args: Array<string | Widget> = [this];
|
||||
// data-position is the stringified position of a given toolbar item, this allows
|
||||
// the model to be aware of start/stop positions during drag & drop and CRUD operations
|
||||
const position = event.currentTarget.getAttribute('data-position');
|
||||
const id = event.currentTarget.getAttribute('data-id');
|
||||
if (position) {
|
||||
args.push(JSON.parse(position));
|
||||
} else if (id) {
|
||||
args.push(id);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
protected renderGroupsInColumn(groups: TabBarToolbarItem[][], alignment: ToolbarAlignment): React.ReactNode[] {
|
||||
const nodes: React.ReactNode[] = [];
|
||||
groups.forEach((group, groupIndex) => {
|
||||
if (nodes.length && group.length) {
|
||||
nodes.push(<div key={`toolbar-separator-${groupIndex}`} className='separator' />);
|
||||
}
|
||||
group.forEach((item, itemIndex) => {
|
||||
const position = { alignment, groupIndex, itemIndex };
|
||||
nodes.push(this.renderItemWithDraggableWrapper(item, position));
|
||||
});
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
|
||||
protected assignRef = (element: HTMLDivElement): void => this.doAssignRef(element);
|
||||
protected doAssignRef(element: HTMLDivElement): void {
|
||||
this.deferredRef.resolve(element);
|
||||
}
|
||||
|
||||
protected override render(): React.ReactNode {
|
||||
const leftGroups = this.model.toolbarItems?.items[ToolbarAlignment.LEFT];
|
||||
const centerGroups = this.model.toolbarItems?.items[ToolbarAlignment.CENTER];
|
||||
const rightGroups = this.model.toolbarItems?.items[ToolbarAlignment.RIGHT];
|
||||
return (
|
||||
<div
|
||||
className='toolbar-wrapper'
|
||||
onContextMenu={this.handleContextMenu}
|
||||
data-id={TOOLBAR_BACKGROUND_DATA_ID}
|
||||
role='menu'
|
||||
tabIndex={0}
|
||||
ref={this.assignRef}
|
||||
>
|
||||
{leftGroups ? this.renderColumnWrapper(ToolbarAlignment.LEFT, leftGroups) : <></>}
|
||||
{centerGroups ? this.renderColumnWrapper(ToolbarAlignment.CENTER, centerGroups) : <></>}
|
||||
{rightGroups ? this.renderColumnWrapper(ToolbarAlignment.RIGHT, rightGroups) : <></>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
protected renderColumnWrapper(alignment: ToolbarAlignment, columnGroup: TabBarToolbarItem[][]): React.ReactNode {
|
||||
let children: React.ReactNode;
|
||||
if (alignment === ToolbarAlignment.LEFT) {
|
||||
children = (
|
||||
<>
|
||||
{this.renderGroupsInColumn(columnGroup, alignment)}
|
||||
{this.renderColumnSpace(alignment)}
|
||||
</>
|
||||
);
|
||||
} else if (alignment === ToolbarAlignment.CENTER) {
|
||||
const isCenterColumnEmpty = !columnGroup.length;
|
||||
if (isCenterColumnEmpty) {
|
||||
children = this.renderColumnSpace(alignment, 'left');
|
||||
} else {
|
||||
children = (
|
||||
<>
|
||||
{this.renderColumnSpace(alignment, 'left')}
|
||||
{this.renderGroupsInColumn(columnGroup, alignment)}
|
||||
{this.renderColumnSpace(alignment, 'right')}
|
||||
</>
|
||||
);
|
||||
}
|
||||
} else if (alignment === ToolbarAlignment.RIGHT) {
|
||||
children = (
|
||||
<>
|
||||
{this.renderColumnSpace(alignment)}
|
||||
{this.renderGroupsInColumn(columnGroup, alignment)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
role='group'
|
||||
className={`toolbar-column ${alignment}`}
|
||||
>
|
||||
{children}
|
||||
</div>);
|
||||
}
|
||||
|
||||
protected renderColumnSpace(alignment: ToolbarAlignment, position?: 'left' | 'right'): React.ReactNode {
|
||||
return (
|
||||
<div
|
||||
className='empty-column-space'
|
||||
data-column={`${alignment}`}
|
||||
data-center-position={position}
|
||||
onDrop={this.handleOnDrop}
|
||||
onDragOver={this.handleOnDragEnter}
|
||||
onDragEnter={this.handleOnDragEnter}
|
||||
onDragLeave={this.handleOnDragLeave}
|
||||
key={`column-space-${alignment}-${position}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
protected renderItemWithDraggableWrapper(item: TabBarToolbarItem, position: ToolbarItemPosition): React.ReactNode {
|
||||
const stringifiedPosition = JSON.stringify(position);
|
||||
const renderBody = item.render(this);
|
||||
|
||||
return (
|
||||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
data-id={item.id}
|
||||
id={item.id}
|
||||
data-position={stringifiedPosition}
|
||||
key={`${item.id}-${stringifiedPosition}`}
|
||||
className={'toolbar-item'}
|
||||
draggable={true}
|
||||
onDragStart={this.handleOnDragStart}
|
||||
onDragOver={this.handleOnDragEnter}
|
||||
onDragLeave={this.handleOnDragLeave}
|
||||
onContextMenu={this.handleContextMenu}
|
||||
onDragEnd={this.handleOnDragEnd}
|
||||
onDrop={this.handleOnDrop}
|
||||
>
|
||||
{renderBody}
|
||||
<div className='hover-overlay' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
protected handleOnDragStart = (e: React.DragEvent<HTMLDivElement>): void => this.doHandleOnDragStart(e);
|
||||
protected doHandleOnDragStart(e: React.DragEvent<HTMLDivElement>): void {
|
||||
const draggedElement = e.currentTarget;
|
||||
draggedElement.classList.add('dragging');
|
||||
e.dataTransfer.setDragImage(draggedElement, 0, 0);
|
||||
const position = JSON.parse(e.currentTarget.getAttribute('data-position') ?? '');
|
||||
this.currentlyDraggedItem = e.currentTarget;
|
||||
this.draggedStartingPosition = position;
|
||||
}
|
||||
|
||||
protected handleOnDragEnter = (e: React.DragEvent<HTMLDivElement>): void => this.doHandleItemOnDragEnter(e);
|
||||
protected doHandleItemOnDragEnter(e: React.DragEvent<HTMLDivElement>): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const targetItemDOMElement = e.currentTarget;
|
||||
const targetItemHoverOverlay = targetItemDOMElement.querySelector('.hover-overlay');
|
||||
const targetItemId = e.currentTarget.getAttribute('data-id');
|
||||
if (targetItemDOMElement.classList.contains('empty-column-space')) {
|
||||
targetItemDOMElement.classList.add('drag-over');
|
||||
} else if (targetItemDOMElement.classList.contains('toolbar-item') && targetItemHoverOverlay) {
|
||||
const { clientX } = e;
|
||||
const { left, right } = e.currentTarget.getBoundingClientRect();
|
||||
const targetMiddleX = (left + right) / 2;
|
||||
if (targetItemId !== this.currentlyDraggedItem?.getAttribute('data-id')) {
|
||||
targetItemHoverOverlay.classList.add('drag-over');
|
||||
if (clientX <= targetMiddleX) {
|
||||
targetItemHoverOverlay.classList.add('location-left');
|
||||
targetItemHoverOverlay.classList.remove('location-right');
|
||||
} else {
|
||||
targetItemHoverOverlay.classList.add('location-right');
|
||||
targetItemHoverOverlay.classList.remove('location-left');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected handleOnDragLeave = (e: React.DragEvent<HTMLDivElement>): void => this.doHandleOnDragLeave(e);
|
||||
protected doHandleOnDragLeave(e: React.DragEvent<HTMLDivElement>): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const targetItemDOMElement = e.currentTarget;
|
||||
const targetItemHoverOverlay = targetItemDOMElement.querySelector('.hover-overlay');
|
||||
if (targetItemDOMElement.classList.contains('empty-column-space')) {
|
||||
targetItemDOMElement.classList.remove('drag-over');
|
||||
} else if (targetItemHoverOverlay && targetItemDOMElement.classList.contains('toolbar-item')) {
|
||||
targetItemHoverOverlay?.classList.remove('drag-over', 'location-left', 'location-right');
|
||||
}
|
||||
}
|
||||
|
||||
protected handleOnDrop = (e: React.DragEvent<HTMLDivElement>): void => this.doHandleOnDrop(e);
|
||||
protected doHandleOnDrop(e: React.DragEvent<HTMLDivElement>): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const targetItemDOMElement = e.currentTarget;
|
||||
const targetItemHoverOverlay = targetItemDOMElement.querySelector('.hover-overlay');
|
||||
if (targetItemDOMElement.classList.contains('empty-column-space')) {
|
||||
this.handleDropInEmptySpace(targetItemDOMElement);
|
||||
targetItemDOMElement.classList.remove('drag-over');
|
||||
} else if (targetItemHoverOverlay && targetItemDOMElement.classList.contains('toolbar-item')) {
|
||||
this.handleDropInExistingGroup(targetItemDOMElement);
|
||||
targetItemHoverOverlay.classList.remove('drag-over', 'location-left', 'location-right');
|
||||
}
|
||||
this.currentlyDraggedItem = undefined;
|
||||
this.draggedStartingPosition = undefined;
|
||||
}
|
||||
|
||||
protected handleDropInExistingGroup(element: EventTarget & HTMLDivElement): void {
|
||||
const position = element.getAttribute('data-position');
|
||||
const targetDirection = element.querySelector('.hover-overlay')?.classList.toString()
|
||||
.split(' ')
|
||||
.find(className => className.includes('location'));
|
||||
const dropPosition = JSON.parse(position ?? '');
|
||||
if (this.currentlyDraggedItem && targetDirection
|
||||
&& this.draggedStartingPosition && !this.arePositionsEquivalent(this.draggedStartingPosition, dropPosition)) {
|
||||
this.model.swapValues(
|
||||
this.draggedStartingPosition,
|
||||
dropPosition,
|
||||
targetDirection as 'location-left' | 'location-right',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected handleDropInEmptySpace(element: EventTarget & HTMLDivElement): void {
|
||||
const column = element.getAttribute('data-column');
|
||||
if (ToolbarAlignmentString.is(column) && this.draggedStartingPosition) {
|
||||
if (column === ToolbarAlignment.CENTER) {
|
||||
const centerPosition = element.getAttribute('data-center-position');
|
||||
this.model.moveItemToEmptySpace(this.draggedStartingPosition, column, centerPosition as 'left' | 'right');
|
||||
} else {
|
||||
this.model.moveItemToEmptySpace(this.draggedStartingPosition, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected arePositionsEquivalent(start: ToolbarItemPosition, end: ToolbarItemPosition): boolean {
|
||||
return start.alignment === end.alignment
|
||||
&& start.groupIndex === end.groupIndex
|
||||
&& start.itemIndex === end.itemIndex;
|
||||
}
|
||||
|
||||
protected handleOnDragEnd = (e: React.DragEvent<HTMLDivElement>): void => this.doHandleOnDragEnd(e);
|
||||
protected doHandleOnDragEnd(e: React.DragEvent<HTMLDivElement>): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.currentlyDraggedItem = undefined;
|
||||
this.draggedStartingPosition = undefined;
|
||||
e.currentTarget.classList.remove('dragging');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { PreferenceProxy } from '@theia/core/lib/common/preferences/preference-proxy';
|
||||
import { PreferenceScope } from '@theia/core/lib/common/preferences/preference-scope';
|
||||
import { PreferenceSchema } from '@theia/core/lib/common/preferences/preference-schema';
|
||||
|
||||
export const TOOLBAR_ENABLE_PREFERENCE_ID = 'toolbar.showToolbar';
|
||||
|
||||
export const ToolbarPreferencesSchema: PreferenceSchema = {
|
||||
properties: {
|
||||
[TOOLBAR_ENABLE_PREFERENCE_ID]: {
|
||||
'type': 'boolean',
|
||||
'description': 'Show toolbar',
|
||||
'default': false,
|
||||
'scope': PreferenceScope.Workspace,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
class ToolbarPreferencesContribution {
|
||||
[TOOLBAR_ENABLE_PREFERENCE_ID]: boolean;
|
||||
}
|
||||
|
||||
export const ToolbarPreferences = Symbol('ToolbarPreferences');
|
||||
export type ToolbarPreferences = PreferenceProxy<ToolbarPreferencesContribution>;
|
||||
25
packages/toolbar/src/node/toolbar-backend-module.ts
Normal file
25
packages/toolbar/src/node/toolbar-backend-module.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2025 STMicroelectronics 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-only WITH Classpath-exception-2.0
|
||||
|
||||
import { PreferenceContribution } from '@theia/core';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { ToolbarPreferencesSchema } from '../common/toolbar-preference-contribution';
|
||||
|
||||
// *****************************************************************************
|
||||
export default new ContainerModule(bind => {
|
||||
bind(PreferenceContribution).toConstantValue({
|
||||
schema: ToolbarPreferencesSchema,
|
||||
});
|
||||
});
|
||||
37
packages/toolbar/tsconfig.json
Normal file
37
packages/toolbar/tsconfig.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core"
|
||||
},
|
||||
{
|
||||
"path": "../editor"
|
||||
},
|
||||
{
|
||||
"path": "../file-search"
|
||||
},
|
||||
{
|
||||
"path": "../filesystem"
|
||||
},
|
||||
{
|
||||
"path": "../monaco"
|
||||
},
|
||||
{
|
||||
"path": "../search-in-workspace"
|
||||
},
|
||||
{
|
||||
"path": "../userstorage"
|
||||
},
|
||||
{
|
||||
"path": "../workspace"
|
||||
}
|
||||
]
|
||||
}
|
||||
110
packages/toolbar/update-icons.js
Normal file
110
packages/toolbar/update-icons.js
Normal file
@@ -0,0 +1,110 @@
|
||||
// *****************************************************************************
|
||||
// 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-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// ============
|
||||
// FONT AWESOME
|
||||
// ============
|
||||
|
||||
// This part generates an JSON array of font-awesome classnames from the font-awesome.css files
|
||||
const fontAwesomeCSSPath = path.resolve(__dirname, '../../node_modules/font-awesome/css/font-awesome.css');
|
||||
const fontAwesomeDestination = path.resolve(__dirname, './src/browser/icons/font-awesome.json');
|
||||
|
||||
// Read the CSS
|
||||
const css = fs.readFileSync(fontAwesomeCSSPath, 'utf-8');
|
||||
|
||||
// Regex to match blocks like:
|
||||
// .fa-remove:before, .fa-close:before, .fa-times:before { content: "\f00d"; }
|
||||
const ruleRegex = /((?:\.fa-[\w-]+:before\s*,\s*)*\.fa-[\w-]+:before)\s*\{[^}]*?\bcontent\s*:\s*(['"])(\\f[0-9a-fA-F]{3,4}|\\[0-9a-fA-F]{1,6})\2[^}]*?\}/gm;
|
||||
|
||||
const mapping = Object.create(null);
|
||||
|
||||
let match;
|
||||
while ((match = ruleRegex.exec(css)) !== null) {
|
||||
const selectors = match[1];
|
||||
const iconContent = match[3].replace(/^\\/, ''); // e.g. "f00d"
|
||||
|
||||
// Each selector may be comma-separated
|
||||
selectors.split(',')
|
||||
.map(s => s.trim())
|
||||
.forEach(sel => {
|
||||
const name = sel.replace(/^\./, '').replace(/:before$/i, '');
|
||||
mapping[name] = iconContent;
|
||||
});
|
||||
}
|
||||
|
||||
// Write result
|
||||
fs.mkdirSync(path.dirname(fontAwesomeDestination), { recursive: true });
|
||||
fs.writeFileSync(fontAwesomeDestination, JSON.stringify(mapping, null, 2), 'utf-8');
|
||||
|
||||
// Update the font-awesome-icons.ts file with the new mapping
|
||||
const fontAwesomeTsPath = path.resolve(__dirname, './src/browser/icons/font-awesome-icons.ts');
|
||||
const faTsFileContent = fs.readFileSync(fontAwesomeTsPath, 'utf-8');
|
||||
|
||||
// Convert mapping to TypeScript format
|
||||
const faMappingEntries = Object.entries(mapping)
|
||||
.map(([key, value]) => ` '${key}': '${value}'`)
|
||||
.join(',\n');
|
||||
|
||||
const newFaMappingValue = `{\n${faMappingEntries}\n}`;
|
||||
|
||||
// Replace only the value of fontAwesomeMapping using regex
|
||||
const updatedFaTsContent = faTsFileContent.replace(
|
||||
/export const fontAwesomeMapping = \{[\s\S]*?\};/,
|
||||
`export const fontAwesomeMapping = ${newFaMappingValue};`
|
||||
);
|
||||
|
||||
fs.writeFileSync(fontAwesomeTsPath, updatedFaTsContent, 'utf-8');
|
||||
|
||||
// ========
|
||||
// CODICONS
|
||||
// ========
|
||||
|
||||
// This part generates a JSON array of codicons mappings from their classnames and their content from the mapping.json file
|
||||
const codiconCSSPath = path.resolve(__dirname, '../../node_modules/@vscode/codicons/src/template/mapping.json')
|
||||
const codiconDestination = path.resolve(__dirname, './src/browser/icons/codicon.json')
|
||||
// Read the codicons mapping file, add 'codicon-' prefix to all keys, and write it to the destination
|
||||
const codiconMapping = JSON.parse(fs.readFileSync(codiconCSSPath, 'utf-8'));
|
||||
const prefixedCodiconMapping = {};
|
||||
|
||||
// Add 'codicon-' prefix to all keys
|
||||
for (const key in codiconMapping) {
|
||||
prefixedCodiconMapping['codicon-' + key] = codiconMapping[key];
|
||||
}
|
||||
|
||||
// Write the modified mapping to the destination
|
||||
fs.writeFileSync(codiconDestination, JSON.stringify(prefixedCodiconMapping, null, 2));
|
||||
|
||||
// Update the codicons.ts file with the new mapping
|
||||
const codiconTsPath = path.resolve(__dirname, './src/browser/icons/codicons.ts');
|
||||
const tsFileContent = fs.readFileSync(codiconTsPath, 'utf-8');
|
||||
|
||||
// Convert mapping to TypeScript format
|
||||
const mappingEntries = Object.entries(prefixedCodiconMapping)
|
||||
.map(([key, value]) => ` '${key}': ${value}`)
|
||||
.join(',\n');
|
||||
|
||||
const newMappingValue = `{\n${mappingEntries}\n}`;
|
||||
|
||||
// Replace only the value of codiconsMapping using regex
|
||||
const updatedTsContent = tsFileContent.replace(
|
||||
/export const codiconsMapping = \{[\s\S]*?\};/,
|
||||
`export const codiconsMapping = ${newMappingValue};`
|
||||
);
|
||||
|
||||
fs.writeFileSync(codiconTsPath, updatedTsContent, 'utf-8');
|
||||
Reference in New Issue
Block a user