diff --git a/packages/create-docusaurus/src/index.ts b/packages/create-docusaurus/src/index.ts index 406acf43ef..55da5f84c3 100755 --- a/packages/create-docusaurus/src/index.ts +++ b/packages/create-docusaurus/src/index.ts @@ -63,6 +63,7 @@ function createTemplateChoices(templates: string[]) { return [ ...templates.map((template) => makeNameAndValueChoice(template)), makeNameAndValueChoice('Git repository'), + makeNameAndValueChoice('Local template'), ]; } @@ -176,13 +177,37 @@ export default async function init( 'Enter a repository URL from GitHub, Bitbucket, GitLab, or any other public repo.\n(e.g: https://github.com/ownerName/repoName.git)', }); template = repoPrompt.gitRepoUrl; + } else if (template === 'Local template') { + const dirPrompt = await prompts({ + type: 'text', + name: 'templateDir', + validate: (dir?: string) => { + if (dir) { + const fullDir = path.resolve(process.cwd(), dir); + if (fs.existsSync(fullDir)) { + return true; + } + return chalk.red( + `The path ${chalk.magenta(fullDir)} does not exist.`, + ); + } + return chalk.red('Please enter a valid path.'); + }, + message: + 'Enter a local folder path, relative to the current working directory.', + }); + template = dirPrompt.templateDir; + } + + if (!template) { + throw new Error('Template should not be empty'); } console.log(` ${chalk.cyan('Creating new Docusaurus project...')} `); - if (template && isValidGitRepoUrl(template)) { + if (isValidGitRepoUrl(template)) { console.log(`Cloning Git template ${chalk.cyan(template)}...`); if ( shell.exec(`git clone --recursive ${template} ${dest}`, {silent: true}) @@ -190,7 +215,7 @@ ${chalk.cyan('Creating new Docusaurus project...')} ) { throw new Error(chalk.red(`Cloning Git template ${template} failed!`)); } - } else if (template && templates.includes(template)) { + } else if (templates.includes(template)) { // Docusaurus templates. if (useTS) { if (!hasTS(template)) { @@ -208,6 +233,14 @@ ${chalk.cyan('Creating new Docusaurus project...')} ); throw err; } + } else if (fs.existsSync(path.resolve(process.cwd(), template))) { + const templateDir = path.resolve(process.cwd(), template); + try { + await fs.copy(templateDir, dest); + } catch (err) { + console.log(`Copying local template ${templateDir} failed!`); + throw err; + } } else { throw new Error('Invalid template.'); } diff --git a/website/docs/installation.md b/website/docs/installation.md index 174653ea01..f7e7ba62d8 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -34,6 +34,8 @@ npx create-docusaurus@latest website classic If you do not specify `name` or `template`, it will prompt you for them. We recommend the `classic` template so that you can get started quickly, and it contains features found in Docusaurus 1. The `classic` template contains `@docusaurus/preset-classic` which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support). You can get up and running extremely quickly with the classic template and customize things later on when you have gained more familiarity with Docusaurus. +The `template` also accepts a git repo URL or a local file path, with the latter evaluated relative to the current working directory. The repo/folder content will be copied to the site directory. + **[FB-Only]:** If you are setting up a new Docusaurus website for a Facebook open source project, use the `facebook` template instead, which comes with some useful Facebook-specific defaults: ```bash