Skip to content

Commit 8ac4c26

Browse files
author
Benjamin Pasero
committed
web - add a home indicator API
1 parent 273bb63 commit 8ac4c26

3 files changed

Lines changed: 101 additions & 25 deletions

File tree

src/vs/workbench/browser/parts/activitybar/activitybarPart.ts

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeServic
2020
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
2121
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
2222
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
23-
import { Dimension, addClass, removeNode } from 'vs/base/browser/dom';
23+
import { Dimension, addClass, removeNode, addClasses } from 'vs/base/browser/dom';
2424
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
2525
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
2626
import { URI, UriComponents } from 'vs/base/common/uri';
@@ -38,7 +38,6 @@ import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menuba
3838
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
3939
import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
4040
import { isWeb } from 'vs/base/common/platform';
41-
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
4241
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
4342
import { getUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync';
4443
import { IProductService } from 'vs/platform/product/common/productService';
@@ -85,19 +84,21 @@ export class ActivitybarPart extends Part implements IActivityBarService {
8584

8685
//#endregion
8786

87+
private content: HTMLElement | undefined;
88+
89+
private homeIndicatorActionLabel: HTMLAnchorElement | undefined = undefined;
90+
91+
private menubar: CustomMenubarControl | undefined;
92+
private menubarContainer: HTMLElement | undefined;
93+
94+
private compositeBar: CompositeBar;
95+
8896
private globalActivityAction: ActivityAction | undefined;
8997
private globalActivityActionBar: ActionBar | undefined;
9098
private readonly globalActivity: ICompositeActivity[] = [];
9199

92-
private customMenubar: CustomMenubarControl | undefined;
93-
private menubar: HTMLElement | undefined;
94-
private content: HTMLElement | undefined;
95-
96100
private readonly cachedViewlets: ICachedViewlet[] = [];
97-
98-
private compositeBar: CompositeBar;
99101
private readonly compositeActions = new Map<string, { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction }>();
100-
101102
private readonly viewletDisposables = new Map<string, IDisposable>();
102103

103104
constructor(
@@ -110,8 +111,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
110111
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
111112
@IContextKeyService private readonly contextKeyService: IContextKeyService,
112113
@IConfigurationService private readonly configurationService: IConfigurationService,
113-
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
114-
@IEnvironmentService private readonly environmentService: IEnvironmentService,
114+
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
115115
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
116116
@IProductService private readonly productService: IProductService
117117
) {
@@ -122,7 +122,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
122122

123123
this.cachedViewlets = this.getCachedViewlets();
124124
for (const cachedViewlet of this.cachedViewlets) {
125-
if (workbenchEnvironmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered.
125+
if (environmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered.
126126
|| this.shouldBeHidden(cachedViewlet.id, cachedViewlet)
127127
) {
128128
cachedViewlet.visible = false;
@@ -297,25 +297,25 @@ export class ActivitybarPart extends Part implements IActivityBarService {
297297
}
298298

299299
private uninstallMenubar() {
300-
if (this.customMenubar) {
301-
this.customMenubar.dispose();
300+
if (this.menubar) {
301+
this.menubar.dispose();
302302
}
303303

304-
if (this.menubar) {
305-
removeNode(this.menubar);
304+
if (this.menubarContainer) {
305+
removeNode(this.menubarContainer);
306306
}
307307
}
308308

309309
private installMenubar() {
310-
this.menubar = document.createElement('div');
311-
addClass(this.menubar, 'menubar');
310+
this.menubarContainer = document.createElement('div');
311+
addClass(this.menubarContainer, 'menubar');
312312

313313
const content = assertIsDefined(this.content);
314-
content.prepend(this.menubar);
314+
content.prepend(this.menubarContainer);
315315

316316
// Menubar: install a custom menu bar depending on configuration
317-
this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
318-
this.customMenubar.create(this.menubar);
317+
this.menubar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
318+
this.menubar.create(this.menubarContainer);
319319
}
320320

321321
createContentArea(parent: HTMLElement): HTMLElement {
@@ -325,6 +325,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
325325
addClass(this.content, 'content');
326326
parent.appendChild(this.content);
327327

328+
// Home action bar
329+
const homeIndicator = this.environmentService.options?.homeIndicator;
330+
if (homeIndicator) {
331+
this.createHomeBar(homeIndicator.href, homeIndicator.title, homeIndicator.icon);
332+
}
333+
328334
// Install menubar if compact
329335
if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') {
330336
this.installMenubar();
@@ -343,12 +349,33 @@ export class ActivitybarPart extends Part implements IActivityBarService {
343349
return this.content;
344350
}
345351

352+
private createHomeBar(href: string, title: string, icon: string): void {
353+
const homeBarContainer = document.createElement('div');
354+
homeBarContainer.setAttribute('aria-label', nls.localize('homeIndicator', "Home"));
355+
homeBarContainer.setAttribute('role', 'toolbar');
356+
addClass(homeBarContainer, 'home-bar');
357+
358+
const content = assertIsDefined(this.content);
359+
content.prepend(homeBarContainer);
360+
361+
this.homeIndicatorActionLabel = document.createElement('a');
362+
this.homeIndicatorActionLabel.tabIndex = 0;
363+
this.homeIndicatorActionLabel.title = title;
364+
this.homeIndicatorActionLabel.setAttribute('aria-label', title);
365+
this.homeIndicatorActionLabel.setAttribute('role', 'button');
366+
this.homeIndicatorActionLabel.href = href;
367+
addClasses(this.homeIndicatorActionLabel, 'action-label', 'codicon', `codicon-${icon}`);
368+
369+
homeBarContainer.appendChild(this.homeIndicatorActionLabel);
370+
}
371+
346372
updateStyles(): void {
347373
super.updateStyles();
348374

349375
// Part container
350376
const container = assertIsDefined(this.getContainer());
351377
const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || '';
378+
const forground = this.getColor(ACTIVITY_BAR_FOREGROUND) || '';
352379
container.style.backgroundColor = background;
353380

354381
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || '';
@@ -360,7 +387,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
360387
container.style.borderLeftWidth = borderColor && !isPositionLeft ? '1px' : '';
361388
container.style.borderLeftStyle = borderColor && !isPositionLeft ? 'solid' : '';
362389
container.style.borderLeftColor = !isPositionLeft ? borderColor : '';
363-
// container.style.outlineColor = this.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND) ?? '';
390+
391+
// Home action label
392+
if (this.homeIndicatorActionLabel) {
393+
this.homeIndicatorActionLabel.style.color = forground;
394+
}
364395
}
365396

366397
private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors {
@@ -570,8 +601,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
570601
if (this.globalActivityActionBar) {
571602
availableHeight -= (this.globalActivityActionBar.viewItems.length * ActivitybarPart.ACTION_HEIGHT); // adjust height for global actions showing
572603
}
573-
if (this.menubar) {
574-
availableHeight -= this.menubar.clientHeight;
604+
if (this.menubarContainer) {
605+
availableHeight -= this.menubarContainer.clientHeight;
575606
}
576607
this.compositeBar.layout(new Dimension(width, availableHeight));
577608
}

src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@
1414
justify-content: space-between;
1515
}
1616

17+
/** Home Bar */
18+
19+
.monaco-workbench .activitybar > .content > .home-bar {
20+
width: 100%;
21+
height: 35px;
22+
display: flex;
23+
align-items: center;
24+
justify-content: center;
25+
}
26+
27+
.monaco-workbench .activitybar > .content > .home-bar > .action-label {
28+
font-size: 24px;
29+
}
30+
31+
/** Viewlet Switcher */
32+
1733
.monaco-workbench .activitybar > .content .monaco-action-bar {
1834
text-align: left;
1935
background-color: inherit;
@@ -31,6 +47,8 @@
3147
height: 100%;
3248
}
3349

50+
/** Menu Bar */
51+
3452
.monaco-workbench .activitybar .menubar {
3553
width: 100%;
3654
height: 35px;

src/vs/workbench/workbench.web.api.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ interface ICommand {
8686
handler: (...args: any[]) => unknown;
8787
}
8888

89+
interface IHomeIndicator {
90+
91+
/**
92+
* The location to open when clicking the home indicator.
93+
*/
94+
href: string;
95+
96+
/**
97+
* The icon name for the home indicator. This needs to be one of the existing
98+
* icons from our Codicon icon set. For example `sync`.
99+
*/
100+
icon: string;
101+
102+
/**
103+
* A tooltip that will appear while hovering over the home indicator.
104+
*/
105+
title: string;
106+
}
107+
89108
interface IWorkbenchConstructionOptions {
90109

91110
//#region Connection related configuration
@@ -181,6 +200,11 @@ interface IWorkbenchConstructionOptions {
181200
*/
182201
readonly commands?: readonly ICommand[];
183202

203+
/**
204+
* Optional home indicator to appear above the hamburger menu in the activity bar.
205+
*/
206+
readonly homeIndicator?: IHomeIndicator;
207+
184208
//#endregion
185209

186210

@@ -324,7 +348,10 @@ export {
324348

325349
// Commands
326350
ICommand,
327-
commands
351+
commands,
352+
353+
// Home Indicator
354+
IHomeIndicator
328355
};
329356

330357
//#endregion

0 commit comments

Comments
 (0)