@newt-app/templates 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -0
- package/dist/index.js +756 -517
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -459,9 +459,9 @@ var page_default = {
|
|
|
459
459
|
import { useQuery } from '@tanstack/react-query';
|
|
460
460
|
import { authClient } from '@/lib/auth-client';
|
|
461
461
|
import { AuthForm } from '@/app/auth-form';
|
|
462
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
462
463
|
import { Link } from '@<%= projectName %>/ui/link';
|
|
463
464
|
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
464
|
-
import { TodoList } from '@/app/todo-list';
|
|
465
465
|
|
|
466
466
|
export default function Home() {
|
|
467
467
|
const { data: session, isPending } = authClient.useSession();
|
|
@@ -474,47 +474,52 @@ export default function Home() {
|
|
|
474
474
|
return (
|
|
475
475
|
<main className="max-w-lg mx-auto min-h-full px-4 py-8 space-y-4">
|
|
476
476
|
<div className="pb-4 border-b">
|
|
477
|
-
<p className="font-mono text-sm text-
|
|
478
|
-
<p className="text-sm text-
|
|
477
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/page.tsx</p>
|
|
478
|
+
<p className="text-sm text-muted-foreground">Delete me to get started!</p>
|
|
479
479
|
</div>
|
|
480
480
|
|
|
481
481
|
<div className="flex items-center gap-3 py-2">
|
|
482
482
|
<Logo className="w-10 h-auto text-foreground" />
|
|
483
483
|
<div>
|
|
484
484
|
<h1 className="text-4xl font-black tracking-tight"><%= projectName %></h1>
|
|
485
|
-
<p className="text-sm text-
|
|
485
|
+
<p className="text-sm text-muted-foreground tracking-widest uppercase">
|
|
486
486
|
Next + Nest = Newt \u{1F49C}
|
|
487
487
|
</p>
|
|
488
488
|
</div>
|
|
489
489
|
</div>
|
|
490
490
|
|
|
491
491
|
<div className="rounded-xl border p-6 space-y-1">
|
|
492
|
-
<p className="text-xs font-mono uppercase tracking-widest text-
|
|
493
|
-
<p className="font-mono text-sm text-
|
|
494
|
-
<p className="text-sm text-
|
|
492
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground">next.js</p>
|
|
493
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/layout.tsx</p>
|
|
494
|
+
<p className="text-sm text-muted-foreground">Next.js rendering</p>
|
|
495
495
|
</div>
|
|
496
496
|
|
|
497
497
|
<div className="rounded-xl border p-6 space-y-1">
|
|
498
|
-
<p className="text-xs font-mono uppercase tracking-widest text-
|
|
499
|
-
<p className="font-mono text-sm text-
|
|
500
|
-
<pre className="mt-2 border rounded-md p-3 text-sm bg-
|
|
498
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground">nest.js</p>
|
|
499
|
+
<p className="font-mono text-sm text-muted-foreground">GET /api/hello</p>
|
|
500
|
+
<pre className="mt-2 border rounded-md p-3 text-sm bg-muted/50">
|
|
501
501
|
<code>{JSON.stringify(hello, null, 2)}</code>
|
|
502
502
|
</pre>
|
|
503
503
|
</div>
|
|
504
504
|
|
|
505
505
|
<div className="rounded-xl border p-6">
|
|
506
|
-
<p className="text-xs font-mono uppercase tracking-widest text-
|
|
506
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground mb-4">better-auth</p>
|
|
507
507
|
{isPending ? (
|
|
508
|
-
<p className="text-sm text-
|
|
508
|
+
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
509
509
|
) : session ? (
|
|
510
|
-
<
|
|
510
|
+
<div className="space-y-3">
|
|
511
|
+
<p className="text-sm">Signed in as {session.user.name}</p>
|
|
512
|
+
<Button onClick={() => void authClient.signOut()}>
|
|
513
|
+
Sign out
|
|
514
|
+
</Button>
|
|
515
|
+
</div>
|
|
511
516
|
) : (
|
|
512
517
|
<AuthForm />
|
|
513
518
|
)}
|
|
514
519
|
</div>
|
|
515
520
|
|
|
516
521
|
<div className="px-2 py-4 text-sm">
|
|
517
|
-
<p className="mb-2 text-
|
|
522
|
+
<p className="mb-2 text-muted-foreground">Learn more</p>
|
|
518
523
|
<ul className="list-disc list-inside space-y-2 mt-2">
|
|
519
524
|
<li>
|
|
520
525
|
<Link href="https://github.com">GitHub</Link>
|
|
@@ -582,7 +587,7 @@ export function AuthForm() {
|
|
|
582
587
|
className={
|
|
583
588
|
tab === 'signup'
|
|
584
589
|
? 'font-semibold'
|
|
585
|
-
: 'text-
|
|
590
|
+
: 'text-muted-foreground hover:text-gray-200'
|
|
586
591
|
}
|
|
587
592
|
>
|
|
588
593
|
Sign up
|
|
@@ -593,7 +598,7 @@ export function AuthForm() {
|
|
|
593
598
|
className={
|
|
594
599
|
tab === 'signin'
|
|
595
600
|
? 'font-semibold'
|
|
596
|
-
: 'text-
|
|
601
|
+
: 'text-muted-foreground hover:text-gray-200'
|
|
597
602
|
}
|
|
598
603
|
>
|
|
599
604
|
Sign in
|
|
@@ -617,7 +622,7 @@ export function AuthForm() {
|
|
|
617
622
|
value={field.state.value}
|
|
618
623
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
619
624
|
required
|
|
620
|
-
className="flex h-9 w-full rounded-md border border-neutral-700 bg-
|
|
625
|
+
className="flex h-9 w-full rounded-md border border-neutral-700 bg-muted/50/50 px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none placeholder:text-neutral-500 focus-visible:border-neutral-500 focus-visible:ring-2 focus-visible:ring-neutral-500/20"
|
|
621
626
|
/>
|
|
622
627
|
</div>
|
|
623
628
|
)}
|
|
@@ -633,7 +638,7 @@ export function AuthForm() {
|
|
|
633
638
|
value={field.state.value}
|
|
634
639
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
635
640
|
required
|
|
636
|
-
className="flex h-9 w-full rounded-md border border-neutral-700 bg-
|
|
641
|
+
className="flex h-9 w-full rounded-md border border-neutral-700 bg-muted/50/50 px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none placeholder:text-neutral-500 focus-visible:border-neutral-500 focus-visible:ring-2 focus-visible:ring-neutral-500/20"
|
|
637
642
|
/>
|
|
638
643
|
</div>
|
|
639
644
|
)}
|
|
@@ -649,7 +654,7 @@ export function AuthForm() {
|
|
|
649
654
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
650
655
|
required
|
|
651
656
|
minLength={8}
|
|
652
|
-
className="flex h-9 w-full rounded-md border border-neutral-700 bg-
|
|
657
|
+
className="flex h-9 w-full rounded-md border border-neutral-700 bg-muted/50/50 px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none placeholder:text-neutral-500 focus-visible:border-neutral-500 focus-visible:ring-2 focus-visible:ring-neutral-500/20"
|
|
653
658
|
/>
|
|
654
659
|
</div>
|
|
655
660
|
)}
|
|
@@ -674,149 +679,6 @@ export function AuthForm() {
|
|
|
674
679
|
}`
|
|
675
680
|
};
|
|
676
681
|
|
|
677
|
-
// src/web/templates/todo-list.ts
|
|
678
|
-
var todo_list_default = {
|
|
679
|
-
filename: "apps/web/app/todo-list.tsx",
|
|
680
|
-
template: `'use client';
|
|
681
|
-
|
|
682
|
-
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
683
|
-
import { useForm } from '@tanstack/react-form';
|
|
684
|
-
import { authClient } from '@/lib/auth-client';
|
|
685
|
-
import { Button } from '@<%= projectName %>/ui/button';
|
|
686
|
-
|
|
687
|
-
interface Todo {
|
|
688
|
-
id: number;
|
|
689
|
-
title: string;
|
|
690
|
-
done: boolean;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
const api = {
|
|
694
|
-
getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
|
|
695
|
-
createTodo: (title: string): Promise<Todo> =>
|
|
696
|
-
fetch('/api/todos', {
|
|
697
|
-
method: 'POST',
|
|
698
|
-
headers: { 'Content-Type': 'application/json' },
|
|
699
|
-
body: JSON.stringify({ title }),
|
|
700
|
-
}).then((r) => r.json()),
|
|
701
|
-
toggleTodo: (id: number): Promise<Todo> =>
|
|
702
|
-
fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
|
|
703
|
-
deleteTodo: (id: number): Promise<void> =>
|
|
704
|
-
fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
|
|
705
|
-
};
|
|
706
|
-
|
|
707
|
-
export function TodoList({
|
|
708
|
-
session,
|
|
709
|
-
}: {
|
|
710
|
-
session: { user: { email: string } };
|
|
711
|
-
}) {
|
|
712
|
-
const queryClient = useQueryClient();
|
|
713
|
-
|
|
714
|
-
const { data: todos = [], isPending } = useQuery({
|
|
715
|
-
queryKey: ['todos'],
|
|
716
|
-
queryFn: api.getTodos,
|
|
717
|
-
});
|
|
718
|
-
|
|
719
|
-
const createMutation = useMutation({
|
|
720
|
-
mutationFn: api.createTodo,
|
|
721
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
722
|
-
});
|
|
723
|
-
|
|
724
|
-
const toggleMutation = useMutation({
|
|
725
|
-
mutationFn: api.toggleTodo,
|
|
726
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
const deleteMutation = useMutation({
|
|
730
|
-
mutationFn: api.deleteTodo,
|
|
731
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
const form = useForm({
|
|
735
|
-
defaultValues: { title: '' },
|
|
736
|
-
onSubmit: async ({ value }) => {
|
|
737
|
-
if (!value.title.trim()) return;
|
|
738
|
-
createMutation.mutate(value.title.trim());
|
|
739
|
-
form.reset();
|
|
740
|
-
},
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
return (
|
|
744
|
-
<>
|
|
745
|
-
<div className="flex items-center justify-between mb-8">
|
|
746
|
-
<h1 className="text-2xl font-semibold">Todos</h1>
|
|
747
|
-
<div className="flex items-center gap-3 text-sm text-gray-400">
|
|
748
|
-
<span>{session.user.email}</span>
|
|
749
|
-
<button
|
|
750
|
-
className="hover:text-gray-100"
|
|
751
|
-
onClick={() => authClient.signOut()}
|
|
752
|
-
>
|
|
753
|
-
Sign out
|
|
754
|
-
</button>
|
|
755
|
-
</div>
|
|
756
|
-
</div>
|
|
757
|
-
|
|
758
|
-
<form
|
|
759
|
-
onSubmit={(e) => {
|
|
760
|
-
e.preventDefault();
|
|
761
|
-
form.handleSubmit();
|
|
762
|
-
}}
|
|
763
|
-
className="flex gap-2 mb-6"
|
|
764
|
-
>
|
|
765
|
-
<form.Field name="title">
|
|
766
|
-
{(field) => (
|
|
767
|
-
<input
|
|
768
|
-
value={field.state.value}
|
|
769
|
-
onChange={(e) => field.handleChange(e.target.value)}
|
|
770
|
-
placeholder="New todo\u2026"
|
|
771
|
-
className="flex h-9 flex-1 rounded-md border border-neutral-700 bg-neutral-800/50 px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none placeholder:text-neutral-500 focus-visible:border-neutral-500 focus-visible:ring-2 focus-visible:ring-neutral-500/20"
|
|
772
|
-
/>
|
|
773
|
-
)}
|
|
774
|
-
</form.Field>
|
|
775
|
-
|
|
776
|
-
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
777
|
-
{(isSubmitting) => (
|
|
778
|
-
<Button type="submit" disabled={isSubmitting || createMutation.isPending}>
|
|
779
|
-
Add
|
|
780
|
-
</Button>
|
|
781
|
-
)}
|
|
782
|
-
</form.Subscribe>
|
|
783
|
-
</form>
|
|
784
|
-
|
|
785
|
-
{isPending ? (
|
|
786
|
-
<p className="text-sm text-gray-400">Loading\u2026</p>
|
|
787
|
-
) : (
|
|
788
|
-
<ul className="divide-y divide-neutral-700">
|
|
789
|
-
{todos.map((todo) => (
|
|
790
|
-
<li key={todo.id} className="flex items-center gap-3 py-3">
|
|
791
|
-
<input
|
|
792
|
-
type="checkbox"
|
|
793
|
-
checked={todo.done}
|
|
794
|
-
onChange={() => toggleMutation.mutate(todo.id)}
|
|
795
|
-
/>
|
|
796
|
-
<span
|
|
797
|
-
className={\`flex-1 text-sm \${todo.done ? 'line-through text-gray-400' : ''}\`}
|
|
798
|
-
>
|
|
799
|
-
{todo.title}
|
|
800
|
-
</span>
|
|
801
|
-
<button
|
|
802
|
-
onClick={() => deleteMutation.mutate(todo.id)}
|
|
803
|
-
className="text-gray-600 hover:text-red-400 text-lg leading-none"
|
|
804
|
-
>
|
|
805
|
-
\xD7
|
|
806
|
-
</button>
|
|
807
|
-
</li>
|
|
808
|
-
))}
|
|
809
|
-
</ul>
|
|
810
|
-
)}
|
|
811
|
-
|
|
812
|
-
{!isPending && todos.length === 0 && (
|
|
813
|
-
<p className="text-sm text-gray-400">No todos yet.</p>
|
|
814
|
-
)}
|
|
815
|
-
</>
|
|
816
|
-
);
|
|
817
|
-
}`
|
|
818
|
-
};
|
|
819
|
-
|
|
820
682
|
// src/web/templates/auth-route.ts
|
|
821
683
|
var auth_route_default = {
|
|
822
684
|
filename: "apps/web/app/api/auth/[...all]/route.ts",
|
|
@@ -874,7 +736,6 @@ var web = {
|
|
|
874
736
|
page_default,
|
|
875
737
|
providers_default,
|
|
876
738
|
auth_form_default,
|
|
877
|
-
todo_list_default,
|
|
878
739
|
auth_route_default,
|
|
879
740
|
auth_client_default,
|
|
880
741
|
manifest_default
|
|
@@ -1047,10 +908,8 @@ var app_module_default = {
|
|
|
1047
908
|
filename: "apps/api/src/app.module.ts",
|
|
1048
909
|
template: `import { Module } from '@nestjs/common';
|
|
1049
910
|
import { AppService } from './app.service';
|
|
1050
|
-
import { TodosModule } from './todos/todos.module';
|
|
1051
911
|
|
|
1052
912
|
@Module({
|
|
1053
|
-
imports: [TodosModule],
|
|
1054
913
|
providers: [AppService],
|
|
1055
914
|
})
|
|
1056
915
|
export class AppModule {}`
|
|
@@ -1092,83 +951,6 @@ describe('AppService', () => {
|
|
|
1092
951
|
});`
|
|
1093
952
|
};
|
|
1094
953
|
|
|
1095
|
-
// src/api/templates/todos-module.ts
|
|
1096
|
-
var todos_module_default = {
|
|
1097
|
-
filename: "apps/api/src/todos/todos.module.ts",
|
|
1098
|
-
template: `import { Module } from '@nestjs/common';
|
|
1099
|
-
import { TodosService } from './todos.service';
|
|
1100
|
-
|
|
1101
|
-
@Module({
|
|
1102
|
-
providers: [TodosService],
|
|
1103
|
-
exports: [TodosService],
|
|
1104
|
-
})
|
|
1105
|
-
export class TodosModule {}`
|
|
1106
|
-
};
|
|
1107
|
-
|
|
1108
|
-
// src/api/templates/todos-service.ts
|
|
1109
|
-
var todos_service_default = {
|
|
1110
|
-
filename: "apps/api/src/todos/todos.service.ts",
|
|
1111
|
-
template: `import { Injectable, NotFoundException } from '@nestjs/common';
|
|
1112
|
-
|
|
1113
|
-
export interface Todo {
|
|
1114
|
-
id: number;
|
|
1115
|
-
title: string;
|
|
1116
|
-
done: boolean;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
@Injectable()
|
|
1120
|
-
export class TodosService {
|
|
1121
|
-
private todos: Todo[] = [];
|
|
1122
|
-
private nextId = 1;
|
|
1123
|
-
|
|
1124
|
-
findAll(): Todo[] {
|
|
1125
|
-
return this.todos;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
create(title: string): Todo {
|
|
1129
|
-
const todo: Todo = { id: this.nextId++, title, done: false };
|
|
1130
|
-
this.todos.push(todo);
|
|
1131
|
-
return todo;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
toggle(id: number): Todo {
|
|
1135
|
-
const todo = this.todos.find((t) => t.id === id);
|
|
1136
|
-
if (!todo) throw new NotFoundException(\`Todo \${id} not found\`);
|
|
1137
|
-
todo.done = !todo.done;
|
|
1138
|
-
return todo;
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
remove(id: number): void {
|
|
1142
|
-
const index = this.todos.findIndex((t) => t.id === id);
|
|
1143
|
-
if (index === -1) throw new NotFoundException(\`Todo \${id} not found\`);
|
|
1144
|
-
this.todos.splice(index, 1);
|
|
1145
|
-
}
|
|
1146
|
-
}`
|
|
1147
|
-
};
|
|
1148
|
-
|
|
1149
|
-
// src/api/templates/todos-service-spec.ts
|
|
1150
|
-
var todos_service_spec_default = {
|
|
1151
|
-
filename: "apps/api/src/todos/todos.service.spec.ts",
|
|
1152
|
-
template: `import { Test, TestingModule } from '@nestjs/testing';
|
|
1153
|
-
import { TodosService } from './todos.service';
|
|
1154
|
-
|
|
1155
|
-
describe('TodosService', () => {
|
|
1156
|
-
let service: TodosService;
|
|
1157
|
-
|
|
1158
|
-
beforeEach(async () => {
|
|
1159
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
1160
|
-
providers: [TodosService],
|
|
1161
|
-
}).compile();
|
|
1162
|
-
|
|
1163
|
-
service = module.get<TodosService>(TodosService);
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
it('should be defined', () => {
|
|
1167
|
-
expect(service).toBeDefined();
|
|
1168
|
-
});
|
|
1169
|
-
});`
|
|
1170
|
-
};
|
|
1171
|
-
|
|
1172
954
|
// src/api/templates/readme.ts
|
|
1173
955
|
var readme_default3 = {
|
|
1174
956
|
filename: "apps/api/README.md",
|
|
@@ -1197,9 +979,6 @@ var api = {
|
|
|
1197
979
|
app_module_default,
|
|
1198
980
|
app_service_default,
|
|
1199
981
|
app_service_spec_default,
|
|
1200
|
-
todos_module_default,
|
|
1201
|
-
todos_service_default,
|
|
1202
|
-
todos_service_spec_default,
|
|
1203
982
|
readme_default3
|
|
1204
983
|
]
|
|
1205
984
|
};
|
|
@@ -1481,6 +1260,7 @@ var globals_css_default = {
|
|
|
1481
1260
|
:root {
|
|
1482
1261
|
--background: oklch(0.145 0 0);
|
|
1483
1262
|
--foreground: oklch(0.985 0 0);
|
|
1263
|
+
--muted: oklch(0.269 0 0);
|
|
1484
1264
|
--muted-foreground: oklch(0.708 0 0);
|
|
1485
1265
|
--border: oklch(0.469 0 0);
|
|
1486
1266
|
}
|
|
@@ -1488,6 +1268,7 @@ var globals_css_default = {
|
|
|
1488
1268
|
@theme inline {
|
|
1489
1269
|
--color-background: var(--background);
|
|
1490
1270
|
--color-foreground: var(--foreground);
|
|
1271
|
+
--color-muted: var(--muted);
|
|
1491
1272
|
--color-muted-foreground: var(--muted-foreground);
|
|
1492
1273
|
--color-border: var(--border);
|
|
1493
1274
|
}
|
|
@@ -1943,9 +1724,9 @@ var page_default2 = {
|
|
|
1943
1724
|
import { useQuery } from '@tanstack/react-query';
|
|
1944
1725
|
import { authClient } from '@/lib/auth-client';
|
|
1945
1726
|
import { AuthForm } from '@/app/auth-form';
|
|
1727
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
1946
1728
|
import { Link } from '@<%= projectName %>/ui/link';
|
|
1947
1729
|
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
1948
|
-
import { TodoList } from '@/app/todo-list';
|
|
1949
1730
|
import { ModeToggle } from '@<%= projectName %>/ui/mode-toggle';
|
|
1950
1731
|
import { Card, CardContent, CardHeader, CardTitle } from '@<%= projectName %>/ui/card';
|
|
1951
1732
|
|
|
@@ -2013,7 +1794,12 @@ export default function Home() {
|
|
|
2013
1794
|
{isPending ? (
|
|
2014
1795
|
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
2015
1796
|
) : session ? (
|
|
2016
|
-
<
|
|
1797
|
+
<div className="space-y-3">
|
|
1798
|
+
<p className="text-sm">Signed in as {session.user.name}</p>
|
|
1799
|
+
<Button variant="outline" onClick={() => authClient.signOut()}>
|
|
1800
|
+
Sign out
|
|
1801
|
+
</Button>
|
|
1802
|
+
</div>
|
|
2017
1803
|
) : (
|
|
2018
1804
|
<AuthForm />
|
|
2019
1805
|
)}
|
|
@@ -2185,169 +1971,22 @@ export function AuthForm() {
|
|
|
2185
1971
|
}`
|
|
2186
1972
|
};
|
|
2187
1973
|
|
|
2188
|
-
// src/shadcn-ui/templates/
|
|
2189
|
-
var
|
|
2190
|
-
filename: "
|
|
2191
|
-
template: `
|
|
1974
|
+
// src/shadcn-ui/templates/accordion.ts
|
|
1975
|
+
var accordion_default = {
|
|
1976
|
+
filename: "packages/ui/src/components/accordion.tsx",
|
|
1977
|
+
template: `import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
|
|
2192
1978
|
|
|
2193
|
-
import {
|
|
2194
|
-
import {
|
|
2195
|
-
import { authClient } from '@/lib/auth-client';
|
|
2196
|
-
import { Button } from '@<%= projectName %>/ui/button';
|
|
2197
|
-
import { Input } from '@<%= projectName %>/ui/input';
|
|
2198
|
-
import { Checkbox } from '@<%= projectName %>/ui/checkbox';
|
|
1979
|
+
import { cn } from "@<%= projectName %>/ui/lib/utils"
|
|
1980
|
+
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
2199
1981
|
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
createTodo: (title: string): Promise<Todo> =>
|
|
2209
|
-
fetch('/api/todos', {
|
|
2210
|
-
method: 'POST',
|
|
2211
|
-
headers: { 'Content-Type': 'application/json' },
|
|
2212
|
-
body: JSON.stringify({ title }),
|
|
2213
|
-
}).then((r) => r.json()),
|
|
2214
|
-
toggleTodo: (id: number): Promise<Todo> =>
|
|
2215
|
-
fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
|
|
2216
|
-
deleteTodo: (id: number): Promise<void> =>
|
|
2217
|
-
fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
|
|
2218
|
-
};
|
|
2219
|
-
|
|
2220
|
-
export function TodoList({
|
|
2221
|
-
session,
|
|
2222
|
-
}: {
|
|
2223
|
-
session: { user: { email: string } };
|
|
2224
|
-
}) {
|
|
2225
|
-
const queryClient = useQueryClient();
|
|
2226
|
-
|
|
2227
|
-
const { data: todos = [], isPending } = useQuery({
|
|
2228
|
-
queryKey: ['todos'],
|
|
2229
|
-
queryFn: api.getTodos,
|
|
2230
|
-
});
|
|
2231
|
-
|
|
2232
|
-
const createMutation = useMutation({
|
|
2233
|
-
mutationFn: api.createTodo,
|
|
2234
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
2235
|
-
});
|
|
2236
|
-
|
|
2237
|
-
const toggleMutation = useMutation({
|
|
2238
|
-
mutationFn: api.toggleTodo,
|
|
2239
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
2240
|
-
});
|
|
2241
|
-
|
|
2242
|
-
const deleteMutation = useMutation({
|
|
2243
|
-
mutationFn: api.deleteTodo,
|
|
2244
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
2245
|
-
});
|
|
2246
|
-
|
|
2247
|
-
const form = useForm({
|
|
2248
|
-
defaultValues: { title: '' },
|
|
2249
|
-
onSubmit: async ({ value }) => {
|
|
2250
|
-
if (!value.title.trim()) return;
|
|
2251
|
-
createMutation.mutate(value.title.trim());
|
|
2252
|
-
form.reset();
|
|
2253
|
-
},
|
|
2254
|
-
});
|
|
2255
|
-
|
|
2256
|
-
return (
|
|
2257
|
-
<>
|
|
2258
|
-
<div className="flex items-center justify-between mb-6">
|
|
2259
|
-
<h1 className="text-2xl font-semibold">Todos</h1>
|
|
2260
|
-
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
|
2261
|
-
<span>{session.user.email}</span>
|
|
2262
|
-
<Button
|
|
2263
|
-
variant="ghost"
|
|
2264
|
-
size="sm"
|
|
2265
|
-
onClick={() => authClient.signOut()}
|
|
2266
|
-
>
|
|
2267
|
-
Sign out
|
|
2268
|
-
</Button>
|
|
2269
|
-
</div>
|
|
2270
|
-
</div>
|
|
2271
|
-
|
|
2272
|
-
<form
|
|
2273
|
-
onSubmit={(e) => {
|
|
2274
|
-
e.preventDefault();
|
|
2275
|
-
form.handleSubmit();
|
|
2276
|
-
}}
|
|
2277
|
-
className="flex gap-2 mb-6"
|
|
2278
|
-
>
|
|
2279
|
-
<form.Field name="title">
|
|
2280
|
-
{(field) => (
|
|
2281
|
-
<Input
|
|
2282
|
-
value={field.state.value}
|
|
2283
|
-
onChange={(e) => field.handleChange(e.target.value)}
|
|
2284
|
-
placeholder="New todo\u2026"
|
|
2285
|
-
className="flex-1"
|
|
2286
|
-
/>
|
|
2287
|
-
)}
|
|
2288
|
-
</form.Field>
|
|
2289
|
-
|
|
2290
|
-
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
2291
|
-
{(isSubmitting) => (
|
|
2292
|
-
<Button type="submit" disabled={isSubmitting || createMutation.isPending}>
|
|
2293
|
-
Add
|
|
2294
|
-
</Button>
|
|
2295
|
-
)}
|
|
2296
|
-
</form.Subscribe>
|
|
2297
|
-
</form>
|
|
2298
|
-
|
|
2299
|
-
{isPending ? (
|
|
2300
|
-
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
2301
|
-
) : (
|
|
2302
|
-
<ul className="divide-y divide-border">
|
|
2303
|
-
{todos.map((todo) => (
|
|
2304
|
-
<li key={todo.id} className="flex items-center gap-3 py-3">
|
|
2305
|
-
<Checkbox
|
|
2306
|
-
checked={todo.done}
|
|
2307
|
-
onCheckedChange={() => toggleMutation.mutate(todo.id)}
|
|
2308
|
-
/>
|
|
2309
|
-
<span
|
|
2310
|
-
className={\`flex-1 text-sm \${todo.done ? 'line-through text-muted-foreground' : ''}\`}
|
|
2311
|
-
>
|
|
2312
|
-
{todo.title}
|
|
2313
|
-
</span>
|
|
2314
|
-
<Button
|
|
2315
|
-
variant="ghost"
|
|
2316
|
-
size="sm"
|
|
2317
|
-
onClick={() => deleteMutation.mutate(todo.id)}
|
|
2318
|
-
className="text-muted-foreground hover:text-destructive h-7 w-7 p-0"
|
|
2319
|
-
>
|
|
2320
|
-
\xD7
|
|
2321
|
-
</Button>
|
|
2322
|
-
</li>
|
|
2323
|
-
))}
|
|
2324
|
-
</ul>
|
|
2325
|
-
)}
|
|
2326
|
-
|
|
2327
|
-
{!isPending && todos.length === 0 && (
|
|
2328
|
-
<p className="text-sm text-muted-foreground">No todos yet.</p>
|
|
2329
|
-
)}
|
|
2330
|
-
</>
|
|
2331
|
-
);
|
|
2332
|
-
}`
|
|
2333
|
-
};
|
|
2334
|
-
|
|
2335
|
-
// src/shadcn-ui/templates/accordion.ts
|
|
2336
|
-
var accordion_default = {
|
|
2337
|
-
filename: "packages/ui/src/components/accordion.tsx",
|
|
2338
|
-
template: `import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
|
|
2339
|
-
|
|
2340
|
-
import { cn } from "@<%= projectName %>/ui/lib/utils"
|
|
2341
|
-
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
2342
|
-
|
|
2343
|
-
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
|
2344
|
-
return (
|
|
2345
|
-
<AccordionPrimitive.Root
|
|
2346
|
-
data-slot="accordion"
|
|
2347
|
-
className={cn("flex w-full flex-col", className)}
|
|
2348
|
-
{...props}
|
|
2349
|
-
/>
|
|
2350
|
-
)
|
|
1982
|
+
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
|
1983
|
+
return (
|
|
1984
|
+
<AccordionPrimitive.Root
|
|
1985
|
+
data-slot="accordion"
|
|
1986
|
+
className={cn("flex w-full flex-col", className)}
|
|
1987
|
+
{...props}
|
|
1988
|
+
/>
|
|
1989
|
+
)
|
|
2351
1990
|
}
|
|
2352
1991
|
|
|
2353
1992
|
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
|
|
@@ -9333,7 +8972,6 @@ var shadcnUi = {
|
|
|
9333
8972
|
page_default2,
|
|
9334
8973
|
providers_default2,
|
|
9335
8974
|
auth_form_default2,
|
|
9336
|
-
todo_list_default2,
|
|
9337
8975
|
accordion_default,
|
|
9338
8976
|
alert_dialog_default,
|
|
9339
8977
|
alert_default,
|
|
@@ -10444,54 +10082,6 @@ export async function inject<T>(token: Type<T> | Abstract<T> | string | symbol):
|
|
|
10444
10082
|
}`
|
|
10445
10083
|
};
|
|
10446
10084
|
|
|
10447
|
-
// src/nest-di-only/templates/web-todos-route.ts
|
|
10448
|
-
var web_todos_route_default = {
|
|
10449
|
-
filename: "apps/web/app/api/todos/route.ts",
|
|
10450
|
-
template: `import { NextResponse } from 'next/server';
|
|
10451
|
-
import { inject } from '@/lib/nest';
|
|
10452
|
-
import { TodosService } from '@<%= projectName %>/api';
|
|
10453
|
-
|
|
10454
|
-
export async function GET() {
|
|
10455
|
-
const todos = await inject(TodosService);
|
|
10456
|
-
return NextResponse.json(todos.findAll());
|
|
10457
|
-
}
|
|
10458
|
-
|
|
10459
|
-
export async function POST(req: Request) {
|
|
10460
|
-
const { title } = await req.json();
|
|
10461
|
-
const todos = await inject(TodosService);
|
|
10462
|
-
return NextResponse.json(todos.create(title), { status: 201 });
|
|
10463
|
-
}`
|
|
10464
|
-
};
|
|
10465
|
-
|
|
10466
|
-
// src/nest-di-only/templates/web-todos-id-route.ts
|
|
10467
|
-
var web_todos_id_route_default = {
|
|
10468
|
-
filename: "apps/web/app/api/todos/[id]/route.ts",
|
|
10469
|
-
template: `import { NextResponse } from 'next/server';
|
|
10470
|
-
import { inject } from '@/lib/nest';
|
|
10471
|
-
import { TodosService } from '@<%= projectName %>/api';
|
|
10472
|
-
|
|
10473
|
-
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
10474
|
-
const { id } = await params;
|
|
10475
|
-
const todos = await inject(TodosService);
|
|
10476
|
-
todos.remove(Number(id));
|
|
10477
|
-
return new NextResponse(null, { status: 204 });
|
|
10478
|
-
}`
|
|
10479
|
-
};
|
|
10480
|
-
|
|
10481
|
-
// src/nest-di-only/templates/web-todos-toggle-route.ts
|
|
10482
|
-
var web_todos_toggle_route_default = {
|
|
10483
|
-
filename: "apps/web/app/api/todos/[id]/toggle/route.ts",
|
|
10484
|
-
template: `import { NextResponse } from 'next/server';
|
|
10485
|
-
import { inject } from '@/lib/nest';
|
|
10486
|
-
import { TodosService } from '@<%= projectName %>/api';
|
|
10487
|
-
|
|
10488
|
-
export async function PATCH(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
10489
|
-
const { id } = await params;
|
|
10490
|
-
const todos = await inject(TodosService);
|
|
10491
|
-
return NextResponse.json(todos.toggle(Number(id)));
|
|
10492
|
-
}`
|
|
10493
|
-
};
|
|
10494
|
-
|
|
10495
10085
|
// src/nest-di-only/templates/web-package-json.ts
|
|
10496
10086
|
var web_package_json_default2 = {
|
|
10497
10087
|
filename: "apps/web/package.json",
|
|
@@ -10613,9 +10203,6 @@ var nestDiOnly = {
|
|
|
10613
10203
|
api_index_default,
|
|
10614
10204
|
web_nest_context_default,
|
|
10615
10205
|
web_hello_route_default,
|
|
10616
|
-
web_todos_route_default,
|
|
10617
|
-
web_todos_id_route_default,
|
|
10618
|
-
web_todos_toggle_route_default,
|
|
10619
10206
|
web_package_json_default2,
|
|
10620
10207
|
web_next_config_default3,
|
|
10621
10208
|
web_tsconfig_default
|
|
@@ -10682,10 +10269,9 @@ import { AuthGuard, AuthModule } from '@thallesp/nestjs-better-auth';
|
|
|
10682
10269
|
import { auth } from '@<%= projectName %>/auth';
|
|
10683
10270
|
import { AppController } from './app.controller';
|
|
10684
10271
|
import { AppService } from './app.service';
|
|
10685
|
-
import { TodosModule } from './todos/todos.module';
|
|
10686
10272
|
|
|
10687
10273
|
@Module({
|
|
10688
|
-
imports: [AuthModule.forRoot({ auth })
|
|
10274
|
+
imports: [AuthModule.forRoot({ auth })],
|
|
10689
10275
|
controllers: [AppController],
|
|
10690
10276
|
providers: [AppService, { provide: APP_GUARD, useClass: AuthGuard }],
|
|
10691
10277
|
})
|
|
@@ -10717,72 +10303,720 @@ async function bootstrap() {
|
|
|
10717
10303
|
void bootstrap();`
|
|
10718
10304
|
};
|
|
10719
10305
|
|
|
10720
|
-
// src/api-controllers/
|
|
10721
|
-
var
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
Param,
|
|
10729
|
-
Patch,
|
|
10730
|
-
Post,
|
|
10731
|
-
} from '@nestjs/common';
|
|
10732
|
-
import { TodosService } from './todos.service';
|
|
10733
|
-
|
|
10734
|
-
@Controller('todos')
|
|
10735
|
-
export class TodosController {
|
|
10736
|
-
constructor(private readonly todosService: TodosService) {}
|
|
10737
|
-
|
|
10738
|
-
@Get()
|
|
10739
|
-
findAll() {
|
|
10740
|
-
return this.todosService.findAll();
|
|
10741
|
-
}
|
|
10742
|
-
|
|
10743
|
-
@Post()
|
|
10744
|
-
create(@Body('title') title: string) {
|
|
10745
|
-
return this.todosService.create(title);
|
|
10746
|
-
}
|
|
10747
|
-
|
|
10748
|
-
@Patch(':id/toggle')
|
|
10749
|
-
toggle(@Param('id') id: string) {
|
|
10750
|
-
return this.todosService.toggle(Number(id));
|
|
10751
|
-
}
|
|
10752
|
-
|
|
10753
|
-
@Delete(':id')
|
|
10754
|
-
remove(@Param('id') id: string) {
|
|
10755
|
-
return this.todosService.remove(Number(id));
|
|
10756
|
-
}
|
|
10757
|
-
}`
|
|
10306
|
+
// src/api-controllers/index.ts
|
|
10307
|
+
var apiControllers = {
|
|
10308
|
+
templates: [
|
|
10309
|
+
app_controller_default,
|
|
10310
|
+
app_controller_spec_default,
|
|
10311
|
+
app_module_default2,
|
|
10312
|
+
main_default
|
|
10313
|
+
]
|
|
10758
10314
|
};
|
|
10315
|
+
var api_controllers_default = apiControllers;
|
|
10759
10316
|
|
|
10760
|
-
// src/
|
|
10761
|
-
var
|
|
10317
|
+
// src/todo-example/templates/todos-module.ts
|
|
10318
|
+
var todos_module_default = {
|
|
10762
10319
|
filename: "apps/api/src/todos/todos.module.ts",
|
|
10763
10320
|
template: `import { Module } from '@nestjs/common';
|
|
10764
|
-
import { TodosController } from './todos.controller';
|
|
10765
10321
|
import { TodosService } from './todos.service';
|
|
10766
10322
|
|
|
10767
10323
|
@Module({
|
|
10768
|
-
controllers: [TodosController],
|
|
10769
10324
|
providers: [TodosService],
|
|
10325
|
+
exports: [TodosService],
|
|
10770
10326
|
})
|
|
10771
10327
|
export class TodosModule {}`
|
|
10772
10328
|
};
|
|
10773
10329
|
|
|
10774
|
-
// src/
|
|
10775
|
-
var
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10330
|
+
// src/todo-example/templates/todos-service.ts
|
|
10331
|
+
var todos_service_default = {
|
|
10332
|
+
filename: "apps/api/src/todos/todos.service.ts",
|
|
10333
|
+
template: `import { Injectable, NotFoundException } from '@nestjs/common';
|
|
10334
|
+
|
|
10335
|
+
export interface Todo {
|
|
10336
|
+
id: number;
|
|
10337
|
+
title: string;
|
|
10338
|
+
done: boolean;
|
|
10339
|
+
}
|
|
10340
|
+
|
|
10341
|
+
@Injectable()
|
|
10342
|
+
export class TodosService {
|
|
10343
|
+
private todos: Todo[] = [];
|
|
10344
|
+
private nextId = 1;
|
|
10345
|
+
|
|
10346
|
+
findAll(): Todo[] {
|
|
10347
|
+
return this.todos;
|
|
10348
|
+
}
|
|
10349
|
+
|
|
10350
|
+
create(title: string): Todo {
|
|
10351
|
+
const todo: Todo = { id: this.nextId++, title, done: false };
|
|
10352
|
+
this.todos.push(todo);
|
|
10353
|
+
return todo;
|
|
10354
|
+
}
|
|
10355
|
+
|
|
10356
|
+
toggle(id: number): Todo {
|
|
10357
|
+
const todo = this.todos.find((t) => t.id === id);
|
|
10358
|
+
if (!todo) throw new NotFoundException(\`Todo \${id} not found\`);
|
|
10359
|
+
todo.done = !todo.done;
|
|
10360
|
+
return todo;
|
|
10361
|
+
}
|
|
10362
|
+
|
|
10363
|
+
remove(id: number): void {
|
|
10364
|
+
const index = this.todos.findIndex((t) => t.id === id);
|
|
10365
|
+
if (index === -1) throw new NotFoundException(\`Todo \${id} not found\`);
|
|
10366
|
+
this.todos.splice(index, 1);
|
|
10367
|
+
}
|
|
10368
|
+
}`
|
|
10369
|
+
};
|
|
10370
|
+
|
|
10371
|
+
// src/todo-example/templates/todos-service-spec.ts
|
|
10372
|
+
var todos_service_spec_default = {
|
|
10373
|
+
filename: "apps/api/src/todos/todos.service.spec.ts",
|
|
10374
|
+
template: `import { Test, TestingModule } from '@nestjs/testing';
|
|
10375
|
+
import { TodosService } from './todos.service';
|
|
10376
|
+
|
|
10377
|
+
describe('TodosService', () => {
|
|
10378
|
+
let service: TodosService;
|
|
10379
|
+
|
|
10380
|
+
beforeEach(async () => {
|
|
10381
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
10382
|
+
providers: [TodosService],
|
|
10383
|
+
}).compile();
|
|
10384
|
+
|
|
10385
|
+
service = module.get<TodosService>(TodosService);
|
|
10386
|
+
});
|
|
10387
|
+
|
|
10388
|
+
it('should be defined', () => {
|
|
10389
|
+
expect(service).toBeDefined();
|
|
10390
|
+
});
|
|
10391
|
+
});`
|
|
10392
|
+
};
|
|
10393
|
+
|
|
10394
|
+
// src/todo-example/templates/todos-controller.ts
|
|
10395
|
+
var todos_controller_default = {
|
|
10396
|
+
filename: "apps/api/src/todos/todos.controller.ts",
|
|
10397
|
+
template: `import {
|
|
10398
|
+
Body,
|
|
10399
|
+
Controller,
|
|
10400
|
+
Delete,
|
|
10401
|
+
Get,
|
|
10402
|
+
Param,
|
|
10403
|
+
Patch,
|
|
10404
|
+
Post,
|
|
10405
|
+
} from '@nestjs/common';
|
|
10406
|
+
import { TodosService } from './todos.service';
|
|
10407
|
+
|
|
10408
|
+
@Controller('todos')
|
|
10409
|
+
export class TodosController {
|
|
10410
|
+
constructor(private readonly todosService: TodosService) {}
|
|
10411
|
+
|
|
10412
|
+
@Get()
|
|
10413
|
+
findAll() {
|
|
10414
|
+
return this.todosService.findAll();
|
|
10415
|
+
}
|
|
10416
|
+
|
|
10417
|
+
@Post()
|
|
10418
|
+
create(@Body('title') title: string) {
|
|
10419
|
+
return this.todosService.create(title);
|
|
10420
|
+
}
|
|
10421
|
+
|
|
10422
|
+
@Patch(':id/toggle')
|
|
10423
|
+
toggle(@Param('id') id: string) {
|
|
10424
|
+
return this.todosService.toggle(Number(id));
|
|
10425
|
+
}
|
|
10426
|
+
|
|
10427
|
+
@Delete(':id')
|
|
10428
|
+
remove(@Param('id') id: string) {
|
|
10429
|
+
return this.todosService.remove(Number(id));
|
|
10430
|
+
}
|
|
10431
|
+
}`
|
|
10432
|
+
};
|
|
10433
|
+
|
|
10434
|
+
// src/todo-example/templates/todos-module-controllers.ts
|
|
10435
|
+
var todos_module_controllers_default = {
|
|
10436
|
+
filename: "apps/api/src/todos/todos.module.ts",
|
|
10437
|
+
template: `import { Module } from '@nestjs/common';
|
|
10438
|
+
import { TodosController } from './todos.controller';
|
|
10439
|
+
import { TodosService } from './todos.service';
|
|
10440
|
+
|
|
10441
|
+
@Module({
|
|
10442
|
+
controllers: [TodosController],
|
|
10443
|
+
providers: [TodosService],
|
|
10444
|
+
})
|
|
10445
|
+
export class TodosModule {}`
|
|
10446
|
+
};
|
|
10447
|
+
|
|
10448
|
+
// src/todo-example/templates/app-module-controllers.ts
|
|
10449
|
+
var app_module_controllers_default = {
|
|
10450
|
+
filename: "apps/api/src/app.module.ts",
|
|
10451
|
+
template: `import { Module } from '@nestjs/common';
|
|
10452
|
+
import { APP_GUARD } from '@nestjs/core';
|
|
10453
|
+
import { AuthGuard, AuthModule } from '@thallesp/nestjs-better-auth';
|
|
10454
|
+
import { auth } from '@<%= projectName %>/auth';
|
|
10455
|
+
import { AppController } from './app.controller';
|
|
10456
|
+
import { AppService } from './app.service';
|
|
10457
|
+
import { TodosModule } from './todos/todos.module';
|
|
10458
|
+
|
|
10459
|
+
@Module({
|
|
10460
|
+
imports: [AuthModule.forRoot({ auth }), TodosModule],
|
|
10461
|
+
controllers: [AppController],
|
|
10462
|
+
providers: [AppService, { provide: APP_GUARD, useClass: AuthGuard }],
|
|
10463
|
+
})
|
|
10464
|
+
export class AppModule {}`
|
|
10465
|
+
};
|
|
10466
|
+
|
|
10467
|
+
// src/todo-example/templates/app-module-di.ts
|
|
10468
|
+
var app_module_di_default = {
|
|
10469
|
+
filename: "apps/api/src/app.module.ts",
|
|
10470
|
+
template: `import { Module } from '@nestjs/common';
|
|
10471
|
+
import { AppService } from './app.service';
|
|
10472
|
+
import { TodosModule } from './todos/todos.module';
|
|
10473
|
+
|
|
10474
|
+
@Module({
|
|
10475
|
+
imports: [TodosModule],
|
|
10476
|
+
providers: [AppService],
|
|
10477
|
+
})
|
|
10478
|
+
export class AppModule {}`
|
|
10479
|
+
};
|
|
10480
|
+
|
|
10481
|
+
// src/todo-example/templates/web-todos-route.ts
|
|
10482
|
+
var web_todos_route_default = {
|
|
10483
|
+
filename: "apps/web/app/api/todos/route.ts",
|
|
10484
|
+
template: `import { NextResponse } from 'next/server';
|
|
10485
|
+
import { inject } from '@/lib/nest';
|
|
10486
|
+
import { TodosService } from '@<%= projectName %>/api';
|
|
10487
|
+
|
|
10488
|
+
export async function GET() {
|
|
10489
|
+
const todos = await inject(TodosService);
|
|
10490
|
+
return NextResponse.json(todos.findAll());
|
|
10491
|
+
}
|
|
10492
|
+
|
|
10493
|
+
export async function POST(req: Request) {
|
|
10494
|
+
const { title } = await req.json();
|
|
10495
|
+
const todos = await inject(TodosService);
|
|
10496
|
+
return NextResponse.json(todos.create(title), { status: 201 });
|
|
10497
|
+
}`
|
|
10498
|
+
};
|
|
10499
|
+
|
|
10500
|
+
// src/todo-example/templates/web-todos-id-route.ts
|
|
10501
|
+
var web_todos_id_route_default = {
|
|
10502
|
+
filename: "apps/web/app/api/todos/[id]/route.ts",
|
|
10503
|
+
template: `import { NextResponse } from 'next/server';
|
|
10504
|
+
import { inject } from '@/lib/nest';
|
|
10505
|
+
import { TodosService } from '@<%= projectName %>/api';
|
|
10506
|
+
|
|
10507
|
+
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
10508
|
+
const { id } = await params;
|
|
10509
|
+
const todos = await inject(TodosService);
|
|
10510
|
+
todos.remove(Number(id));
|
|
10511
|
+
return new NextResponse(null, { status: 204 });
|
|
10512
|
+
}`
|
|
10513
|
+
};
|
|
10514
|
+
|
|
10515
|
+
// src/todo-example/templates/web-todos-toggle-route.ts
|
|
10516
|
+
var web_todos_toggle_route_default = {
|
|
10517
|
+
filename: "apps/web/app/api/todos/[id]/toggle/route.ts",
|
|
10518
|
+
template: `import { NextResponse } from 'next/server';
|
|
10519
|
+
import { inject } from '@/lib/nest';
|
|
10520
|
+
import { TodosService } from '@<%= projectName %>/api';
|
|
10521
|
+
|
|
10522
|
+
export async function PATCH(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
10523
|
+
const { id } = await params;
|
|
10524
|
+
const todos = await inject(TodosService);
|
|
10525
|
+
return NextResponse.json(todos.toggle(Number(id)));
|
|
10526
|
+
}`
|
|
10527
|
+
};
|
|
10528
|
+
|
|
10529
|
+
// src/todo-example/templates/web-todo-list.ts
|
|
10530
|
+
var web_todo_list_default = {
|
|
10531
|
+
filename: "apps/web/app/todo-list.tsx",
|
|
10532
|
+
template: `'use client';
|
|
10533
|
+
|
|
10534
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
10535
|
+
import { useForm } from '@tanstack/react-form';
|
|
10536
|
+
import { authClient } from '@/lib/auth-client';
|
|
10537
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
10538
|
+
|
|
10539
|
+
interface Todo {
|
|
10540
|
+
id: number;
|
|
10541
|
+
title: string;
|
|
10542
|
+
done: boolean;
|
|
10543
|
+
}
|
|
10544
|
+
|
|
10545
|
+
const api = {
|
|
10546
|
+
getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
|
|
10547
|
+
createTodo: (title: string): Promise<Todo> =>
|
|
10548
|
+
fetch('/api/todos', {
|
|
10549
|
+
method: 'POST',
|
|
10550
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10551
|
+
body: JSON.stringify({ title }),
|
|
10552
|
+
}).then((r) => r.json()),
|
|
10553
|
+
toggleTodo: (id: number): Promise<Todo> =>
|
|
10554
|
+
fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
|
|
10555
|
+
deleteTodo: (id: number): Promise<void> =>
|
|
10556
|
+
fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
|
|
10557
|
+
};
|
|
10558
|
+
|
|
10559
|
+
export function TodoList({
|
|
10560
|
+
session,
|
|
10561
|
+
}: {
|
|
10562
|
+
session: { user: { email: string } };
|
|
10563
|
+
}) {
|
|
10564
|
+
const queryClient = useQueryClient();
|
|
10565
|
+
|
|
10566
|
+
const { data: todos = [], isPending } = useQuery({
|
|
10567
|
+
queryKey: ['todos'],
|
|
10568
|
+
queryFn: api.getTodos,
|
|
10569
|
+
});
|
|
10570
|
+
|
|
10571
|
+
const createMutation = useMutation({
|
|
10572
|
+
mutationFn: api.createTodo,
|
|
10573
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10574
|
+
});
|
|
10575
|
+
|
|
10576
|
+
const toggleMutation = useMutation({
|
|
10577
|
+
mutationFn: api.toggleTodo,
|
|
10578
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10579
|
+
});
|
|
10580
|
+
|
|
10581
|
+
const deleteMutation = useMutation({
|
|
10582
|
+
mutationFn: api.deleteTodo,
|
|
10583
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10584
|
+
});
|
|
10585
|
+
|
|
10586
|
+
const form = useForm({
|
|
10587
|
+
defaultValues: { title: '' },
|
|
10588
|
+
onSubmit: async ({ value }) => {
|
|
10589
|
+
if (!value.title.trim()) return;
|
|
10590
|
+
createMutation.mutate(value.title.trim());
|
|
10591
|
+
form.reset();
|
|
10592
|
+
},
|
|
10593
|
+
});
|
|
10594
|
+
|
|
10595
|
+
return (
|
|
10596
|
+
<>
|
|
10597
|
+
<div className="flex items-center justify-between mb-8">
|
|
10598
|
+
<h1 className="text-2xl font-semibold">Todos</h1>
|
|
10599
|
+
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
|
10600
|
+
<span>{session.user.email}</span>
|
|
10601
|
+
<button
|
|
10602
|
+
className="hover:text-gray-100"
|
|
10603
|
+
onClick={() => authClient.signOut()}
|
|
10604
|
+
>
|
|
10605
|
+
Sign out
|
|
10606
|
+
</button>
|
|
10607
|
+
</div>
|
|
10608
|
+
</div>
|
|
10609
|
+
|
|
10610
|
+
<form
|
|
10611
|
+
onSubmit={(e) => {
|
|
10612
|
+
e.preventDefault();
|
|
10613
|
+
form.handleSubmit();
|
|
10614
|
+
}}
|
|
10615
|
+
className="flex gap-2 mb-6"
|
|
10616
|
+
>
|
|
10617
|
+
<form.Field name="title">
|
|
10618
|
+
{(field) => (
|
|
10619
|
+
<input
|
|
10620
|
+
value={field.state.value}
|
|
10621
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
10622
|
+
placeholder="New todo\u2026"
|
|
10623
|
+
className="flex h-9 flex-1 rounded-md border border-neutral-700 bg-muted/50/50 px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none placeholder:text-neutral-500 focus-visible:border-neutral-500 focus-visible:ring-2 focus-visible:ring-neutral-500/20"
|
|
10624
|
+
/>
|
|
10625
|
+
)}
|
|
10626
|
+
</form.Field>
|
|
10627
|
+
|
|
10628
|
+
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
10629
|
+
{(isSubmitting) => (
|
|
10630
|
+
<Button type="submit" disabled={isSubmitting || createMutation.isPending}>
|
|
10631
|
+
Add
|
|
10632
|
+
</Button>
|
|
10633
|
+
)}
|
|
10634
|
+
</form.Subscribe>
|
|
10635
|
+
</form>
|
|
10636
|
+
|
|
10637
|
+
{isPending ? (
|
|
10638
|
+
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
10639
|
+
) : (
|
|
10640
|
+
<ul className="divide-y divide-neutral-700">
|
|
10641
|
+
{todos.map((todo) => (
|
|
10642
|
+
<li key={todo.id} className="flex items-center gap-3 py-3">
|
|
10643
|
+
<input
|
|
10644
|
+
type="checkbox"
|
|
10645
|
+
checked={todo.done}
|
|
10646
|
+
onChange={() => toggleMutation.mutate(todo.id)}
|
|
10647
|
+
/>
|
|
10648
|
+
<span
|
|
10649
|
+
className={\`flex-1 text-sm \${todo.done ? 'line-through text-muted-foreground' : ''}\`}
|
|
10650
|
+
>
|
|
10651
|
+
{todo.title}
|
|
10652
|
+
</span>
|
|
10653
|
+
<button
|
|
10654
|
+
onClick={() => deleteMutation.mutate(todo.id)}
|
|
10655
|
+
className="text-gray-600 hover:text-red-400 text-lg leading-none"
|
|
10656
|
+
>
|
|
10657
|
+
\xD7
|
|
10658
|
+
</button>
|
|
10659
|
+
</li>
|
|
10660
|
+
))}
|
|
10661
|
+
</ul>
|
|
10662
|
+
)}
|
|
10663
|
+
|
|
10664
|
+
{!isPending && todos.length === 0 && (
|
|
10665
|
+
<p className="text-sm text-muted-foreground">No todos yet.</p>
|
|
10666
|
+
)}
|
|
10667
|
+
</>
|
|
10668
|
+
);
|
|
10669
|
+
}`
|
|
10670
|
+
};
|
|
10671
|
+
|
|
10672
|
+
// src/todo-example/templates/web-page.ts
|
|
10673
|
+
var web_page_default = {
|
|
10674
|
+
filename: "apps/web/app/page.tsx",
|
|
10675
|
+
template: `'use client';
|
|
10676
|
+
|
|
10677
|
+
import { useQuery } from '@tanstack/react-query';
|
|
10678
|
+
import { authClient } from '@/lib/auth-client';
|
|
10679
|
+
import { AuthForm } from '@/app/auth-form';
|
|
10680
|
+
import { Link } from '@<%= projectName %>/ui/link';
|
|
10681
|
+
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
10682
|
+
import { TodoList } from '@/app/todo-list';
|
|
10683
|
+
|
|
10684
|
+
export default function Home() {
|
|
10685
|
+
const { data: session, isPending } = authClient.useSession();
|
|
10686
|
+
|
|
10687
|
+
const { data: hello } = useQuery({
|
|
10688
|
+
queryKey: ['hello'],
|
|
10689
|
+
queryFn: () => fetch('/api/hello').then((r) => r.json()),
|
|
10690
|
+
});
|
|
10691
|
+
|
|
10692
|
+
return (
|
|
10693
|
+
<main className="max-w-lg mx-auto min-h-full px-4 py-8 space-y-4">
|
|
10694
|
+
<div className="pb-4 border-b">
|
|
10695
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/page.tsx</p>
|
|
10696
|
+
<p className="text-sm text-muted-foreground">Delete me to get started!</p>
|
|
10697
|
+
</div>
|
|
10698
|
+
|
|
10699
|
+
<div className="flex items-center gap-3 py-2">
|
|
10700
|
+
<Logo className="w-10 h-auto text-foreground" />
|
|
10701
|
+
<div>
|
|
10702
|
+
<h1 className="text-4xl font-black tracking-tight"><%= projectName %></h1>
|
|
10703
|
+
<p className="text-sm text-muted-foreground tracking-widest uppercase">
|
|
10704
|
+
Next + Nest = Newt \u{1F49C}
|
|
10705
|
+
</p>
|
|
10706
|
+
</div>
|
|
10707
|
+
</div>
|
|
10708
|
+
|
|
10709
|
+
<div className="rounded-xl border p-6 space-y-1">
|
|
10710
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground">next.js</p>
|
|
10711
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/layout.tsx</p>
|
|
10712
|
+
<p className="text-sm text-muted-foreground">Next.js rendering</p>
|
|
10713
|
+
</div>
|
|
10714
|
+
|
|
10715
|
+
<div className="rounded-xl border p-6 space-y-1">
|
|
10716
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground">nest.js</p>
|
|
10717
|
+
<p className="font-mono text-sm text-muted-foreground">GET /api/hello</p>
|
|
10718
|
+
<pre className="mt-2 border rounded-md p-3 text-sm bg-muted/50">
|
|
10719
|
+
<code>{JSON.stringify(hello, null, 2)}</code>
|
|
10720
|
+
</pre>
|
|
10721
|
+
</div>
|
|
10722
|
+
|
|
10723
|
+
<div className="rounded-xl border p-6">
|
|
10724
|
+
<p className="text-xs font-mono uppercase tracking-widest text-muted-foreground mb-4">better-auth</p>
|
|
10725
|
+
{isPending ? (
|
|
10726
|
+
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
10727
|
+
) : session ? (
|
|
10728
|
+
<TodoList session={session} />
|
|
10729
|
+
) : (
|
|
10730
|
+
<AuthForm />
|
|
10731
|
+
)}
|
|
10732
|
+
</div>
|
|
10733
|
+
|
|
10734
|
+
<div className="px-2 py-4 text-sm">
|
|
10735
|
+
<p className="mb-2 text-muted-foreground">Learn more</p>
|
|
10736
|
+
<ul className="list-disc list-inside space-y-2 mt-2">
|
|
10737
|
+
<li>
|
|
10738
|
+
<Link href="https://github.com">GitHub</Link>
|
|
10739
|
+
</li>
|
|
10740
|
+
<li>
|
|
10741
|
+
<Link href="https://nextjs.org">Next.js</Link>
|
|
10742
|
+
</li>
|
|
10743
|
+
<li>
|
|
10744
|
+
<Link href="https://nestjs.com">NestJS</Link>
|
|
10745
|
+
</li>
|
|
10746
|
+
</ul>
|
|
10747
|
+
</div>
|
|
10748
|
+
</main>
|
|
10749
|
+
);
|
|
10750
|
+
}`
|
|
10751
|
+
};
|
|
10752
|
+
|
|
10753
|
+
// src/todo-example/templates/shadcn-todo-list.ts
|
|
10754
|
+
var shadcn_todo_list_default = {
|
|
10755
|
+
filename: "apps/web/app/todo-list.tsx",
|
|
10756
|
+
template: `'use client';
|
|
10757
|
+
|
|
10758
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
10759
|
+
import { useForm } from '@tanstack/react-form';
|
|
10760
|
+
import { authClient } from '@/lib/auth-client';
|
|
10761
|
+
import { Button } from '@<%= projectName %>/ui/button';
|
|
10762
|
+
import { Input } from '@<%= projectName %>/ui/input';
|
|
10763
|
+
import { Checkbox } from '@<%= projectName %>/ui/checkbox';
|
|
10764
|
+
|
|
10765
|
+
interface Todo {
|
|
10766
|
+
id: number;
|
|
10767
|
+
title: string;
|
|
10768
|
+
done: boolean;
|
|
10769
|
+
}
|
|
10770
|
+
|
|
10771
|
+
const api = {
|
|
10772
|
+
getTodos: (): Promise<Todo[]> => fetch('/api/todos').then((r) => r.json()),
|
|
10773
|
+
createTodo: (title: string): Promise<Todo> =>
|
|
10774
|
+
fetch('/api/todos', {
|
|
10775
|
+
method: 'POST',
|
|
10776
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10777
|
+
body: JSON.stringify({ title }),
|
|
10778
|
+
}).then((r) => r.json()),
|
|
10779
|
+
toggleTodo: (id: number): Promise<Todo> =>
|
|
10780
|
+
fetch(\`/api/todos/\${id}/toggle\`, { method: 'PATCH' }).then((r) => r.json()),
|
|
10781
|
+
deleteTodo: (id: number): Promise<void> =>
|
|
10782
|
+
fetch(\`/api/todos/\${id}\`, { method: 'DELETE' }).then(() => undefined),
|
|
10783
|
+
};
|
|
10784
|
+
|
|
10785
|
+
export function TodoList({
|
|
10786
|
+
session,
|
|
10787
|
+
}: {
|
|
10788
|
+
session: { user: { email: string } };
|
|
10789
|
+
}) {
|
|
10790
|
+
const queryClient = useQueryClient();
|
|
10791
|
+
|
|
10792
|
+
const { data: todos = [], isPending } = useQuery({
|
|
10793
|
+
queryKey: ['todos'],
|
|
10794
|
+
queryFn: api.getTodos,
|
|
10795
|
+
});
|
|
10796
|
+
|
|
10797
|
+
const createMutation = useMutation({
|
|
10798
|
+
mutationFn: api.createTodo,
|
|
10799
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10800
|
+
});
|
|
10801
|
+
|
|
10802
|
+
const toggleMutation = useMutation({
|
|
10803
|
+
mutationFn: api.toggleTodo,
|
|
10804
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10805
|
+
});
|
|
10806
|
+
|
|
10807
|
+
const deleteMutation = useMutation({
|
|
10808
|
+
mutationFn: api.deleteTodo,
|
|
10809
|
+
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
|
10810
|
+
});
|
|
10811
|
+
|
|
10812
|
+
const form = useForm({
|
|
10813
|
+
defaultValues: { title: '' },
|
|
10814
|
+
onSubmit: async ({ value }) => {
|
|
10815
|
+
if (!value.title.trim()) return;
|
|
10816
|
+
createMutation.mutate(value.title.trim());
|
|
10817
|
+
form.reset();
|
|
10818
|
+
},
|
|
10819
|
+
});
|
|
10820
|
+
|
|
10821
|
+
return (
|
|
10822
|
+
<>
|
|
10823
|
+
<div className="flex items-center justify-between mb-6">
|
|
10824
|
+
<h1 className="text-2xl font-semibold">Todos</h1>
|
|
10825
|
+
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
|
10826
|
+
<span>{session.user.email}</span>
|
|
10827
|
+
<Button
|
|
10828
|
+
variant="ghost"
|
|
10829
|
+
size="sm"
|
|
10830
|
+
onClick={() => authClient.signOut()}
|
|
10831
|
+
>
|
|
10832
|
+
Sign out
|
|
10833
|
+
</Button>
|
|
10834
|
+
</div>
|
|
10835
|
+
</div>
|
|
10836
|
+
|
|
10837
|
+
<form
|
|
10838
|
+
onSubmit={(e) => {
|
|
10839
|
+
e.preventDefault();
|
|
10840
|
+
form.handleSubmit();
|
|
10841
|
+
}}
|
|
10842
|
+
className="flex gap-2 mb-6"
|
|
10843
|
+
>
|
|
10844
|
+
<form.Field name="title">
|
|
10845
|
+
{(field) => (
|
|
10846
|
+
<Input
|
|
10847
|
+
value={field.state.value}
|
|
10848
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
10849
|
+
placeholder="New todo\u2026"
|
|
10850
|
+
className="flex-1"
|
|
10851
|
+
/>
|
|
10852
|
+
)}
|
|
10853
|
+
</form.Field>
|
|
10854
|
+
|
|
10855
|
+
<form.Subscribe selector={(s) => s.isSubmitting}>
|
|
10856
|
+
{(isSubmitting) => (
|
|
10857
|
+
<Button type="submit" disabled={isSubmitting || createMutation.isPending}>
|
|
10858
|
+
Add
|
|
10859
|
+
</Button>
|
|
10860
|
+
)}
|
|
10861
|
+
</form.Subscribe>
|
|
10862
|
+
</form>
|
|
10863
|
+
|
|
10864
|
+
{isPending ? (
|
|
10865
|
+
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
10866
|
+
) : (
|
|
10867
|
+
<ul className="divide-y divide-border">
|
|
10868
|
+
{todos.map((todo) => (
|
|
10869
|
+
<li key={todo.id} className="flex items-center gap-3 py-3">
|
|
10870
|
+
<Checkbox
|
|
10871
|
+
checked={todo.done}
|
|
10872
|
+
onCheckedChange={() => toggleMutation.mutate(todo.id)}
|
|
10873
|
+
/>
|
|
10874
|
+
<span
|
|
10875
|
+
className={\`flex-1 text-sm \${todo.done ? 'line-through text-muted-foreground' : ''}\`}
|
|
10876
|
+
>
|
|
10877
|
+
{todo.title}
|
|
10878
|
+
</span>
|
|
10879
|
+
<Button
|
|
10880
|
+
variant="ghost"
|
|
10881
|
+
size="sm"
|
|
10882
|
+
onClick={() => deleteMutation.mutate(todo.id)}
|
|
10883
|
+
className="text-muted-foreground hover:text-destructive h-7 w-7 p-0"
|
|
10884
|
+
>
|
|
10885
|
+
\xD7
|
|
10886
|
+
</Button>
|
|
10887
|
+
</li>
|
|
10888
|
+
))}
|
|
10889
|
+
</ul>
|
|
10890
|
+
)}
|
|
10891
|
+
|
|
10892
|
+
{!isPending && todos.length === 0 && (
|
|
10893
|
+
<p className="text-sm text-muted-foreground">No todos yet.</p>
|
|
10894
|
+
)}
|
|
10895
|
+
</>
|
|
10896
|
+
);
|
|
10897
|
+
}`
|
|
10898
|
+
};
|
|
10899
|
+
|
|
10900
|
+
// src/todo-example/templates/shadcn-page.ts
|
|
10901
|
+
var shadcn_page_default = {
|
|
10902
|
+
filename: "apps/web/app/page.tsx",
|
|
10903
|
+
template: `'use client';
|
|
10904
|
+
|
|
10905
|
+
import { useQuery } from '@tanstack/react-query';
|
|
10906
|
+
import { authClient } from '@/lib/auth-client';
|
|
10907
|
+
import { AuthForm } from '@/app/auth-form';
|
|
10908
|
+
import { Link } from '@<%= projectName %>/ui/link';
|
|
10909
|
+
import { Logo } from '@<%= projectName %>/ui/logo';
|
|
10910
|
+
import { TodoList } from '@/app/todo-list';
|
|
10911
|
+
import { ModeToggle } from '@<%= projectName %>/ui/mode-toggle';
|
|
10912
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@<%= projectName %>/ui/card';
|
|
10913
|
+
|
|
10914
|
+
export default function Home() {
|
|
10915
|
+
const { data: session, isPending } = authClient.useSession();
|
|
10916
|
+
|
|
10917
|
+
const { data: hello } = useQuery({
|
|
10918
|
+
queryKey: ['hello'],
|
|
10919
|
+
queryFn: () => fetch('/api/hello').then((r) => r.json()),
|
|
10920
|
+
});
|
|
10921
|
+
|
|
10922
|
+
return (
|
|
10923
|
+
<main className="max-w-lg mx-auto min-h-full px-4 py-8 space-y-4">
|
|
10924
|
+
<div className="pb-4 border-b flex items-start justify-between">
|
|
10925
|
+
<div>
|
|
10926
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/page.tsx</p>
|
|
10927
|
+
<p className="text-sm text-muted-foreground">Delete me to get started!</p>
|
|
10928
|
+
</div>
|
|
10929
|
+
<ModeToggle />
|
|
10930
|
+
</div>
|
|
10931
|
+
|
|
10932
|
+
<div className="flex items-center gap-3 py-2">
|
|
10933
|
+
<Logo className="w-10 h-auto text-foreground" />
|
|
10934
|
+
<div>
|
|
10935
|
+
<h1 className="text-4xl font-black tracking-tight"><%= projectName %></h1>
|
|
10936
|
+
<p className="text-sm text-muted-foreground tracking-widest uppercase">
|
|
10937
|
+
Next + Nest = Newt \u{1F49C}
|
|
10938
|
+
</p>
|
|
10939
|
+
</div>
|
|
10940
|
+
</div>
|
|
10941
|
+
|
|
10942
|
+
<Card>
|
|
10943
|
+
<CardHeader>
|
|
10944
|
+
<CardTitle className="text-xs font-mono uppercase tracking-widest text-muted-foreground">
|
|
10945
|
+
next.js
|
|
10946
|
+
</CardTitle>
|
|
10947
|
+
</CardHeader>
|
|
10948
|
+
<CardContent>
|
|
10949
|
+
<p className="font-mono text-sm text-muted-foreground">apps/web/layout.tsx</p>
|
|
10950
|
+
<p className="text-sm text-muted-foreground">Next.js rendering</p>
|
|
10951
|
+
</CardContent>
|
|
10952
|
+
</Card>
|
|
10953
|
+
|
|
10954
|
+
<Card>
|
|
10955
|
+
<CardHeader>
|
|
10956
|
+
<CardTitle className="text-xs font-mono uppercase tracking-widest text-muted-foreground">
|
|
10957
|
+
nest.js
|
|
10958
|
+
</CardTitle>
|
|
10959
|
+
</CardHeader>
|
|
10960
|
+
<CardContent>
|
|
10961
|
+
<p className="font-mono text-sm text-muted-foreground">GET /api/hello</p>
|
|
10962
|
+
<pre className="mt-2 rounded-md border p-3 text-sm bg-muted/50">
|
|
10963
|
+
<code>{JSON.stringify(hello, null, 2)}</code>
|
|
10964
|
+
</pre>
|
|
10965
|
+
</CardContent>
|
|
10966
|
+
</Card>
|
|
10967
|
+
|
|
10968
|
+
<Card>
|
|
10969
|
+
<CardHeader>
|
|
10970
|
+
<CardTitle className="text-xs font-mono uppercase tracking-widest text-muted-foreground">
|
|
10971
|
+
better-auth
|
|
10972
|
+
</CardTitle>
|
|
10973
|
+
</CardHeader>
|
|
10974
|
+
<CardContent>
|
|
10975
|
+
{isPending ? (
|
|
10976
|
+
<p className="text-sm text-muted-foreground">Loading\u2026</p>
|
|
10977
|
+
) : session ? (
|
|
10978
|
+
<TodoList session={session} />
|
|
10979
|
+
) : (
|
|
10980
|
+
<AuthForm />
|
|
10981
|
+
)}
|
|
10982
|
+
</CardContent>
|
|
10983
|
+
</Card>
|
|
10984
|
+
|
|
10985
|
+
<div className="px-2 py-4 text-sm">
|
|
10986
|
+
<p className="mb-2 text-muted-foreground">Learn more</p>
|
|
10987
|
+
<ul className="list-disc list-inside space-y-2 mt-2">
|
|
10988
|
+
<li>
|
|
10989
|
+
<Link href="https://github.com">GitHub</Link>
|
|
10990
|
+
</li>
|
|
10991
|
+
<li>
|
|
10992
|
+
<Link href="https://nextjs.org">Next.js</Link>
|
|
10993
|
+
</li>
|
|
10994
|
+
<li>
|
|
10995
|
+
<Link href="https://nestjs.com">NestJS</Link>
|
|
10996
|
+
</li>
|
|
10997
|
+
</ul>
|
|
10998
|
+
</div>
|
|
10999
|
+
</main>
|
|
11000
|
+
);
|
|
11001
|
+
}`
|
|
11002
|
+
};
|
|
11003
|
+
|
|
11004
|
+
// src/todo-example/index.ts
|
|
11005
|
+
var todoExampleApi = {
|
|
11006
|
+
templates: [todos_module_default, todos_service_default, todos_service_spec_default]
|
|
11007
|
+
};
|
|
11008
|
+
var todoExampleControllers = {
|
|
11009
|
+
templates: [todos_controller_default, todos_module_controllers_default, app_module_controllers_default]
|
|
11010
|
+
};
|
|
11011
|
+
var todoExampleDi = {
|
|
11012
|
+
templates: [web_todos_route_default, web_todos_id_route_default, web_todos_toggle_route_default, app_module_di_default]
|
|
11013
|
+
};
|
|
11014
|
+
var todoExampleWeb = {
|
|
11015
|
+
templates: [web_todo_list_default, web_page_default]
|
|
11016
|
+
};
|
|
11017
|
+
var todoExampleShadcn = {
|
|
11018
|
+
templates: [shadcn_todo_list_default, shadcn_page_default]
|
|
11019
|
+
};
|
|
10786
11020
|
|
|
10787
11021
|
// src/index.ts
|
|
10788
11022
|
var staticDir = new URL("./static/", import.meta.url);
|
|
@@ -10805,7 +11039,12 @@ var templates = {
|
|
|
10805
11039
|
deploymentCustomServer: single_process_custom_server_default,
|
|
10806
11040
|
deploymentSpa: single_process_static_export_default,
|
|
10807
11041
|
nestDiOnly: nest_di_only_default,
|
|
10808
|
-
apiControllers: api_controllers_default
|
|
11042
|
+
apiControllers: api_controllers_default,
|
|
11043
|
+
todoExampleApi,
|
|
11044
|
+
todoExampleControllers,
|
|
11045
|
+
todoExampleDi,
|
|
11046
|
+
todoExampleWeb,
|
|
11047
|
+
todoExampleShadcn
|
|
10809
11048
|
};
|
|
10810
11049
|
export {
|
|
10811
11050
|
getStaticFilePath,
|