create-nxpress-app 1.0.6 → 1.0.8
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 +119 -117
- package/package.json +2 -1
- package/templates/app/index.ejs +92 -0
- package/templates/app/index.hbs +113 -0
- package/templates/app/index.html +76 -0
- package/templates/app/index.ts +38 -0
- package/templates/app/layout.ejs +39 -0
- package/templates/app/layout.hbs +37 -0
- package/templates/app.css +2 -0
- package/templates/public/logo.png +0 -0
- package/templates/server.ts +10 -0
package/dist/index.js
CHANGED
|
@@ -12,6 +12,40 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
12
12
|
const path_1 = __importDefault(require("path"));
|
|
13
13
|
const util_1 = require("util");
|
|
14
14
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
15
|
+
const deps = ["@nxpress/core"];
|
|
16
|
+
const devDeps = ["@types/express", "@types/node", "typescript"];
|
|
17
|
+
function getInstallCommands(pm, depsList, devDepsList) {
|
|
18
|
+
const depsStr = depsList.join(" ");
|
|
19
|
+
const devDepsStr = devDepsList.join(" ");
|
|
20
|
+
switch (pm) {
|
|
21
|
+
case "npm":
|
|
22
|
+
return {
|
|
23
|
+
depsCmd: `npm install ${depsStr}`,
|
|
24
|
+
devDepsCmd: `npm install -D ${devDepsStr}`,
|
|
25
|
+
};
|
|
26
|
+
case "yarn":
|
|
27
|
+
return {
|
|
28
|
+
depsCmd: `yarn add ${depsStr}`,
|
|
29
|
+
devDepsCmd: `yarn add -D ${devDepsStr}`,
|
|
30
|
+
};
|
|
31
|
+
case "bun":
|
|
32
|
+
return {
|
|
33
|
+
depsCmd: `bun add ${depsStr}`,
|
|
34
|
+
devDepsCmd: `bun add -d ${devDepsStr}`,
|
|
35
|
+
};
|
|
36
|
+
case "deno":
|
|
37
|
+
return {
|
|
38
|
+
depsCmd: `deno add ${depsStr}`,
|
|
39
|
+
devDepsCmd: `deno add -D ${devDepsStr}`,
|
|
40
|
+
};
|
|
41
|
+
case "pnpm":
|
|
42
|
+
default:
|
|
43
|
+
return {
|
|
44
|
+
depsCmd: `pnpm add ${depsStr}`,
|
|
45
|
+
devDepsCmd: `pnpm add -D ${devDepsStr}`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
15
49
|
const program = new commander_1.Command();
|
|
16
50
|
program
|
|
17
51
|
.name("create-nxpress-app")
|
|
@@ -23,7 +57,7 @@ program
|
|
|
23
57
|
.option("--app-dir <dir>", "Directory for application routes")
|
|
24
58
|
.option("--components-dir <dir>", "Directory for components")
|
|
25
59
|
.option("--public-dir <dir>", "Directory for static assets")
|
|
26
|
-
.option("--
|
|
60
|
+
.option("--pkg-manager <pm>", "Package manager (pnpm, npm, yarn, bun, deno)")
|
|
27
61
|
.action(async (projectDirArg, options) => {
|
|
28
62
|
console.log();
|
|
29
63
|
(0, prompts_1.intro)(chalk_1.default.bgCyan.black(" Create Nxpress App "));
|
|
@@ -135,17 +169,47 @@ program
|
|
|
135
169
|
publicDirName = pubRes;
|
|
136
170
|
}
|
|
137
171
|
}
|
|
138
|
-
let
|
|
139
|
-
if (
|
|
140
|
-
const
|
|
141
|
-
message: "
|
|
142
|
-
|
|
172
|
+
let pkgManager = options.pkgManager;
|
|
173
|
+
if (process.stdin.isTTY && !options.pkgManager) {
|
|
174
|
+
const selectedPm = await (0, prompts_1.select)({
|
|
175
|
+
message: "Which package manager do you want to use?",
|
|
176
|
+
options: [
|
|
177
|
+
{
|
|
178
|
+
value: "pnpm",
|
|
179
|
+
label: "pnpm (Default)",
|
|
180
|
+
hint: "Fast & disk space efficient",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
value: "npm",
|
|
184
|
+
label: "npm",
|
|
185
|
+
hint: "Default Node.js package manager",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
value: "yarn",
|
|
189
|
+
label: "yarn",
|
|
190
|
+
hint: "Classic/Berry package manager",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
value: "bun",
|
|
194
|
+
label: "bun",
|
|
195
|
+
hint: "Ultra-fast runtime & package manager",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
value: "deno",
|
|
199
|
+
label: "deno",
|
|
200
|
+
hint: "Modern JavaScript/TypeScript runtime",
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
initialValue: "pnpm",
|
|
143
204
|
});
|
|
144
|
-
if ((0, prompts_1.isCancel)(
|
|
205
|
+
if ((0, prompts_1.isCancel)(selectedPm)) {
|
|
145
206
|
(0, prompts_1.cancel)("Operation cancelled.");
|
|
146
207
|
process.exit(0);
|
|
147
208
|
}
|
|
148
|
-
|
|
209
|
+
pkgManager = selectedPm;
|
|
210
|
+
}
|
|
211
|
+
if (!pkgManager) {
|
|
212
|
+
pkgManager = "pnpm";
|
|
149
213
|
}
|
|
150
214
|
const s = (0, prompts_1.spinner)();
|
|
151
215
|
s.start("Scaffolding project...");
|
|
@@ -157,102 +221,47 @@ program
|
|
|
157
221
|
fs_extra_1.default.ensureDirSync(appDir);
|
|
158
222
|
fs_extra_1.default.ensureDirSync(componentsDir);
|
|
159
223
|
fs_extra_1.default.ensureDirSync(publicDir);
|
|
224
|
+
const templatesDir = path_1.default.resolve(__dirname, "..", "templates");
|
|
160
225
|
const ext = engine === "handlebars" ? "hbs" : engine;
|
|
161
|
-
//
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<meta charset="UTF-8">
|
|
179
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
180
|
-
<title><%= title %></title>
|
|
181
|
-
</head>
|
|
182
|
-
<body class="bg-slate-900 text-white min-h-screen">
|
|
183
|
-
<%- body %>
|
|
184
|
-
</body>
|
|
185
|
-
</html>`
|
|
186
|
-
: `<!DOCTYPE html>
|
|
187
|
-
<html lang="en">
|
|
188
|
-
<head>
|
|
189
|
-
<meta charset="UTF-8">
|
|
190
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
191
|
-
<title>Nxpress App</title>
|
|
192
|
-
</head>
|
|
193
|
-
<body class="bg-slate-900 text-white min-h-screen">
|
|
194
|
-
<!-- Content -->
|
|
195
|
-
</body>
|
|
196
|
-
</html>`;
|
|
197
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `layout.${ext}`), layoutContent);
|
|
198
|
-
// Index page
|
|
199
|
-
const indexPageContent = engine === "handlebars"
|
|
200
|
-
? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
|
|
201
|
-
<h1 class="text-5xl font-bold mb-4 bg-linear-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
|
|
202
|
-
Welcome to {{title}}
|
|
203
|
-
</h1>
|
|
204
|
-
<p class="text-xl text-slate-400 mb-8">{{description}}</p>
|
|
205
|
-
<div class="inline-block bg-slate-800 border border-slate-700 rounded-lg p-6 text-left">
|
|
206
|
-
<p class="text-sm font-mono text-cyan-400">Edit <span class="text-amber-300">${appDirName}/index.${ext}</span> to get started.</p>
|
|
207
|
-
</div>
|
|
208
|
-
</div>`
|
|
209
|
-
: engine === "ejs"
|
|
210
|
-
? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
|
|
211
|
-
<h1 class="text-5xl font-bold mb-4 bg-linear-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
|
|
212
|
-
Welcome to <%= title %>
|
|
213
|
-
</h1>
|
|
214
|
-
<p class="text-xl text-slate-400 mb-8"><%= description %></p>
|
|
215
|
-
<div class="inline-block bg-slate-800 border border-slate-700 rounded-lg p-6 text-left">
|
|
216
|
-
<p class="text-sm font-mono text-cyan-400">Edit <span class="text-amber-300">${appDirName}/index.${ext}</span> to get started.</p>
|
|
217
|
-
</div>
|
|
218
|
-
</div>`
|
|
219
|
-
: `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
|
|
220
|
-
<h1 class="text-5xl font-bold mb-4 bg-linear-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
|
|
221
|
-
Welcome to Nxpress
|
|
222
|
-
</h1>
|
|
223
|
-
<p class="text-xl text-slate-400 mb-8">Express.js with Next.js developer experience</p>
|
|
224
|
-
</div>`;
|
|
225
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `index.${ext}`), indexPageContent);
|
|
226
|
+
// Copy public assets (e.g., logo.png)
|
|
227
|
+
const templatePublicDir = path_1.default.join(templatesDir, "public");
|
|
228
|
+
if (fs_extra_1.default.existsSync(templatePublicDir)) {
|
|
229
|
+
fs_extra_1.default.copySync(templatePublicDir, publicDir);
|
|
230
|
+
}
|
|
231
|
+
// Root layout from template
|
|
232
|
+
const layoutTemplatePath = path_1.default.join(templatesDir, "app", `layout.${ext}`);
|
|
233
|
+
if (fs_extra_1.default.existsSync(layoutTemplatePath)) {
|
|
234
|
+
fs_extra_1.default.copySync(layoutTemplatePath, path_1.default.join(appDir, `layout.${ext}`));
|
|
235
|
+
}
|
|
236
|
+
// Index page from template
|
|
237
|
+
const indexTemplatePath = path_1.default.join(templatesDir, "app", `index.${ext}`);
|
|
238
|
+
if (fs_extra_1.default.existsSync(indexTemplatePath)) {
|
|
239
|
+
let content = fs_extra_1.default.readFileSync(indexTemplatePath, "utf8");
|
|
240
|
+
content = content.replace(/app\/index\.(hbs|ejs|html)/g, `${appDirName}/index.${ext}`);
|
|
241
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `index.${ext}`), content);
|
|
242
|
+
}
|
|
226
243
|
// Data loader for index page
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
title: 'Nxpress App',
|
|
232
|
-
description: 'Express.js with Next.js developer experience',
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
`;
|
|
236
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(appDir, "index.ts"), indexTsContent);
|
|
244
|
+
const indexTsTemplatePath = path_1.default.join(templatesDir, "app", "index.ts");
|
|
245
|
+
if (fs_extra_1.default.existsSync(indexTsTemplatePath)) {
|
|
246
|
+
fs_extra_1.default.copySync(indexTsTemplatePath, path_1.default.join(appDir, "index.ts"));
|
|
247
|
+
}
|
|
237
248
|
// App CSS for Tailwind v4
|
|
238
|
-
|
|
249
|
+
const appCssTemplatePath = path_1.default.join(templatesDir, "app.css");
|
|
250
|
+
if (fs_extra_1.default.existsSync(appCssTemplatePath)) {
|
|
251
|
+
fs_extra_1.default.copySync(appCssTemplatePath, path_1.default.join(targetPath, "app.css"));
|
|
252
|
+
}
|
|
239
253
|
// Server file
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
console.log(\`Nxpress server running on http://localhost:\${PORT}\`);
|
|
249
|
-
});
|
|
250
|
-
`;
|
|
251
|
-
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "server.ts"), serverTsContent);
|
|
252
|
-
const pkgVersion = "1.0.5";
|
|
254
|
+
const serverTsTemplatePath = path_1.default.join(templatesDir, "server.ts");
|
|
255
|
+
if (fs_extra_1.default.existsSync(serverTsTemplatePath)) {
|
|
256
|
+
let serverContent = fs_extra_1.default.readFileSync(serverTsTemplatePath, "utf8");
|
|
257
|
+
serverContent = serverContent
|
|
258
|
+
.replace("{{ENGINE}}", engine === "handlebars" ? "hbs" : engine)
|
|
259
|
+
.replace("{{PORT}}", port.toString());
|
|
260
|
+
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "server.ts"), serverContent);
|
|
261
|
+
}
|
|
253
262
|
// nxpress.config.json
|
|
254
263
|
const nxConfig = {
|
|
255
|
-
$schema: `https://unpkg.com/@nxpress/core
|
|
264
|
+
$schema: `https://unpkg.com/@nxpress/core@latest/schema.json`,
|
|
256
265
|
port,
|
|
257
266
|
engine: engine === "handlebars" ? "hbs" : engine,
|
|
258
267
|
appDir: appDirName,
|
|
@@ -270,14 +279,6 @@ app.listen(PORT, () => {
|
|
|
270
279
|
build: "tsc",
|
|
271
280
|
start: "nxpress start",
|
|
272
281
|
},
|
|
273
|
-
dependencies: {
|
|
274
|
-
"@nxpress/core": `^${pkgVersion}`,
|
|
275
|
-
},
|
|
276
|
-
devDependencies: {
|
|
277
|
-
"@types/express": "^5.0.6",
|
|
278
|
-
"@types/node": "^26.1.1",
|
|
279
|
-
typescript: "^7.0.2",
|
|
280
|
-
},
|
|
281
282
|
};
|
|
282
283
|
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "package.json"), JSON.stringify(projectPkgJson, null, 2));
|
|
283
284
|
// tsconfig.json for target project
|
|
@@ -303,20 +304,21 @@ dist
|
|
|
303
304
|
`;
|
|
304
305
|
fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, ".gitignore"), gitignoreContent);
|
|
305
306
|
s.stop("Project structure created successfully.");
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
307
|
+
const instSpinner = (0, prompts_1.spinner)();
|
|
308
|
+
instSpinner.start(`Installing dependencies with ${pkgManager}...`);
|
|
309
|
+
try {
|
|
310
|
+
const { depsCmd, devDepsCmd } = getInstallCommands(pkgManager, deps, devDeps);
|
|
311
|
+
await execAsync(depsCmd, { cwd: targetPath });
|
|
312
|
+
await execAsync(devDepsCmd, { cwd: targetPath });
|
|
313
|
+
instSpinner.stop("Dependencies installed successfully.");
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
instSpinner.stop("Failed to install dependencies automatically.");
|
|
316
317
|
}
|
|
318
|
+
const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
|
|
317
319
|
(0, prompts_1.outro)(`Project created in ${chalk_1.default.cyan(projectDir)}!\n\n` +
|
|
318
320
|
`Next steps:\n` +
|
|
319
321
|
` ${chalk_1.default.cyan(`cd ${projectDir}`)}\n` +
|
|
320
|
-
` ${chalk_1.default.cyan(
|
|
322
|
+
` ${chalk_1.default.cyan(devCmd)}`);
|
|
321
323
|
});
|
|
322
324
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nxpress-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "CLI tool to create Nxpress applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"fs-extra": "^11.4.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
+
"@types/express": "^5.0.6",
|
|
31
32
|
"@types/fs-extra": "^11.0.4",
|
|
32
33
|
"@types/node": "^26.1.1",
|
|
33
34
|
"typescript": "^7.0.2"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<div class="min-h-screen flex flex-col justify-between max-w-6xl mx-auto px-6 py-8">
|
|
2
|
+
<header class="flex items-center justify-between py-4 border-b border-slate-800/80">
|
|
3
|
+
<div class="flex items-center gap-3">
|
|
4
|
+
<span class="font-bold text-lg text-slate-100 tracking-tight">Nxpress</span>
|
|
5
|
+
<span
|
|
6
|
+
class="text-xs font-mono px-2 py-0.5 rounded-full bg-indigo-500/10 text-indigo-400 border border-indigo-500/20 font-medium">
|
|
7
|
+
v<%= version %>
|
|
8
|
+
</span>
|
|
9
|
+
</div>
|
|
10
|
+
<% if (!E.NODE_ENV || E.NODE_ENV.toLowerCase() !=='prod' ) { %>
|
|
11
|
+
<div class="flex items-center gap-2">
|
|
12
|
+
<span
|
|
13
|
+
class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
|
14
|
+
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
|
|
15
|
+
Dev Server Active
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
18
|
+
<% } %>
|
|
19
|
+
</header>
|
|
20
|
+
|
|
21
|
+
<main class="py-16 md:py-24 text-center my-auto">
|
|
22
|
+
<div class="flex justify-center mb-6">
|
|
23
|
+
<img src="/logo.png" alt="Nxpress"
|
|
24
|
+
class="w-16 h-16 sm:w-20 sm:h-20 object-contain drop-shadow-[0_0_25px_rgba(99,102,241,0.5)] transition-transform hover:scale-105 duration-300" />
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<h1
|
|
28
|
+
class="text-4xl sm:text-6xl md:text-7xl font-extrabold tracking-tight text-white mb-6 max-w-4xl mx-auto leading-[1.1]">
|
|
29
|
+
Build fast Node apps with
|
|
30
|
+
<span class="bg-linear-to-r from-indigo-400 via-sky-400 to-cyan-300 bg-clip-text text-transparent">
|
|
31
|
+
<%= title %>
|
|
32
|
+
</span>
|
|
33
|
+
</h1>
|
|
34
|
+
|
|
35
|
+
<p class="text-lg sm:text-xl text-slate-400 max-w-2xl mx-auto mb-10 leading-relaxed">
|
|
36
|
+
<%= description %>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<div class="max-w-xl mx-auto mb-16">
|
|
40
|
+
<div
|
|
41
|
+
class="group relative rounded-2xl bg-linear-to-b from-slate-800/80 to-slate-900/90 border border-slate-700/80 p-5 shadow-2xl backdrop-blur-md transition-all hover:border-indigo-500/40">
|
|
42
|
+
<div
|
|
43
|
+
class="flex items-center justify-between mb-3 text-xs text-slate-400 font-mono border-b border-slate-800 pb-3">
|
|
44
|
+
<div class="flex items-center gap-2">
|
|
45
|
+
<span class="w-3 h-3 rounded-full bg-rose-500/80 inline-block"></span>
|
|
46
|
+
<span class="w-3 h-3 rounded-full bg-amber-500/80 inline-block"></span>
|
|
47
|
+
<span class="w-3 h-3 rounded-full bg-emerald-500/80 inline-block"></span>
|
|
48
|
+
<span class="ml-2 text-slate-500">app/index.ejs</span>
|
|
49
|
+
</div>
|
|
50
|
+
<span class="text-indigo-400 font-sans text-[11px] font-semibold tracking-wide uppercase">Quick Start</span>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="text-left font-mono text-sm py-2">
|
|
53
|
+
<p class="text-slate-300">
|
|
54
|
+
<span class="text-purple-400">Edit</span>
|
|
55
|
+
<span
|
|
56
|
+
class="text-emerald-300 px-1.5 py-0.5 rounded bg-slate-800 border border-slate-700">app/index.ejs</span>
|
|
57
|
+
<span class="text-slate-400">to customize this page.</span>
|
|
58
|
+
</p>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 max-w-4xl mx-auto text-left">
|
|
64
|
+
<% features.forEach(function(feat) { %>
|
|
65
|
+
<div
|
|
66
|
+
class="p-6 rounded-2xl bg-slate-900/50 border border-slate-800/80 hover:border-slate-700 transition-all duration-200 group">
|
|
67
|
+
<div class="flex items-center justify-between mb-3">
|
|
68
|
+
<span
|
|
69
|
+
class="text-xs font-semibold px-2.5 py-1 rounded-md bg-slate-800 text-indigo-400 border border-slate-700/50">
|
|
70
|
+
<%= feat.tag %>
|
|
71
|
+
</span>
|
|
72
|
+
<span class="text-slate-600 group-hover:text-slate-400 transition-colors text-sm">→</span>
|
|
73
|
+
</div>
|
|
74
|
+
<h3 class="text-base font-bold text-slate-100 mb-1.5 group-hover:text-indigo-300 transition-colors">
|
|
75
|
+
<%= feat.title %>
|
|
76
|
+
</h3>
|
|
77
|
+
<p class="text-sm text-slate-400 leading-relaxed">
|
|
78
|
+
<%= feat.desc %>
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
<% }); %>
|
|
82
|
+
</div>
|
|
83
|
+
</main>
|
|
84
|
+
|
|
85
|
+
<footer
|
|
86
|
+
class="py-6 border-t border-slate-800/60 text-center text-xs text-slate-500 flex flex-col sm:flex-row items-center justify-between gap-3">
|
|
87
|
+
<p>Powered by <span class="text-slate-300 font-medium">Nxpress</span></p>
|
|
88
|
+
<p class="font-mono text-slate-600">
|
|
89
|
+
<%= R.base %>
|
|
90
|
+
</p>
|
|
91
|
+
</footer>
|
|
92
|
+
</div>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<div class="min-h-screen flex flex-col justify-between max-w-6xl mx-auto px-6 py-8">
|
|
2
|
+
<!-- Top Navigation -->
|
|
3
|
+
<header class="flex items-center justify-between py-4 border-b border-slate-800/80">
|
|
4
|
+
<div class="flex items-center gap-3">
|
|
5
|
+
<span class="font-bold text-lg text-slate-100 tracking-tight">
|
|
6
|
+
Nxpress
|
|
7
|
+
</span>
|
|
8
|
+
<span
|
|
9
|
+
class="text-xs font-mono px-2 py-0.5 rounded-full bg-indigo-500/10 text-indigo-400 border border-indigo-500/20 font-medium">
|
|
10
|
+
v{{version}}
|
|
11
|
+
</span>
|
|
12
|
+
</div>
|
|
13
|
+
{{#if (ne (lower E.NODE_ENV) 'prod')}}
|
|
14
|
+
<div class="flex items-center gap-2">
|
|
15
|
+
<span
|
|
16
|
+
class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
|
17
|
+
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
|
|
18
|
+
Dev Server Active
|
|
19
|
+
</span>
|
|
20
|
+
</div>
|
|
21
|
+
{{/if}}
|
|
22
|
+
</header>
|
|
23
|
+
|
|
24
|
+
<!-- Hero Section -->
|
|
25
|
+
<main class="py-16 md:py-24 text-center my-auto">
|
|
26
|
+
<div class="flex justify-center mb-6">
|
|
27
|
+
<img src="/logo.png" alt="Nxpress"
|
|
28
|
+
class="w-16 h-16 sm:w-20 sm:h-20 object-contain drop-shadow-[0_0_25px_rgba(99,102,241,0.5)] transition-transform hover:scale-105 duration-300" />
|
|
29
|
+
</div>
|
|
30
|
+
<h1
|
|
31
|
+
class="text-4xl sm:text-6xl md:text-7xl font-extrabold tracking-tight text-white mb-6 max-w-4xl mx-auto leading-[1.1]">
|
|
32
|
+
Build fast Node apps with
|
|
33
|
+
<span class="bg-linear-to-r from-indigo-400 via-sky-400 to-cyan-300 bg-clip-text text-transparent">
|
|
34
|
+
{{title}}
|
|
35
|
+
</span>
|
|
36
|
+
</h1>
|
|
37
|
+
<p class="text-lg sm:text-xl text-slate-400 max-w-2xl mx-auto mb-10 leading-relaxed">
|
|
38
|
+
{{description}}
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
<!-- Code Snippet Card -->
|
|
42
|
+
<div class="max-w-xl mx-auto mb-16">
|
|
43
|
+
<div
|
|
44
|
+
class="group relative rounded-2xl bg-linear-to-b from-slate-800/80 to-slate-900/90 border border-slate-700/80 p-5 shadow-2xl backdrop-blur-md transition-all hover:border-indigo-500/40">
|
|
45
|
+
<div
|
|
46
|
+
class="flex items-center justify-between mb-3 text-xs text-slate-400 font-mono border-b border-slate-800 pb-3">
|
|
47
|
+
<div class="flex items-center gap-2">
|
|
48
|
+
<span class="w-3 h-3 rounded-full bg-rose-500/80 inline-block"></span>
|
|
49
|
+
<span class="w-3 h-3 rounded-full bg-amber-500/80 inline-block"></span>
|
|
50
|
+
<span class="w-3 h-3 rounded-full bg-emerald-500/80 inline-block"></span>
|
|
51
|
+
<span class="ml-2 text-slate-500">
|
|
52
|
+
app/index.hbs
|
|
53
|
+
</span>
|
|
54
|
+
</div>
|
|
55
|
+
<span class="text-indigo-400 font-sans text-[11px] font-semibold tracking-wide uppercase">
|
|
56
|
+
Quick Start
|
|
57
|
+
</span>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="text-left font-mono text-sm py-2">
|
|
60
|
+
<p class="text-slate-300">
|
|
61
|
+
<span class="text-purple-400">
|
|
62
|
+
Edit
|
|
63
|
+
</span>
|
|
64
|
+
<span class="text-emerald-300 px-1.5 py-0.5 rounded bg-slate-800 border border-slate-700">
|
|
65
|
+
app/index.hbs
|
|
66
|
+
</span>
|
|
67
|
+
<span class="text-slate-400">
|
|
68
|
+
to customize this page.
|
|
69
|
+
</span>
|
|
70
|
+
</p>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<!-- Feature Grid -->
|
|
76
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 max-w-4xl mx-auto text-left">
|
|
77
|
+
{{#each features}}
|
|
78
|
+
<div
|
|
79
|
+
class="p-6 rounded-2xl bg-slate-900/50 border border-slate-800/80 hover:border-slate-700 transition-all duration-200 group">
|
|
80
|
+
<div class="flex items-center justify-between mb-3">
|
|
81
|
+
<span
|
|
82
|
+
class="text-xs font-semibold px-2.5 py-1 rounded-md bg-slate-800 text-indigo-400 border border-slate-700/50">
|
|
83
|
+
{{this.tag}}
|
|
84
|
+
</span>
|
|
85
|
+
<span class="text-slate-600 group-hover:text-slate-400 transition-colors text-sm">
|
|
86
|
+
→
|
|
87
|
+
</span>
|
|
88
|
+
</div>
|
|
89
|
+
<h3 class="text-base font-bold text-slate-100 mb-1.5 group-hover:text-indigo-300 transition-colors">
|
|
90
|
+
{{this.title}}
|
|
91
|
+
</h3>
|
|
92
|
+
<p class="text-sm text-slate-400 leading-relaxed">
|
|
93
|
+
{{this.desc}}
|
|
94
|
+
</p>
|
|
95
|
+
</div>
|
|
96
|
+
{{/each}}
|
|
97
|
+
</div>
|
|
98
|
+
</main>
|
|
99
|
+
|
|
100
|
+
<!-- Footer -->
|
|
101
|
+
<footer
|
|
102
|
+
class="py-6 border-t border-slate-800/60 text-center text-xs text-slate-500 flex flex-col sm:flex-row items-center justify-between gap-3">
|
|
103
|
+
<p>
|
|
104
|
+
Powered by
|
|
105
|
+
<span class="text-slate-300 font-medium">
|
|
106
|
+
Nxpress
|
|
107
|
+
</span>
|
|
108
|
+
</p>
|
|
109
|
+
<p class="font-mono text-slate-600">
|
|
110
|
+
{{R.base}}
|
|
111
|
+
</p>
|
|
112
|
+
</footer>
|
|
113
|
+
</div>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="dark h-full">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta name="description" content="Express.js speed with Next.js developer experience.">
|
|
8
|
+
<title>Nxpress App</title>
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link
|
|
12
|
+
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap"
|
|
13
|
+
rel="stylesheet">
|
|
14
|
+
<link rel="stylesheet" href="/tailwind.css">
|
|
15
|
+
<style>
|
|
16
|
+
body {
|
|
17
|
+
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
code,
|
|
21
|
+
pre {
|
|
22
|
+
font-family: 'JetBrains Mono', monospace;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
</head>
|
|
26
|
+
|
|
27
|
+
<body
|
|
28
|
+
class="bg-[#0b0f19] text-slate-100 min-h-full antialiased selection:bg-indigo-500 selection:text-white relative overflow-x-hidden">
|
|
29
|
+
<div
|
|
30
|
+
class="pointer-events-none absolute top-0 left-1/2 -translate-x-1/2 w-full max-w-7xl h-125 bg-radial from-indigo-500/15 via-purple-500/5 to-transparent blur-3xl -z-10">
|
|
31
|
+
</div>
|
|
32
|
+
<div class="pointer-events-none absolute top-1/3 right-10 w-96 h-96 bg-blue-500/10 rounded-full blur-3xl -z-10"></div>
|
|
33
|
+
|
|
34
|
+
<!-- Content -->
|
|
35
|
+
<div class="min-h-screen flex flex-col justify-between max-w-6xl mx-auto px-6 py-8">
|
|
36
|
+
<header class="flex items-center justify-between py-4 border-b border-slate-800/80">
|
|
37
|
+
<div class="flex items-center gap-3">
|
|
38
|
+
<span class="font-bold text-lg text-slate-100 tracking-tight">Nxpress</span>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="flex items-center gap-2">
|
|
41
|
+
<span
|
|
42
|
+
class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-medium bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
|
43
|
+
<span class="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse"></span>
|
|
44
|
+
Dev Server Active
|
|
45
|
+
</span>
|
|
46
|
+
</div>
|
|
47
|
+
</header>
|
|
48
|
+
|
|
49
|
+
<main class="py-16 md:py-24 text-center my-auto">
|
|
50
|
+
<div class="flex justify-center mb-6">
|
|
51
|
+
<img src="/logo.png" alt="Nxpress"
|
|
52
|
+
class="w-16 h-16 sm:w-20 sm:h-20 object-contain drop-shadow-[0_0_25px_rgba(99,102,241,0.5)] transition-transform hover:scale-105 duration-300" />
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<h1
|
|
56
|
+
class="text-4xl sm:text-6xl md:text-7xl font-extrabold tracking-tight text-white mb-6 max-w-4xl mx-auto leading-[1.1]">
|
|
57
|
+
Welcome to
|
|
58
|
+
<span class="bg-linear-to-r from-indigo-400 via-sky-400 to-cyan-300 bg-clip-text text-transparent">
|
|
59
|
+
Nxpress
|
|
60
|
+
</span>
|
|
61
|
+
</h1>
|
|
62
|
+
|
|
63
|
+
<p class="text-lg sm:text-xl text-slate-400 max-w-2xl mx-auto mb-10 leading-relaxed">
|
|
64
|
+
Express.js speed with Next.js developer experience.
|
|
65
|
+
</p>
|
|
66
|
+
</main>
|
|
67
|
+
|
|
68
|
+
<footer
|
|
69
|
+
class="py-6 border-t border-slate-800/60 text-center text-xs text-slate-500 flex flex-col sm:flex-row items-center justify-between gap-3">
|
|
70
|
+
<p>Powered by <span class="text-slate-300 font-medium">Nxpress</span></p>
|
|
71
|
+
</footer>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
</body>
|
|
75
|
+
|
|
76
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Request, Response } from "express";
|
|
2
|
+
|
|
3
|
+
export async function props(req: Request, res: Response) {
|
|
4
|
+
let version = "1.0.8";
|
|
5
|
+
try {
|
|
6
|
+
const f = await fetch("https://registry.npmjs.org/@nxpress/core/latest");
|
|
7
|
+
version = (await f.json()).version;
|
|
8
|
+
} catch (err) {
|
|
9
|
+
console.error("Getting Nxpress version failed.", err);
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
title: "Nxpress Framework",
|
|
13
|
+
version: version,
|
|
14
|
+
description: "Express.js speed with Next.js developer experience.",
|
|
15
|
+
features: [
|
|
16
|
+
{
|
|
17
|
+
title: "File-Based Routing",
|
|
18
|
+
desc: "Automatic route handling mapped to the app directory structure.",
|
|
19
|
+
tag: "Zero Config",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
title: "Server Data Props",
|
|
23
|
+
desc: "Export props functions in route files for SSR data loading.",
|
|
24
|
+
tag: "SSR Ready",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
title: "Tailwind CSS Integration",
|
|
28
|
+
desc: "Modern styling out of the box with zero boilerplate.",
|
|
29
|
+
tag: "Styling",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
title: "Fast Handlebars Engine",
|
|
33
|
+
desc: "Dynamic server rendering with seamless layout templates.",
|
|
34
|
+
tag: "Templating",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="dark h-full">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta name="description" content="<%= description %>">
|
|
8
|
+
<title>
|
|
9
|
+
<%= title %>
|
|
10
|
+
</title>
|
|
11
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
|
+
<link
|
|
14
|
+
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap"
|
|
15
|
+
rel="stylesheet">
|
|
16
|
+
<link rel="stylesheet" href="/tailwind.css">
|
|
17
|
+
<style>
|
|
18
|
+
body {
|
|
19
|
+
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
code,
|
|
23
|
+
pre {
|
|
24
|
+
font-family: 'JetBrains Mono', monospace;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
|
|
29
|
+
<body
|
|
30
|
+
class="bg-[#0b0f19] text-slate-100 min-h-full antialiased selection:bg-indigo-500 selection:text-white relative overflow-x-hidden">
|
|
31
|
+
<div
|
|
32
|
+
class="pointer-events-none absolute top-0 left-1/2 -translate-x-1/2 w-full max-w-7xl h-125 bg-radial from-indigo-500/15 via-purple-500/5 to-transparent blur-3xl -z-10">
|
|
33
|
+
</div>
|
|
34
|
+
<div class="pointer-events-none absolute top-1/3 right-10 w-96 h-96 bg-blue-500/10 rounded-full blur-3xl -z-10"></div>
|
|
35
|
+
|
|
36
|
+
<%- body %>
|
|
37
|
+
</body>
|
|
38
|
+
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="dark h-full">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<meta name="description" content="{{description}}">
|
|
8
|
+
<title>{{title}}</title>
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link
|
|
12
|
+
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap"
|
|
13
|
+
rel="stylesheet">
|
|
14
|
+
<link rel="stylesheet" href="/tailwind.css">
|
|
15
|
+
<style>
|
|
16
|
+
body {
|
|
17
|
+
font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
code,
|
|
21
|
+
pre {
|
|
22
|
+
font-family: 'JetBrains Mono', monospace;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
</head>
|
|
26
|
+
|
|
27
|
+
<body
|
|
28
|
+
class="bg-[#0b0f19] text-slate-100 min-h-full antialiased selection:bg-indigo-500 selection:text-white relative overflow-x-hidden">
|
|
29
|
+
<div
|
|
30
|
+
class="pointer-events-none absolute top-0 left-1/2 -translate-x-1/2 w-full max-w-7xl h-125 bg-radial from-indigo-500/15 via-purple-500/5 to-transparent blur-3xl -z-10">
|
|
31
|
+
</div>
|
|
32
|
+
<div class="pointer-events-none absolute top-1/3 right-10 w-96 h-96 bg-blue-500/10 rounded-full blur-3xl -z-10"></div>
|
|
33
|
+
|
|
34
|
+
{{{body}}}
|
|
35
|
+
</body>
|
|
36
|
+
|
|
37
|
+
</html>
|
|
Binary file
|