diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index c0aadf8e40082decaf89996b4967b8c5a2bf4294..79dbdfe746cc5a7a6e1e9fc3fc4ba076a018fe58 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -294,12 +294,14 @@ export class ListView implements ISpliceable, IDisposable { item.row.domNode.style.top = `${this.elementTop(index)}px`; item.row.domNode.style.height = `${item.size}px`; item.row.domNode.setAttribute('data-index', `${index}`); + item.row.domNode.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false'); renderer.renderElement(item.element, index, item.row.templateData); } private updateItemInDOM(item: IItem, index: number): void { item.row.domNode.style.top = `${this.elementTop(index)}px`; item.row.domNode.setAttribute('data-index', `${index}`); + item.row.domNode.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false'); } private removeItemFromDOM(item: IItem): void { diff --git a/src/vs/platform/statusbar/common/statusbar.ts b/src/vs/platform/statusbar/common/statusbar.ts index a7287a62e9fc58d7f314dc34b7e2c05ba7b4af57..fffa1184e333d40a92e692f5c45788ad0cb6ded9 100644 --- a/src/vs/platform/statusbar/common/statusbar.ts +++ b/src/vs/platform/statusbar/common/statusbar.ts @@ -51,6 +51,11 @@ export interface IStatusbarEntry { * An optional extension ID if this entry is provided from an extension. */ extensionId?: string; + + /** + * Wether to show a beak above the status bar entry. + */ + showBeak?: boolean; } export interface IStatusbarService { diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css b/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css index 066804bea772a8ad72571f81094c94ae4607de5d..c8356cea89686a77e32b4d5c4044ad0a62a0db1c 100644 --- a/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css +++ b/src/vs/workbench/browser/parts/notifications/media/notificationsCenter.css @@ -7,14 +7,13 @@ position: absolute; z-index: 1000; right: 8px; - bottom: 30px; /* above status bar */ + bottom: 31px; display: none; overflow: hidden; } .monaco-workbench.nostatusbar > .notifications-center { - right: 12px; - bottom: 12px; + bottom: 8px; } .monaco-workbench > .notifications-center.visible { diff --git a/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css b/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css index 80cb61d0eb45b412d0e583628cdfd9f654973302..bf75bd6e55b9d858eb2cec3564ba7b9c4468dc6c 100644 --- a/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css +++ b/src/vs/workbench/browser/parts/notifications/media/notificationsToasts.css @@ -7,14 +7,13 @@ position: absolute; z-index: 1000; right: 3px; - bottom: 28px; /* above status bar */ + bottom: 26px; display: none; overflow: hidden; } .monaco-workbench.nostatusbar > .notifications-toasts { - right: 12px; - bottom: 12px; + bottom: 3px; } .monaco-workbench > .notifications-toasts.visible { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 428f1158a7178e6a0879c186b846b7b5778e3ef2..dcbbaa575621ebbfd49099cdd833ef9d37821806 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -23,7 +23,7 @@ import { localize } from 'vs/nls'; export class NotificationsCenter extends Themable { - private static MAX_DIMENSIONS = new Dimension(600, 400); + private static MAX_DIMENSIONS = new Dimension(450, 400); private notificationsCenterContainer: HTMLElement; private notificationsList: NotificationsList; @@ -166,7 +166,7 @@ export class NotificationsCenter extends Themable { protected updateStyles(): void { if (this.notificationsCenterContainer) { const widgetShadowColor = this.getColor(widgetShadow); - this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null; + this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null; } } @@ -219,6 +219,6 @@ export class NotificationsCenter extends Themable { registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const notificationBorderColor = theme.getColor(NOTIFICATIONS_BORDER); if (notificationBorderColor) { - collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`); + collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .monaco-list-row[data-last-element="false"] > .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`); } }); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index c9215fa253c60a61f90d7e7542281b7f8b0c6d99..30a1a50dffa3679ff4f405c9cbf660a43fd0f05f 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -72,7 +72,8 @@ export class NotificationsStatus { this.statusItem = this.statusbarService.addEntry({ text: this.counter === 0 ? '$(megaphone)' : `$(megaphone) ${this.counter}`, command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER_COMMAND_ID : this.model.notifications.length > 0 ? SHOW_NOTIFICATIONS_CENTER_COMMAND_ID : void 0, - tooltip: this.getTooltip() + tooltip: this.getTooltip(), + showBeak: this.isNotificationsCenterVisible }, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index dfa261b41287557109e1b413d527fb30cc384dec..0f4f959b177072232174006f7a1f02669bd5ef38 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -299,7 +299,7 @@ export class NotificationsToasts extends Themable { protected updateStyles(): void { this.mapNotificationToToast.forEach(toast => { const widgetShadowColor = this.getColor(widgetShadow); - toast.container.style.boxShadow = widgetShadowColor ? `0 2px 8px ${widgetShadowColor}` : null; + toast.container.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null; }); } diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 77ace7d3011220cf1616f78128f90c48d2b6f4dd..886fc5547295bf89655cf9bab39c7cc5ef409c6f 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -9,7 +9,6 @@ height: 22px; font-size: 12px; padding: 0 10px; - overflow: hidden; } .monaco-workbench > .part.statusbar > .statusbar-item { @@ -19,6 +18,21 @@ vertical-align: top; } +.monaco-workbench > .part.statusbar > .statusbar-item.has-beak { + position: relative; +} + +.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { + content: ''; + position: absolute; + left: 11px; + top: -5px; + border-bottom-width: 5px; + border-bottom-style: solid; + border-left: 5px solid transparent; + border-right: 5px solid transparent; +} + .monaco-workbench > .part.statusbar > .statusbar-item.left > :first-child { margin-right: 5px; } diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 60f6efe34df732b1b8dfd7be2089ab45703b8cf2..8c875405a935d06c0fadbd3ee265babf0576bdd4 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -29,7 +29,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/ import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { isThemeColor } from 'vs/editor/common/editorCommon'; import { Color } from 'vs/base/common/color'; -import { addClass, EventHelper } from 'vs/base/browser/dom'; +import { addClass, EventHelper, createStyleSheet } from 'vs/base/browser/dom'; import { INotificationService } from 'vs/platform/notification/common/notification'; export class StatusbarPart extends Part implements IStatusbarService { @@ -42,6 +42,8 @@ export class StatusbarPart extends Part implements IStatusbarService { private statusItemsContainer: Builder; private statusMsgDispose: IDisposable; + private styleElement: HTMLStyleElement; + constructor( id: string, @IInstantiationService private instantiationService: IInstantiationService, @@ -60,7 +62,7 @@ export class StatusbarPart extends Part implements IStatusbarService { public addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable { // Render entry in status bar - const el = this.doCreateStatusItem(alignment, priority); + const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : void 0); const item = this.instantiationService.createInstance(StatusBarEntryItem, entry); const toDispose = item.render(el); @@ -140,18 +142,31 @@ export class StatusbarPart extends Part implements IStatusbarService { const container = this.getContainer(); + // Background colors + const backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND); + container.style('background-color', backgroundColor); container.style('color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); - container.style('background-color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND)); + // Border color const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder); container.style('border-top-width', borderColor ? '1px' : null); container.style('border-top-style', borderColor ? 'solid' : null); container.style('border-top-color', borderColor); + + // Notification Beak + if (!this.styleElement) { + this.styleElement = createStyleSheet(container.getHTMLElement()); + } + + this.styleElement.innerHTML = `.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`; } - private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0): HTMLElement { + private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, extraClass?: string): HTMLElement { const el = document.createElement('div'); addClass(el, 'statusbar-item'); + if (extraClass) { + addClass(el, extraClass); + } if (alignment === StatusbarAlignment.RIGHT) { addClass(el, 'right'); diff --git a/src/vs/workbench/parts/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/parts/debug/browser/statusbarColorProvider.ts index 579b84ebb1828cff4710c80deb6842278bd03d6a..4afe110097b63e41398f01400702e80e179b7060 100644 --- a/src/vs/workbench/parts/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/parts/debug/browser/statusbarColorProvider.ts @@ -11,7 +11,7 @@ import { IPartService, Parts } from 'vs/workbench/services/part/common/partServi import { IDebugService, State } from 'vs/workbench/parts/debug/common/debug'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_BACKGROUND, Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_BORDER } from 'vs/workbench/common/theme'; -import { addClass, removeClass } from 'vs/base/browser/dom'; +import { addClass, removeClass, createStyleSheet } from 'vs/base/browser/dom'; // colors for theming @@ -34,6 +34,7 @@ export const STATUS_BAR_DEBUGGING_BORDER = registerColor('statusBar.debuggingBor }, localize('statusBarDebuggingBorder', "Status bar border color separating to the sidebar and editor when a program is being debugged. The status bar is shown in the bottom of the window")); export class StatusBarColorProvider extends Themable implements IWorkbenchContribution { + private styleElement: HTMLStyleElement; constructor( @IThemeService themeService: IThemeService, @@ -61,13 +62,23 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri removeClass(container, 'debugging'); } - container.style.backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND)); + // Container Colors + const backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND)); + container.style.backgroundColor = backgroundColor; container.style.color = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_DEBUGGING_FOREGROUND, STATUS_BAR_FOREGROUND)); + // Border Color const borderColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_DEBUGGING_BORDER, STATUS_BAR_BORDER)) || this.getColor(contrastBorder); container.style.borderTopWidth = borderColor ? '1px' : null; container.style.borderTopStyle = borderColor ? 'solid' : null; container.style.borderTopColor = borderColor; + + // Notification Beak + if (!this.styleElement) { + this.styleElement = createStyleSheet(container); + } + + this.styleElement.innerHTML = `.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor} !important; }`; } private getColorKey(noFolderColor: string, debuggingColor: string, normalColor: string): string {