Skip to content

Commit

Permalink
[create-astro] Finalize developer experience... with gradients 🚀 (#3313)
Browse files Browse the repository at this point in the history
* wip: port gradient helpers from sandbox ideas

* feat: wire up rocket gradient 🚀

* feat: wire up rocket gradient on install step

* refactor: update "next steps" wording

* deps: add chalk (for rendering gradient)

* chore: changeset

* chore: clean up sstray template string
  • Loading branch information
bholmesdev authored May 11, 2022
1 parent f40705d commit 1a5335e
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/strong-students-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-astro': patch
---

Update "next steps" with more informative text on each CLI command. Oh, and gradients. A lot more gradients.
1 change: 1 addition & 0 deletions packages/create-astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"@types/degit": "^2.8.3",
"@types/prompts": "^2.0.14",
"chalk": "^5.0.1",
"degit": "^2.8.4",
"execa": "^6.1.0",
"kleur": "^4.1.4",
Expand Down
91 changes: 91 additions & 0 deletions packages/create-astro/src/gradient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import chalk from 'chalk';
import ora from 'ora';
import type { Ora } from 'ora';

const gradientColors = [
`#ff5e00`,
`#ff4c29`,
`#ff383f`,
`#ff2453`,
`#ff0565`,
`#ff007b`,
`#f5008b`,
`#e6149c`,
`#d629ae`,
`#c238bd`,
];

export const rocketAscii = '■■▶';

// get a reference to scroll through while loading
// visual representation of what this generates:
// gradientColors: "..xxXX"
// referenceGradient: "..xxXXXXxx....xxXX"
const referenceGradient = [
...gradientColors,
// draw the reverse of the gradient without
// accidentally mutating the gradient (ugh, reverse())
...[...gradientColors].reverse(),
...gradientColors,
];

// async-friendly setTimeout
const sleep = (time: number) =>
new Promise((resolve) => {
setTimeout(resolve, time);
});

function getGradientAnimFrames() {
const frames = [];
for (let start = 0; start < gradientColors.length * 2; start++) {
const end = start + gradientColors.length - 1;
frames.push(
referenceGradient
.slice(start, end)
.map((g) => chalk.bgHex(g)(' '))
.join('')
);
}
return frames;
}

function getIntroAnimFrames() {
const frames = [];
for (let end = 1; end <= gradientColors.length; end++) {
const leadingSpacesArr = Array.from(
new Array(Math.abs(gradientColors.length - end - 1)),
() => ' '
);
const gradientArr = gradientColors.slice(0, end).map((g) => chalk.bgHex(g)(' '));
frames.push([...leadingSpacesArr, ...gradientArr].join(''));
}
return frames;
}

/**
* Generate loading spinner with rocket flames!
* @param text display text next to rocket
* @returns Ora spinner for running .stop()
*/
export async function loadWithRocketGradient(text: string): Promise<Ora> {
const frames = getIntroAnimFrames();
const intro = ora({
spinner: {
interval: 30,
frames,
},
text: `${rocketAscii} ${text}`,
});
intro.start();
await sleep((frames.length - 1) * intro.interval);
intro.stop();
const spinner = ora({
spinner: {
interval: 80,
frames: getGradientAnimFrames(),
},
text: `${rocketAscii} ${text}`,
}).start();

return spinner;
}
47 changes: 24 additions & 23 deletions packages/create-astro/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ora from 'ora';
import { TEMPLATES } from './templates.js';
import { logger, defaultLogLevel } from './logger.js';
import { execa, execaCommand } from 'execa';
import { loadWithRocketGradient, rocketAscii } from './gradient.js';

// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
// to no longer require `--` to pass args and instead pass `--` directly to us. This
Expand Down Expand Up @@ -42,10 +43,6 @@ export async function main() {
logger.debug('Verbose logging turned on');
console.log(`\n${bold('Welcome to Astro!')} ${gray(`(create-astro v${version})`)}`);

let spinner = ora({ color: 'green', text: 'Prepare for liftoff.' });

spinner.succeed();

let cwd = args['_'][2] as string;

if (cwd && isEmpty(cwd)) {
Expand Down Expand Up @@ -95,6 +92,8 @@ export async function main() {
process.exit(1);
}

const templateSpinner = await loadWithRocketGradient('Copying project files...');

const hash = args.commit ? `#${args.commit}` : '';

const templateTarget = `withastro/astro/examples/${options.template}#latest`;
Expand All @@ -111,8 +110,6 @@ export async function main() {
verbose: defaultLogLevel === 'debug' ? true : false,
});

spinner = ora({ color: 'green', text: 'Copying project files...' }).start();

// Copy
if (!args.dryrun) {
try {
Expand Down Expand Up @@ -152,7 +149,7 @@ export async function main() {
)
);
}
spinner.fail();
templateSpinner.fail();
process.exit(1);
}

Expand All @@ -167,8 +164,8 @@ export async function main() {
);
}

spinner.succeed();
console.log(bold(green('✔') + ' Done!'));
templateSpinner.text = green('Template copied!');
templateSpinner.succeed();

const installResponse = await prompts({
type: 'confirm',
Expand All @@ -184,15 +181,18 @@ export async function main() {
if (installResponse.install && !args.dryrun) {
const installExec = execa(pkgManager, ['install'], { cwd });
const installingPackagesMsg = `Installing packages${emojiWithFallback(' 📦', '...')}`;
spinner = ora({ color: 'green', text: installingPackagesMsg }).start();
const installSpinner = await loadWithRocketGradient(installingPackagesMsg);
await new Promise<void>((resolve, reject) => {
installExec.stdout?.on('data', function (data) {
spinner.text = `${installingPackagesMsg}\n${bold(`[${pkgManager}]`)} ${data}`;
installSpinner.text = `${rocketAscii} ${installingPackagesMsg}\n${bold(
`[${pkgManager}]`
)} ${data}`;
});
installExec.on('error', (error) => reject(error));
installExec.on('close', () => resolve());
});
spinner.succeed();
installSpinner.text = green('Packages installed!');
installSpinner.succeed();
}

const astroAddCommand = installResponse.install
Expand Down Expand Up @@ -240,21 +240,22 @@ export async function main() {
await execaCommand('git init', { cwd });
}

ora({ text: green('Done. Ready for liftoff!') }).succeed();
console.log(`\n${bgCyan(black(' Next steps '))}\n`);

const relative = path.relative(process.cwd(), cwd);
const startCommand = [];
if (relative !== '') {
startCommand.push(bold(cyan(`cd ${relative}`)));
}
const projectDir = path.relative(process.cwd(), cwd);
const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`;

console.log(
`You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.`
);
console.log(
`Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.`
);
if (!installResponse.install) {
startCommand.push(bold(cyan(`${pkgManager} install`)));
console.log(yellow(`Remember to install dependencies first!`));
}
startCommand.push(bold(cyan(pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`)));
console.log(startCommand.join(' && '));

console.log(`\nTo close the dev server, hit ${bold(cyan('Ctrl-C'))}`);
console.log(`Stuck? Visit us at ${cyan('https://astro.build/chat')}\n`);
console.log(`\nStuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`);
}

function emojiWithFallback(char: string, fallback: string) {
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1a5335e

Please sign in to comment.