Skip to content

Commit

Permalink
CLI: Support template for Tailwind CSS + Next Docs MDX
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama committed Dec 30, 2023
1 parent db840c2 commit 579ecaa
Show file tree
Hide file tree
Showing 39 changed files with 760 additions and 155 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-walls-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-next-docs-app': minor
---

Support template for Tailwind CSS + Next Docs MDX
5 changes: 2 additions & 3 deletions apps/docs/content/docs/ui/commands/create-next-docs-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ yarn create next-docs-app

### Options

You can choose one of two examples: `simple` and `advanced`.
You can choose a built-in content source, including Contentlayer and Next Docs MDX.

- Simple: with Typescript and Next.js
- Advanced: with Tailwind CSS, Typescript and Next.js
It can also configure Tailwind CSS for styling.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@vercel/style-guide": "^5.1.0",
"concurrently": "^8.2.1",
"prettier": "^3.0.3",
"rimraf": "^5.0.5",
"tsup": "8.0.1",
"turbo": "1.11.2",
"typescript": "5.3.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-next-docs/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
extends: ['custom/library'],
ignorePatterns: ['./templates/**/*'],
ignorePatterns: ['/template/**/*'],
};
4 changes: 0 additions & 4 deletions packages/create-next-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@ pnpx create-next-docs-app
#or
yarn create next-docs-app
```

## Examples

The examples are automatically generated from `./examples`
7 changes: 3 additions & 4 deletions packages/create-next-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@
"author": "Fuma Nama",
"bin": "./dist/index.js",
"files": [
"templates/*",
"template/*",
"static/*",
"dist/*"
],
"scripts": {
"build": "pnpm sync && tsup",
"clean": "rmdir /q/s dist && rmdir /q/s templates",
"build": "tsup",
"clean": "rimraf dist",
"dev": "tsup --watch",
"lint": "eslint .",
"sync": "node ./scripts/sync.js",
"types:check": "tsc --noEmit"
},
"dependencies": {
Expand Down
47 changes: 0 additions & 47 deletions packages/create-next-docs/scripts/sync.js

This file was deleted.

204 changes: 130 additions & 74 deletions packages/create-next-docs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import path from 'node:path';
import {
cancel,
confirm,
group,
intro,
isCancel,
outro,
Expand All @@ -13,46 +14,53 @@ import {
text,
} from '@clack/prompts';
import * as color from 'picocolors';
import packagePackageJson from '../package.json';
import { autoInstall, getPackageManager } from './auto-install';

const cwd = process.cwd();
const sourceDir = path.resolve(__dirname, '../');
const manager = getPackageManager();

async function main(): Promise<void> {
const cwd = process.cwd();
const sourceDir = path.resolve(__dirname, '../');
intro(color.bgCyan(color.bold('Create Next Docs')));

const inputName = await text({
message: 'Project name',
placeholder: 'my-app',
defaultValue: 'my-app',
});

if (isCancel(inputName)) {
cancel();
return;
}
const options = await group(
{
name: () =>
text({
message: 'Project name',
placeholder: 'my-app',
defaultValue: 'my-app',
}),
type: () =>
select({
message: 'Choose a content source',
initialValue: 'next-docs-mdx' as Source,
options: [
{ value: 'next-docs-mdx', label: 'Next Docs MDX' },
{ value: 'contentlayer', label: 'Contentlayer' },
],
}),
tailwindcss: () => confirm({ message: 'Use Tailwind CSS for styling?' }),
autoInstall: () =>
confirm({
message: `Do you want to install packages automatically? (detected as ${manager})`,
}),
},
{
onCancel: () => {
cancel('Installation Stopped.');
process.exit(0);
},
},
);

const pathname = inputName.toLowerCase().replace(/\s/, '-');
const dest = path.resolve(cwd, pathname);
const name = path.basename(dest);

const type = await select({
message: 'Which example you want to install?',
initialValue: 'simple',
options: [
{ value: 'simple', label: 'Default (Contentlayer)' },
{ value: 'advanced', label: 'Advanced (Contentlayer)' },
{ value: 'simple-mdx', label: 'Default (Next Docs MDX)' },
],
});

if (isCancel(type)) {
cancel();
return;
}
const projectName = options.name.toLowerCase().replace(/\s/, '-');
const dest = path.resolve(cwd, projectName);

if (existsSync(dest)) {
const del = await confirm({
message: `${pathname} already exists, do you want to delete it?`,
message: `${projectName} already exists, do you want to delete it?`,
});

if (isCancel(del)) {
Expand All @@ -62,64 +70,67 @@ async function main(): Promise<void> {

if (del) {
const info = spinner();
info.start(`Deleting ${pathname}`);
info.start(`Deleting ${projectName}`);

await fs.rm(dest, {
recursive: true,
force: true,
});

info.stop(`Deleted ${pathname}`);
info.stop(`Deleted ${projectName}`);
}
}

const info = spinner();
info.start(`Copying files to ${pathname}`);
info.start(`Copying files to ${projectName}`);

await copy(path.join(sourceDir, `templates/${type}`), dest);
await copy(path.join(sourceDir, `template/${options.type}`), dest);
await copy(
path.join(sourceDir, 'static/content'),
path.join(dest, 'content/docs'),
);

info.message('Updating package.json');
await updatePackageJson(path.join(dest, 'package.json'), name);
if (options.tailwindcss) {
await copy(path.join(sourceDir, `template/+tailwindcss`), dest);
}

info.message('Updating README.md');
await generateReadme(
path.join(sourceDir, 'static/README.md'),
path.join(dest, 'README.md'),
name,
info.message('Writing package.json');

const packageJson = createPackageJson(
projectName,
options.type,
options.tailwindcss,
);
await fs.writeFile(path.join(dest, 'package.json'), packageJson);

info.message('Updating README.md');
const readMe = await getReadme(projectName);

await fs.writeFile(path.join(dest, 'README.md'), readMe);

info.message('Adding .gitignore');
await fs.copyFile(
path.join(sourceDir, 'static/example.gitignore'),
path.join(dest, '.gitignore'),
);

info.stop('Project Generated');
const manager = getPackageManager();
const shouldInstall = await confirm({
message: `Do you want to install packages automatically? (detected as ${manager})`,
});
if (isCancel(shouldInstall)) cancel();
if (shouldInstall) {
if (options.autoInstall) {
info.message('Installing dependencies');
await autoInstall(manager, dest);
}

info.stop('Project Generated');

outro(color.bgGreen(color.bold('Done')));

if (type === 'advanced') {
if (options.tailwindcss) {
console.log('✔ Tailwind CSS');
}

console.log('✔ Typescript');

console.log(color.bold('\nOpen the project'));
console.log(color.cyan(`cd ${pathname}`));
console.log(color.cyan(`cd ${projectName}`));

console.log(color.bold('\nRun Development Server'));
console.log(color.cyan('npm run dev | pnpm run dev | yarn dev'));
Expand All @@ -131,30 +142,75 @@ async function main(): Promise<void> {
process.exit(0);
}

async function updatePackageJson(
fileName: string,
projectName: string,
): Promise<void> {
const packageJson = JSON.parse(
(await fs.readFile(fileName)).toString(),
) as Record<string, unknown>;
packageJson.name = projectName;
async function getReadme(projectName: string): Promise<string> {
const template = await fs
.readFile(path.join(sourceDir, 'static/README.md'))
.then((res) => res.toString());

await fs.writeFile(fileName, JSON.stringify(packageJson, undefined, 2));
return `# ${projectName}\n\n${template}`;
}

async function generateReadme(
templatePath: string,
destination: string,
projectName: string,
): Promise<void> {
const template = await fs
.readFile(templatePath)
.then((res) => res.toString());
const content = `# ${projectName}\n\n${template}`;
type Source = 'contentlayer' | 'next-docs-mdx';

function createPackageJson(
name: string,
source: Source,
tailwindCss: boolean,
): string {
const nextDocsVersion = packagePackageJson.version;

const packageJson = {
name,
version: '0.0.0',
private: true,
scripts: {
build: 'next build',
dev: 'next dev',
start: 'next start',
},
dependencies: {
next: '14.0.4',
'next-docs-ui': nextDocsVersion,
'next-docs-zeta': nextDocsVersion,
react: '18.2.0',
'react-dom': '18.2.0',
},
devDependencies: {
'@types/react': '18.2.0',
'@types/react-dom': '18.2.1',
typescript: '5.3.3',
},
};

if (source === 'contentlayer') {
Object.assign(packageJson.dependencies, {
contentlayer: '0.3.4',
'next-contentlayer': '0.3.4',
});

Object.assign(packageJson, {
overrides: {
unified: '^11.0.4',
'mdx-bundler': '^10.0.1',
},
});
}

if (source === 'next-docs-mdx') {
Object.assign(packageJson.dependencies, {
'next-docs-mdx': nextDocsVersion,
});
}

if (tailwindCss) {
Object.assign(packageJson.devDependencies, {
autoprefixer: '10.4.16',
postcss: '8.4.32',
tailwindcss: '3.3.7',
});
}

await fs.writeFile(destination, content);
return JSON.stringify(packageJson, undefined, 2);
}

async function copy(
Expand Down
Loading

0 comments on commit 579ecaa

Please sign in to comment.