Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


![CI](https://github.com/msz-tech/create-nexter/actions/workflows/ci.yaml/badge.svg?branch=main&style=flat-square)
![npm version](https://img.shields.io/npm/v/create-nexter)
[![npm version](https://img.shields.io/npm/v/create-nexter?style=flat-square)](https://www.npmjs.com/package/create-nexter)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)

## Table of Contents
Expand Down
38 changes: 22 additions & 16 deletions src/generators/projectGenerator.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import path from 'path';
import { fileURLToPath } from 'url';
import spawn from 'cross-spawn';
import { copyTemplateFiles } from '../utils/copyTemplateFiles.js';

// Pour __dirname avec ESModules
const __dirname = path.dirname(fileURLToPath(import.meta.url));

export default function generateProject(language, projectName) {
return new Promise((resolve, reject) => {

const args = [
'create-next-app@15.4.1',
projectName,
language === 'ts' ? '--typescript' : '--javascript',
'--no-tailwind', // Ne pas installer tailwind par défaut
'--no-tailwind',
'--eslint',
'--src-dir',
'--no-app',
Expand All @@ -20,6 +19,8 @@ export default function generateProject(language, projectName) {
'--yes',
];

console.log(`🚀 Creating Next.js project (${language}) named '${projectName}'...`);

const cmd = 'npx';
const child = spawn(cmd, args, { stdio: 'inherit' });

Expand All @@ -30,25 +31,30 @@ export default function generateProject(language, projectName) {

console.log('📦 Installing TailwindCSS and PostCSS plugins...');

// Installer tailwindcss + plugins PostCSS obligatoires
const extraDeps = [
'tailwindcss@3.3.2',
'postcss@8.4.21',
'autoprefixer@10.4.14',
'lucide-react'
];
const extraDeps = [
'tailwindcss@3.3.2',
'postcss@8.4.21',
'autoprefixer@10.4.14',
'lucide-react',
];

const install = spawn('npm', ['install', '-D', ...extraDeps], {
cwd: path.resolve(projectName),
stdio: 'inherit',
});

install.on('close', (installCode) => {
if (installCode === 0) {
console.log('✅ TailwindCSS and PostCSS plugins installed.');
install.on('close', async (installCode) => {
if (installCode !== 0) {
return reject(new Error('❌ Failed to install TailwindCSS/PostCSS plugins.'));
}

try {
console.log(`📁 Copying template files for language: ${language}...`);
await copyTemplateFiles(path.resolve(projectName), language);
console.log('✅ Project generation complete!');
resolve();
} else {
reject(new Error('❌ Failed to install TailwindCSS/PostCSS plugins.'));
} catch (error) {
reject(new Error(`❌ Error copying template files: ${error.message}`));
}
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default async function main() {

await cleanProject(projectName, language);

await copyTemplateFiles(projectName);
await copyTemplateFiles(projectName, language);



Expand Down
2 changes: 1 addition & 1 deletion src/ui/cliWelcome.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ export function displayWelcome() {

console.log(gradient.pastel.multiline(msg));
console.log(chalk.cyanBright('Welcome to create-nexter CLI!\n'));
console.log(chalk.white('Effortless Next.js project scaffolding, built for scalable and maintainable applications.\n'));
console.log(chalk.white('Effortless Next.js project scaffolding, built for scalable and maintainable applications.\n'));
}
30 changes: 24 additions & 6 deletions src/utils/copyTemplateFiles.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
import path from 'path';
import fsExtra from 'fs-extra';
const { copy, readdir } = fsExtra;
const { copy, readdir, pathExists } = fsExtra;
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export async function copyTemplateFiles(targetDir) {
const templateDir = path.join(__dirname, '../../templates');
console.log('Template dir:', templateDir);
console.log('Target dir:', targetDir);
/**
* Copy template files based on the selected language (ts or js)
* @param {string} targetDir - The directory where the template files will be copied
* @param {string} language - 'ts' or 'js' to select the appropriate template folder
*/
export async function copyTemplateFiles(targetDir, language) {
if (!['ts', 'js'].includes(language)) {
throw new Error(`Invalid language '${language}'. Expected 'ts' or 'js'.`);
}

const templateDir = path.join(__dirname, '../../templates', language);

const exists = await pathExists(templateDir);
if (!exists) {
throw new Error(`Template directory does not exist: ${templateDir}`);
}

console.log(`[copyTemplateFiles] Copying template for language: ${language}`);
console.log(`[copyTemplateFiles] From: ${templateDir}`);
console.log(`[copyTemplateFiles] To: ${targetDir}`);

const files = await readdir(templateDir);
console.log('Files in templateDir:', files);
console.log(`[copyTemplateFiles] Files to copy: ${files.join(', ')}`);

await copy(templateDir, targetDir, {
overwrite: true,
recursive: true,
});

console.log(`[copyTemplateFiles] Copy completed successfully.`);
}
File renamed without changes.
5 changes: 5 additions & 0 deletions templates/js/src/pages/_app.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import "../styles/global.css";

export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
9 changes: 9 additions & 0 deletions templates/js/src/pages/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Hero } from "../components/Hero";

export default function Home() {
return (
<main className="min-h-screen bg-white">
<Hero />
</main>
);
}
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions templates/ts/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
43 changes: 43 additions & 0 deletions templates/ts/src/components/Hero/Hero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Github, BookOpen } from "lucide-react";

export default function Hero() {
return (
<section className="relative min-h-screen flex flex-col items-center justify-center text-center px-6 bg-gradient-to-br from-sky-50 via-blue-100 to-white overflow-hidden">
{/* Background Blur Circles */}
<div className="absolute -top-32 -left-32 w-[400px] h-[400px] bg-sky-200 opacity-30 rounded-full blur-3xl"></div>
<div className="absolute bottom-0 right-0 w-[300px] h-[300px] bg-blue-300 opacity-20 rounded-full blur-2xl"></div>

{/* Main Content */}
<div className="relative z-10 max-w-2xl">
<div className="mb-6 inline-flex items-center justify-center w-16 h-16 rounded-full bg-blue-100 text-blue-600 font-bold text-xl shadow-md">
NX
</div>

<h1 className="text-4xl md:text-5xl font-bold text-slate-900 mb-4">
Create Nexter
</h1>

<p className="text-slate-600 text-lg md:text-xl mb-8">
Kickstart your next project with <strong>Next.js 15</strong> and <strong>Tailwind CSS 3.3.2</strong>. No config, just code.
</p>

<div className="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="#"
className="inline-flex items-center justify-center px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md shadow transition"
>
<BookOpen className="mr-2 h-5 w-5" />
Get Started
</a>
<a
href="#"
className="inline-flex items-center justify-center px-6 py-3 border border-blue-600 text-blue-600 hover:bg-blue-50 font-medium rounded-md transition"
>
<Github className="mr-2 h-5 w-5" />
View on GitHub
</a>
</div>
</div>
</section>
);
}
1 change: 1 addition & 0 deletions templates/ts/src/components/Hero/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Hero } from './Hero';
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions templates/ts/src/styles/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* Import Google Fonts Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;


body {
font-family: 'Poppins', ui-sans-serif, system-ui, sans-serif;
}
25 changes: 25 additions & 0 deletions templates/ts/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx}",
"./src/components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
primary: {
light: '#E0F2FE',
dark: '#0F172A',
accent: '#38BDF8',
},
},
backgroundImage: {
'hero-gradient': 'linear-gradient(135deg, #e0f2fe 0%, #bae6fd 50%, #f0f9ff 100%)',
},
fontFamily: {
sans: ['Poppins', 'ui-sans-serif', 'system-ui'],
},
},
},
plugins: [],
};
Loading