Skip to content

Commit c9c3321

Browse files
authored
Simplify welcome widget (microsoft#184876)
1 parent b4dd4d5 commit c9c3321

File tree

3 files changed

+52
-69
lines changed

3 files changed

+52
-69
lines changed

src/vs/workbench/contrib/welcomeDialog/browser/media/welcomeWidget.css

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
border-radius: 6px;
77
}
88

9-
.welcome-widget {
10-
height: min-content;
11-
border-radius: 6px;
9+
.dialog-message-detail-title > div > p > .codicon[class*='codicon-']::before{
10+
position: relative;
11+
color: var(--vscode-textLink-foreground);
12+
padding-right: 10px;
13+
font-size: larger;
1214
}
1315

1416
.dialog-message-detail-title {
1517
height: 22px;
16-
padding-bottom: 4px;
1718
font-size: large;
1819
}
1920

src/vs/workbench/contrib/welcomeDialog/browser/welcomeDialog.contribution.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
2323
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
2424
import { LanguageService } from 'vs/editor/common/services/languageService';
2525
import { ILanguageService } from 'vs/editor/common/languages/language';
26-
import { GettingStartedDetailsRenderer } from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer';
2726
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
2827
import { localize } from 'vs/nls';
2928
import { applicationConfigurationNodeBase } from 'vs/workbench/common/configuration';
@@ -77,22 +76,18 @@ class WelcomeDialogContribution extends Disposable implements IWorkbenchContribu
7776
const scheduler = new RunOnceScheduler(() => {
7877
if (codeEditor === codeEditorService.getActiveCodeEditor()) {
7978
this.isRendered = true;
80-
const detailsRenderer = new GettingStartedDetailsRenderer(fileService, notificationService, extensionService, languageService);
8179

8280
const welcomeWidget = new WelcomeWidget(
8381
codeEditor,
8482
instantiationService,
8583
commandService,
8684
telemetryService,
87-
openerService,
88-
webviewService,
89-
detailsRenderer);
85+
openerService);
9086

9187
welcomeWidget.render(welcomeDialog.title,
9288
welcomeDialog.message,
9389
welcomeDialog.buttonText,
94-
welcomeDialog.buttonCommand,
95-
welcomeDialog.media);
90+
welcomeDialog.buttonCommand);
9691
}
9792
}, 3000);
9893

src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
import 'vs/css!./media/welcomeWidget';
77
import { Disposable } from 'vs/base/common/lifecycle';
88
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
9-
import { $, append, hide } from 'vs/base/browser/dom'; import { RunOnceScheduler } from 'vs/base/common/async';
9+
import { $, append, hide } from 'vs/base/browser/dom';
1010
import { MarkdownString } from 'vs/base/common/htmlContent';
1111
import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer';
1212
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1313
import { ButtonBar } from 'vs/base/browser/ui/button/button';
1414
import { mnemonicButtonLabel } from 'vs/base/common/labels';
1515
import { ICommandService } from 'vs/platform/commands/common/commands';
16-
import { defaultButtonStyles, defaultDialogStyles } from 'vs/platform/theme/browser/defaultStyles';
16+
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
1717
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1818
import { Action, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
1919
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -25,16 +25,12 @@ import { Link } from 'vs/platform/opener/browser/link';
2525
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
2626
import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
2727
import { IOpenerService } from 'vs/platform/opener/common/opener';
28-
import { generateUuid } from 'vs/base/common/uuid';
29-
import { GettingStartedDetailsRenderer } from 'vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedDetailsRenderer';
30-
import { FileAccess } from 'vs/base/common/network';
31-
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
28+
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
29+
import { Color } from 'vs/base/common/color';
30+
import { contrastBorder, editorWidgetBackground, editorWidgetForeground, widgetBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
3231

3332
export class WelcomeWidget extends Disposable implements IOverlayWidget {
3433

35-
private static readonly WIDGET_TIMEOUT: number = 15000;
36-
private static readonly WELCOME_MEDIA_PATH = 'vs/workbench/contrib/welcomeGettingStarted/common/media/';
37-
3834
private readonly _rootDomNode: HTMLElement;
3935
private readonly element: HTMLElement;
4036
private readonly messageContainer: HTMLElement;
@@ -45,9 +41,7 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
4541
private readonly instantiationService: IInstantiationService,
4642
private readonly commandService: ICommandService,
4743
private readonly telemetryService: ITelemetryService,
48-
private readonly openerService: IOpenerService,
49-
private readonly webviewService: IWebviewService,
50-
private readonly detailsRenderer: GettingStartedDetailsRenderer
44+
private readonly openerService: IOpenerService
5145
) {
5246
super();
5347
this._rootDomNode = document.createElement('div');
@@ -64,7 +58,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
6458
async executeCommand(commandId: string, ...args: string[]) {
6559
try {
6660
await this.commandService.executeCommand(commandId, ...args);
67-
this._hide(false);
6861
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
6962
id: commandId,
7063
from: 'welcomeWidget'
@@ -74,41 +67,38 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
7467
}
7568
}
7669

77-
public async render(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }) {
70+
public async render(title: string, message: string, buttonText: string, buttonAction: string) {
7871
if (!this._editor._getViewModel()) {
7972
return;
8073
}
8174

82-
await this.buildWidgetContent(title, message, buttonText, buttonAction, media);
75+
await this.buildWidgetContent(title, message, buttonText, buttonAction);
8376
this._editor.addOverlayWidget(this);
84-
this._revealTemporarily();
77+
this._show();
8578
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
8679
id: 'welcomeWidgetRendered',
8780
from: 'welcomeWidget'
8881
});
8982
}
9083

91-
private async buildWidgetContent(title: string, message: string, buttonText: string, buttonAction: string, media: { altText: string; path: string }) {
84+
private async buildWidgetContent(title: string, message: string, buttonText: string, buttonAction: string) {
9285

9386
const actionBar = this._register(new ActionBar(this.element, {}));
9487

9588
const action = this._register(new Action('dialog.close', localize('dialogClose', "Close Dialog"), ThemeIcon.asClassName(Codicon.dialogClose), true, async () => {
96-
this._hide(true);
89+
this._hide();
9790
}));
9891
actionBar.push(action, { icon: true, label: false });
9992

100-
if (media) {
101-
await this.buildSVGMediaComponent(media.path);
102-
}
103-
104-
const renderBody = (message: string): MarkdownString => {
105-
const mds = new MarkdownString(undefined, { supportHtml: true });
93+
const renderBody = (message: string, icon: string): MarkdownString => {
94+
const mds = new MarkdownString(undefined, { supportThemeIcons: true, supportHtml: true });
95+
mds.appendMarkdown(`<a class="copilot">$(${icon})</a>`);
10696
mds.appendMarkdown(message);
10797
return mds;
10898
};
10999

110100
const titleElement = this.messageContainer.appendChild($('#monaco-dialog-message-detail.dialog-message-detail-title'));
111-
const titleElementMdt = this.markdownRenderer.render(renderBody(title));
101+
const titleElementMdt = this.markdownRenderer.render(renderBody(title, 'zap'));
112102
titleElement.appendChild(titleElementMdt.element);
113103

114104
this.buildStepMarkdownDescription(this.messageContainer, message.split('\n').filter(x => x).map(text => parseLinkedText(text)));
@@ -125,7 +115,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
125115
}));
126116

127117
buttonBar.buttons[0].focus();
128-
this.applyStyles();
129118
}
130119

131120
private buildStepMarkdownDescription(container: HTMLElement, text: LinkedText[]) {
@@ -158,18 +147,6 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
158147
return container;
159148
}
160149

161-
private async buildSVGMediaComponent(path: string) {
162-
163-
const mediaContainer = this.messageContainer.appendChild($('.dialog-image-container'));
164-
mediaContainer.id = generateUuid();
165-
166-
const webview = this._register(this.webviewService.createWebviewElement({ title: undefined, options: {}, contentOptions: {}, extension: undefined }));
167-
webview.mountTo(mediaContainer);
168-
169-
const body = await this.detailsRenderer.renderSVG(FileAccess.asFileUri(`${WelcomeWidget.WELCOME_MEDIA_PATH}${path}`));
170-
webview.setHtml(body);
171-
}
172-
173150
getId(): string {
174151
return 'editor.contrib.welcomeWidget';
175152
}
@@ -184,14 +161,8 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
184161
};
185162
}
186163

187-
private _hideSoon = this._register(new RunOnceScheduler(() => this._hide(false), WelcomeWidget.WIDGET_TIMEOUT));
188164
private _isVisible: boolean = false;
189165

190-
private _revealTemporarily(): void {
191-
this._show();
192-
this._hideSoon.schedule();
193-
}
194-
195166
private _show(): void {
196167
if (this._isVisible) {
197168
return;
@@ -200,32 +171,48 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget {
200171
this._rootDomNode.style.display = 'block';
201172
}
202173

203-
private _hide(isUserDismissed: boolean): void {
174+
private _hide(): void {
204175
if (!this._isVisible) {
205176
return;
206177
}
207178

208-
this._isVisible = false;
179+
this._isVisible = true;
209180
this._rootDomNode.style.display = 'none';
210181
this._editor.removeOverlayWidget(this);
211182
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
212-
id: isUserDismissed ? 'welcomeWidgetDismissed' : 'welcomeWidgetHidden',
183+
id: 'welcomeWidgetDismissed',
213184
from: 'welcomeWidget'
214185
});
215186
}
187+
}
188+
189+
registerThemingParticipant((theme, collector) => {
190+
const addBackgroundColorRule = (selector: string, color: Color | undefined): void => {
191+
if (color) {
192+
collector.addRule(`.monaco-editor ${selector} { background-color: ${color}; }`);
193+
}
194+
};
216195

217-
private applyStyles(): void {
218-
const style = defaultDialogStyles;
196+
const widgetBackground = theme.getColor(editorWidgetBackground);
197+
addBackgroundColorRule('.welcome-widget', widgetBackground);
219198

220-
const fgColor = style.dialogForeground;
221-
const bgColor = style.dialogBackground;
222-
const shadowColor = style.dialogShadow ? `0 0px 8px ${style.dialogShadow}` : '';
223-
const border = style.dialogBorder ? `1px solid ${style.dialogBorder}` : '';
199+
const widgetShadowColor = theme.getColor(widgetShadow);
200+
if (widgetShadowColor) {
201+
collector.addRule(`.welcome-widget { box-shadow: 0 0 8px 2px ${widgetShadowColor}; }`);
202+
}
224203

225-
this._rootDomNode.style.boxShadow = shadowColor;
204+
const widgetBorderColor = theme.getColor(widgetBorder);
205+
if (widgetBorderColor) {
206+
collector.addRule(`.welcome-widget { border-left: 1px solid ${widgetBorderColor}; border-right: 1px solid ${widgetBorderColor}; border-bottom: 1px solid ${widgetBorderColor}; }`);
207+
}
226208

227-
this._rootDomNode.style.color = fgColor ?? '';
228-
this._rootDomNode.style.backgroundColor = bgColor ?? '';
229-
this._rootDomNode.style.border = border;
209+
const hcBorder = theme.getColor(contrastBorder);
210+
if (hcBorder) {
211+
collector.addRule(`.welcome-widget { border: 1px solid ${hcBorder}; }`);
230212
}
231-
}
213+
214+
const foreground = theme.getColor(editorWidgetForeground);
215+
if (foreground) {
216+
collector.addRule(`.welcome-widget { color: ${foreground}; }`);
217+
}
218+
});

0 commit comments

Comments
 (0)