Skip to content

Commit

Permalink
feat: add a welcome screen for extension (#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk authored Feb 18, 2021
1 parent da14e8a commit df0b20a
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 8 deletions.
1 change: 0 additions & 1 deletion Releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
Releases of the extension can be downloaded from
[Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno).


### [canary/0.0.10](https://github.com/denoland/vscode_deno/compare/canary/0.0.9...canary/0.0.10) / 2021.02.13

- fix: don't remove required files when packaging vsix
Expand Down
11 changes: 11 additions & 0 deletions client/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import { EXTENSION_NS } from "./constants";
import { pickInitWorkspace } from "./initialize_project";
import { cache as cacheReq } from "./lsp_extensions";
import { WelcomePanel } from "./welcome";

import {
commands,
ExtensionContext,
Expand Down Expand Up @@ -104,3 +106,12 @@ export function status(
return window.showTextDocument(document, ViewColumn.Two, true);
};
}

export function welcome(
context: ExtensionContext,
_client: LanguageClient,
): Callback {
return () => {
WelcomePanel.createOrShow(context.extensionUri);
};
}
1 change: 1 addition & 0 deletions client/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

export const EXTENSION_ID = "denoland.vscode-deno-canary";
export const EXTENSION_NS = "deno";
export const EXTENSION_TS_PLUGIN = "typescript-deno-plugin";
export const TS_LANGUAGE_FEATURES_EXTENSION =
Expand Down
13 changes: 13 additions & 0 deletions client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export async function activate(
registerCommand("initializeWorkspace", commands.initializeWorkspace);
registerCommand("showReferences", commands.showReferences);
registerCommand("status", commands.status);
registerCommand("welcome", commands.welcome);

context.subscriptions.push(client.start());
tsApi = await getTsApi();
Expand All @@ -164,6 +165,8 @@ export async function activate(
EXTENSION_TS_PLUGIN,
getSettings(),
);

showWelcomePage(context);
}

export function deactivate(): Thenable<void> | undefined {
Expand All @@ -173,6 +176,16 @@ export function deactivate(): Thenable<void> | undefined {
return client.stop();
}

function showWelcomePage(context: vscode.ExtensionContext) {
const welcomeShown = context.globalState.get<boolean>("deno.welcomeShown") ??
false;

if (!welcomeShown) {
commands.welcome(context, client)();
context.globalState.update("deno.welcomeShown", true);
}
}

/** Internal function factory that returns a registerCommand function that is
* bound to the extension context. */
function createRegisterCommand(
Expand Down
187 changes: 187 additions & 0 deletions client/src/welcome.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

import * as vscode from "vscode";
import { EXTENSION_ID } from "./constants";

function getNonce() {
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

export class WelcomePanel {
#panel: vscode.WebviewPanel;
#extensionUri: vscode.Uri;
#mediaRoot: vscode.Uri;
#disposables: vscode.Disposable[] = [];

private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this.#panel = panel;
this.#extensionUri = extensionUri;
this.#mediaRoot = vscode.Uri.joinPath(this.#extensionUri, "media");

this.#update();

this.#panel.onDidDispose(() => this.dispose(), null, this.#disposables);

this.#panel.webview.onDidReceiveMessage(
(message) => {
switch (message.command) {
case "openDocument": {
const uri = vscode.Uri.joinPath(
this.#extensionUri,
message.document,
);
vscode.commands.executeCommand("markdown.showPreviewToSide", uri);
return;
}
case "openSetting": {
vscode.commands.executeCommand(
"workbench.action.openSettings",
message.setting,
);
return;
}
case "init": {
vscode.commands.executeCommand("deno.initializeWorkspace");
return;
}
}
},
null,
this.#disposables,
);
}

dispose() {
WelcomePanel.currentPanel = undefined;

this.#panel.dispose();

for (const handle of this.#disposables) {
if (handle) {
handle.dispose();
}
}
}

#update = () => {
const { webview } = this.#panel;
this.#panel.webview.html = this.#getHtmlForWebview(webview);
};

#getHtmlForWebview = (webview: vscode.Webview) => {
const scriptPath = vscode.Uri.joinPath(this.#mediaRoot, "welcome.js");
const stylesPath = vscode.Uri.joinPath(this.#mediaRoot, "welcome.css");
const logoPath = vscode.Uri.joinPath(this.#extensionUri, "deno.png");
const denoExtension = vscode.extensions.getExtension(EXTENSION_ID)!;
const denoExtensionVersion = denoExtension.packageJSON.version;

const scriptURI = webview.asWebviewUri(scriptPath);
const stylesURI = webview.asWebviewUri(stylesPath);
const logoURI = webview.asWebviewUri(logoPath);

const nonce = getNonce();

return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--
Use a CSP that only allows loading images from https or from our
extension directory and only allows scripts that have a specific nonce
-->
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; img-src ${webview.cspSource} https:; script-src 'nonce-${nonce}';">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${stylesURI}" rel="stylesheet">
<title>Deno for VSCode</title>
</head>
<body>
<main class="Content">
<div class="Header">
<img src="${logoURI}" alt="Deno Extension Logo" class="Header-logo" />
<div class="Header-details">
<h1 class="Header-title">Deno for VSCode v${denoExtensionVersion}</h1>
<p>The official Deno extension for Visual Studio Code, powered by the Deno Language Server.</p>
<ul class="Header-links">
<li><a href="#" class="Command" data-command="openDocument" data-document="Releases.md">Release notes</a></li>
<li><a href="https://github.com/denoland/vscode_deno/">GitHub</a></li>
<li><a href="https://discord.gg/deno">Discord</a></li>
</ul>
</div>
</div>
<div class="Cards">
<div class="Card">
<div class="Card-inner">
<p class="Card-title">Enabling Deno</p>
<p class="Card-content">
<p>
The extension does not assume it applies to all workspaces you use
with VSCode. You can enable Deno in a workspace by running the
<em><a href="#" class="Command" data-command="init">Deno:
Initialize Workspace Configuration</a></em> command.
</p>
<p>
You can also enable or disable it in the
<a href="#" class="Command" data-command="openSetting" data-setting="deno.enable">settings</a>.
<em>It is not recommended to enable it globally, unless of course
you only edit Deno projects with VSCode.</em>
</p>
</p>
</div>
</div>
<div class="Card">
<div class="Card-inner">
<p class="Card-title">Getting started with Deno</p>
<p class="Card-content">
If you are new to Deno, check out the
<a href="https://deno.land/manual/getting_started">getting started
section</a> of the Deno manual.
</p>
</div>
</div>
</div>
</main>
<script nonce="${nonce}" src="${scriptURI}"></script>
</body>
</html>`;
};

static currentPanel: WelcomePanel | undefined;
static readonly viewType = "welcomeDeno";

static createOrShow(extensionUri: vscode.Uri) {
const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn
: undefined;

if (WelcomePanel.currentPanel) {
WelcomePanel.currentPanel.#panel.reveal(column);
return;
}

const panel = vscode.window.createWebviewPanel(
WelcomePanel.viewType,
"Deno for VSCode",
column ?? vscode.ViewColumn.One,
{
enableScripts: true,
localResourceRoots: [vscode.Uri.joinPath(extensionUri)],
},
);
panel.iconPath = vscode.Uri.joinPath(extensionUri, "deno.png");

WelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);
}

static revive(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
WelcomePanel.currentPanel = new WelcomePanel(panel, extensionUri);
}
}
78 changes: 78 additions & 0 deletions media/welcome.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. */

.Content {
font-size: 1rem;
line-height: 1.5rem;
margin: auto;
max-width: 60rem;
}

.Header {
align-items: center;
display: flex;
border-bottom: 0.0625rem solid #ccc;
margin-bottom: 2rem;
padding-bottom: 1.25rem;
}
.Header-logo {
width: 12rem;
margin-right: 3rem;
}
.Header-title {
font-size: 1.75rem;
}

.Cards {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.Card {
max-width: 40rem;
flex: 1;
}
.Card-inner {
display: flex;
flex: 1;
flex-direction: column;
padding: 0rem;
}
.Card-title {
font-size: 1.5rem;
font-weight: 500;
}
.Card-content {
margin: 0;
}


a:link,
a:visited {
text-decoration: none;
}
.Command:hover,
a:hover {
text-decoration: underline;
}

@media (min-width: 40rem) {
.Header-links {
list-style: none;
padding: 0;
}
.Header-links li {
float: left;
}
.Header-links li:not(:first-child):before {
content: "|";
color: #ccc;
padding: 0 1rem;
}
.Cards {
flex-direction: row;
justify-content: space-between;
}
.Card:not(:last-child) {
margin-right: 4rem;
}
}
13 changes: 13 additions & 0 deletions media/welcome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

(function () {
const vscode = acquireVsCodeApi();

const commands = document.querySelectorAll('.Command');
for (const command of commands) {
const msg = JSON.parse(JSON.stringify(command.dataset));
command.addEventListener("click", () => {
vscode.postMessage(msg);
});
}
}());
Loading

0 comments on commit df0b20a

Please sign in to comment.