From e49f09d2cbe264484e7549bbdfb021ea79805a19 Mon Sep 17 00:00:00 2001 From: Simon Graband Date: Wed, 22 Mar 2023 09:11:49 +0100 Subject: [PATCH] Add extended tab bar preview option Add functionality to render more information on tab bar hover. Also makes sure the feedback is styled be using the hoverService. This currently applies to horizontal tab bars. Right now the title and the caption will be rendered. To not remove the old behavior this feature is enabled via the setting `window.extendedTabBarPreview`. Also added possibility to specify cssClasses to be added to a hover, when requesting it from the HoverService. This way special hovers, like the extended tab bar preview, can easily be styled with CSS. Contributed on behalf of STMicroelectronics --- packages/core/src/browser/core-preferences.ts | 6 +++ packages/core/src/browser/hover-service.ts | 10 ++++- packages/core/src/browser/shell/tab-bars.ts | 39 +++++++++++++++---- .../core/src/browser/style/hover-service.css | 4 ++ packages/core/src/browser/style/tabs.css | 16 ++++++++ 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/packages/core/src/browser/core-preferences.ts b/packages/core/src/browser/core-preferences.ts index f6b77dcbc42ef..8b9e445200678 100644 --- a/packages/core/src/browser/core-preferences.ts +++ b/packages/core/src/browser/core-preferences.ts @@ -80,6 +80,11 @@ export const corePreferenceSchema: PreferenceSchema = { default: 'code', markdownDescription: nls.localizeByDefault('Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`.') }, + 'window.extendedTabBarPreview': { + type: 'boolean', + default: false, + description: 'Controls whether more information about the tab should be displayed in horizontal tab bars.' + }, 'window.menuBarVisibility': { type: 'string', enum: ['classic', 'visible', 'hidden', 'compact'], @@ -241,6 +246,7 @@ export interface CoreConfiguration { 'breadcrumbs.enabled': boolean; 'files.encoding': string; 'keyboard.dispatch': 'code' | 'keyCode'; + 'window.extendedTabBarPreview': boolean; 'window.menuBarVisibility': 'classic' | 'visible' | 'hidden' | 'compact'; 'window.title': string; 'window.titleSeparator': string; diff --git a/packages/core/src/browser/hover-service.ts b/packages/core/src/browser/hover-service.ts index 1747dfeadd11f..12dfe3340f177 100644 --- a/packages/core/src/browser/hover-service.ts +++ b/packages/core/src/browser/hover-service.ts @@ -57,6 +57,11 @@ export interface HoverRequest { * if the specified content does not fit in the window next to the target element */ position: HoverPosition + /** + * Additional css classes that should be added to the hover box. + * Used to style certain boxes different e.g. for the extended tab preview. + */ + cssClasses?: string [] } @injectable() @@ -101,7 +106,10 @@ export class HoverService { protected async renderHover(request: HoverRequest): Promise { const host = this.hoverHost; - const { target, content, position } = request; + const { target, content, position, cssClasses } = request; + if (cssClasses) { + host.classList.add(...cssClasses); + } this.hoverTarget = target; if (content instanceof HTMLElement) { host.appendChild(content); diff --git a/packages/core/src/browser/shell/tab-bars.ts b/packages/core/src/browser/shell/tab-bars.ts index 6d3faade9659c..5ac68e95b9d87 100644 --- a/packages/core/src/browser/shell/tab-bars.ts +++ b/packages/core/src/browser/shell/tab-bars.ts @@ -157,9 +157,7 @@ export class TabBarRenderer extends TabBar.Renderer { ? nls.localizeByDefault('Unpin') : nls.localizeByDefault('Close'); - const hover = this.tabBar && this.tabBar.orientation === 'horizontal' ? { - title: title.caption - } : { + const hover = this.tabBar && (this.tabBar.orientation === 'horizontal' && !this.corePreferences?.['window.extendedTabBarPreview']) ? { title: title.caption } : { onmouseenter: this.handleMouseEnterEvent }; @@ -474,16 +472,41 @@ export class TabBarRenderer extends TabBar.Renderer { return h.div({ className: baseClassName, style }, data.title.iconLabel); } + protected renderExtendedTabBarPreview = (title: Title) => { + const hoverBox = document.createElement('div'); + hoverBox.classList.add('theia-horizontal-tabBar-hover-div'); + const labelElement = document.createElement('p'); + labelElement.classList.add('theia-horizontal-tabBar-hover-title'); + labelElement.textContent = title.label; + hoverBox.append(labelElement); + if (title.caption) { + const captionElement = document.createElement('p'); + captionElement.classList.add('theia-horizontal-tabBar-hover-caption'); + captionElement.textContent = title.caption; + hoverBox.appendChild(captionElement); + } + return hoverBox; + }; + protected handleMouseEnterEvent = (event: MouseEvent) => { if (this.tabBar && this.hoverService && event.currentTarget instanceof HTMLElement) { const id = event.currentTarget.id; const title = this.tabBar.titles.find(t => this.createTabId(t) === id); if (title) { - this.hoverService.requestHover({ - content: title.caption, - target: event.currentTarget, - position: 'right' - }); + if (this.tabBar.orientation === 'horizontal') { + this.hoverService.requestHover({ + content: this.renderExtendedTabBarPreview(title), + target: event.currentTarget, + position: 'bottom', + cssClasses: ['extended-tab-preview'] + }); + } else { + this.hoverService.requestHover({ + content: title.caption, + target: event.currentTarget, + position: 'right' + }); + } } } }; diff --git a/packages/core/src/browser/style/hover-service.css b/packages/core/src/browser/style/hover-service.css index 8ed6a774418e5..86ba955b654b0 100644 --- a/packages/core/src/browser/style/hover-service.css +++ b/packages/core/src/browser/style/hover-service.css @@ -93,3 +93,7 @@ border-top: 5px solid transparent; border-bottom: 5px solid transparent; } + +.theia-hover.extended-tab-preview { + border-radius: 10px; +} diff --git a/packages/core/src/browser/style/tabs.css b/packages/core/src/browser/style/tabs.css index 51150ef36507d..2f22436b11bb6 100644 --- a/packages/core/src/browser/style/tabs.css +++ b/packages/core/src/browser/style/tabs.css @@ -414,3 +414,19 @@ flex-flow: row nowrap; min-width: 100%; } + +.theia-horizontal-tabBar-hover-div { + margin: 0px 4px; +} + +.theia-horizontal-tabBar-hover-title { + font-weight: bolder; + font-size: medium; + margin: 0px 0px; +} + +.theia-horizontal-tabBar-hover-caption { + font-size: small; + margin: 0px 0px; + margin-top: 4px; +}