diff --git a/packages/create-next-app/helpers/examples.ts b/packages/create-next-app/helpers/examples.ts index 746f5cd3a860a..34b80b7313898 100644 --- a/packages/create-next-app/helpers/examples.ts +++ b/packages/create-next-app/helpers/examples.ts @@ -20,3 +20,10 @@ export async function downloadAndExtractExample( tar.extract({ cwd: root, strip: 3 }, [`next.js-canary/examples/${name}`]) ) } + +export async function listExamples(): Promise { + const res = await got( + 'https://api.github.com/repositories/70107786/contents/examples' + ).catch(e => e) + return JSON.parse(res.body) +} diff --git a/packages/create-next-app/index.ts b/packages/create-next-app/index.ts index 99377ebcd6fcc..6adc75dd2c6e3 100644 --- a/packages/create-next-app/index.ts +++ b/packages/create-next-app/index.ts @@ -9,6 +9,7 @@ import { createApp } from './create-app' import { validateNpmName } from './helpers/validate-pkg' import packageJson from './package.json' import { shouldUseYarn } from './helpers/should-use-yarn' +import { listExamples } from './helpers/examples' let projectPath: string = '' @@ -83,6 +84,55 @@ async function run() { process.exit(1) } + if (!program.example) { + const wantsRes = await prompts({ + type: 'confirm', + name: 'wantsExample', + message: 'Would you like to create your an app from an example?', + initial: false, + }) + + if (wantsRes.wantsExample) { + const examplesJSON = await listExamples() + const options = examplesJSON.map((example: any) => { + return { title: example.name, value: example.name } + }) + + // The search function built into `prompts` isn’t very helpful: + // someone searching for `styled-components` would get no results since + // the example is called `with-styled-components`, and `prompts` searches + // the beginnings of titles. + + // To solve this, we implement a basic fuzzy search here. + const fuzzyMatch = (pattern: string, str: string) => { + pattern = '.*' + pattern.split('').join('.*') + '.*' + const re = new RegExp(pattern) + return re.test(str) + } + + const fuzzySuggest = (input: any, choices: any) => + Promise.resolve( + choices.filter((choice: any) => fuzzyMatch(input, choice.title)) + ) + + const nameRes = await prompts({ + type: 'autocomplete', + name: 'exampleName', + message: 'Pick an example', + suggest: fuzzySuggest, + choices: options, + }) + + if (!nameRes.exampleName) { + console.error( + 'Could not locate an example with that name. Creating project from blank starter instead.' + ) + } + + program.example = nameRes.exampleName + } + } + await createApp({ appPath: resolvedProjectPath, useNpm: !!program.useNpm,