create-tnt-stack 0.5.1 → 0.5.2

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.js CHANGED
@@ -51,7 +51,7 @@ Using: ${I.cyan.bold(s)}
51
51
  `).start();if(O.existsSync(a))if(O.readdirSync(a).length===0)e!=="."&&n.info(`${I.cyan.bold(e)} exists but is empty, continuing...
52
52
  `);else{n.stopAndPersist();let l=await it({message:`${I.redBright.bold("Warning:")} ${I.cyan.bold(e)} already exists and isn't empty. How would you like to proceed?`,choices:[{value:"abort",name:"Abort installation (recommended)"},{value:"clear",name:"Clear the directory and continue installation"},{value:"overwrite",name:"Continue installation and overwrite conflicting files"}],default:"abort"});l==="abort"&&(n.fail("Aborting installation..."),process.exit(1)),await ot({message:`Are you sure you want to ${l==="clear"?"clear the directory":"overwrite conflicting files"}`,default:!1})||(n.fail("Aborting installation..."),process.exit(1)),l==="clear"&&(n.info(`Emptying ${I.cyan.bold(e)} and creating tnt app...
53
53
  `),O.emptyDirSync(a))}n.start(),O.copySync(t,a),O.renameSync(W.join(a,"_gitignore"),W.join(a,".gitignore"));let i=e==="."?"App":I.cyan.bold(e);n.succeed(`${i} ${I.green.bold("scaffolded successfully!")}
54
- `)}import v from"path";import B from"fs-extra";function Pe({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/layout"),o=e.payload.inUse,n=v.join(s,"base.tsx"),i=v.join(a,`src/app/${o?"(frontend)":""}/layout.tsx`);B.copySync(n,i)}function _e({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/page"),o=e.payload.inUse,t=e.authjs.inUse,n=e.prisma.inUse,i="base.tsx";o&&(i="with-payload.tsx"),t&&(i="with-authjs.tsx"),n&&(i="with-prisma.tsx");let l=v.join(s,i),d=v.join(a,`src/app/${o?"(frontend)":""}/page.tsx`);B.copySync(l,d)}function Se({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/globals"),o=e.payload.inUse,n=v.join(s,"base.css"),i=v.join(a,`src/app/${o?"(frontend)":""}/globals.css`);B.copySync(n,i)}async function xe({projectName:e,scopedAppName:a,packages:s,noInstall:o,databaseProvider:t}){let n=h(),i=lt.resolve(process.cwd(),e);return await we({projectName:e,projectDir:i,pkgManager:n,scopedAppName:a,noInstall:o,databaseProvider:t}),ke({projectName:e,scopedAppName:a,projectDir:i,pkgManager:n,packages:s,noInstall:o,databaseProvider:t}),Pe({packages:s,projectDir:i}),_e({packages:s,projectDir:i}),Se({packages:s,projectDir:i}),i}import{execSync as z}from"child_process";import V from"path";import{confirm as Ie}from"@inquirer/prompts";import T from"chalk";import{execa as D}from"execa";import Ae from"fs-extra";import pt from"ora";function ct(e){try{return z("git --version",{cwd:e}),!0}catch{return!1}}function K(e){return Ae.existsSync(V.join(e,".git"))}async function H(e){try{return await D("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}}function mt(){let a=z("git --version").toString().trim().split(" ")[2],s=a?.split(".")[0],o=a?.split(".")[1];return{major:Number(s),minor:Number(o)}}function dt(){return z("git config --global init.defaultBranch || echo main").toString().trim()}async function je(e){if(r.info("Initializing Git..."),!ct(e)){r.warn("Git is not installed. Skipping Git initialization.");return}let a=pt(`Creating a new git repo...
54
+ `)}import v from"path";import B from"fs-extra";function Pe({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/layout"),o=e.payload.inUse,n=v.join(s,"base.tsx"),i=v.join(a,`src/app/${o?"(frontend)":""}/layout.tsx`);B.copySync(n,i)}function _e({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/page"),o=e.payload.inUse,t=e.authjs.inUse,n=e.prisma.inUse,i="base.tsx";o&&(i="with-payload.tsx"),t&&(i="with-authjs.tsx"),n&&(i="with-prisma.tsx"),t&&n&&(i="with-authjs-prisma.tsx");let l=v.join(s,i),d=v.join(a,`src/app/${o?"(frontend)":""}/page.tsx`);B.copySync(l,d)}function Se({packages:e,projectDir:a}){let s=v.join(c,"template/packages/src/app/globals"),o=e.payload.inUse,n=v.join(s,"base.css"),i=v.join(a,`src/app/${o?"(frontend)":""}/globals.css`);B.copySync(n,i)}async function xe({projectName:e,scopedAppName:a,packages:s,noInstall:o,databaseProvider:t}){let n=h(),i=lt.resolve(process.cwd(),e);return await we({projectName:e,projectDir:i,pkgManager:n,scopedAppName:a,noInstall:o,databaseProvider:t}),ke({projectName:e,scopedAppName:a,projectDir:i,pkgManager:n,packages:s,noInstall:o,databaseProvider:t}),Pe({packages:s,projectDir:i}),_e({packages:s,projectDir:i}),Se({packages:s,projectDir:i}),i}import{execSync as z}from"child_process";import V from"path";import{confirm as Ie}from"@inquirer/prompts";import T from"chalk";import{execa as D}from"execa";import Ae from"fs-extra";import pt from"ora";function ct(e){try{return z("git --version",{cwd:e}),!0}catch{return!1}}function K(e){return Ae.existsSync(V.join(e,".git"))}async function H(e){try{return await D("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}}function mt(){let a=z("git --version").toString().trim().split(" ")[2],s=a?.split(".")[0],o=a?.split(".")[1];return{major:Number(s),minor:Number(o)}}function dt(){return z("git config --global init.defaultBranch || echo main").toString().trim()}async function je(e){if(r.info("Initializing Git..."),!ct(e)){r.warn("Git is not installed. Skipping Git initialization.");return}let a=pt(`Creating a new git repo...
55
55
  `).start(),s=K(e),o=await H(e),t=V.parse(e).name;if(o&&s){if(a.stop(),!await Ie({message:`${T.redBright.bold("Warning:")} Git is already initialized in "${t}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,default:!1})){a.info("Skipping Git initialization.");return}Ae.removeSync(V.join(e,".git"))}else if(o&&!s&&(a.stop(),!await Ie({message:`${T.redBright.bold("Warning:")} "${t}" is already in a git worktree. Would you still like to initialize a new git repository in this directory?`,default:!1}))){a.info("Skipping Git initialization.");return}try{let n=dt(),{major:i,minor:l}=mt();i<2||i==2&&l<28?(await D("git",["init"],{cwd:e}),await D("git",["symbolic-ref","HEAD",`refs/heads/${n}`],{cwd:e})):await D("git",["init",`--initial-branch=${n}`],{cwd:e}),await D("git",["add","."],{cwd:e}),a.succeed(`${T.green("Successfully initialized and staged")} ${T.green.bold("git")}
56
56
  `)}catch{a.fail(`${T.bold.red("Failed:")} could not initialize git. Update git to the latest version!
57
57
  `)}}import ft from"chalk";import{execa as Ce}from"execa";import Oe from"ora";var Y=async(e,a,s)=>{let{onDataHandle:o,args:t=["install"],stdout:n="pipe"}=s,i=Oe(`Running ${a} install...`).start(),l=Ce(a,t,{cwd:e,stdout:n});return await new Promise((d,g)=>{o&&l.stdout?.on("data",o(i)),l.on("error",u=>g(u)),l.on("close",()=>d())}),i},gt=async(e,a)=>{switch(e){case"npm":return await Ce(e,["install"],{cwd:a,stderr:"inherit"}),null;case"pnpm":return Y(a,e,{onDataHandle:s=>o=>{let t=o.toString();t.includes("Progress")&&(s.text=t.includes("|")?t.split(" | ")[1]??"":t)}});case"yarn":return Y(a,e,{onDataHandle:s=>o=>{s.text=o.toString()}});case"bun":return Y(a,e,{stdout:"ignore"})}},Te=async({projectDir:e})=>{r.info("Installing dependencies...");let a=h();(await gt(a,e)??Oe()).succeed(ft.green(`Successfully installed dependencies!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-tnt-stack",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Create web application with the TNT-Powered stack",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,8 +11,9 @@ datasource db {
11
11
  }
12
12
 
13
13
  model Post {
14
- id String @id @default(cuid())
15
- name String
14
+ id String @id @default(cuid())
15
+ name String
16
+
16
17
  createdAt DateTime @default(now())
17
18
  updatedAt DateTime @updatedAt
18
19
 
@@ -15,14 +15,15 @@ datasource db {
15
15
  }
16
16
 
17
17
  model Post {
18
- id String @id @default(cuid())
19
- name String
20
- createdAt DateTime @default(now())
21
- updatedAt DateTime @updatedAt
18
+ id String @id @default(cuid())
19
+ name String
22
20
 
23
21
  createdBy User @relation(fields: [createdById], references: [id])
24
22
  createdById String
25
23
 
24
+ createdAt DateTime @default(now())
25
+ updatedAt DateTime @updatedAt
26
+
26
27
  @@index([name])
27
28
  }
28
29
 
@@ -0,0 +1,221 @@
1
+ import { fileURLToPath } from "url"
2
+ import { revalidatePath } from "next/cache"
3
+
4
+ import { auth, signIn, signOut } from "@/server/auth"
5
+ import { db } from "@/server/db"
6
+
7
+ export default async function HomePage() {
8
+ const session = await auth()
9
+ const user = session?.user
10
+
11
+ const posts = await db.post.findMany()
12
+
13
+ const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`
14
+
15
+ return (
16
+ <main className="mx-auto flex h-screen max-w-5xl flex-col items-center justify-between overflow-hidden p-6 sm:p-[45px]">
17
+ <header className="ml-auto">
18
+ {user ? (
19
+ <button
20
+ onClick={async () => {
21
+ "use server"
22
+ await signOut()
23
+ }}
24
+ className="cursor-pointer rounded-md bg-rose-400 px-4 py-2"
25
+ >
26
+ Sign Out
27
+ </button>
28
+ ) : (
29
+ <button
30
+ onClick={async () => {
31
+ "use server"
32
+ await signIn("discord")
33
+ }}
34
+ className="cursor-pointer rounded-md bg-purple-400 px-4 py-2"
35
+ >
36
+ Sign In
37
+ </button>
38
+ )}
39
+ </header>
40
+
41
+ <div className="flex grow flex-col items-center justify-center">
42
+ {/* Logo */}
43
+ <picture className="relative">
44
+ <div className="absolute inset-0 animate-pulse rounded-xl bg-gradient-to-r from-purple-500 to-cyan-500 opacity-20 blur-xl dark:from-purple-800 dark:to-cyan-800" />
45
+ <source srcSet="https://github.com/SlickYeet/create-tnt-stack/blob/main/docs/public/logo.light.png?raw=true" />
46
+ <img
47
+ src="https://github.com/SlickYeet/create-tnt-stack/blob/main/docs/public/logo.light.png?raw=true"
48
+ alt="Logo"
49
+ width={65}
50
+ height={65}
51
+ className="block h-auto max-w-full"
52
+ />
53
+ </picture>
54
+
55
+ <h1 className="mt-6 bg-gradient-to-r from-purple-500 to-cyan-500 bg-clip-text text-center text-4xl leading-10 text-transparent sm:text-5xl sm:leading-14 md:text-6xl md:leading-20 lg:mt-10 lg:text-7xl lg:font-bold">
56
+ TNT-Powered Next.js App
57
+ </h1>
58
+ <p className="mt-4 text-center text-lg text-neutral-700 md:text-xl lg:mt-6 dark:text-neutral-300">
59
+ Build modern web applications with today&apos;s most popular tools
60
+ </p>
61
+
62
+ <div className="mt-12 flex items-center gap-3">
63
+ <a
64
+ href="https://create.tntstack.org"
65
+ target="_blank"
66
+ rel="noopener noreferrer"
67
+ className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
68
+ >
69
+ Website
70
+ <svg
71
+ xmlns="http://www.w3.org/2000/svg"
72
+ viewBox="0 0 24 24"
73
+ strokeLinecap="round"
74
+ strokeLinejoin="round"
75
+ className="mb-1.5 size-4 fill-none stroke-current stroke-2"
76
+ >
77
+ <path d="M7 7h10v10" />
78
+ <path d="M7 17 17 7" />
79
+ </svg>
80
+ </a>
81
+ <a
82
+ href="https://create.tntstack.org/introduction"
83
+ target="_blank"
84
+ rel="noopener noreferrer"
85
+ className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
86
+ >
87
+ Docs
88
+ <svg
89
+ xmlns="http://www.w3.org/2000/svg"
90
+ viewBox="0 0 24 24"
91
+ strokeLinecap="round"
92
+ strokeLinejoin="round"
93
+ className="mb-1.5 size-4 fill-none stroke-current stroke-2"
94
+ >
95
+ <path d="M7 7h10v10" />
96
+ <path d="M7 17 17 7" />
97
+ </svg>
98
+ </a>
99
+ <a
100
+ href="https://github.com/SlickYeet/create-tnt-stack"
101
+ target="_blank"
102
+ rel="noopener noreferrer"
103
+ className="flex items-center rounded-md border border-white px-2 py-1 outline-none focus:opacity-80 active:opacity-70"
104
+ >
105
+ GitHub
106
+ <svg
107
+ xmlns="http://www.w3.org/2000/svg"
108
+ viewBox="0 0 24 24"
109
+ strokeLinecap="round"
110
+ strokeLinejoin="round"
111
+ className="mb-1.5 size-4 fill-none stroke-current stroke-2"
112
+ >
113
+ <path d="M7 7h10v10" />
114
+ <path d="M7 17 17 7" />
115
+ </svg>
116
+ </a>
117
+ </div>
118
+
119
+ <div className="mt-12 flex flex-col items-center gap-3">
120
+ <div className="mb-4">
121
+ <h1 className="mb-4 text-center">
122
+ <span className="text-2xl text-neutral-700 dark:text-neutral-300">
123
+ Posts {posts.length}
124
+ </span>
125
+ </h1>
126
+
127
+ {user && (
128
+ <form
129
+ action={async (formData: FormData) => {
130
+ "use server"
131
+
132
+ if (!user) throw new Error("Unauthorized")
133
+
134
+ const name =
135
+ formData.get("name")?.toString() ||
136
+ `New Post ${posts.length + 1}`
137
+
138
+ await db.post.create({
139
+ data: {
140
+ id: crypto.randomUUID(),
141
+ name,
142
+ createdBy: {
143
+ connect: {
144
+ id: user.id,
145
+ },
146
+ },
147
+ },
148
+ })
149
+
150
+ revalidatePath("/")
151
+ }}
152
+ >
153
+ <input
154
+ type="text"
155
+ name="name"
156
+ placeholder="New Post"
157
+ className="h-8 rounded-md border border-neutral-300 px-2 outline-none dark:border-neutral-700 dark:bg-neutral-800"
158
+ />
159
+ <button
160
+ type="submit"
161
+ className="ml-2 size-8 cursor-pointer rounded-md bg-neutral-200 outline-none hover:opacity-80 focus:opacity-80 dark:bg-neutral-800"
162
+ >
163
+ +
164
+ </button>
165
+ </form>
166
+ )}
167
+ </div>
168
+
169
+ <div className="grid w-full grid-cols-1 gap-2 space-y-2 sm:grid-cols-2">
170
+ {posts.map((post) => (
171
+ <div
172
+ key={post.id}
173
+ className="flex h-10 max-w-40 items-center rounded-md bg-neutral-200 px-2 py-1 dark:bg-neutral-800"
174
+ >
175
+ <span className="truncate text-sm text-neutral-700 dark:text-neutral-300">
176
+ {post.name}
177
+ </span>
178
+ {user && (
179
+ <form
180
+ action={async () => {
181
+ "use server"
182
+
183
+ if (!user) throw new Error("Unauthorized")
184
+
185
+ await db.post.delete({
186
+ where: {
187
+ id: post.id,
188
+ createdById: user.id,
189
+ },
190
+ })
191
+
192
+ revalidatePath("/")
193
+ }}
194
+ className="ml-auto"
195
+ >
196
+ <button
197
+ type="submit"
198
+ className="ml-2 cursor-pointer rounded-md text-rose-500 outline-none hover:opacity-80 focus:opacity-80"
199
+ >
200
+ x
201
+ </button>
202
+ </form>
203
+ )}
204
+ </div>
205
+ ))}
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <div className="flex flex-col items-center gap-1 text-sm text-neutral-600 lg:flex-row lg:gap-2 dark:text-neutral-400">
211
+ <p className="m-0">Get started by editing </p>
212
+ <a
213
+ href={fileURL}
214
+ className="rounded-md bg-neutral-200 px-2 py-1 dark:bg-neutral-800"
215
+ >
216
+ <code>src/app/page.tsx</code>
217
+ </a>
218
+ </div>
219
+ </main>
220
+ )
221
+ }