mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
docs: add open in IDX support (#57099)
This change adds a menu to the in-browser code editor on adev and adds the option for open in IDX. PR Close #57099
This commit is contained in:
parent
56816bbdb2
commit
ca8bd5be99
12 changed files with 273 additions and 3 deletions
|
|
@ -80,6 +80,7 @@ APPLICATION_DEPS = [
|
|||
"@npm//@lezer/javascript",
|
||||
"@npm//@lezer/common",
|
||||
"@npm//@stackblitz/sdk",
|
||||
"@npm//open-in-idx",
|
||||
"@npm//@xterm/xterm",
|
||||
"@npm//@xterm/addon-fit",
|
||||
"@npm//algoliasearch",
|
||||
|
|
|
|||
|
|
@ -68,11 +68,23 @@
|
|||
<button
|
||||
class="adev-editor-download-button"
|
||||
type="button"
|
||||
(click)="openCurrentCodeInStackBlitz()"
|
||||
aria-label="Open current code in editor in StackBlitz"
|
||||
aria-label="Open current code in editor in an online editor"
|
||||
[cdkMenuTriggerFor]="launcherMenu"
|
||||
>
|
||||
<docs-icon>launch</docs-icon>
|
||||
</button>
|
||||
<!-- launcher dropdown window -->
|
||||
<ng-template #launcherMenu>
|
||||
<div class="adev-editor-dropdown" cdkMenu>
|
||||
<button cdkMenuItem (click)="openCurrentSolutionInIDX()">
|
||||
<span>Open in IDX </span>
|
||||
<img class="icon" src="assets/images/tutorials/common/idx_logo.svg" height="32">
|
||||
</button>
|
||||
<button cdkMenuItem (click)="openCurrentCodeInStackBlitz()">
|
||||
Open in StackBlitz
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
<button
|
||||
class="adev-editor-download-button"
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -186,3 +186,34 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adev-editor-dropdown {
|
||||
border: 1px solid var(--senary-contrast);
|
||||
border-radius: 0.25rem;
|
||||
padding: 0;
|
||||
transform: translateY(-0.7rem);
|
||||
|
||||
button {
|
||||
background: var(--page-background);
|
||||
font-size: 0.875rem;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding-block: 0.5rem;
|
||||
color: var(--quaternary-contrast);
|
||||
transition: color 0.3s ease, background 0.3s ease;
|
||||
font-weight: 400;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background: var(--senary-contrast);
|
||||
color: var(--primary-contrast);
|
||||
}
|
||||
.icon {
|
||||
margin: initial;
|
||||
padding: initial;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import {DiagnosticWithLocation, DiagnosticsState} from './services/diagnostics-s
|
|||
import {DownloadManager} from '../download-manager.service';
|
||||
import {StackBlitzOpener} from '../stackblitz-opener.service';
|
||||
import {ClickOutside, IconComponent} from '@angular/docs';
|
||||
import {CdkMenu, CdkMenuItem, CdkMenuTrigger} from '@angular/cdk/menu';
|
||||
import {IDXLauncher} from '../idx-launcher.service';
|
||||
|
||||
export const REQUIRED_FILES = new Set([
|
||||
'src/main.ts',
|
||||
|
|
@ -46,7 +48,16 @@ const ANGULAR_DEV = 'https://angular.dev';
|
|||
templateUrl: './code-editor.component.html',
|
||||
styleUrls: ['./code-editor.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [NgIf, NgFor, MatTabsModule, IconComponent, ClickOutside],
|
||||
imports: [
|
||||
NgIf,
|
||||
NgFor,
|
||||
MatTabsModule,
|
||||
IconComponent,
|
||||
ClickOutside,
|
||||
CdkMenu,
|
||||
CdkMenuItem,
|
||||
CdkMenuTrigger,
|
||||
],
|
||||
})
|
||||
export class CodeEditor implements AfterViewInit, OnDestroy {
|
||||
@ViewChild('codeEditorWrapper') private codeEditorWrapperRef!: ElementRef<HTMLDivElement>;
|
||||
|
|
@ -78,6 +89,7 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
|
|||
private readonly diagnosticsState = inject(DiagnosticsState);
|
||||
private readonly downloadManager = inject(DownloadManager);
|
||||
private readonly stackblitzOpener = inject(StackBlitzOpener);
|
||||
private readonly idxLauncher = inject(IDXLauncher);
|
||||
private readonly title = inject(Title);
|
||||
private readonly location = inject(Location);
|
||||
private readonly embeddedTutorialManager = inject(EmbeddedTutorialManager);
|
||||
|
|
@ -117,6 +129,9 @@ export class CodeEditor implements AfterViewInit, OnDestroy {
|
|||
this.codeMirrorEditor.disable();
|
||||
}
|
||||
|
||||
openCurrentSolutionInIDX(): void {
|
||||
this.idxLauncher.openCurrentSolutionInIDX();
|
||||
}
|
||||
async openCurrentCodeInStackBlitz(): Promise<void> {
|
||||
const title = this.title.getTitle();
|
||||
|
||||
|
|
|
|||
51
adev/src/app/editor/idx-launcher.service.ts
Normal file
51
adev/src/app/editor/idx-launcher.service.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {EnvironmentInjector, Injectable, inject} from '@angular/core';
|
||||
import {injectAsync} from '../core/services/inject-async';
|
||||
import * as IDX from 'open-in-idx';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class IDXLauncher {
|
||||
private readonly environmentInjector = inject(EnvironmentInjector);
|
||||
|
||||
async openCurrentSolutionInIDX(): Promise<void> {
|
||||
const nodeRuntimeSandbox = await injectAsync(this.environmentInjector, () =>
|
||||
import('./node-runtime-sandbox.service').then((c) => c.NodeRuntimeSandbox),
|
||||
);
|
||||
|
||||
const runtimeFiles = await nodeRuntimeSandbox.getSolutionFiles();
|
||||
const workspaceFiles: Record<string, string> = {};
|
||||
|
||||
for (let i = 0; i < runtimeFiles.length; i++) {
|
||||
const file = runtimeFiles[i];
|
||||
|
||||
//don't include config.json, BUILD.bazel, package-lock.json, package.json.template
|
||||
const doNotAllowList = [
|
||||
'config.json',
|
||||
'BUILD.bazel',
|
||||
'package-lock.json',
|
||||
'package.json.template',
|
||||
];
|
||||
|
||||
const path = file.path.replace(/^\//, '');
|
||||
|
||||
//don't include binary formats
|
||||
if (!doNotAllowList.includes(path) && typeof file.content === 'string') {
|
||||
if (path === 'idx/dev.nix') {
|
||||
workspaceFiles['.idx/dev.nix'] = file.content as string;
|
||||
} else {
|
||||
workspaceFiles[path] = file.content as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
IDX.newAdhocWorkspace({files: workspaceFiles});
|
||||
}
|
||||
}
|
||||
14
adev/src/assets/images/tutorials/common/idx_logo.svg
Normal file
14
adev/src/assets/images/tutorials/common/idx_logo.svg
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(1,0,0,1,-2.417,0)">
|
||||
<path d="M20.084,23.5C20.084,22.81 19.524,22.25 18.834,22.25L12.167,22.25C11.477,22.25 10.917,22.81 10.917,23.5C10.917,24.19 11.477,24.75 12.167,24.75L18.834,24.75C19.524,24.75 20.084,24.19 20.084,23.5Z" style="fill:rgb(137,100,232);"/>
|
||||
<path d="M22.583,19.75C22.583,19.06 22.023,18.5 21.333,18.5L20.083,18.5C19.393,18.5 18.833,19.06 18.833,19.75C18.833,20.44 19.393,21 20.083,21L21.333,21C22.023,21 22.583,20.44 22.583,19.75Z" style="fill:rgb(23,184,119);"/>
|
||||
<path d="M17.583,19.75C17.583,19.06 17.023,18.5 16.333,18.5L15.083,18.5C14.393,18.5 13.833,19.06 13.833,19.75C13.833,20.44 14.393,21 15.083,21L16.333,21C17.023,21 17.583,20.44 17.583,19.75Z" style="fill:rgb(23,184,119);"/>
|
||||
<path d="M22.167,16C22.167,15.31 21.607,14.75 20.917,14.75L18,14.75C17.31,14.75 16.75,15.31 16.75,16C16.75,16.69 17.31,17.25 18,17.25L20.917,17.25C21.607,17.25 22.167,16.69 22.167,16Z" style="fill:rgb(255,162,62);"/>
|
||||
<path d="M25.917,16C25.917,15.31 25.357,14.75 24.667,14.75C23.977,14.75 23.417,15.31 23.417,16C23.417,16.69 23.977,17.25 24.667,17.25C25.357,17.25 25.917,16.69 25.917,16Z" style="fill:rgb(255,162,62);"/>
|
||||
<path d="M23,12.25C23,11.56 22.44,11 21.75,11L15.083,11C14.393,11 13.833,11.56 13.833,12.25C13.833,12.94 14.393,13.5 15.083,13.5L21.75,13.5C22.44,13.5 23,12.94 23,12.25Z" style="fill:rgb(37,166,233);"/>
|
||||
<path d="M20.084,8.5C20.084,7.81 19.524,7.25 18.834,7.25L15.917,7.25C15.227,7.25 14.667,7.81 14.667,8.5C14.667,9.19 15.227,9.75 15.917,9.75L18.834,9.75C19.524,9.75 20.084,9.19 20.084,8.5Z" style="fill:rgb(137,100,232);"/>
|
||||
<path d="M13.417,8.5C13.417,7.81 12.857,7.25 12.167,7.25C11.477,7.25 10.917,7.81 10.917,8.5C10.917,9.19 11.477,9.75 12.167,9.75C12.857,9.75 13.417,9.19 13.417,8.5Z" style="fill:rgb(137,100,232);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
35
adev/src/content/tutorials/first-app/common/idx/dev.nix
Normal file
35
adev/src/content/tutorials/first-app/common/idx/dev.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# To learn more about how to use Nix to configure your environment
|
||||
# see: https://developers.google.com/idx/guides/customize-idx-env
|
||||
{ pkgs, ... }: {
|
||||
# Which nixpkgs channel to use.
|
||||
channel = "stable-23.11"; # or "unstable"
|
||||
# Use https://search.nixos.org/packages to find packages
|
||||
packages = [
|
||||
pkgs.nodejs_18
|
||||
];
|
||||
# Sets environment variables in the workspace
|
||||
env = {};
|
||||
idx = {
|
||||
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
||||
extensions = [
|
||||
"angular.ng-template"
|
||||
];
|
||||
workspace = {
|
||||
# Runs when a workspace is first created with this \`dev.nix\` file
|
||||
onCreate = {
|
||||
npm-install = "npm install --no-audit --prefer-offline";
|
||||
};
|
||||
# To run something each time the environment is rebuilt, use the \`onStart\` hook
|
||||
};
|
||||
# Enable previews and customize configuration
|
||||
previews = {
|
||||
enable = true;
|
||||
previews = {
|
||||
web = {
|
||||
command = ["npm" "run" "start" "--" "--port" "$PORT" "--host" "0.0.0.0"];
|
||||
manager = "web";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
35
adev/src/content/tutorials/homepage/idx/dev.nix
Normal file
35
adev/src/content/tutorials/homepage/idx/dev.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# To learn more about how to use Nix to configure your environment
|
||||
# see: https://developers.google.com/idx/guides/customize-idx-env
|
||||
{ pkgs, ... }: {
|
||||
# Which nixpkgs channel to use.
|
||||
channel = "stable-23.11"; # or "unstable"
|
||||
# Use https://search.nixos.org/packages to find packages
|
||||
packages = [
|
||||
pkgs.nodejs_18
|
||||
];
|
||||
# Sets environment variables in the workspace
|
||||
env = {};
|
||||
idx = {
|
||||
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
||||
extensions = [
|
||||
"angular.ng-template"
|
||||
];
|
||||
workspace = {
|
||||
# Runs when a workspace is first created with this \`dev.nix\` file
|
||||
onCreate = {
|
||||
npm-install = "npm install --no-audit --prefer-offline";
|
||||
};
|
||||
# To run something each time the environment is rebuilt, use the \`onStart\` hook
|
||||
};
|
||||
# Enable previews and customize configuration
|
||||
previews = {
|
||||
enable = true;
|
||||
previews = {
|
||||
web = {
|
||||
command = ["npm" "run" "start" "--" "--port" "$PORT" "--host" "0.0.0.0"];
|
||||
manager = "web";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
35
adev/src/content/tutorials/learn-angular/common/idx/dev.nix
Normal file
35
adev/src/content/tutorials/learn-angular/common/idx/dev.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# To learn more about how to use Nix to configure your environment
|
||||
# see: https://developers.google.com/idx/guides/customize-idx-env
|
||||
{ pkgs, ... }: {
|
||||
# Which nixpkgs channel to use.
|
||||
channel = "stable-23.11"; # or "unstable"
|
||||
# Use https://search.nixos.org/packages to find packages
|
||||
packages = [
|
||||
pkgs.nodejs_18
|
||||
];
|
||||
# Sets environment variables in the workspace
|
||||
env = {};
|
||||
idx = {
|
||||
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
||||
extensions = [
|
||||
"angular.ng-template"
|
||||
];
|
||||
workspace = {
|
||||
# Runs when a workspace is first created with this \`dev.nix\` file
|
||||
onCreate = {
|
||||
npm-install = "npm install --no-audit --prefer-offline";
|
||||
};
|
||||
# To run something each time the environment is rebuilt, use the \`onStart\` hook
|
||||
};
|
||||
# Enable previews and customize configuration
|
||||
previews = {
|
||||
enable = true;
|
||||
previews = {
|
||||
web = {
|
||||
command = ["npm" "run" "start" "--" "--port" "$PORT" "--host" "0.0.0.0"];
|
||||
manager = "web";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
35
adev/src/content/tutorials/playground/common/idx/dev.nix
Normal file
35
adev/src/content/tutorials/playground/common/idx/dev.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# To learn more about how to use Nix to configure your environment
|
||||
# see: https://developers.google.com/idx/guides/customize-idx-env
|
||||
{ pkgs, ... }: {
|
||||
# Which nixpkgs channel to use.
|
||||
channel = "stable-23.11"; # or "unstable"
|
||||
# Use https://search.nixos.org/packages to find packages
|
||||
packages = [
|
||||
pkgs.nodejs_18
|
||||
];
|
||||
# Sets environment variables in the workspace
|
||||
env = {};
|
||||
idx = {
|
||||
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
|
||||
extensions = [
|
||||
"angular.ng-template"
|
||||
];
|
||||
workspace = {
|
||||
# Runs when a workspace is first created with this \`dev.nix\` file
|
||||
onCreate = {
|
||||
npm-install = "npm install --no-audit --prefer-offline";
|
||||
};
|
||||
# To run something each time the environment is rebuilt, use the \`onStart\` hook
|
||||
};
|
||||
# Enable previews and customize configuration
|
||||
previews = {
|
||||
enable = true;
|
||||
previews = {
|
||||
web = {
|
||||
command = ["npm" "run" "start" "--" "--port" "$PORT" "--host" "0.0.0.0"];
|
||||
manager = "web";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -126,6 +126,7 @@
|
|||
"memo-decorator": "^2.0.1",
|
||||
"ngx-flamegraph": "0.0.12",
|
||||
"ngx-progressbar": "^11.1.0",
|
||||
"open-in-idx": "^0.1.1",
|
||||
"protractor": "^7.0.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"requirejs": "^2.3.6",
|
||||
|
|
|
|||
|
|
@ -13260,6 +13260,11 @@ onetime@^5.1.0, onetime@^5.1.2:
|
|||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
open-in-idx@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/open-in-idx/-/open-in-idx-0.1.1.tgz#390cb0985146a461f5a662ed1fd0db3fce55b2f0"
|
||||
integrity sha512-4Cks2eY4bnWpBP/fEj1deRrVYbHME36g0w4/IFDG4iwnkD7CwmK9HrF3A3LR/RKHs5AXUMj49YxnwdIxEizDpA==
|
||||
|
||||
open@8.4.2:
|
||||
version "8.4.2"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9"
|
||||
|
|
|
|||
Loading…
Reference in a new issue