From a83f47abf39faf8c01964fd322cc2515ea6d466f Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 27 Aug 2019 21:10:49 -0400 Subject: [PATCH] feat(frontend): update home screens --- .../application/application.spec.ts | 4 +- .../src/schematics/application/application.ts | 287 ++++++++++++++++-- .../application/files/src/favicon.ico | Bin 0 -> 15086 bytes .../files/app/src/app/__fileName__.__style__ | 36 +++ .../app/src/app/__fileName__.tsx__tmpl__ | 48 ++- .../application/files/app/src/favicon.ico | Bin 3870 -> 15086 bytes .../application/application.spec.ts | 2 +- .../files/app/src/app/app.element.__style__ | 133 ++++++++ .../files/app/src/app/app.element.ts__tmpl__ | 93 +++++- .../application/files/app/src/favicon.ico | Bin 7406 -> 15086 bytes 10 files changed, 562 insertions(+), 41 deletions(-) create mode 100644 packages/angular/src/schematics/application/files/src/favicon.ico diff --git a/packages/angular/src/schematics/application/application.spec.ts b/packages/angular/src/schematics/application/application.spec.ts index 4db4b1fa45f59..436d642c78fd6 100644 --- a/packages/angular/src/schematics/application/application.spec.ts +++ b/packages/angular/src/schematics/application/application.spec.ts @@ -284,7 +284,7 @@ describe('app', () => { ).toBeTruthy(); expect( getFileContent(tree, 'apps/my-dir/my-app/src/app/app.component.html') - ).toContain('This is an Angular app built with'); + ).toContain('Thank you for using and showing some ♥ for Nx.'); }); it("should update `template`'s property of AppComponent with Nx content", async () => { @@ -295,7 +295,7 @@ describe('app', () => { ); expect( getFileContent(tree, 'apps/my-dir/my-app/src/app/app.component.ts') - ).toContain('This is an Angular app built with'); + ).toContain('Thank you for using and showing some ♥ for Nx.'); }); }); diff --git a/packages/angular/src/schematics/application/application.ts b/packages/angular/src/schematics/application/application.ts index d19915aef2570..5ee0ab2e75ad2 100644 --- a/packages/angular/src/schematics/application/application.ts +++ b/packages/angular/src/schematics/application/application.ts @@ -44,6 +44,225 @@ interface NormalizedSchema extends Schema { parsedTags: string[]; } +const nrwlHomeTemplate = { + html: ` +
+ Nx logo +

Welcome to {{title}}!

+
+
+

Resources & Tools

+

+ Thank you for using and showing some ♥ for Nx. +

+ +

+ Here are some links to help you get started. +

+ +

Next Steps

+

Here are some things you can do with Nx.

+
+ Add UI library +
+\`# Generate UI lib
+ng g @nrwl/angular:lib ui
+
+# Add a component
+ng g @nrwl/angular:component xyz --project ui\`
+
+
+ View dependency graph +
\`nx dep-graph\`
+
+
+ Run affected commands +
+\`# see what's been affected by changes
+ng affected:dep-graph
+
+# run tests for current changes
+ng affected:test
+
+# run e2e tests for current changes
+ng affected:e2e
+\`
+
+
+ `, + css: ` +/* + * Remove template code below + */ +:host { + display: block; + font-family: sans-serif; + min-width: 300px; + max-width: 600px; + margin: 50px auto; +} + +.gutter-left { + margin-left: 9px; +} + +.col-span-2 { + grid-column: span 2; +} + +.flex { + display: flex; + align-items: center; + justify-content: center; +} + +header { + background-color: #143055; + color: white; + padding: 5px; + border-radius: 3px; +} + +main { + padding: 0 36px; +} + +p { + text-align: center; +} + +h1 { + text-align: center; + margin-left: 18px; + font-size: 24px; +} + +h2 { + text-align: center; + font-size: 20px; + margin: 40px 0 10px 0; +} + +.resources { + text-align: center; + list-style: none; + padding: 0; + display: grid; + grid-gap: 9px; + grid-template-columns: 1fr 1fr; +} + +.resource { + color: #0094ba; + height: 36px; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 4px; + padding: 3px 9px; + text-decoration: none; +} + +.resource:hover { + background-color: rgba(68, 138, 255, 0.04); +} + +pre { + padding: 9px; + border-radius: 4px; + background-color: black; + color: #eee; +} + +details { + border-radius: 4px; + color: #333; + background-color: rgba(0, 0, 0, 0); + border: 1px solid rgba(0, 0, 0, 0.12); + padding: 3px 9px; + margin-bottom: 9px; +} + +summary { + cursor: pointer; + outline: none; + height: 36px; + line-height: 36px; +} + +.github-star-container { + margin-top: 12px; + line-height: 20px; +} + +.github-star-container a { + display: flex; + align-items: center; + text-decoration: none; + color: #333; +} + +.github-star-badge { + color: #24292e; + display: flex; + align-items: center; + font-size: 12px; + padding: 3px 10px; + border: 1px solid rgba(27,31,35,.2); + border-radius: 3px; + background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%); + margin-left: 4px; + font-weight: 600; +} + +.github-star-badge:hover { + background-image: linear-gradient(-180deg,#f0f3f6,#e6ebf1 90%); + border-color: rgba(27,31,35,.35); + background-position: -.5em; +} +.github-star-badge .material-icons { + height: 16px; + width: 16px; + margin-right: 4px; +} + ` +}; + function addRouterRootConfiguration(options: NormalizedSchema): Rule { return (host: Tree) => { const modulePath = `${options.appProjectRoot}/src/app/app.module.ts`; @@ -95,27 +314,47 @@ function addRouterRootConfiguration(options: NormalizedSchema): Rule { }; } +function updateComponentStyles(options: NormalizedSchema): Rule { + return (host: Tree) => { + const content = nrwlHomeTemplate.css; + + if (!options.inlineStyle) { + const filesMap = { + css: `${options.appProjectRoot}/src/app/app.component.css`, + scss: `${options.appProjectRoot}/src/app/app.component.scss`, + less: `${options.appProjectRoot}/src/app/app.component.less`, + styl: `${options.appProjectRoot}/src/app/app.component.styl` + }; + return host.overwrite(filesMap[options.style], content); + } + + // Inline component update + const modulePath = `${options.appProjectRoot}/src/app/app.component.ts`; + const templateNodeValue = getDecoratorPropertyValueNode( + host, + modulePath, + 'Component', + 'styles', + '@angular/core' + ); + replaceNodeValue( + host, + modulePath, + templateNodeValue, + `[\`\n${content}\n\`],\n` + ); + }; +} + +/** + * + * @param options + */ function updateComponentTemplate(options: NormalizedSchema): Rule { return (host: Tree) => { - const baseContent = ` -
-

Welcome to {{title}}!

- -
- -

This is an Angular app built with Nx.

-

🔎 **Nx is a set of Extensible Dev Tools for Monorepos.**

- -

Quick Start & Documentation

- - -`; const content = options.routing - ? `${baseContent}\n` - : baseContent; + ? `${nrwlHomeTemplate.html}\n` + : nrwlHomeTemplate.html; if (!options.inlineTemplate) { return host.overwrite( @@ -124,6 +363,7 @@ function updateComponentTemplate(options: NormalizedSchema): Rule { ); } + // Inline component update const modulePath = `${options.appProjectRoot}/src/app/app.component.ts`; const templateNodeValue = getDecoratorPropertyValueNode( host, @@ -136,7 +376,7 @@ function updateComponentTemplate(options: NormalizedSchema): Rule { host, modulePath, templateNodeValue, - `\`\n${baseContent}\n\`,\n` + `\`\n${nrwlHomeTemplate.html}\n\`,\n` ); }; } @@ -177,8 +417,12 @@ function updateLinting(options: NormalizedSchema): Rule { ]); } -function addTsconfigs(options: NormalizedSchema): Rule { +function addSchematicFiles( + appProjectRoot: string, + options: NormalizedSchema +): Rule { return chain([ + host => host.delete(`${appProjectRoot}/src/favicon.ico`), mergeWith( apply(url('./files'), [ template({ @@ -385,7 +629,7 @@ export default function(schema: Schema): Rule { skipInstall: true, skipPackageJson: false }), - addTsconfigs(options), + addSchematicFiles(appProjectRoot, options), options.e2eTestRunner === 'protractor' ? move(e2eProjectRoot, options.e2eProjectRoot) : removeE2e(options, e2eProjectRoot), @@ -403,6 +647,7 @@ export default function(schema: Schema): Rule { move(appProjectRoot, options.appProjectRoot), updateProject(options), updateComponentTemplate(options), + updateComponentStyles(options), options.routing ? addRouterRootConfiguration(options) : noop(), updateLinting(options), options.unitTestRunner === 'jest' diff --git a/packages/angular/src/schematics/application/files/src/favicon.ico b/packages/angular/src/schematics/application/files/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 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 @@ -121,7 +157,17 @@ var innerJsx = `

Resources & Tools

- Thank you for using and showing some ♥ for Nx.
+ Thank you for using and showing some ♥ for Nx. +

+ +

Here are some links to help you get started.

`; } } diff --git a/packages/web/src/schematics/application/files/app/src/favicon.ico b/packages/web/src/schematics/application/files/app/src/favicon.ico index d0d1682ac8c10c174c206b23c456da5ebd1ccbbb..317ebcb2336e0833a22dddf0ab287849f26fda57 100644 GIT binary patch literal 15086 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 TYX{!d4!j$c)peIQ?ZCePy;yYr