From b842dd3a814148cd32f85c94b6ace5353bbb6b2f Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Mon, 8 May 2023 14:04:42 -0400 Subject: [PATCH 1/7] feat(nx-plugin): add trpc to nx generator, use v16 config, improve template adds option to the nx generator to let users add the new trpc client. moves v16 app to use the new ApplicationConfig pattern. improves templates by adding separate templates for tailwind and non tailwind. same for trpc and non trpc. --- .../app/files/tRPC/src/note.ts__template__ | 5 + .../app/files/tRPC/src/public/assets/.gitkeep | 0 .../files/tRPC/src/public/assets/spartan.svg | 7 + .../server/routes/trpc/[trpc].ts__template__ | 8 + .../src/server/trpc/context.ts__template__ | 7 + .../server/trpc/routers/index.ts__template__ | 8 + .../server/trpc/routers/notes.ts__template__ | 32 +++ .../tRPC/src/server/trpc/trpc.ts__template__ | 10 + .../files/tRPC/src/trpc-client.ts__template__ | 11 + .../src/app/pages/index.page.ts__template__ | 249 ++++++++++++++++++ .../src/main.ts__template__ | 11 +- .../vite.config.ts__template__ | 5 + .../src/app.config.server.ts__template__ | 10 + .../src/app.config.ts__template__ | 16 ++ .../src/app/pages/index.page.ts__template__ | 249 ++++++++++++++++++ .../src/main.providers.ts__template__ | 5 - .../src/main.server.ts__template__ | 20 +- .../src/main.ts__template__ | 9 +- .../src/wait-for.ts__template__ | 19 ++ .../vite.config.ts__template__ | 5 + .../nx-plugin/src/generators/app/generator.ts | 7 +- .../src/generators/app/lib/add-trpc.ts | 35 +++ .../nx-plugin/src/generators/app/schema.d.ts | 3 +- .../nx-plugin/src/generators/app/schema.json | 12 +- .../nx-plugin/src/generators/app/versions.ts | 5 +- 25 files changed, 714 insertions(+), 34 deletions(-) create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/server/routes/trpc/[trpc].ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/context.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/index.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/trpc.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.ts__template__ delete mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.providers.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/lib/add-trpc.ts diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ new file mode 100644 index 000000000..45cfbb172 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ @@ -0,0 +1,5 @@ +export type Note = { + id: number; + note: string; + createdAt: Date; +}; diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep b/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg b/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg new file mode 100644 index 000000000..1a67c165b --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/routes/trpc/[trpc].ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/routes/trpc/[trpc].ts__template__ new file mode 100644 index 000000000..1dbb2168c --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/routes/trpc/[trpc].ts__template__ @@ -0,0 +1,8 @@ +import { appRouter } from '../../trpc/routers'; +import { createContext } from '../../trpc/context'; +import { createTrpcNitroHandler } from '@analogjs/trpc'; +// export API handler +export default createTrpcNitroHandler({ + router: appRouter, + createContext, +}); diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/context.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/context.ts__template__ new file mode 100644 index 000000000..3542761db --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/context.ts__template__ @@ -0,0 +1,7 @@ +import { inferAsyncReturnType } from '@trpc/server'; +/** + * Creates context for an incoming request + * @link https://trpc.io/docs/context + */ +export const createContext = () => ({}); +export type Context = inferAsyncReturnType; diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/index.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/index.ts__template__ new file mode 100644 index 000000000..49c415a63 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/index.ts__template__ @@ -0,0 +1,8 @@ +import { router } from '../trpc'; +import { noteRouter } from './notes'; + +export const appRouter = router({ + note: noteRouter, +}); +// export type definition of API +export type AppRouter = typeof appRouter; diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ new file mode 100644 index 000000000..1b890989c --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ @@ -0,0 +1,32 @@ +import { z } from 'zod'; +import { publicProcedure, router } from '../trpc'; +import { Note } from '../../../note'; + +let noteId = 0; +const notes: Note[] = []; +export const noteRouter = router({ + create: publicProcedure + .input( + z.object({ + title: z.string(), + }) + ) + .mutation(({ input }) => + notes.push({ + id: noteId++, + note: input.title, + createdAt: new Date(), + }) + ), + list: publicProcedure.query(() => notes), + remove: publicProcedure + .input( + z.object({ + id: z.number(), + }) + ) + .mutation(({ input }) => { + const index = notes.findIndex((note) => input.id === note.id); + notes.splice(index, 1); + }), +}); diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/trpc.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/trpc.ts__template__ new file mode 100644 index 000000000..2ec64756b --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/trpc.ts__template__ @@ -0,0 +1,10 @@ +import { initTRPC } from '@trpc/server'; +import { Context } from './context'; + +const t = initTRPC.context().create({}); +/** + * Unprotected procedure + **/ +export const publicProcedure = t.procedure; +export const router = t.router; +export const middleware = t.middleware; diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ new file mode 100644 index 000000000..20c63d431 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ @@ -0,0 +1,11 @@ +import { AppRouter } from './server/trpc/routers'; +import { createTrpcClient } from '@analogjs/trpc'; +import { inject } from '@angular/core'; + +export const { provideTRPCClient, tRPCClient } = createTrpcClient({ + url: 'http://localhost:4205/api/trpc', +}); + +export function injectTRPCClient() { + return inject(tRPCClient); +} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ index 5552a2c7b..23a5d9807 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ @@ -1,3 +1,250 @@ +<% if (addTRPC) { %> + <% if (addTailwind) { %> +import { Component } from '@angular/core'; +import { injectTRPCClient } from '../../trpc-client'; +import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '../../wait-for'; +import { Note } from '../../note'; + +const inputTw = + 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 focus:bg-white dark:focus:bg-dark placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; +const btnTw = + 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; + +@Component({ + selector: 'trpc-app-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + host: { + class: 'block h-full p-4', + }, + template: ` +
+

Analog + tRPC

+ Spartan Logo +
+
+ + +
+
+
+
+

{{ note.createdAt | date }}

+ +
+

{{ note.note }}

+
+ +
+

No notes yet!

+

Add a new one and see them appear here...

+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newTitle = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newTitle }) + .then(() => this.fetchPosts()); + this.newTitle = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} + <% } else { %> +import { Component } from '@angular/core'; +import { injectTRPCClient } from '../../trpc-client'; +import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '../../wait-for'; +import { Note } from '../../note'; + +@Component({ + selector: 'trpc-app-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + template: ` +
+

Analog + tRPC

+ Spartan Logo +
+
+ + +
+
+
+
+

{{ note.createdAt | date }}

+ +
+

{{ note.note }}

+
+ +
+

No notes yet!

+

Add a new one and see them appear here...

+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newTitle = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newTitle }) + .then(() => this.fetchPosts()); + this.newTitle = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} + <% } %> +<% } else { %> + <% if (addTailwind) { %> +import { Component } from '@angular/core'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + host: { + class: 'block h-full p-4', + }, + template: ` + + +

Vite + Angular

+ +
+ +
+ +

+ Check out + Analog, the fullstack meta-framework for Angular powered by Vite! +

+ +

+ Click on the Vite and Angular logos to learn more. +

+ ` +}) +export default class HomeComponent { + count = 0; + + increment() { + this.count++; + } +} + <% } else { %> import { Component } from '@angular/core'; @Component({ @@ -60,3 +307,5 @@ export default class HomeComponent { this.count++; } } + <% } %> +<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ index 0a459af40..83b68164b 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ @@ -1,10 +1,17 @@ import 'zone.js'; import { bootstrapApplication } from '@angular/platform-browser'; import { provideFileRouter } from '@analogjs/router'; - +<% if (addTRPC) { %> +import { provideTRPCClient } from './trpc-client'; +<% } %> import { AppComponent } from './app/app.component'; import { mainProviders } from './main.providers'; bootstrapApplication(AppComponent, { - providers: [provideFileRouter(), ...mainProviders], + providers: [ + provideFileRouter(), +<% if (addTRPC) { %> + provideTRPCClient(), +<% } %> + ...mainProviders], }); diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ index ca40eb47a..db8aff219 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ @@ -12,6 +12,11 @@ export default defineConfig(({ mode }) => { optimizeDeps: { include: ['@angular/common', '@angular/forms'], }, + <% if (addTRPC) { %> + ssr: { + noExternal: '@analogjs/trpc/**', + }, + <% } %> build: { target: ['es2020'], }, diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ new file mode 100644 index 000000000..9f31a6cee --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ @@ -0,0 +1,10 @@ +import { ApplicationConfig, mergeApplicationConfig } from '@angular/core'; +import { provideServerRendering } from '@angular/platform-server'; +import { provideClientHydration } from '@angular/platform-browser'; +import { appConfig } from './app.config'; + +const serverConfig: ApplicationConfig = { + providers: [provideServerRendering(), provideClientHydration()], +}; + +export const config = mergeApplicationConfig(appConfig, serverConfig); diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.ts__template__ new file mode 100644 index 000000000..2e8b3e004 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.ts__template__ @@ -0,0 +1,16 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideClientHydration } from '@angular/platform-browser'; +import { provideFileRouter } from '@analogjs/router'; +<% if (addTRPC) { %> +import { provideTRPCClient } from './trpc-client'; +<% } %> + +export const appConfig: ApplicationConfig = { + providers: [ + provideFileRouter(), + provideClientHydration(), +<% if (addTRPC) { %> + provideTRPCClient(), +<% } %> + ], +}; diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ index 5552a2c7b..23a5d9807 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ @@ -1,3 +1,250 @@ +<% if (addTRPC) { %> + <% if (addTailwind) { %> +import { Component } from '@angular/core'; +import { injectTRPCClient } from '../../trpc-client'; +import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '../../wait-for'; +import { Note } from '../../note'; + +const inputTw = + 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 focus:bg-white dark:focus:bg-dark placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; +const btnTw = + 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; + +@Component({ + selector: 'trpc-app-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + host: { + class: 'block h-full p-4', + }, + template: ` +
+

Analog + tRPC

+ Spartan Logo +
+
+ + +
+
+
+
+

{{ note.createdAt | date }}

+ +
+

{{ note.note }}

+
+ +
+

No notes yet!

+

Add a new one and see them appear here...

+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newTitle = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newTitle }) + .then(() => this.fetchPosts()); + this.newTitle = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} + <% } else { %> +import { Component } from '@angular/core'; +import { injectTRPCClient } from '../../trpc-client'; +import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '../../wait-for'; +import { Note } from '../../note'; + +@Component({ + selector: 'trpc-app-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + template: ` +
+

Analog + tRPC

+ Spartan Logo +
+
+ + +
+
+
+
+

{{ note.createdAt | date }}

+ +
+

{{ note.note }}

+
+ +
+

No notes yet!

+

Add a new one and see them appear here...

+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newTitle = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newTitle }) + .then(() => this.fetchPosts()); + this.newTitle = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} + <% } %> +<% } else { %> + <% if (addTailwind) { %> +import { Component } from '@angular/core'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + host: { + class: 'block h-full p-4', + }, + template: ` + + +

Vite + Angular

+ +
+ +
+ +

+ Check out + Analog, the fullstack meta-framework for Angular powered by Vite! +

+ +

+ Click on the Vite and Angular logos to learn more. +

+ ` +}) +export default class HomeComponent { + count = 0; + + increment() { + this.count++; + } +} + <% } else { %> import { Component } from '@angular/core'; @Component({ @@ -60,3 +307,5 @@ export default class HomeComponent { this.count++; } } + <% } %> +<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.providers.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.providers.ts__template__ deleted file mode 100644 index bce1d8737..000000000 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.providers.ts__template__ +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Common providers shared with client and server-side. - */ - -export const mainProviders = []; diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.server.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.server.ts__template__ index c6a59c92e..29ad24c06 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.server.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.server.ts__template__ @@ -1,32 +1,20 @@ import 'zone.js/node'; import { enableProdMode } from '@angular/core'; -import { bootstrapApplication } from '@angular/platform-browser'; -import { - provideServerRendering, - renderApplication, -} from '@angular/platform-server'; - +import { renderApplication } from '@angular/platform-server'; import { AppComponent } from './app/app.component'; -import { mainProviders } from './main.providers'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { config } from './app.config.server'; if (import.meta.env.PROD) { enableProdMode(); } -export function bootstrap() { - return bootstrapApplication(AppComponent, { - providers: [ - mainProviders, - provideServerRendering(), - ], - }); -} +const bootstrap = () => bootstrapApplication(AppComponent, config); export default async function render(url: string, document: string) { const html = await renderApplication(bootstrap, { document, url, }); - return html; } diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.ts__template__ index 0a459af40..6a31bd61f 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/main.ts__template__ @@ -1,10 +1,9 @@ import 'zone.js'; import { bootstrapApplication } from '@angular/platform-browser'; -import { provideFileRouter } from '@analogjs/router'; import { AppComponent } from './app/app.component'; -import { mainProviders } from './main.providers'; +import { appConfig } from './app.config'; -bootstrapApplication(AppComponent, { - providers: [provideFileRouter(), ...mainProviders], -}); +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err) +); diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ new file mode 100644 index 000000000..2821a2b39 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ @@ -0,0 +1,19 @@ +import { firstValueFrom, isObservable, Observable } from 'rxjs'; + +declare const Zone: any; + +export async function waitFor(prom: Promise | Observable): Promise { + if (isObservable(prom)) { + prom = firstValueFrom(prom); + } + const macroTask = Zone.current.scheduleMacroTask( + `AnalogContentResolve-${Math.random()}`, + () => {}, + {}, + () => {} + ); + return prom.then((p: T) => { + macroTask.invoke(); + return p; + }); +} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ index ca40eb47a..b3919b2b9 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ @@ -12,6 +12,11 @@ export default defineConfig(({ mode }) => { optimizeDeps: { include: ['@angular/common', '@angular/forms'], }, +<% if (addTRPC) { %> + ssr: { + noExternal: '@analogjs/trpc/**', + }, +<% } %> build: { target: ['es2020'], }, diff --git a/packages/nx-plugin/src/generators/app/generator.ts b/packages/nx-plugin/src/generators/app/generator.ts index b2c85aa47..004a821e9 100644 --- a/packages/nx-plugin/src/generators/app/generator.ts +++ b/packages/nx-plugin/src/generators/app/generator.ts @@ -15,6 +15,7 @@ import { addAnalogDependencies } from './lib/add-analog-dependencies'; import { initializeAngularWorkspace } from './lib/initialize-analog-workspace'; import { addFiles } from './lib/add-files'; import { addTailwindConfig } from './lib/add-tailwind-config'; +import { addTRPC } from './lib/add-trpc'; export interface NormalizedOptions extends AnalogNxApplicationGeneratorOptions, @@ -97,7 +98,7 @@ export async function appGenerator( addFiles(tree, normalizedOptions, majorAngularVersion); - if (!normalizedOptions.skipTailwind) { + if (normalizedOptions.addTailwind) { await addTailwindConfig( tree, normalizedOptions.projectRoot, @@ -106,6 +107,10 @@ export async function appGenerator( ); } + if (normalizedOptions.addTRPC) { + await addTRPC(tree, normalizedOptions.projectRoot, majorAngularVersion); + } + if (!normalizedOptions.skipFormat) { await formatFiles(tree); } diff --git a/packages/nx-plugin/src/generators/app/lib/add-trpc.ts b/packages/nx-plugin/src/generators/app/lib/add-trpc.ts new file mode 100644 index 000000000..fde7a129d --- /dev/null +++ b/packages/nx-plugin/src/generators/app/lib/add-trpc.ts @@ -0,0 +1,35 @@ +import { + addDependenciesToPackageJson, + generateFiles, + Tree, +} from '@nrwl/devkit'; +import * as path from 'path'; +import { + V15_ANALOG_TRPC, + V15_ZOD, + V16_ANALOG_JS_TRPC, + V16_ZOD, +} from '../versions'; + +export async function addTRPC( + tree: Tree, + projectRoot: string, + majorAngularVersion: number +) { + addDependenciesToPackageJson( + tree, + { + '@analogjs/trpc': + majorAngularVersion === 15 ? V15_ANALOG_TRPC : V16_ANALOG_JS_TRPC, + zod: majorAngularVersion === 15 ? V15_ZOD : V16_ZOD, + }, + {} + ); + + generateFiles( + tree, + path.join(__dirname, '..', 'files', 'trpc'), + projectRoot, + { template: '' } + ); +} diff --git a/packages/nx-plugin/src/generators/app/schema.d.ts b/packages/nx-plugin/src/generators/app/schema.d.ts index b4d68940b..c6010f7ea 100644 --- a/packages/nx-plugin/src/generators/app/schema.d.ts +++ b/packages/nx-plugin/src/generators/app/schema.d.ts @@ -1,6 +1,7 @@ export interface AnalogNxApplicationGeneratorOptions { name: string; tags?: string; - skipTailwind?: boolean; + addTailwind?: boolean; + addTRPC?: boolean; skipFormat?: boolean; } diff --git a/packages/nx-plugin/src/generators/app/schema.json b/packages/nx-plugin/src/generators/app/schema.json index 05da1044f..716804883 100644 --- a/packages/nx-plugin/src/generators/app/schema.json +++ b/packages/nx-plugin/src/generators/app/schema.json @@ -14,10 +14,16 @@ }, "x-prompt": "What name would you like to use for your AnalogJs app?" }, - "skipTailwind": { + "addTailwind": { "type": "boolean", - "description": "Skip adding tailwind if set to true.", - "x-prompt": "Skip adding TailwindCSS?", + "description": "Adds tailwind if set to true.", + "x-prompt": "Add TailwindCSS for styling?", + "default": true + }, + "addTRPC": { + "type": "boolean", + "description": "Adds tRPC if set to true.", + "x-prompt": "Add tRPC for typesafe client/server interaction?", "default": false }, "tags": { diff --git a/packages/nx-plugin/src/generators/app/versions.ts b/packages/nx-plugin/src/generators/app/versions.ts index 546b0cda5..fc61c4033 100644 --- a/packages/nx-plugin/src/generators/app/versions.ts +++ b/packages/nx-plugin/src/generators/app/versions.ts @@ -19,6 +19,7 @@ export const V16_TYPESCRIPT = '~5.0.2'; export const V16_VITE = '^4.0.3'; export const V16_VITE_TSCONFIG_PATHS = '^4.0.2'; export const V16_VITEST = '^0.31.0'; +export const V16_ZOD = '^3.21.4'; // V15 // dependencies @@ -27,6 +28,7 @@ export const V15_NRWL_DEVKIT = '15.9.2'; export const V15_NRWL_ANGULAR = '15.9.2'; export const V15_ANALOG_JS_CONTENT = '^0.2.0-beta.6'; export const V15_ANALOG_JS_ROUTER = '^0.2.0-beta.6'; +export const V15_ANALOG_TRPC = '^0.2.0-beta.6'; export const V15_ANGULAR_PLATFORM_SERVER = '^15.0.0'; export const V15_FRONT_MATTER = '^4.0.2'; export const V15_MARKED = '^4.2.12'; @@ -39,4 +41,5 @@ export const V15_JSDOM = '^20.0.0'; export const V15_TYPESCRIPT = '~4.8.4'; export const V15_VITE = '^4.0.3'; export const V15_VITE_TSCONFIG_PATHS = '^4.0.2'; -export const V15_VITEST = '^0.25.8'; +export const V15_VITEST = '^0.31.0'; +export const V15_ZOD = '^3.21.4'; From acc747fbe5a976c8721d9cf04b26860e5bef564b Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Wed, 10 May 2023 09:24:31 -0400 Subject: [PATCH 2/7] fix(trpc): add superjson needed for transfer-state & fix type issue making options optional --- packages/trpc/package.json | 3 ++- packages/trpc/src/lib/client/client.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/trpc/package.json b/packages/trpc/package.json index 54f7d6744..0f6f8a8cf 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -23,7 +23,8 @@ "@angular/core": "^16.0.0", "@trpc/client": "10.25.0", "@trpc/server": "10.25.0", - "isomorphic-fetch": "^3.0.0" + "isomorphic-fetch": "^3.0.0", + "superjson": "^1.12.3" }, "dependencies": { "tslib": "^2.3.0" diff --git a/packages/trpc/src/lib/client/client.ts b/packages/trpc/src/lib/client/client.ts index bc151f609..eee94d453 100644 --- a/packages/trpc/src/lib/client/client.ts +++ b/packages/trpc/src/lib/client/client.ts @@ -16,7 +16,7 @@ import { CreateTRPCClientOptions } from '@trpc/client/src/createTRPCUntypedClien export type TrpcOptions = { url: string; - options: Partial>; + options?: Partial>; }; export type TrpcClient = ReturnType< From 88d52ba822ca2f8de3fad6a812c77862731b41a7 Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Wed, 10 May 2023 09:29:19 -0400 Subject: [PATCH 3/7] feat(nx-plugin): add trpc dependencies to auto install, fix project config, improve templates peer dependencies for tRPC client are now auto installed if user opts to use trpc in their project. also made minor improvements to make vite.config and tRPC config match. continued to improve styling of template files, but this is still biggest work in progress. --- .../app/files/tRPC/src/note.ts__template__ | 2 +- .../server/trpc/routers/notes.ts__template__ | 2 +- .../files/tRPC/src/trpc-client.ts__template__ | 2 +- .../src/app/app.component.ts__template__ | 2 ++ .../src/app/pages/index.page.ts__template__ | 4 +-- .../src/styles.css__template__ | 7 +++++ .../vite.config.ts__template__ | 5 ++++ .../src/app/app.component.ts__template__ | 2 ++ .../src/app/pages/index.page.ts__template__ | 4 +-- .../src/styles.css__template__ | 7 +++++ .../vite.config.ts__template__ | 5 ++++ .../nx-plugin/src/generators/app/generator.ts | 7 ++++- .../app/lib/add-analog-project-config.ts | 2 +- .../src/generators/app/lib/add-trpc.ts | 30 ++++++++++++++++--- .../nx-plugin/src/generators/app/versions.ts | 12 +++++++- 15 files changed, 79 insertions(+), 14 deletions(-) diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ index 45cfbb172..f982d17fb 100644 --- a/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/note.ts__template__ @@ -1,5 +1,5 @@ export type Note = { id: number; note: string; - createdAt: Date; + createdAt: string; }; diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ index 1b890989c..be3d3481d 100644 --- a/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/server/trpc/routers/notes.ts__template__ @@ -15,7 +15,7 @@ export const noteRouter = router({ notes.push({ id: noteId++, note: input.title, - createdAt: new Date(), + createdAt: new Date().toISOString(), }) ), list: publicProcedure.query(() => notes), diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ index 20c63d431..4e9a2d42b 100644 --- a/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ @@ -3,7 +3,7 @@ import { createTrpcClient } from '@analogjs/trpc'; import { inject } from '@angular/core'; export const { provideTRPCClient, tRPCClient } = createTrpcClient({ - url: 'http://localhost:4205/api/trpc', + url: 'http://127.0.0.1:4205/api/trpc', }); export function injectTRPCClient() { diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ index de8a935a6..2d74a9fbd 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ @@ -6,6 +6,7 @@ import { RouterOutlet } from '@angular/router'; standalone: true, imports: [RouterOutlet], template: ` `, +<% if (!addTailwind) { %> styles: [ ` :host { @@ -16,5 +17,6 @@ import { RouterOutlet } from '@angular/router'; } `, ], +<% } %> }) export class AppComponent {} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ index 23a5d9807..8e957cc08 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ @@ -8,7 +8,7 @@ import { waitFor } from '../../wait-for'; import { Note } from '../../note'; const inputTw = - 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 focus:bg-white dark:focus:bg-dark placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; + 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; const btnTw = 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; @@ -17,7 +17,7 @@ const btnTw = standalone: true, imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], host: { - class: 'block h-full p-4', + class: 'block h-full bg-zinc-900 text-zinc-50 p-4', }, template: `
diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ index 8e92f8fcd..0d413b917 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ @@ -1,3 +1,9 @@ + <% if (addTailwind) { %> +html, body { + display: block; + height: 100%; +} + <% } else { %> /* You can add global styles to this file, and also import other style files */ :root { font-family: Inter, Avenir, Helvetica, Arial, sans-serif; @@ -73,3 +79,4 @@ button:focus-visible { background-color: #f9f9f9; } } + <% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ index db8aff219..336c11215 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ @@ -9,6 +9,11 @@ import tsConfigPaths from 'vite-tsconfig-paths'; export default defineConfig(({ mode }) => { return { publicDir: 'src/public', + <% if (addTRPC) { %> + server: { + host: '127.0.0.1' + }, + <% } %> optimizeDeps: { include: ['@angular/common', '@angular/forms'], }, diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ index de8a935a6..2d74a9fbd 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ @@ -6,6 +6,7 @@ import { RouterOutlet } from '@angular/router'; standalone: true, imports: [RouterOutlet], template: ` `, +<% if (!addTailwind) { %> styles: [ ` :host { @@ -16,5 +17,6 @@ import { RouterOutlet } from '@angular/router'; } `, ], +<% } %> }) export class AppComponent {} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ index 23a5d9807..8e957cc08 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ @@ -8,7 +8,7 @@ import { waitFor } from '../../wait-for'; import { Note } from '../../note'; const inputTw = - 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 focus:bg-white dark:focus:bg-dark placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; + 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; const btnTw = 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; @@ -17,7 +17,7 @@ const btnTw = standalone: true, imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], host: { - class: 'block h-full p-4', + class: 'block h-full bg-zinc-900 text-zinc-50 p-4', }, template: `
diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ index 8e92f8fcd..0d413b917 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ @@ -1,3 +1,9 @@ + <% if (addTailwind) { %> +html, body { + display: block; + height: 100%; +} + <% } else { %> /* You can add global styles to this file, and also import other style files */ :root { font-family: Inter, Avenir, Helvetica, Arial, sans-serif; @@ -73,3 +79,4 @@ button:focus-visible { background-color: #f9f9f9; } } + <% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ index b3919b2b9..9846a2a64 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ @@ -9,6 +9,11 @@ import tsConfigPaths from 'vite-tsconfig-paths'; export default defineConfig(({ mode }) => { return { publicDir: 'src/public', + <% if (addTRPC) { %> + server: { + host: '127.0.0.1' + }, + <% } %> optimizeDeps: { include: ['@angular/common', '@angular/forms'], }, diff --git a/packages/nx-plugin/src/generators/app/generator.ts b/packages/nx-plugin/src/generators/app/generator.ts index 004a821e9..b9bf35291 100644 --- a/packages/nx-plugin/src/generators/app/generator.ts +++ b/packages/nx-plugin/src/generators/app/generator.ts @@ -108,7 +108,12 @@ export async function appGenerator( } if (normalizedOptions.addTRPC) { - await addTRPC(tree, normalizedOptions.projectRoot, majorAngularVersion); + await addTRPC( + tree, + normalizedOptions.projectRoot, + majorAngularVersion, + normalizedOptions + ); } if (!normalizedOptions.skipFormat) { diff --git a/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts b/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts index 5d46030c8..07cbe9cc0 100644 --- a/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts +++ b/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts @@ -43,7 +43,7 @@ export function addAnalogProjectConfig( defaultConfiguration: 'development', options: { buildTarget: `${projectName}:build`, - port: 4200, + port: 4205, }, configurations: { development: { diff --git a/packages/nx-plugin/src/generators/app/lib/add-trpc.ts b/packages/nx-plugin/src/generators/app/lib/add-trpc.ts index fde7a129d..081f117dc 100644 --- a/packages/nx-plugin/src/generators/app/lib/add-trpc.ts +++ b/packages/nx-plugin/src/generators/app/lib/add-trpc.ts @@ -5,31 +5,53 @@ import { } from '@nrwl/devkit'; import * as path from 'path'; import { - V15_ANALOG_TRPC, + V15_ANALOG_JS_TRPC, + V15_ISOMORPHIC_FETCH, + V15_SUPERJSON, + V15_TRPC_CLIENT, + V15_TRPC_SERVER, V15_ZOD, V16_ANALOG_JS_TRPC, + V16_SUPERJSON, + V16_TRPC_CLIENT, + V16_TRPC_SERVER, V16_ZOD, } from '../versions'; +import { NormalizedOptions } from '../generator'; export async function addTRPC( tree: Tree, projectRoot: string, - majorAngularVersion: number + majorAngularVersion: number, + options: NormalizedOptions ) { addDependenciesToPackageJson( tree, { '@analogjs/trpc': - majorAngularVersion === 15 ? V15_ANALOG_TRPC : V16_ANALOG_JS_TRPC, + majorAngularVersion === 15 ? V15_ANALOG_JS_TRPC : V16_ANALOG_JS_TRPC, + '@trpc/client': + majorAngularVersion === 15 ? V15_TRPC_CLIENT : V16_TRPC_CLIENT, + '@trpc/server': + majorAngularVersion === 15 ? V15_TRPC_SERVER : V16_TRPC_SERVER, + superjson: majorAngularVersion === 15 ? V15_SUPERJSON : V16_SUPERJSON, + 'isomorphic-fetch': + majorAngularVersion === 15 + ? V15_ISOMORPHIC_FETCH + : V15_ISOMORPHIC_FETCH, zod: majorAngularVersion === 15 ? V15_ZOD : V16_ZOD, }, {} ); + const templateOptions = { + ...options, + template: '', + }; generateFiles( tree, path.join(__dirname, '..', 'files', 'trpc'), projectRoot, - { template: '' } + templateOptions ); } diff --git a/packages/nx-plugin/src/generators/app/versions.ts b/packages/nx-plugin/src/generators/app/versions.ts index fc61c4033..7e6478538 100644 --- a/packages/nx-plugin/src/generators/app/versions.ts +++ b/packages/nx-plugin/src/generators/app/versions.ts @@ -6,6 +6,12 @@ export const V16_NX_DEVKIT = '^16.0.0'; export const V16_NX_ANGULAR = '^16.0.0'; export const V16_ANALOG_JS_CONTENT = '^0.2.0-beta.6'; export const V16_ANALOG_JS_ROUTER = '^0.2.0-beta.6'; +export const V16_ANALOG_JS_TRPC = '^0.2.0-beta.6'; +export const V16_TRPC_CLIENT = '^10.25.0'; +export const V16_TRPC_SERVER = '^10.25.0'; +export const V16_ISOMORPHIC_FETCH = '^3.0.0'; +export const V16_SUPERJSON = '^1.12.3'; + export const V16_ANGULAR_PLATFORM_SERVER = '^16.0.0'; export const V16_FRONT_MATTER = '^4.0.2'; export const V16_MARKED = '^4.2.12'; @@ -28,7 +34,11 @@ export const V15_NRWL_DEVKIT = '15.9.2'; export const V15_NRWL_ANGULAR = '15.9.2'; export const V15_ANALOG_JS_CONTENT = '^0.2.0-beta.6'; export const V15_ANALOG_JS_ROUTER = '^0.2.0-beta.6'; -export const V15_ANALOG_TRPC = '^0.2.0-beta.6'; +export const V15_ANALOG_JS_TRPC = '^0.2.0-beta.6'; +export const V15_TRPC_CLIENT = '^10.25.0'; +export const V15_TRPC_SERVER = '^10.25.0'; +export const V15_ISOMORPHIC_FETCH = '^3.0.0'; +export const V15_SUPERJSON = '^1.12.3'; export const V15_ANGULAR_PLATFORM_SERVER = '^15.0.0'; export const V15_FRONT_MATTER = '^4.0.2'; export const V15_MARKED = '^4.2.12'; From 082d04387c9ec77f9a2f3b8b54e7ee42337e3fc6 Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Wed, 10 May 2023 12:40:14 -0400 Subject: [PATCH 4/7] fix(nx-plugin): set defaults for tailwind & trpc options --- packages/nx-plugin/src/generators/app/generator.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/nx-plugin/src/generators/app/generator.ts b/packages/nx-plugin/src/generators/app/generator.ts index b9bf35291..d8e670d49 100644 --- a/packages/nx-plugin/src/generators/app/generator.ts +++ b/packages/nx-plugin/src/generators/app/generator.ts @@ -44,6 +44,9 @@ function normalizeOptions( : []; const offsetFromRoot = determineOffsetFromRoot(projectRoot); const nxPackageNamespace = major(nxVersion) >= 16 ? '@nx' : '@nrwl'; + const addTailwind = options.addTailwind ?? true; + const addTRPC = options.addTRPC ?? false; + return { ...options, ...allNames, @@ -54,6 +57,8 @@ function normalizeOptions( offsetFromRoot, appsDir, nxPackageNamespace, + addTailwind, + addTRPC, }; } From a593d73f3f062c2a15fcb58d869da5fd69066bf5 Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Wed, 10 May 2023 18:51:35 -0400 Subject: [PATCH 5/7] fix(nx-plugin): add much nicer template index pages this commit adds template pages that can be used in the nx plugin and display the features of analog and some general information. if we like these templates we can also adapt them for create-analog. an example of what the template looks like is also added to the trpc-app. --- apps/trpc-app/index.html | 4 +- apps/trpc-app/src/app/app.component.ts | 3 - apps/trpc-app/src/app/pages/index.page.ts | 414 +++++- .../src/app/app.component.ts__template__ | 12 - .../src/app/pages/index.page.ts__template__ | 1291 ++++++++++++++--- .../src/styles.css__template__ | 79 +- .../src/app/app.component.ts__template__ | 12 - .../src/app/pages/index.page.ts__template__ | 1291 ++++++++++++++--- .../src/styles.css__template__ | 79 +- 9 files changed, 2556 insertions(+), 629 deletions(-) diff --git a/apps/trpc-app/index.html b/apps/trpc-app/index.html index 14d7cfcd4..86e7a0476 100644 --- a/apps/trpc-app/index.html +++ b/apps/trpc-app/index.html @@ -1,5 +1,5 @@ - + SPARTAN - Notes App @@ -8,7 +8,7 @@ - + diff --git a/apps/trpc-app/src/app/app.component.ts b/apps/trpc-app/src/app/app.component.ts index 0781b1e94..9dd3769eb 100644 --- a/apps/trpc-app/src/app/app.component.ts +++ b/apps/trpc-app/src/app/app.component.ts @@ -5,9 +5,6 @@ import { RouterOutlet } from '@angular/router'; selector: 'trpc-app-root', standalone: true, imports: [RouterOutlet], - host: { - class: 'max-w-screen-md mx-auto block h-full bg-zinc-900 text-zinc-50', - }, changeDetection: ChangeDetectionStrategy.Default, template: ` `, }) diff --git a/apps/trpc-app/src/app/pages/index.page.ts b/apps/trpc-app/src/app/pages/index.page.ts index c271146d5..4e9d6a536 100644 --- a/apps/trpc-app/src/app/pages/index.page.ts +++ b/apps/trpc-app/src/app/pages/index.page.ts @@ -5,65 +5,387 @@ import { FormsModule, NgForm } from '@angular/forms'; import { waitFor } from '../../wait-for'; import { Note } from '../../note'; -const inputTw = - 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 focus:bg-white dark:focus:bg-dark placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; -const btnTw = - 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; - @Component({ selector: 'trpc-app-home', standalone: true, imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], host: { - class: 'block h-full p-4', + class: + 'flex min-h-screen flex-col h-full text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', }, template: ` -
-

Analog + tRPC

- Spartan Logo -
-
- - - -
-
-
+
+
+ Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
-
-

{{ note.createdAt | date }}

+
+

+ Features +

+

+ Analog comes with a set of tools that aim to let you build powerful + full stack applications while providing the best possible developer + experience. +

+
+
+
+
+ Installed +
+
+ + + +
+

Angular

+

+ Ready to built enterprise grade applications with Angular. +

+
+
+
+
+
+ Installed +
+
+ + + + + +
+

Vite

+

+ Based on Vite. Super fast. Super ecosystem. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nitro

+

+ Backend server that runs everywhere +

+
+
+
+
+
+ Installed +
+
+ + + +
+

TailwindCSS

+

+ The utility first CSS framework. +

+
+
+
+
+
+ Installed +
+
+ + + + + + + + + + +
+

tRPC

+

+ End-to-end typesafe APIs made easy. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nx

+

+ Next generation build system with first class monorepo + support. +

+
+
+
+
+
+

+ To see all available features and learn how to use them check out + the official + documentation. +

+
+
+
+
+

+ Proudly Open Source +

+

+ Analog is open source and powered by open source software. +
+ The code is available on + GitHub. +

+
+
+ +
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
-

{{ note.note }}

-
-
-

No notes yet!

-

Add a new one and see them appear here...

-
-
+
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+ + `, }) export default class HomeComponent { diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ index 2d74a9fbd..086a368dc 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/app.component.ts__template__ @@ -6,17 +6,5 @@ import { RouterOutlet } from '@angular/router'; standalone: true, imports: [RouterOutlet], template: ` `, -<% if (!addTailwind) { %> - styles: [ - ` - :host { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; - } - `, - ], -<% } %> }) export class AppComponent {} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ index 8e957cc08..043b7ad01 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ @@ -1,75 +1,428 @@ -<% if (addTRPC) { %> - <% if (addTailwind) { %> +<% if (addTailwind) { %> import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +<% if (addTRPC) { %> import { injectTRPCClient } from '../../trpc-client'; -import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; import { FormsModule, NgForm } from '@angular/forms'; import { waitFor } from '../../wait-for'; import { Note } from '../../note'; - -const inputTw = - 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; -const btnTw = - 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; +<% } %> @Component({ - selector: 'trpc-app-home', + selector: '<%= fileName %>-home', standalone: true, - imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], host: { - class: 'block h-full bg-zinc-900 text-zinc-50 p-4', + class: + 'flex min-h-screen flex-col h-full text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', }, template: ` -
-

Analog + tRPC

- Spartan Logo -
-
- - -
-
-
+
+
+ Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
-
-

{{ note.createdAt | date }}

+
+

+ Features +

+

+ Analog comes with a set of tools that aim to let you build powerful + full stack applications while providing the best possible developer + experience. +

+
+
+
+
+ Installed +
+
+ + + +
+

Angular

+

+ Ready to built enterprise grade applications with Angular. +

+
+
+
+
+
+ Installed +
+
+ + + + + +
+

Vite

+

+ Based on Vite. Super fast. Super ecosystem. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nitro

+

+ Backend server that runs everywhere +

+
+
+
+
+<% if (addTailwind) { %> +
+ Installed +
+<% } %> +
+ + + +
+

TailwindCSS

+

+ The utility first CSS framework. +

+
+
+
+
+<% if (addTRPC) { %> +
+ Installed +
+<% } %> +
+ + + + + + + + + + +
+

tRPC

+

+ End-to-end typesafe APIs made easy. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nx

+

+ Next generation build system with first class monorepo + support. +

+
+
+
+
+
+

+ To see all available features and learn how to use them check out + the official + documentation. +

+
+
+ +
+
+

+ Proudly Open Source +

+

+ Analog is open source and powered by open source software. +
+ The code is available on + GitHub. +

+
+
+ +<% if (addTRPC) { %> +
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
-

{{ note.note }}

-
-
-

No notes yet!

-

Add a new one and see them appear here...

-
-
+
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+ +<% } %> +<% if (!addTRPC) { %> +
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+<% } %> + `, }) export default class HomeComponent { private _trpc = injectTRPCClient(); public loadingPosts = false; public notes: Note[] = []; - public newTitle = ''; + public newNote = ''; constructor() { waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); @@ -85,9 +438,9 @@ export default class HomeComponent { return; } this._trpc.note.create - .mutate({ title: this.newTitle }) + .mutate({ title: this.newNote }) .then(() => this.fetchPosts()); - this.newTitle = ''; + this.newNote = ''; form.form.reset(); } @@ -102,65 +455,704 @@ export default class HomeComponent { this.notes = notes; }); } + +<% if (!addTRPC) { %> + public count = 0; + public increment() { + this.count++; + } +<% } %> } - <% } else { %> + +<% } else { %> import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +<% if (addTRPC) { %> import { injectTRPCClient } from '../../trpc-client'; -import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; import { FormsModule, NgForm } from '@angular/forms'; import { waitFor } from '../../wait-for'; import { Note } from '../../note'; +<% } %> @Component({ - selector: 'trpc-app-home', + selector: '<%= fileName %>-home', standalone: true, - imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], + styles: [ + ` + :host { + display: flex; + padding: 2rem; + flex-direction: column; + height: 100%; + min-height: 100vh; + } + + .main { + margin-left: auto; + margin-right: auto; + flex: 1 1 0; + } + + .section-main { + padding-top: 1.5rem; + padding-bottom: 2rem; + margin-top: 1.5rem; + } + + @media (min-width: 768px) { + .section-main { + padding-top: 2.5rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section-main { + padding-top: 8rem; + padding-bottom: 8rem; + } + } + + .button-container { + display: flex; + text-align: center; + flex-direction: column; + align-items: center; + gap: 1rem; + } + + .button-badge { + padding-top: 0.375rem; + padding-bottom: 0.375rem; + padding-left: 1rem; + padding-right: 1rem; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + border-radius: 1rem; + background-color: rgb(228 228 231); + } + + .heading-1 { + font-size: 1.875rem; + line-height: 2.25rem; + font-weight: 500; + } + + @media (min-width: 640px) { + .heading-1 { + font-size: 2.25rem; /* 36px */ + line-height: 2.5rem; /* 40px */ + } + } + + @media (min-width: 768px) { + .heading-1 { + font-size: 3rem; /* 48px */ + line-height: 1; + } + } + + @media (min-width: 1024px) { + .heading-1 { + font-size: 3.75rem; /* 60px */ + line-height: 1; + } + } + + .paragraph-intro { + line-height: 1.5; + } + + @media (min-width: 640px) { + .paragraph-intro { + font-size: 1.25rem; + line-height: 2rem; + } + } + + .button-group { + display: flex; + gap: 1rem; + } + + .primary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(9, 9, 11); + color: rgb(250, 250, 250); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border-radius: 0.375rem; + } + + .secondary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color, border-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(250, 250, 250); + color: rgb(9, 9, 11); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border: 1px solid rgb(161, 161, 170, 0.25); + border-radius: 0.375rem; + } + + .secondary-button:hover { + background-color: rgb(244 244 245); + color: rgb(9, 9, 11); + } + + .section { + margin-top: 8rem; + margin-bottom: 8rem; + padding-top: 2rem; + padding-bottom: 2rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + .dark .section { + background-color: transparent; + } + + @media (min-width: 768px) { + .section { + padding-top: 3rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section { + padding-top: 6rem; + } + } + + .intro-container { + margin-left: auto; + margin-right: auto; + max-width: 58rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + text-align: center; + } + + .title { + font-weight: 500; + font-size: 3rem; + line-height: 1.1; + text-align: center; + } + + .description { + max-width: 85%; + font-size: 1.125rem; + line-height: 1.75rem; + } + + .feature-grid { + padding: 0.5rem; + margin-left: auto; + margin-right: auto; + display: grid; + justify-content: center; + gap: 1rem; + } + + @media (min-width: 640px) { + .feature-grid { + max-width: 64rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + + @media (min-width: 768px) { + .feature-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + + .feature-card { + position: relative; + overflow: hidden; + border: 1px solid rgb(228 228 231); + border-radius: 0.375rem; + padding: 0.5rem; + } + + .status-badge { + position: absolute; + top: 0.5rem; + right: 0.5rem; + border-radius: 0.5rem; + background-color: rgb(228, 228, 231); + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + } + + .card-content { + display: flex; + height: 180px; + flex-direction: column; + justify-content: space-between; + border-radius: 0.375rem; + padding: 1.5rem; + } + + .icon { + height: 3rem; + width: 3rem; + fill: currentColor; + } + + .card-details { + margin-top: 0.5rem; + } + + .card-title { + font-weight: bold; + } + + .card-description { + font-size: 0.875rem; + color: rgb(39, 39, 42); + } + + .further-info-container { + margin-left: auto; + margin-right: auto; + text-align: center; + max-width: 58rem; + } + + .description { + font-size: 1.125rem; + line-height: 1.75rem; + } + + .link { + text-decoration: underline; + text-underline-offset: 0.25rem; + } +<% if (addTRPC) { %> + .note-form { + display: flex; + padding-bottom: 0.5rem; + margin-top: 2rem; + align-items: center; + } + .note-input { + display: flex; + height: 2.5rem; + width: 100%; + border-radius: 0.375rem; + border: 1px solid rgb(161, 161, 170, 0.25); + background-color: transparent; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + outline: none; + font-family: inherit; + color: inherit; + } + + .note-input::placeholder { + color: rgb(161, 161, 170, 0.8); + } + + .note-input:focus-visible { + outline-width: 2px; + outline-style: solid; + outline-color: rgb(39, 39, 42); + outline-offset: 2px; + } + .note-input:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + .add-note-button { + margin-left: 0.5rem; + height: 2.5rem !important; + } + .hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + .note { + position: relative; + } + .note-grid { + display: flex; + margin-top: 1rem; + flex-direction: column; + gap: 1rem; + } + .delete-note-icon { + width: 1rem; + height: 1rem; + } + .delete-note-button { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0.5rem !important; + height: 2rem !important; + } +<% } %> +<% if (!addTRPC) { %> + .count { + margin-left: 0.25rem; + font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + } +<% } %> + `, + ], template: ` -
-

Analog + tRPC

- Spartan Logo -
-
- - -
-
-
-
-

{{ note.createdAt | date }}

+
+
+
+ Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Features

+

+ Analog comes with a set of tools that aim to let you build powerful + full stack applications while providing the best possible developer + experience. +

+
+
+
+
Installed
+
+ + + +
+

Angular

+

+ Ready to built enterprise grade applications with Angular. +

+
+
+
+
+
Installed
+
+ + + + + +
+

Vite

+

+ Based on Vite. Super fast. Super ecosystem. +

+
+
+
+
+
Installed
+
+ + + +
+

Nitro

+

+ Backend server that runs everywhere +

+
+
+
+
+
+ + + +
+

TailwindCSS

+

The utility first CSS framework.

+
+
+
+
+<% if (addTRPC) { %> +
Installed
+<% } %> +
+ + + + + + + + + + +
+

tRPC

+

+ End-to-end typesafe APIs made easy. +

+
+
+
+
+
Installed
+
+ + + +
+

Nx

+

+ Next generation build system with first class monorepo + support. +

+
+
+
+
+
+

+ To see all available features and learn how to use them, check out + the official + documentation. +

+
+
+
+
+

Proudly Open Source

+

+ Analog is open source and powered by open source software. +
+ The code is available on + GitHub. +

+
+
+<% if (addTRPC) { %> +
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
-

{{ note.note }}

-
-
-

No notes yet!

-

Add a new one and see them appear here...

-
-
+
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+ +<% } %> +<% if (!addTRPC) { %> +
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+<% } %> + `, }) export default class HomeComponent { +<% if (addTRPC) { %> private _trpc = injectTRPCClient(); public loadingPosts = false; public notes: Note[] = []; - public newTitle = ''; + public newNote = ''; constructor() { waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); @@ -176,9 +1168,9 @@ export default class HomeComponent { return; } this._trpc.note.create - .mutate({ title: this.newTitle }) + .mutate({ title: this.newNote }) .then(() => this.fetchPosts()); - this.newTitle = ''; + this.newNote = ''; form.form.reset(); } @@ -193,119 +1185,12 @@ export default class HomeComponent { this.notes = notes; }); } -} - <% } %> -<% } else { %> - <% if (addTailwind) { %> -import { Component } from '@angular/core'; - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - host: { - class: 'block h-full p-4', - }, - template: ` - - -

Vite + Angular

- -
- -
- -

- Check out - Analog, the fullstack meta-framework for Angular powered by Vite! -

- -

- Click on the Vite and Angular logos to learn more. -

- ` -}) -export default class HomeComponent { - count = 0; - - increment() { - this.count++; - } -} - <% } else { %> -import { Component } from '@angular/core'; - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - template: ` - - -

Vite + Angular

- -
- -
- -

- Check out - Analog, the fullstack meta-framework for Angular powered by Vite! -

- -

- Click on the Vite and Angular logos to learn more. -

- `, - styles: [ - ` - .logo { - height: 6em; - padding: 1.5em; - will-change: filter; - } - .logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); - } - .logo.angular:hover { - filter: drop-shadow(0 0 2em #42b883aa); - } - .read-the-docs { - color: #888; - } - `, - ], -}) -export default class HomeComponent { - count = 0; - - increment() { +<% } %> +<% if (!addTRPC) { %> + public count = 0; + public increment() { this.count++; } } - <% } %> +<% } %> <% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ index 0d413b917..14260d4cc 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ @@ -1,82 +1,13 @@ - <% if (addTailwind) { %> html, body { display: block; height: 100%; } - <% } else { %> -/* You can add global styles to this file, and also import other style files */ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; +<% if (!addTailwind) { %> +html { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } - a { - font-weight: 500; - color: #646cff; + color: inherit; text-decoration: inherit; } -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -.card { - padding: 2em; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} - <% } %> +<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ index 2d74a9fbd..086a368dc 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/app.component.ts__template__ @@ -6,17 +6,5 @@ import { RouterOutlet } from '@angular/router'; standalone: true, imports: [RouterOutlet], template: ` `, -<% if (!addTailwind) { %> - styles: [ - ` - :host { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; - } - `, - ], -<% } %> }) export class AppComponent {} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ index 8e957cc08..043b7ad01 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ @@ -1,75 +1,428 @@ -<% if (addTRPC) { %> - <% if (addTailwind) { %> +<% if (addTailwind) { %> import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +<% if (addTRPC) { %> import { injectTRPCClient } from '../../trpc-client'; -import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; import { FormsModule, NgForm } from '@angular/forms'; import { waitFor } from '../../wait-for'; import { Note } from '../../note'; - -const inputTw = - 'focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:outline-0 block w-full appearance-none rounded-lg px-3 py-2 transition-colors text-base leading-tight md:text-sm bg-black/[.05] dark:bg-zinc-50/10 placeholder:text-zinc-500 dark:placeholder:text-zinc-400 contrast-more:border contrast-more:border-current'; -const btnTw = - 'focus-visible:ring-2 focus-visible:ring-zinc-50 focus-visible:outline-0 flex items-center justify-center rounded-lg px-2 py-1.5 text-sm font-bold tracking-tight shadow-xl shadow-red-500/20 bg-[#DD0031] hover:bg-opacity-70 text-zinc-800 hover:text-primary-darker'; +<% } %> @Component({ - selector: 'trpc-app-home', + selector: '<%= fileName %>-home', standalone: true, - imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], host: { - class: 'block h-full bg-zinc-900 text-zinc-50 p-4', + class: + 'flex min-h-screen flex-col h-full text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', }, template: ` -
-

Analog + tRPC

- Spartan Logo -
-
- - -
-
-
+
+
+ Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
-
-

{{ note.createdAt | date }}

+
+

+ Features +

+

+ Analog comes with a set of tools that aim to let you build powerful + full stack applications while providing the best possible developer + experience. +

+
+
+
+
+ Installed +
+
+ + + +
+

Angular

+

+ Ready to built enterprise grade applications with Angular. +

+
+
+
+
+
+ Installed +
+
+ + + + + +
+

Vite

+

+ Based on Vite. Super fast. Super ecosystem. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nitro

+

+ Backend server that runs everywhere +

+
+
+
+
+<% if (addTailwind) { %> +
+ Installed +
+<% } %> +
+ + + +
+

TailwindCSS

+

+ The utility first CSS framework. +

+
+
+
+
+<% if (addTRPC) { %> +
+ Installed +
+<% } %> +
+ + + + + + + + + + +
+

tRPC

+

+ End-to-end typesafe APIs made easy. +

+
+
+
+
+
+ Installed +
+
+ + + +
+

Nx

+

+ Next generation build system with first class monorepo + support. +

+
+
+
+
+
+

+ To see all available features and learn how to use them check out + the official + documentation. +

+
+
+ +
+
+

+ Proudly Open Source +

+

+ Analog is open source and powered by open source software. +
+ The code is available on + GitHub. +

+
+
+ +<% if (addTRPC) { %> +
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
-

{{ note.note }}

-
-
-

No notes yet!

-

Add a new one and see them appear here...

-
-
+
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+ +<% } %> +<% if (!addTRPC) { %> +
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+<% } %> + `, }) export default class HomeComponent { private _trpc = injectTRPCClient(); public loadingPosts = false; public notes: Note[] = []; - public newTitle = ''; + public newNote = ''; constructor() { waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); @@ -85,9 +438,9 @@ export default class HomeComponent { return; } this._trpc.note.create - .mutate({ title: this.newTitle }) + .mutate({ title: this.newNote }) .then(() => this.fetchPosts()); - this.newTitle = ''; + this.newNote = ''; form.form.reset(); } @@ -102,65 +455,704 @@ export default class HomeComponent { this.notes = notes; }); } + +<% if (!addTRPC) { %> + public count = 0; + public increment() { + this.count++; + } +<% } %> } - <% } else { %> + +<% } else { %> import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +<% if (addTRPC) { %> import { injectTRPCClient } from '../../trpc-client'; -import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; import { FormsModule, NgForm } from '@angular/forms'; import { waitFor } from '../../wait-for'; import { Note } from '../../note'; +<% } %> @Component({ - selector: 'trpc-app-home', + selector: '<%= fileName %>-home', standalone: true, - imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf, JsonPipe], + imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], + styles: [ + ` + :host { + display: flex; + padding: 2rem; + flex-direction: column; + height: 100%; + min-height: 100vh; + } + + .main { + margin-left: auto; + margin-right: auto; + flex: 1 1 0; + } + + .section-main { + padding-top: 1.5rem; + padding-bottom: 2rem; + margin-top: 1.5rem; + } + + @media (min-width: 768px) { + .section-main { + padding-top: 2.5rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section-main { + padding-top: 8rem; + padding-bottom: 8rem; + } + } + + .button-container { + display: flex; + text-align: center; + flex-direction: column; + align-items: center; + gap: 1rem; + } + + .button-badge { + padding-top: 0.375rem; + padding-bottom: 0.375rem; + padding-left: 1rem; + padding-right: 1rem; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + border-radius: 1rem; + background-color: rgb(228 228 231); + } + + .heading-1 { + font-size: 1.875rem; + line-height: 2.25rem; + font-weight: 500; + } + + @media (min-width: 640px) { + .heading-1 { + font-size: 2.25rem; /* 36px */ + line-height: 2.5rem; /* 40px */ + } + } + + @media (min-width: 768px) { + .heading-1 { + font-size: 3rem; /* 48px */ + line-height: 1; + } + } + + @media (min-width: 1024px) { + .heading-1 { + font-size: 3.75rem; /* 60px */ + line-height: 1; + } + } + + .paragraph-intro { + line-height: 1.5; + } + + @media (min-width: 640px) { + .paragraph-intro { + font-size: 1.25rem; + line-height: 2rem; + } + } + + .button-group { + display: flex; + gap: 1rem; + } + + .primary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(9, 9, 11); + color: rgb(250, 250, 250); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border-radius: 0.375rem; + } + + .secondary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color, border-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(250, 250, 250); + color: rgb(9, 9, 11); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border: 1px solid rgb(161, 161, 170, 0.25); + border-radius: 0.375rem; + } + + .secondary-button:hover { + background-color: rgb(244 244 245); + color: rgb(9, 9, 11); + } + + .section { + margin-top: 8rem; + margin-bottom: 8rem; + padding-top: 2rem; + padding-bottom: 2rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + .dark .section { + background-color: transparent; + } + + @media (min-width: 768px) { + .section { + padding-top: 3rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section { + padding-top: 6rem; + } + } + + .intro-container { + margin-left: auto; + margin-right: auto; + max-width: 58rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + text-align: center; + } + + .title { + font-weight: 500; + font-size: 3rem; + line-height: 1.1; + text-align: center; + } + + .description { + max-width: 85%; + font-size: 1.125rem; + line-height: 1.75rem; + } + + .feature-grid { + padding: 0.5rem; + margin-left: auto; + margin-right: auto; + display: grid; + justify-content: center; + gap: 1rem; + } + + @media (min-width: 640px) { + .feature-grid { + max-width: 64rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + + @media (min-width: 768px) { + .feature-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + + .feature-card { + position: relative; + overflow: hidden; + border: 1px solid rgb(228 228 231); + border-radius: 0.375rem; + padding: 0.5rem; + } + + .status-badge { + position: absolute; + top: 0.5rem; + right: 0.5rem; + border-radius: 0.5rem; + background-color: rgb(228, 228, 231); + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + } + + .card-content { + display: flex; + height: 180px; + flex-direction: column; + justify-content: space-between; + border-radius: 0.375rem; + padding: 1.5rem; + } + + .icon { + height: 3rem; + width: 3rem; + fill: currentColor; + } + + .card-details { + margin-top: 0.5rem; + } + + .card-title { + font-weight: bold; + } + + .card-description { + font-size: 0.875rem; + color: rgb(39, 39, 42); + } + + .further-info-container { + margin-left: auto; + margin-right: auto; + text-align: center; + max-width: 58rem; + } + + .description { + font-size: 1.125rem; + line-height: 1.75rem; + } + + .link { + text-decoration: underline; + text-underline-offset: 0.25rem; + } +<% if (addTRPC) { %> + .note-form { + display: flex; + padding-bottom: 0.5rem; + margin-top: 2rem; + align-items: center; + } + .note-input { + display: flex; + height: 2.5rem; + width: 100%; + border-radius: 0.375rem; + border: 1px solid rgb(161, 161, 170, 0.25); + background-color: transparent; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + outline: none; + font-family: inherit; + color: inherit; + } + + .note-input::placeholder { + color: rgb(161, 161, 170, 0.8); + } + + .note-input:focus-visible { + outline-width: 2px; + outline-style: solid; + outline-color: rgb(39, 39, 42); + outline-offset: 2px; + } + .note-input:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + .add-note-button { + margin-left: 0.5rem; + height: 2.5rem !important; + } + .hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + .note { + position: relative; + } + .note-grid { + display: flex; + margin-top: 1rem; + flex-direction: column; + gap: 1rem; + } + .delete-note-icon { + width: 1rem; + height: 1rem; + } + .delete-note-button { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0.5rem !important; + height: 2rem !important; + } +<% } %> +<% if (!addTRPC) { %> + .count { + margin-left: 0.25rem; + font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + } +<% } %> + `, + ], template: ` -
-

Analog + tRPC

- Spartan Logo -
-
- - -
-
-
-
-

{{ note.createdAt | date }}

+
+
+
+ Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Features

+

+ Analog comes with a set of tools that aim to let you build powerful + full stack applications while providing the best possible developer + experience. +

+
+
+
+
Installed
+
+ + + +
+

Angular

+

+ Ready to built enterprise grade applications with Angular. +

+
+
+
+
+
Installed
+
+ + + + + +
+

Vite

+

+ Based on Vite. Super fast. Super ecosystem. +

+
+
+
+
+
Installed
+
+ + + +
+

Nitro

+

+ Backend server that runs everywhere +

+
+
+
+
+
+ + + +
+

TailwindCSS

+

The utility first CSS framework.

+
+
+
+
+<% if (addTRPC) { %> +
Installed
+<% } %> +
+ + + + + + + + + + +
+

tRPC

+

+ End-to-end typesafe APIs made easy. +

+
+
+
+
+
Installed
+
+ + + +
+

Nx

+

+ Next generation build system with first class monorepo + support. +

+
+
+
+
+
+

+ To see all available features and learn how to use them, check out + the official + documentation. +

+
+
+
+
+

Proudly Open Source

+

+ Analog is open source and powered by open source software. +
+ The code is available on + GitHub. +

+
+
+<% if (addTRPC) { %> +
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
-

{{ note.note }}

-
-
-

No notes yet!

-

Add a new one and see them appear here...

-
-
+
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+ +<% } %> +<% if (!addTRPC) { %> +
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+<% } %> + `, }) export default class HomeComponent { +<% if (addTRPC) { %> private _trpc = injectTRPCClient(); public loadingPosts = false; public notes: Note[] = []; - public newTitle = ''; + public newNote = ''; constructor() { waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); @@ -176,9 +1168,9 @@ export default class HomeComponent { return; } this._trpc.note.create - .mutate({ title: this.newTitle }) + .mutate({ title: this.newNote }) .then(() => this.fetchPosts()); - this.newTitle = ''; + this.newNote = ''; form.form.reset(); } @@ -193,119 +1185,12 @@ export default class HomeComponent { this.notes = notes; }); } -} - <% } %> -<% } else { %> - <% if (addTailwind) { %> -import { Component } from '@angular/core'; - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - host: { - class: 'block h-full p-4', - }, - template: ` - - -

Vite + Angular

- -
- -
- -

- Check out - Analog, the fullstack meta-framework for Angular powered by Vite! -

- -

- Click on the Vite and Angular logos to learn more. -

- ` -}) -export default class HomeComponent { - count = 0; - - increment() { - this.count++; - } -} - <% } else { %> -import { Component } from '@angular/core'; - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - template: ` - - -

Vite + Angular

- -
- -
- -

- Check out - Analog, the fullstack meta-framework for Angular powered by Vite! -

- -

- Click on the Vite and Angular logos to learn more. -

- `, - styles: [ - ` - .logo { - height: 6em; - padding: 1.5em; - will-change: filter; - } - .logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); - } - .logo.angular:hover { - filter: drop-shadow(0 0 2em #42b883aa); - } - .read-the-docs { - color: #888; - } - `, - ], -}) -export default class HomeComponent { - count = 0; - - increment() { +<% } %> +<% if (!addTRPC) { %> + public count = 0; + public increment() { this.count++; } } - <% } %> +<% } %> <% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ index 0d413b917..14260d4cc 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ @@ -1,82 +1,13 @@ - <% if (addTailwind) { %> html, body { display: block; height: 100%; } - <% } else { %> -/* You can add global styles to this file, and also import other style files */ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; +<% if (!addTailwind) { %> +html { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } - a { - font-weight: 500; - color: #646cff; + color: inherit; text-decoration: inherit; } -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -.card { - padding: 2em; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} - <% } %> +<% } %> From 8a1e4050c8fcbe1ac32ee2f3e670ed169f07f369 Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Thu, 11 May 2023 11:04:26 -0400 Subject: [PATCH 6/7] feat(trpc): export wait-for utility as part of trpc package --- apps/trpc-app/src/app/pages/index.page.ts | 2 +- .../src/generators/app/files/tRPC/src/public/assets/.gitkeep | 0 packages/trpc/src/index.ts | 1 + {apps/trpc-app/src => packages/trpc/src/lib/utils}/wait-for.ts | 0 4 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep rename {apps/trpc-app/src => packages/trpc/src/lib/utils}/wait-for.ts (100%) diff --git a/apps/trpc-app/src/app/pages/index.page.ts b/apps/trpc-app/src/app/pages/index.page.ts index 4e9d6a536..38791085c 100644 --- a/apps/trpc-app/src/app/pages/index.page.ts +++ b/apps/trpc-app/src/app/pages/index.page.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { injectTRPCClient } from '../../trpc-client'; import { AsyncPipe, DatePipe, JsonPipe, NgFor, NgIf } from '@angular/common'; import { FormsModule, NgForm } from '@angular/forms'; -import { waitFor } from '../../wait-for'; +import { waitFor } from '@analogjs/trpc'; import { Note } from '../../note'; @Component({ diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep b/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/trpc/src/index.ts b/packages/trpc/src/index.ts index 45ff545b1..f42f4337c 100644 --- a/packages/trpc/src/index.ts +++ b/packages/trpc/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/client/client'; export * from './lib/server/server'; +export * from './lib/utils/wait-for'; diff --git a/apps/trpc-app/src/wait-for.ts b/packages/trpc/src/lib/utils/wait-for.ts similarity index 100% rename from apps/trpc-app/src/wait-for.ts rename to packages/trpc/src/lib/utils/wait-for.ts From 17329ef64ddc8dae2cef96febbf833f9307cba28 Mon Sep 17 00:00:00 2001 From: Robin Goetz Date: Thu, 11 May 2023 11:08:46 -0400 Subject: [PATCH 7/7] refactor(nx-plugin): move to separate templates instead of using if/else logic in single file --- .../src/app/pages/index.page.ts__template__ | 585 ++++++++ .../src/app/pages/index.page.ts__template__ | 355 +++++ .../src/app/pages/index.page.ts__template__ | 269 ++++ .../src/app/pages/index.page.ts__template__ | 158 +++ .../files/tRPC/src/public/assets/spartan.svg | 7 - .../files/tRPC/src/trpc-client.ts__template__ | 2 +- .../src/app/pages/index.page.ts__template__ | 1196 ----------------- .../src/main.ts__template__ | 4 +- .../src/styles.css__template__ | 9 - .../vite.config.ts__template__ | 8 +- .../src/app.config.server.ts__template__ | 3 +- .../src/app/pages/index.page.ts__template__ | 1196 ----------------- .../src/styles.css__template__ | 9 - .../src/wait-for.ts__template__ | 19 - .../vite.config.ts__template__ | 8 +- .../nx-plugin/src/generators/app/generator.ts | 3 + .../app/lib/add-analog-project-config.ts | 2 +- .../src/generators/app/lib/add-index-pages.ts | 21 + 18 files changed, 1402 insertions(+), 2452 deletions(-) create mode 100644 packages/nx-plugin/src/generators/app/files/index-pages/css-trpc/src/app/pages/index.page.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/index-pages/css/src/app/pages/index.page.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/index-pages/tailwind-trpc/src/app/pages/index.page.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/files/index-pages/tailwind/src/app/pages/index.page.ts__template__ delete mode 100644 packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg delete mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ delete mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ delete mode 100644 packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ create mode 100644 packages/nx-plugin/src/generators/app/lib/add-index-pages.ts diff --git a/packages/nx-plugin/src/generators/app/files/index-pages/css-trpc/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/index-pages/css-trpc/src/app/pages/index.page.ts__template__ new file mode 100644 index 000000000..45d01a38a --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/index-pages/css-trpc/src/app/pages/index.page.ts__template__ @@ -0,0 +1,585 @@ +import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '@analogjs/trpc'; +import { injectTRPCClient } from '../../trpc-client'; +import { Note } from '../../note'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf], + styles: [ + ` + + a { + color: inherit; + text-decoration: inherit; + } + + :host { + display: flex; + padding: 2rem; + flex-direction: column; + height: 100%; + min-height: 100vh; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + } + + .main { + margin-left: auto; + margin-right: auto; + flex: 1 1 0; + } + + .section-main { + padding-top: 1.5rem; + padding-bottom: 2rem; + margin-top: 1.5rem; + } + + @media (min-width: 768px) { + .section-main { + padding-top: 2.5rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section-main { + padding-top: 8rem; + padding-bottom: 8rem; + } + } + + .main-icon { + margin-left: auto; + margin-right: auto; + margin-bottom: -1rem; + width: 4rem; + height: 4rem; + } + + .container-main { + display: flex; + text-align: center; + flex-direction: column; + align-items: center; + gap: 1rem; + } + + .button-badge { + padding-top: 0.375rem; + padding-bottom: 0.375rem; + padding-left: 1rem; + padding-right: 1rem; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + border-radius: 1rem; + background-color: rgb(228 228 231); + } + + .text-analog-red { + color: rgb(221,0,49); + } + + .heading-1 { + font-size: 1.875rem; + line-height: 2.25rem; + font-weight: 500; + margin: 1rem 0; + } + + @media (min-width: 640px) { + .heading-1 { + font-size: 2.25rem; /* 36px */ + line-height: 2.5rem; /* 40px */ + } + } + + @media (min-width: 768px) { + .heading-1 { + font-size: 3rem; /* 48px */ + line-height: 1; + } + } + + @media (min-width: 1024px) { + .heading-1 { + font-size: 3.75rem; /* 60px */ + line-height: 1; + } + } + + .paragraph-intro { + line-height: 1.5; + } + + @media (min-width: 640px) { + .paragraph-intro { + font-size: 1.25rem; + line-height: 2rem; + } + } + + .button-group { + display: flex; + gap: 1rem; + } + + .primary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(9, 9, 11); + color: rgb(250, 250, 250); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border-radius: 0.375rem; + } + + .secondary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color, border-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(250, 250, 250); + color: rgb(9, 9, 11); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border: 1px solid rgb(161, 161, 170, 0.25); + border-radius: 0.375rem; + } + + .secondary-button:hover { + background-color: rgb(244 244 245); + color: rgb(9, 9, 11); + } + + .section { + margin-top: 8rem; + margin-bottom: 8rem; + padding-top: 2rem; + padding-bottom: 2rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + @media (min-width: 768px) { + .section { + padding-top: 3rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section { + padding-top: 6rem; + } + } + + .intro-container { + margin-left: auto; + margin-right: auto; + max-width: 58rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + text-align: center; + } + + .title { + font-weight: 500; + font-size: 3rem; + line-height: 1.1; + text-align: center; + margin: 0; + } + + .description { + max-width: 85%; + font-size: 1.125rem; + line-height: 1.75rem; + } + + + + .feature-card { + position: relative; + overflow: hidden; + border: 1px solid rgb(228 228 231); + border-radius: 0.375rem; + padding: 0.5rem; + } + + .status-badge { + position: absolute; + top: 0.5rem; + right: 0.5rem; + border-radius: 0.5rem; + background-color: rgb(228, 228, 231); + padding: 0.375rem 0.75rem; + font-size: 0.75rem; + font-weight: 500; + } + + .card-content { + display: flex; + height: 180px; + flex-direction: column; + justify-content: space-between; + border-radius: 0.375rem; + padding: 1.5rem; + } + + + .card-details { + margin-top: 0.5rem; + } + + .card-title { + font-weight: bold; + } + + .card-description { + font-size: 0.875rem; + color: rgb(39, 39, 42); + } + + .further-info-container { + margin-left: auto; + margin-right: auto; + text-align: center; + max-width: 58rem; + } + + .description { + font-size: 1.125rem; + line-height: 1.75rem; + } + + + .note-form { + display: flex; + padding-bottom: 0.5rem; + margin-top: 2rem; + align-items: center; + } + .note-input { + display: flex; + height: 2.5rem; + width: 100%; + border-radius: 0.375rem; + border: 1px solid rgb(161, 161, 170, 0.25); + background-color: transparent; + padding: 0.5rem 0.75rem; + font-size: 0.875rem; + outline: none; + font-family: inherit; + color: inherit; + } + + .note-input::placeholder { + color: rgb(161, 161, 170, 0.8); + } + + .note-input:focus-visible { + outline-width: 2px; + outline-style: solid; + outline-color: rgb(39, 39, 42); + outline-offset: 2px; + } + .note-input:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + .add-note-button { + margin-left: 0.5rem; + height: 2.5rem !important; + } + .hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + .note { + position: relative; + } + .note-grid { + display: flex; + margin-top: 1rem; + flex-direction: column; + gap: 1rem; + } + .delete-note-icon { + width: 1rem; + height: 1rem; + } + .delete-note-button { + position: absolute; + top: 1rem; + right: 1rem; + padding: 0.5rem !important; + height: 2rem !important; + } + `, + ], + template: ` +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
+
+ +
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newNote = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newNote }) + .then(() => this.fetchPosts()); + this.newNote = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} diff --git a/packages/nx-plugin/src/generators/app/files/index-pages/css/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/index-pages/css/src/app/pages/index.page.ts__template__ new file mode 100644 index 000000000..0844bc9c0 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/index-pages/css/src/app/pages/index.page.ts__template__ @@ -0,0 +1,355 @@ +import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + imports: [AsyncPipe, NgFor, DatePipe, NgIf], + styles: [ + ` + a { + color: inherit; + text-decoration: inherit; + } + + :host { + display: flex; + padding: 2rem; + flex-direction: column; + height: 100%; + min-height: 100vh; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + } + + .main { + margin-left: auto; + margin-right: auto; + flex: 1 1 0; + } + + .section-main { + padding-top: 1.5rem; + padding-bottom: 2rem; + margin-top: 1.5rem; + } + + @media (min-width: 768px) { + .section-main { + padding-top: 2.5rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section-main { + padding-top: 8rem; + padding-bottom: 8rem; + } + } + + .main-icon { + margin-left: auto; + margin-right: auto; + margin-bottom: -1rem; + width: 4rem; + height: 4rem; + } + + .container-main { + display: flex; + text-align: center; + flex-direction: column; + align-items: center; + gap: 1rem; + } + + .button-badge { + padding-top: 0.375rem; + padding-bottom: 0.375rem; + padding-left: 1rem; + padding-right: 1rem; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 500; + border-radius: 1rem; + background-color: rgb(228 228 231); + } + + .text-analog-red { + color: rgb(221,0,49); + } + + .heading-1 { + font-size: 1.875rem; + line-height: 2.25rem; + font-weight: 500; + margin: 1rem 0; + } + + @media (min-width: 640px) { + .heading-1 { + font-size: 2.25rem; /* 36px */ + line-height: 2.5rem; /* 40px */ + } + } + + @media (min-width: 768px) { + .heading-1 { + font-size: 3rem; /* 48px */ + line-height: 1; + } + } + + @media (min-width: 1024px) { + .heading-1 { + font-size: 3.75rem; /* 60px */ + line-height: 1; + } + } + + .paragraph-intro { + line-height: 1.5; + } + + @media (min-width: 640px) { + .paragraph-intro { + font-size: 1.25rem; + line-height: 2rem; + } + } + + .button-group { + display: flex; + gap: 1rem; + } + + .primary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(9, 9, 11); + color: rgb(250, 250, 250); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border-radius: 0.375rem; + } + + .secondary-button { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + transition-property: color, background-color, border-color; + transition-duration: 150ms; + outline-offset: 2px; + opacity: 1; + pointer-events: auto; + background-color: rgb(250, 250, 250); + color: rgb(9, 9, 11); + height: 2.75rem; + padding-left: 2rem; + padding-right: 2rem; + border: 1px solid rgb(161, 161, 170, 0.25); + border-radius: 0.375rem; + } + + .secondary-button:hover { + background-color: rgb(244 244 245); + color: rgb(9, 9, 11); + } + + .section { + margin-top: 8rem; + margin-bottom: 8rem; + padding-top: 2rem; + padding-bottom: 2rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + @media (min-width: 768px) { + .section { + padding-top: 3rem; + padding-bottom: 3rem; + } + } + + @media (min-width: 1024px) { + .section { + padding-top: 6rem; + } + } + + .intro-container { + margin-left: auto; + margin-right: auto; + max-width: 58rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + text-align: center; + } + + .title { + font-weight: 500; + font-size: 3rem; + line-height: 1.1; + text-align: center; + margin: 0; + } + + .description { + max-width: 85%; + font-size: 1.125rem; + line-height: 1.75rem; + } + + .count { + margin-left: 0.25rem; + font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + } + `, + ], + template: ` +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+
+ `, +}) +export default class HomeComponent { + public count = 0; + public increment() { + this.count++; + } +} diff --git a/packages/nx-plugin/src/generators/app/files/index-pages/tailwind-trpc/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/index-pages/tailwind-trpc/src/app/pages/index.page.ts__template__ new file mode 100644 index 000000000..e4cafac27 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/index-pages/tailwind-trpc/src/app/pages/index.page.ts__template__ @@ -0,0 +1,269 @@ +import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; +import { FormsModule, NgForm } from '@angular/forms'; +import { waitFor } from '@analogjs/trpc'; +import { injectTRPCClient } from '../../trpc-client'; +import { Note } from '../../note'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + imports: [AsyncPipe, FormsModule, NgFor, DatePipe, NgIf], + host: { + class: + 'flex min-h-screen flex-col text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', + }, + template: ` +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Leave a note

+

+ This is an example of how to you can use tRPC to superpower you + client server interaction. +

+
+
+ + + +
+
+
+ +
+
+

{{ note.note }}

+

+ {{ note.createdAt | date }} +

+
+
+
+
+ +
+
+
+

+ {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} +

+

+ {{ + loadingPosts + ? '' + : 'Add a new one and see them appear here...' + }} +

+
+
+
+
+
+ `, +}) +export default class HomeComponent { + private _trpc = injectTRPCClient(); + public loadingPosts = false; + public notes: Note[] = []; + public newNote = ''; + + constructor() { + waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); + } + + public noteTrackBy = (index: number, note: Note) => { + return note.id; + }; + + public addPost(form: NgForm) { + if (!form.valid) { + form.form.markAllAsTouched(); + return; + } + this._trpc.note.create + .mutate({ title: this.newNote }) + .then(() => this.fetchPosts()); + this.newNote = ''; + form.form.reset(); + } + + public removePost(id: number) { + this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); + } + + private fetchPosts() { + this.loadingPosts = true; + this._trpc.note.list.query().then((notes) => { + this.loadingPosts = false; + this.notes = notes; + }); + } +} diff --git a/packages/nx-plugin/src/generators/app/files/index-pages/tailwind/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/index-pages/tailwind/src/app/pages/index.page.ts__template__ new file mode 100644 index 000000000..4a952e685 --- /dev/null +++ b/packages/nx-plugin/src/generators/app/files/index-pages/tailwind/src/app/pages/index.page.ts__template__ @@ -0,0 +1,158 @@ +import { Component } from '@angular/core'; +import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; + +@Component({ + selector: '<%= fileName %>-home', + standalone: true, + imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], + host: { + class: + 'flex min-h-screen flex-col text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', + }, + template: ` +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + Follow along on Twitter +

+ Analog. The fullstack Angular meta-framework +

+

+ Analog is for building applications and websites with Angular. +
Powered by Vite. +

+ +
+
+
+
+

Counter

+

+ This is a simple interactive counter. Powered by Angular. +

+ +
+
+
+ `, +}) +export default class HomeComponent { + public count = 0; + public increment() { + this.count++; + } +} diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg b/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg deleted file mode 100644 index 1a67c165b..000000000 --- a/packages/nx-plugin/src/generators/app/files/tRPC/src/public/assets/spartan.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ index 4e9a2d42b..772bdb334 100644 --- a/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/tRPC/src/trpc-client.ts__template__ @@ -3,7 +3,7 @@ import { createTrpcClient } from '@analogjs/trpc'; import { inject } from '@angular/core'; export const { provideTRPCClient, tRPCClient } = createTrpcClient({ - url: 'http://127.0.0.1:4205/api/trpc', + url: 'http://127.0.0.1:4200/api/trpc', }); export function injectTRPCClient() { diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ deleted file mode 100644 index 043b7ad01..000000000 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/app/pages/index.page.ts__template__ +++ /dev/null @@ -1,1196 +0,0 @@ -<% if (addTailwind) { %> -import { Component } from '@angular/core'; -import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; -<% if (addTRPC) { %> -import { injectTRPCClient } from '../../trpc-client'; -import { FormsModule, NgForm } from '@angular/forms'; -import { waitFor } from '../../wait-for'; -import { Note } from '../../note'; -<% } %> - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], - host: { - class: - 'flex min-h-screen flex-col h-full text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', - }, - template: ` -
-
-
- Follow along on Twitter -

- Analog. The fullstack Angular meta-framework -

-

- Analog is for building applications and websites with Angular. -
Powered by Vite. -

- -
-
-
-
-

- Features -

-

- Analog comes with a set of tools that aim to let you build powerful - full stack applications while providing the best possible developer - experience. -

-
-
-
-
- Installed -
-
- - - -
-

Angular

-

- Ready to built enterprise grade applications with Angular. -

-
-
-
-
-
- Installed -
-
- - - - - -
-

Vite

-

- Based on Vite. Super fast. Super ecosystem. -

-
-
-
-
-
- Installed -
-
- - - -
-

Nitro

-

- Backend server that runs everywhere -

-
-
-
-
-<% if (addTailwind) { %> -
- Installed -
-<% } %> -
- - - -
-

TailwindCSS

-

- The utility first CSS framework. -

-
-
-
-
-<% if (addTRPC) { %> -
- Installed -
-<% } %> -
- - - - - - - - - - -
-

tRPC

-

- End-to-end typesafe APIs made easy. -

-
-
-
-
-
- Installed -
-
- - - -
-

Nx

-

- Next generation build system with first class monorepo - support. -

-
-
-
-
-
-

- To see all available features and learn how to use them check out - the official - documentation. -

-
-
- -
-
-

- Proudly Open Source -

-

- Analog is open source and powered by open source software. -
- The code is available on - GitHub. -

-
-
- -<% if (addTRPC) { %> -
-
-

Leave a note

-

- This is an example of how to you can use tRPC to superpower you - client server interaction. -

-
-
- - - -
-
-
- -
-
-

{{ note.note }}

-

- {{ note.createdAt | date }} -

-
-
-
-
- -
-
-
-

- {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} -

-

- {{ - loadingPosts - ? '' - : 'Add a new one and see them appear here...' - }} -

-
-
-
-
-<% } %> -<% if (!addTRPC) { %> -
-
-

Counter

-

- This is a simple interactive counter. Powered by Angular. -

- -
-
-<% } %> -
- `, -}) -export default class HomeComponent { - private _trpc = injectTRPCClient(); - public loadingPosts = false; - public notes: Note[] = []; - public newNote = ''; - - constructor() { - waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); - } - - public noteTrackBy = (index: number, note: Note) => { - return note.id; - }; - - public addPost(form: NgForm) { - if (!form.valid) { - form.form.markAllAsTouched(); - return; - } - this._trpc.note.create - .mutate({ title: this.newNote }) - .then(() => this.fetchPosts()); - this.newNote = ''; - form.form.reset(); - } - - public removePost(id: number) { - this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); - } - - private fetchPosts() { - this.loadingPosts = true; - this._trpc.note.list.query().then((notes) => { - this.loadingPosts = false; - this.notes = notes; - }); - } - -<% if (!addTRPC) { %> - public count = 0; - public increment() { - this.count++; - } -<% } %> -} - -<% } else { %> -import { Component } from '@angular/core'; -import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; -<% if (addTRPC) { %> -import { injectTRPCClient } from '../../trpc-client'; -import { FormsModule, NgForm } from '@angular/forms'; -import { waitFor } from '../../wait-for'; -import { Note } from '../../note'; -<% } %> - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], - styles: [ - ` - :host { - display: flex; - padding: 2rem; - flex-direction: column; - height: 100%; - min-height: 100vh; - } - - .main { - margin-left: auto; - margin-right: auto; - flex: 1 1 0; - } - - .section-main { - padding-top: 1.5rem; - padding-bottom: 2rem; - margin-top: 1.5rem; - } - - @media (min-width: 768px) { - .section-main { - padding-top: 2.5rem; - padding-bottom: 3rem; - } - } - - @media (min-width: 1024px) { - .section-main { - padding-top: 8rem; - padding-bottom: 8rem; - } - } - - .button-container { - display: flex; - text-align: center; - flex-direction: column; - align-items: center; - gap: 1rem; - } - - .button-badge { - padding-top: 0.375rem; - padding-bottom: 0.375rem; - padding-left: 1rem; - padding-right: 1rem; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 500; - border-radius: 1rem; - background-color: rgb(228 228 231); - } - - .heading-1 { - font-size: 1.875rem; - line-height: 2.25rem; - font-weight: 500; - } - - @media (min-width: 640px) { - .heading-1 { - font-size: 2.25rem; /* 36px */ - line-height: 2.5rem; /* 40px */ - } - } - - @media (min-width: 768px) { - .heading-1 { - font-size: 3rem; /* 48px */ - line-height: 1; - } - } - - @media (min-width: 1024px) { - .heading-1 { - font-size: 3.75rem; /* 60px */ - line-height: 1; - } - } - - .paragraph-intro { - line-height: 1.5; - } - - @media (min-width: 640px) { - .paragraph-intro { - font-size: 1.25rem; - line-height: 2rem; - } - } - - .button-group { - display: flex; - gap: 1rem; - } - - .primary-button { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 0.875rem; - font-weight: 500; - transition-property: color, background-color; - transition-duration: 150ms; - outline-offset: 2px; - opacity: 1; - pointer-events: auto; - background-color: rgb(9, 9, 11); - color: rgb(250, 250, 250); - height: 2.75rem; - padding-left: 2rem; - padding-right: 2rem; - border-radius: 0.375rem; - } - - .secondary-button { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 0.875rem; - font-weight: 500; - transition-property: color, background-color, border-color; - transition-duration: 150ms; - outline-offset: 2px; - opacity: 1; - pointer-events: auto; - background-color: rgb(250, 250, 250); - color: rgb(9, 9, 11); - height: 2.75rem; - padding-left: 2rem; - padding-right: 2rem; - border: 1px solid rgb(161, 161, 170, 0.25); - border-radius: 0.375rem; - } - - .secondary-button:hover { - background-color: rgb(244 244 245); - color: rgb(9, 9, 11); - } - - .section { - margin-top: 8rem; - margin-bottom: 8rem; - padding-top: 2rem; - padding-bottom: 2rem; - display: flex; - flex-direction: column; - gap: 0.5rem; - } - - .dark .section { - background-color: transparent; - } - - @media (min-width: 768px) { - .section { - padding-top: 3rem; - padding-bottom: 3rem; - } - } - - @media (min-width: 1024px) { - .section { - padding-top: 6rem; - } - } - - .intro-container { - margin-left: auto; - margin-right: auto; - max-width: 58rem; - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem; - text-align: center; - } - - .title { - font-weight: 500; - font-size: 3rem; - line-height: 1.1; - text-align: center; - } - - .description { - max-width: 85%; - font-size: 1.125rem; - line-height: 1.75rem; - } - - .feature-grid { - padding: 0.5rem; - margin-left: auto; - margin-right: auto; - display: grid; - justify-content: center; - gap: 1rem; - } - - @media (min-width: 640px) { - .feature-grid { - max-width: 64rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - } - - @media (min-width: 768px) { - .feature-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - } - - .feature-card { - position: relative; - overflow: hidden; - border: 1px solid rgb(228 228 231); - border-radius: 0.375rem; - padding: 0.5rem; - } - - .status-badge { - position: absolute; - top: 0.5rem; - right: 0.5rem; - border-radius: 0.5rem; - background-color: rgb(228, 228, 231); - padding: 0.375rem 0.75rem; - font-size: 0.75rem; - font-weight: 500; - } - - .card-content { - display: flex; - height: 180px; - flex-direction: column; - justify-content: space-between; - border-radius: 0.375rem; - padding: 1.5rem; - } - - .icon { - height: 3rem; - width: 3rem; - fill: currentColor; - } - - .card-details { - margin-top: 0.5rem; - } - - .card-title { - font-weight: bold; - } - - .card-description { - font-size: 0.875rem; - color: rgb(39, 39, 42); - } - - .further-info-container { - margin-left: auto; - margin-right: auto; - text-align: center; - max-width: 58rem; - } - - .description { - font-size: 1.125rem; - line-height: 1.75rem; - } - - .link { - text-decoration: underline; - text-underline-offset: 0.25rem; - } -<% if (addTRPC) { %> - .note-form { - display: flex; - padding-bottom: 0.5rem; - margin-top: 2rem; - align-items: center; - } - .note-input { - display: flex; - height: 2.5rem; - width: 100%; - border-radius: 0.375rem; - border: 1px solid rgb(161, 161, 170, 0.25); - background-color: transparent; - padding: 0.5rem 0.75rem; - font-size: 0.875rem; - outline: none; - font-family: inherit; - color: inherit; - } - - .note-input::placeholder { - color: rgb(161, 161, 170, 0.8); - } - - .note-input:focus-visible { - outline-width: 2px; - outline-style: solid; - outline-color: rgb(39, 39, 42); - outline-offset: 2px; - } - .note-input:disabled { - cursor: not-allowed; - opacity: 0.5; - } - - .add-note-button { - margin-left: 0.5rem; - height: 2.5rem !important; - } - .hidden { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - } - .note { - position: relative; - } - .note-grid { - display: flex; - margin-top: 1rem; - flex-direction: column; - gap: 1rem; - } - .delete-note-icon { - width: 1rem; - height: 1rem; - } - .delete-note-button { - position: absolute; - top: 1rem; - right: 1rem; - padding: 0.5rem !important; - height: 2rem !important; - } -<% } %> -<% if (!addTRPC) { %> - .count { - margin-left: 0.25rem; - font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; - } -<% } %> - `, - ], - template: ` -
-
-
- Follow along on Twitter -

- Analog. The fullstack Angular meta-framework -

-

- Analog is for building applications and websites with Angular. -
Powered by Vite. -

- -
-
-
-
-

Features

-

- Analog comes with a set of tools that aim to let you build powerful - full stack applications while providing the best possible developer - experience. -

-
-
-
-
Installed
-
- - - -
-

Angular

-

- Ready to built enterprise grade applications with Angular. -

-
-
-
-
-
Installed
-
- - - - - -
-

Vite

-

- Based on Vite. Super fast. Super ecosystem. -

-
-
-
-
-
Installed
-
- - - -
-

Nitro

-

- Backend server that runs everywhere -

-
-
-
-
-
- - - -
-

TailwindCSS

-

The utility first CSS framework.

-
-
-
-
-<% if (addTRPC) { %> -
Installed
-<% } %> -
- - - - - - - - - - -
-

tRPC

-

- End-to-end typesafe APIs made easy. -

-
-
-
-
-
Installed
-
- - - -
-

Nx

-

- Next generation build system with first class monorepo - support. -

-
-
-
-
-
-

- To see all available features and learn how to use them, check out - the official - documentation. -

-
-
-
-
-

Proudly Open Source

-

- Analog is open source and powered by open source software. -
- The code is available on - GitHub. -

-
-
-<% if (addTRPC) { %> -
-
-

Leave a note

-

- This is an example of how to you can use tRPC to superpower you - client server interaction. -

-
-
- - - -
-
-
- -
-
-

{{ note.note }}

-

- {{ note.createdAt | date }} -

-
-
-
-
- -
-
-
-

- {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} -

-

- {{ - loadingPosts - ? '' - : 'Add a new one and see them appear here...' - }} -

-
-
-
-
-<% } %> -<% if (!addTRPC) { %> -
-
-

Counter

-

- This is a simple interactive counter. Powered by Angular. -

- -
-
-<% } %> -
- `, -}) -export default class HomeComponent { -<% if (addTRPC) { %> - private _trpc = injectTRPCClient(); - public loadingPosts = false; - public notes: Note[] = []; - public newNote = ''; - - constructor() { - waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); - } - - public noteTrackBy = (index: number, note: Note) => { - return note.id; - }; - - public addPost(form: NgForm) { - if (!form.valid) { - form.form.markAllAsTouched(); - return; - } - this._trpc.note.create - .mutate({ title: this.newNote }) - .then(() => this.fetchPosts()); - this.newNote = ''; - form.form.reset(); - } - - public removePost(id: number) { - this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); - } - - private fetchPosts() { - this.loadingPosts = true; - this._trpc.note.list.query().then((notes) => { - this.loadingPosts = false; - this.notes = notes; - }); - } -<% } %> -<% if (!addTRPC) { %> - public count = 0; - public increment() { - this.count++; - } -} -<% } %> -<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ index 83b68164b..c83df9926 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/main.ts__template__ @@ -1,11 +1,11 @@ import 'zone.js'; import { bootstrapApplication } from '@angular/platform-browser'; import { provideFileRouter } from '@analogjs/router'; +import { AppComponent } from './app/app.component'; +import { mainProviders } from './main.providers'; <% if (addTRPC) { %> import { provideTRPCClient } from './trpc-client'; <% } %> -import { AppComponent } from './app/app.component'; -import { mainProviders } from './main.providers'; bootstrapApplication(AppComponent, { providers: [ diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ index 14260d4cc..336c6fd63 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/src/styles.css__template__ @@ -2,12 +2,3 @@ html, body { display: block; height: 100%; } -<% if (!addTailwind) { %> -html { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} -a { - color: inherit; - text-decoration: inherit; -} -<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ index 336c11215..a3d676f13 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v15/vite.config.ts__template__ @@ -13,15 +13,13 @@ export default defineConfig(({ mode }) => { server: { host: '127.0.0.1' }, - <% } %> - optimizeDeps: { - include: ['@angular/common', '@angular/forms'], - }, - <% if (addTRPC) { %> ssr: { noExternal: '@analogjs/trpc/**', }, <% } %> + optimizeDeps: { + include: ['@angular/common', '@angular/forms'], + }, build: { target: ['es2020'], }, diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ index 9f31a6cee..1ee614143 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app.config.server.ts__template__ @@ -1,10 +1,9 @@ import { ApplicationConfig, mergeApplicationConfig } from '@angular/core'; import { provideServerRendering } from '@angular/platform-server'; -import { provideClientHydration } from '@angular/platform-browser'; import { appConfig } from './app.config'; const serverConfig: ApplicationConfig = { - providers: [provideServerRendering(), provideClientHydration()], + providers: [provideServerRendering()], }; export const config = mergeApplicationConfig(appConfig, serverConfig); diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ deleted file mode 100644 index 043b7ad01..000000000 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/app/pages/index.page.ts__template__ +++ /dev/null @@ -1,1196 +0,0 @@ -<% if (addTailwind) { %> -import { Component } from '@angular/core'; -import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; -<% if (addTRPC) { %> -import { injectTRPCClient } from '../../trpc-client'; -import { FormsModule, NgForm } from '@angular/forms'; -import { waitFor } from '../../wait-for'; -import { Note } from '../../note'; -<% } %> - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], - host: { - class: - 'flex min-h-screen flex-col h-full text-zinc-900 bg-zinc-50 px-4 pt-8 pb-32', - }, - template: ` -
-
-
- Follow along on Twitter -

- Analog. The fullstack Angular meta-framework -

-

- Analog is for building applications and websites with Angular. -
Powered by Vite. -

- -
-
-
-
-

- Features -

-

- Analog comes with a set of tools that aim to let you build powerful - full stack applications while providing the best possible developer - experience. -

-
-
-
-
- Installed -
-
- - - -
-

Angular

-

- Ready to built enterprise grade applications with Angular. -

-
-
-
-
-
- Installed -
-
- - - - - -
-

Vite

-

- Based on Vite. Super fast. Super ecosystem. -

-
-
-
-
-
- Installed -
-
- - - -
-

Nitro

-

- Backend server that runs everywhere -

-
-
-
-
-<% if (addTailwind) { %> -
- Installed -
-<% } %> -
- - - -
-

TailwindCSS

-

- The utility first CSS framework. -

-
-
-
-
-<% if (addTRPC) { %> -
- Installed -
-<% } %> -
- - - - - - - - - - -
-

tRPC

-

- End-to-end typesafe APIs made easy. -

-
-
-
-
-
- Installed -
-
- - - -
-

Nx

-

- Next generation build system with first class monorepo - support. -

-
-
-
-
-
-

- To see all available features and learn how to use them check out - the official - documentation. -

-
-
- -
-
-

- Proudly Open Source -

-

- Analog is open source and powered by open source software. -
- The code is available on - GitHub. -

-
-
- -<% if (addTRPC) { %> -
-
-

Leave a note

-

- This is an example of how to you can use tRPC to superpower you - client server interaction. -

-
-
- - - -
-
-
- -
-
-

{{ note.note }}

-

- {{ note.createdAt | date }} -

-
-
-
-
- -
-
-
-

- {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} -

-

- {{ - loadingPosts - ? '' - : 'Add a new one and see them appear here...' - }} -

-
-
-
-
-<% } %> -<% if (!addTRPC) { %> -
-
-

Counter

-

- This is a simple interactive counter. Powered by Angular. -

- -
-
-<% } %> -
- `, -}) -export default class HomeComponent { - private _trpc = injectTRPCClient(); - public loadingPosts = false; - public notes: Note[] = []; - public newNote = ''; - - constructor() { - waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); - } - - public noteTrackBy = (index: number, note: Note) => { - return note.id; - }; - - public addPost(form: NgForm) { - if (!form.valid) { - form.form.markAllAsTouched(); - return; - } - this._trpc.note.create - .mutate({ title: this.newNote }) - .then(() => this.fetchPosts()); - this.newNote = ''; - form.form.reset(); - } - - public removePost(id: number) { - this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); - } - - private fetchPosts() { - this.loadingPosts = true; - this._trpc.note.list.query().then((notes) => { - this.loadingPosts = false; - this.notes = notes; - }); - } - -<% if (!addTRPC) { %> - public count = 0; - public increment() { - this.count++; - } -<% } %> -} - -<% } else { %> -import { Component } from '@angular/core'; -import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; -<% if (addTRPC) { %> -import { injectTRPCClient } from '../../trpc-client'; -import { FormsModule, NgForm } from '@angular/forms'; -import { waitFor } from '../../wait-for'; -import { Note } from '../../note'; -<% } %> - -@Component({ - selector: '<%= fileName %>-home', - standalone: true, - imports: [AsyncPipe, <% if (addTRPC) { %>FormsModule,<% } %> NgFor, DatePipe, NgIf], - styles: [ - ` - :host { - display: flex; - padding: 2rem; - flex-direction: column; - height: 100%; - min-height: 100vh; - } - - .main { - margin-left: auto; - margin-right: auto; - flex: 1 1 0; - } - - .section-main { - padding-top: 1.5rem; - padding-bottom: 2rem; - margin-top: 1.5rem; - } - - @media (min-width: 768px) { - .section-main { - padding-top: 2.5rem; - padding-bottom: 3rem; - } - } - - @media (min-width: 1024px) { - .section-main { - padding-top: 8rem; - padding-bottom: 8rem; - } - } - - .button-container { - display: flex; - text-align: center; - flex-direction: column; - align-items: center; - gap: 1rem; - } - - .button-badge { - padding-top: 0.375rem; - padding-bottom: 0.375rem; - padding-left: 1rem; - padding-right: 1rem; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 500; - border-radius: 1rem; - background-color: rgb(228 228 231); - } - - .heading-1 { - font-size: 1.875rem; - line-height: 2.25rem; - font-weight: 500; - } - - @media (min-width: 640px) { - .heading-1 { - font-size: 2.25rem; /* 36px */ - line-height: 2.5rem; /* 40px */ - } - } - - @media (min-width: 768px) { - .heading-1 { - font-size: 3rem; /* 48px */ - line-height: 1; - } - } - - @media (min-width: 1024px) { - .heading-1 { - font-size: 3.75rem; /* 60px */ - line-height: 1; - } - } - - .paragraph-intro { - line-height: 1.5; - } - - @media (min-width: 640px) { - .paragraph-intro { - font-size: 1.25rem; - line-height: 2rem; - } - } - - .button-group { - display: flex; - gap: 1rem; - } - - .primary-button { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 0.875rem; - font-weight: 500; - transition-property: color, background-color; - transition-duration: 150ms; - outline-offset: 2px; - opacity: 1; - pointer-events: auto; - background-color: rgb(9, 9, 11); - color: rgb(250, 250, 250); - height: 2.75rem; - padding-left: 2rem; - padding-right: 2rem; - border-radius: 0.375rem; - } - - .secondary-button { - display: inline-flex; - align-items: center; - justify-content: center; - font-size: 0.875rem; - font-weight: 500; - transition-property: color, background-color, border-color; - transition-duration: 150ms; - outline-offset: 2px; - opacity: 1; - pointer-events: auto; - background-color: rgb(250, 250, 250); - color: rgb(9, 9, 11); - height: 2.75rem; - padding-left: 2rem; - padding-right: 2rem; - border: 1px solid rgb(161, 161, 170, 0.25); - border-radius: 0.375rem; - } - - .secondary-button:hover { - background-color: rgb(244 244 245); - color: rgb(9, 9, 11); - } - - .section { - margin-top: 8rem; - margin-bottom: 8rem; - padding-top: 2rem; - padding-bottom: 2rem; - display: flex; - flex-direction: column; - gap: 0.5rem; - } - - .dark .section { - background-color: transparent; - } - - @media (min-width: 768px) { - .section { - padding-top: 3rem; - padding-bottom: 3rem; - } - } - - @media (min-width: 1024px) { - .section { - padding-top: 6rem; - } - } - - .intro-container { - margin-left: auto; - margin-right: auto; - max-width: 58rem; - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem; - text-align: center; - } - - .title { - font-weight: 500; - font-size: 3rem; - line-height: 1.1; - text-align: center; - } - - .description { - max-width: 85%; - font-size: 1.125rem; - line-height: 1.75rem; - } - - .feature-grid { - padding: 0.5rem; - margin-left: auto; - margin-right: auto; - display: grid; - justify-content: center; - gap: 1rem; - } - - @media (min-width: 640px) { - .feature-grid { - max-width: 64rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - } - - @media (min-width: 768px) { - .feature-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } - } - - .feature-card { - position: relative; - overflow: hidden; - border: 1px solid rgb(228 228 231); - border-radius: 0.375rem; - padding: 0.5rem; - } - - .status-badge { - position: absolute; - top: 0.5rem; - right: 0.5rem; - border-radius: 0.5rem; - background-color: rgb(228, 228, 231); - padding: 0.375rem 0.75rem; - font-size: 0.75rem; - font-weight: 500; - } - - .card-content { - display: flex; - height: 180px; - flex-direction: column; - justify-content: space-between; - border-radius: 0.375rem; - padding: 1.5rem; - } - - .icon { - height: 3rem; - width: 3rem; - fill: currentColor; - } - - .card-details { - margin-top: 0.5rem; - } - - .card-title { - font-weight: bold; - } - - .card-description { - font-size: 0.875rem; - color: rgb(39, 39, 42); - } - - .further-info-container { - margin-left: auto; - margin-right: auto; - text-align: center; - max-width: 58rem; - } - - .description { - font-size: 1.125rem; - line-height: 1.75rem; - } - - .link { - text-decoration: underline; - text-underline-offset: 0.25rem; - } -<% if (addTRPC) { %> - .note-form { - display: flex; - padding-bottom: 0.5rem; - margin-top: 2rem; - align-items: center; - } - .note-input { - display: flex; - height: 2.5rem; - width: 100%; - border-radius: 0.375rem; - border: 1px solid rgb(161, 161, 170, 0.25); - background-color: transparent; - padding: 0.5rem 0.75rem; - font-size: 0.875rem; - outline: none; - font-family: inherit; - color: inherit; - } - - .note-input::placeholder { - color: rgb(161, 161, 170, 0.8); - } - - .note-input:focus-visible { - outline-width: 2px; - outline-style: solid; - outline-color: rgb(39, 39, 42); - outline-offset: 2px; - } - .note-input:disabled { - cursor: not-allowed; - opacity: 0.5; - } - - .add-note-button { - margin-left: 0.5rem; - height: 2.5rem !important; - } - .hidden { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - } - .note { - position: relative; - } - .note-grid { - display: flex; - margin-top: 1rem; - flex-direction: column; - gap: 1rem; - } - .delete-note-icon { - width: 1rem; - height: 1rem; - } - .delete-note-button { - position: absolute; - top: 1rem; - right: 1rem; - padding: 0.5rem !important; - height: 2rem !important; - } -<% } %> -<% if (!addTRPC) { %> - .count { - margin-left: 0.25rem; - font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; - } -<% } %> - `, - ], - template: ` -
-
-
- Follow along on Twitter -

- Analog. The fullstack Angular meta-framework -

-

- Analog is for building applications and websites with Angular. -
Powered by Vite. -

- -
-
-
-
-

Features

-

- Analog comes with a set of tools that aim to let you build powerful - full stack applications while providing the best possible developer - experience. -

-
-
-
-
Installed
-
- - - -
-

Angular

-

- Ready to built enterprise grade applications with Angular. -

-
-
-
-
-
Installed
-
- - - - - -
-

Vite

-

- Based on Vite. Super fast. Super ecosystem. -

-
-
-
-
-
Installed
-
- - - -
-

Nitro

-

- Backend server that runs everywhere -

-
-
-
-
-
- - - -
-

TailwindCSS

-

The utility first CSS framework.

-
-
-
-
-<% if (addTRPC) { %> -
Installed
-<% } %> -
- - - - - - - - - - -
-

tRPC

-

- End-to-end typesafe APIs made easy. -

-
-
-
-
-
Installed
-
- - - -
-

Nx

-

- Next generation build system with first class monorepo - support. -

-
-
-
-
-
-

- To see all available features and learn how to use them, check out - the official - documentation. -

-
-
-
-
-

Proudly Open Source

-

- Analog is open source and powered by open source software. -
- The code is available on - GitHub. -

-
-
-<% if (addTRPC) { %> -
-
-

Leave a note

-

- This is an example of how to you can use tRPC to superpower you - client server interaction. -

-
-
- - - -
-
-
- -
-
-

{{ note.note }}

-

- {{ note.createdAt | date }} -

-
-
-
-
- -
-
-
-

- {{ loadingPosts ? 'Loading...' : 'No notes yet...' }} -

-

- {{ - loadingPosts - ? '' - : 'Add a new one and see them appear here...' - }} -

-
-
-
-
-<% } %> -<% if (!addTRPC) { %> -
-
-

Counter

-

- This is a simple interactive counter. Powered by Angular. -

- -
-
-<% } %> -
- `, -}) -export default class HomeComponent { -<% if (addTRPC) { %> - private _trpc = injectTRPCClient(); - public loadingPosts = false; - public notes: Note[] = []; - public newNote = ''; - - constructor() { - waitFor(this._trpc.note.list.query().then((notes) => (this.notes = notes))); - } - - public noteTrackBy = (index: number, note: Note) => { - return note.id; - }; - - public addPost(form: NgForm) { - if (!form.valid) { - form.form.markAllAsTouched(); - return; - } - this._trpc.note.create - .mutate({ title: this.newNote }) - .then(() => this.fetchPosts()); - this.newNote = ''; - form.form.reset(); - } - - public removePost(id: number) { - this._trpc.note.remove.mutate({ id }).then(() => this.fetchPosts()); - } - - private fetchPosts() { - this.loadingPosts = true; - this._trpc.note.list.query().then((notes) => { - this.loadingPosts = false; - this.notes = notes; - }); - } -<% } %> -<% if (!addTRPC) { %> - public count = 0; - public increment() { - this.count++; - } -} -<% } %> -<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ index 14260d4cc..336c6fd63 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/styles.css__template__ @@ -2,12 +2,3 @@ html, body { display: block; height: 100%; } -<% if (!addTailwind) { %> -html { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} -a { - color: inherit; - text-decoration: inherit; -} -<% } %> diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ deleted file mode 100644 index 2821a2b39..000000000 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/src/wait-for.ts__template__ +++ /dev/null @@ -1,19 +0,0 @@ -import { firstValueFrom, isObservable, Observable } from 'rxjs'; - -declare const Zone: any; - -export async function waitFor(prom: Promise | Observable): Promise { - if (isObservable(prom)) { - prom = firstValueFrom(prom); - } - const macroTask = Zone.current.scheduleMacroTask( - `AnalogContentResolve-${Math.random()}`, - () => {}, - {}, - () => {} - ); - return prom.then((p: T) => { - macroTask.invoke(); - return p; - }); -} diff --git a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ index 9846a2a64..a3d676f13 100644 --- a/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ +++ b/packages/nx-plugin/src/generators/app/files/template-angular-v16/vite.config.ts__template__ @@ -13,15 +13,13 @@ export default defineConfig(({ mode }) => { server: { host: '127.0.0.1' }, + ssr: { + noExternal: '@analogjs/trpc/**', + }, <% } %> optimizeDeps: { include: ['@angular/common', '@angular/forms'], }, -<% if (addTRPC) { %> - ssr: { - noExternal: '@analogjs/trpc/**', - }, -<% } %> build: { target: ['es2020'], }, diff --git a/packages/nx-plugin/src/generators/app/generator.ts b/packages/nx-plugin/src/generators/app/generator.ts index d8e670d49..7d93ba165 100644 --- a/packages/nx-plugin/src/generators/app/generator.ts +++ b/packages/nx-plugin/src/generators/app/generator.ts @@ -16,6 +16,7 @@ import { initializeAngularWorkspace } from './lib/initialize-analog-workspace'; import { addFiles } from './lib/add-files'; import { addTailwindConfig } from './lib/add-tailwind-config'; import { addTRPC } from './lib/add-trpc'; +import { addIndexPages } from './lib/add-index-pages'; export interface NormalizedOptions extends AnalogNxApplicationGeneratorOptions, @@ -121,6 +122,8 @@ export async function appGenerator( ); } + addIndexPages(tree, normalizedOptions); + if (!normalizedOptions.skipFormat) { await formatFiles(tree); } diff --git a/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts b/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts index 07cbe9cc0..5d46030c8 100644 --- a/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts +++ b/packages/nx-plugin/src/generators/app/lib/add-analog-project-config.ts @@ -43,7 +43,7 @@ export function addAnalogProjectConfig( defaultConfiguration: 'development', options: { buildTarget: `${projectName}:build`, - port: 4205, + port: 4200, }, configurations: { development: { diff --git a/packages/nx-plugin/src/generators/app/lib/add-index-pages.ts b/packages/nx-plugin/src/generators/app/lib/add-index-pages.ts new file mode 100644 index 000000000..f1ebc285c --- /dev/null +++ b/packages/nx-plugin/src/generators/app/lib/add-index-pages.ts @@ -0,0 +1,21 @@ +import { generateFiles, Tree } from '@nrwl/devkit'; +import * as path from 'path'; +import { NormalizedOptions } from '../generator'; + +export function addIndexPages(tree: Tree, options: NormalizedOptions) { + const templateOptions = { + ...options, + template: '', + }; + let pageDirectory = options.addTailwind ? 'tailwind' : 'css'; + if (options.addTRPC) { + pageDirectory += '-trpc'; + } + + generateFiles( + tree, + path.join(__dirname, '..', 'files', 'index-pages', pageDirectory), + options.projectRoot, + templateOptions + ); +}