diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index a6f4c935a75d524dc485a786144c8fc0bcbc5c64..8ea6337ab40a2eec73bd0fa6c82eb0d6fb2e2664 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -844,9 +844,10 @@ export class VSCodeMenu { const keyboardShortcutsUrl = platform.isLinux ? product.keyboardShortcutsUrlLinux : platform.isMacintosh ? product.keyboardShortcutsUrlMac : product.keyboardShortcutsUrlWin; arrays.coalesce([ - product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(product.documentationUrl, 'openDocumentationUrl') }) : null, + new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.welcomePage') }), + product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.openDocumentationUrl') }) : null, product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes') }) : null, - (product.documentationUrl || product.releaseNotesUrl) ? __separator__() : null, + __separator__(), keyboardShortcutsUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'workbench.action.keybindingsReference') }) : null, product.introductoryVideosUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")), click: () => this.openUrl(product.introductoryVideosUrl, 'openIntroductoryVideosUrl') }) : null, (product.introductoryVideosUrl || keyboardShortcutsUrl) ? __separator__() : null, diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index bef43bb139faaf210f9a389180f6ec1a1e27f93c..568f7a5aae09857859f5910dd6752f5dbfed284f 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -856,6 +856,27 @@ export class KeybindingsReferenceAction extends Action { } } +export class OpenDocumentationUrlAction extends Action { + + public static ID = 'workbench.action.openDocumentationUrl'; + public static LABEL = nls.localize('openDocumentationUrl', "Documentation"); + + private static URL = product.documentationUrl; + public static AVAILABLE = !!OpenDocumentationUrlAction.URL; + + constructor( + id: string, + label: string + ) { + super(id, label); + } + + public run(): TPromise { + window.open(OpenDocumentationUrlAction.URL); + return null; + } +} + // --- commands CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string, string]) { diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 4b0791da85e810282ab0f35eb1d268a940ab59c2..8ceacfc882b8268972076e44e6d73c6512dd82b5 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -19,7 +19,7 @@ import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRe import { IPartService } from 'vs/workbench/services/part/common/partService'; import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; -import { CloseEditorAction, KeybindingsReferenceAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction } from 'vs/workbench/electron-browser/actions'; +import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction } from 'vs/workbench/electron-browser/actions'; import { MessagesVisibleContext, NoEditorsVisibleContext, InZenModeContext } from 'vs/workbench/electron-browser/workbench'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IWindowsService } from 'vs/platform/windows/common/windows'; @@ -42,6 +42,9 @@ if (!!product.reportIssueUrl) { if (KeybindingsReferenceAction.AVAILABLE) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(KeybindingsReferenceAction, KeybindingsReferenceAction.ID, KeybindingsReferenceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_R) }), 'Help: Keyboard Shortcuts Reference', helpCategory); } +if (OpenDocumentationUrlAction.AVAILABLE) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenDocumentationUrlAction, OpenDocumentationUrlAction.ID, OpenDocumentationUrlAction.LABEL), 'Help: Documentation', helpCategory); +} workbenchActionsRegistry.registerWorkbenchAction( new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, diff --git a/src/vs/workbench/electron-browser/workbench.main.ts b/src/vs/workbench/electron-browser/workbench.main.ts index 0cc830ceb80901c75a09dc70f6372b7dcfc5cbdd..0a62fcbc3a082f82b516812473ec9381ac7d2874 100644 --- a/src/vs/workbench/electron-browser/workbench.main.ts +++ b/src/vs/workbench/electron-browser/workbench.main.ts @@ -65,6 +65,8 @@ import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution'; import 'vs/workbench/parts/extensions/browser/extensionsQuickOpen'; import 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet'; // can be packaged separately +import 'vs/workbench/parts/welcomePage/electron-browser/welcomePage.contribution'; + import 'vs/workbench/parts/explorers/browser/treeExplorer.contribution'; import 'vs/workbench/parts/explorers/browser/treeExplorerViewlet'; // can be packaged separately diff --git a/src/vs/workbench/parts/welcomePage/electron-browser/code.png b/src/vs/workbench/parts/welcomePage/electron-browser/code.png new file mode 100644 index 0000000000000000000000000000000000000000..a7b64b954d59a976f697c52a989a4d93830a39ca Binary files /dev/null and b/src/vs/workbench/parts/welcomePage/electron-browser/code.png differ diff --git a/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.contribution.ts b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.contribution.ts new file mode 100644 index 0000000000000000000000000000000000000000..76ef03d58e5b3b34dcc612278d1f1c431e5cd706 --- /dev/null +++ b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.contribution.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { localize } from 'vs/nls'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/platform'; +import { WelcomePageContribution, WelcomePageAction } from 'vs/workbench/parts/welcomePage/electron-browser/welcomePage'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; + +Registry.as(ConfigurationExtensions.Configuration) + .registerConfiguration({ + 'id': 'workbench', + 'order': 7, + 'title': localize('workbenchConfigurationTitle', "Workbench"), + 'properties': { + 'workbench.welcome.enabled': { + 'type': 'boolean', + 'default': true, + 'description': localize('welcomePage.enabled', "When enabled, will show the Welcome experience on startup.") + }, + } + }); + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(WelcomePageContribution); + +Registry.as(ActionExtensions.WorkbenchActions) + .registerWorkbenchAction(new SyncActionDescriptor(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help")); diff --git a/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.css b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.css new file mode 100644 index 0000000000000000000000000000000000000000..0e510cbe46e67f2fc393ce67f886cd2ed077f5c8 --- /dev/null +++ b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.css @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench > .part.editor > .content .monaco-workbench > .part.editor > .content .welcomePage { + font-family: "Lucida Grande", sans-serif; +} + +.monaco-workbench > .part.editor > .content .welcomePage .splash { + position: absolute; + top: 50%; + left: 25%; + transform: translate(-50%, -50%); + width: 35%; +} +.monaco-workbench > .part.editor > .content .welcomePage .splash h1, +.monaco-workbench > .part.editor > .content .welcomePage .splash h2 { + text-align: center; + padding: 0; + margin: 0; + border: none; +} +.monaco-workbench > .part.editor > .content .welcomePage .splash .vscode-icon { + width: 1.5em; + height: 1.5em; + vertical-align: middle; + padding-right: 0.5em; +} + +.monaco-workbench > .part.editor > .content .welcomePage .splash .title { + margin-bottom: 2em; +} + +.monaco-workbench > .part.editor > .content .welcomePage .splash p { + margin-top: 17px; + margin-bottom: 5px; +} +.monaco-workbench > .part.editor > .content .welcomePage .splash ul { + margin: 0; +} +.monaco-workbench > .part.editor > .content .welcomePage .splash ul { + list-style: none; + padding: 0; +} + +.monaco-workbench > .part.editor > .content .welcomePage .splash .recent li { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.monaco-workbench > .part.editor > .content .welcomePage .splash .recent .path { + padding-left: 1em; + opacity: 0.7; +} + +.monaco-workbench > .part.editor > .content .welcomePage .splash .title, +.monaco-workbench > .part.editor > .content .welcomePage .splash .showOnStartup { + white-space: nowrap; +} + +.monaco-workbench > .part.editor > .content .welcomePage .commands { + position: absolute; + top: 50%; + left: 75%; + transform: translate(-50%, -50%); + width: 35%; +} +.monaco-workbench > .part.editor > .content .welcomePage .commands h3 { + text-align: center; +} +.monaco-workbench > .part.editor > .content .welcomePage .commands ul { + list-style: none; + padding: 0; +} +.monaco-workbench > .part.editor > .content .welcomePage .commands li { + margin: 15px 0px; +} +.monaco-workbench > .part.editor > .content .welcomePage .commands li button { + margin: 0; + padding: 10px 20px; + border: 2px solid; + border-radius: 10px; + height: 46px; + width: 100%; + font-size: 15px; + text-align: left; + outline: none; + cursor: pointer; + white-space: nowrap; +} + +.monaco-workbench > .part.editor > .content .welcomePage .commands li button { + color: #6c6c6c; + background: #eee; + border-color: #ccc; +} + +.vs-dark .monaco-workbench > .part.editor > .content .welcomePage .commands li button { + color: #ccc; + background: #333; + border-color: black; +} + +.hc-black .monaco-workbench > .part.editor > .content .welcomePage .commands li button { + color: white; + background: black; + border-color: #f38518; + border-width: 1px; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.html b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.html new file mode 100644 index 0000000000000000000000000000000000000000..e2944b78ae2afbefed1bb0ad275e151ff566ef7d --- /dev/null +++ b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.html @@ -0,0 +1,43 @@ + +
+
+
+

Visual Studio Code

+

Editing Evolved

+
+ +
+

Recent:

+
    + +
+
+
+

Find help:

+ +
+

+
+
+

Welcome to Visual Studio Code!

+
    +
  • +
  • +
  • +
  • +
  • +
  • +
+
+
\ No newline at end of file diff --git a/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.ts new file mode 100644 index 0000000000000000000000000000000000000000..7152211ffc3e08d86aff51670471ee49b97f8e70 --- /dev/null +++ b/src/vs/workbench/parts/welcomePage/electron-browser/welcomePage.ts @@ -0,0 +1,129 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import * as path from 'path'; +import { WalkThroughInput } from 'vs/workbench/parts/walkThrough/common/walkThroughInput'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IPartService } from 'vs/workbench/services/part/common/partService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { Position } from 'vs/platform/editor/common/editor'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { localize } from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; + +const enabledKey = 'workbench.welcome.enabled'; + +export class WelcomePageContribution implements IWorkbenchContribution { + + constructor( + @IPartService partService: IPartService, + @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService configurationService: IConfigurationService, + ) { + const enabled = configurationService.lookup(enabledKey).value; + if (enabled) { + partService.joinCreation().then(() => { + instantiationService.createInstance(WelcomePage); + }).then(null, onUnexpectedError); + } + } + + public getId() { + return 'vs.welcomePage'; + } +} + +export class WelcomePageAction extends Action { + + public static ID = 'workbench.action.welcomePage'; + public static LABEL = localize('welcomePage', "Welcome"); + + constructor( + id: string, + label: string, + @IInstantiationService private instantiationService: IInstantiationService + ) { + super(id, label); + } + + public run(): TPromise { + this.instantiationService.createInstance(WelcomePage); + return null; + } +} + +class WelcomePage { + + constructor( + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IInstantiationService private instantiationService: IInstantiationService, + @IWindowService private windowService: IWindowService, + @IWindowsService private windowsService: IWindowsService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IConfigurationService private configurationService: IConfigurationService, + @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + ) { + this.create(); + } + + private create() { + const recentlyOpened = this.windowService.getRecentlyOpen(); + const uri = URI.parse(require.toUrl('./welcomePage.html')); + const input = this.instantiationService.createInstance(WalkThroughInput, localize('welcome.title', "Welcome"), '', uri, container => this.onReady(container, recentlyOpened)); + this.editorService.openEditor(input, { pinned: true }, Position.ONE) + .then(null, onUnexpectedError); + } + + private onReady(container: HTMLElement, recentlyOpened: TPromise<{ files: string[]; folders: string[]; }>): void { + const enabled = this.configurationService.lookup(enabledKey).value; + const showOnStartup = container.querySelector('#showOnStartup'); + if (enabled) { + showOnStartup.setAttribute('checked', 'checked'); + } + showOnStartup.addEventListener('click', e => { + this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: enabledKey, value: showOnStartup.checked }) + .then(null, onUnexpectedError); + }); + + recentlyOpened.then(({folders}) => { + const ul = container.querySelector('.recent ul'); + if (this.contextService.hasWorkspace()) { + const current = this.contextService.getWorkspace().resource.fsPath; + folders = folders.filter(folder => folder !== current); + } + folders.slice(0, 5).forEach(folder => { + const li = document.createElement('li'); + + const a = document.createElement('a'); + const name = path.basename(folder); + a.innerText = name; + a.title = folder; + a.href = 'javascript:void(0)'; + a.addEventListener('click', e => { + this.windowsService.openWindow([folder]); + e.preventDefault(); + }); + li.appendChild(a); + + const span = document.createElement('span'); + span.classList.add('path'); + const parentFolder = path.dirname(folder); + span.innerText = parentFolder; + span.title = folder; + li.appendChild(span); + + ul.appendChild(li); + }); + }).then(null, onUnexpectedError); + } +}