diff --git a/site/index.html b/site/index.html
index 95cba83..10b6b5a 100644
--- a/site/index.html
+++ b/site/index.html
@@ -35,6 +35,23 @@
+

diff --git a/site/make-badge.ts b/site/make-badge.ts
index cfafc78..086469c 100644
--- a/site/make-badge.ts
+++ b/site/make-badge.ts
@@ -3,6 +3,9 @@ const DEBOUNCE_TIME = 300;
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('make-badge-input') as HTMLInputElement;
+ const modeSelect = document.getElementById(
+ 'make-badge-mode'
+ ) as HTMLSelectElement;
const imgOutput = document.getElementById(
'make-badge-img'
) as HTMLImageElement;
@@ -14,26 +17,43 @@ document.addEventListener('DOMContentLoaded', () => {
'make-badge-embed-html'
) as HTMLTextAreaElement;
- input.addEventListener(
- 'input',
- debounce(() => setBadgeSrc(input, imgOutput))
- );
- input.addEventListener('input', () =>
- setStatusAndEmbedCodes(input.value, info, embedMd, embedHtml)
+ const setBadgeSrcDebounced = debounce(() =>
+ setBadgeSrc(input, modeSelect, imgOutput)
);
+ const setStatusInstant = () =>
+ setStatusAndEmbedCodes(
+ input.value,
+ modeSelect.value,
+ info,
+ embedMd,
+ embedHtml
+ );
+
+ input.addEventListener('input', setBadgeSrcDebounced);
+ input.addEventListener('input', setStatusInstant);
+ modeSelect.addEventListener('change', setBadgeSrcDebounced);
+ modeSelect.addEventListener('change', setStatusInstant);
+
imgOutput.addEventListener('error', () => handleImgError(info));
imgOutput.addEventListener('load', () => handleImgLoad(info));
- setStatusAndEmbedCodes('', info, embedMd, embedHtml);
+ setStatusAndEmbedCodes('', 'install', info, embedMd, embedHtml);
});
function setBadgeSrc(
input: HTMLInputElement,
+ modeSelect: HTMLSelectElement,
imgOutput: HTMLImageElement
): void {
const pkg = input.value;
+ const mode = modeSelect.value;
+
if (pkg) {
- imgOutput.src = `${NPM_BADGE_URL}${pkg}`;
+ let src = `${NPM_BADGE_URL}${pkg}`;
+ if (mode !== 'install') {
+ src = `${src}?mode=${mode}`;
+ }
+ imgOutput.src = src;
}
}
@@ -47,6 +67,7 @@ function handleImgLoad(info: HTMLSpanElement): void {
function setStatusAndEmbedCodes(
name: string,
+ mode: string,
info: HTMLSpanElement,
embedMd: HTMLTextAreaElement,
embedHtml: HTMLTextAreaElement
@@ -57,8 +78,9 @@ function setStatusAndEmbedCodes(
} else {
info.textContent = 'Loading...';
}
+ const modeQuery = mode === 'install' ? '' : `?mode=${mode}`;
- const badgeLink = `${NPM_BADGE_URL}${name}`;
+ const badgeLink = `${NPM_BADGE_URL}${name}${modeQuery}`;
const npmLink = `https://www.npmjs.com/package/${name}`;
embedMd.value = `[](${npmLink})`;
diff --git a/site/style.scss b/site/style.scss
index a74c118..57fb06b 100644
--- a/site/style.scss
+++ b/site/style.scss
@@ -37,7 +37,8 @@ a {
}
input,
-textarea {
+textarea,
+select {
font-size: inherit;
color: inherit;
padding: 8px;
@@ -63,6 +64,7 @@ main {
display: flex;
justify-content: space-around;
gap: 32px;
+ margin-bottom: 32px;
@media screen and (max-width: 1024px) {
flex-direction: column;
@@ -89,7 +91,8 @@ main {
.input-row {
margin-bottom: 16px;
- input {
+ input,
+ select {
margin-right: 8px;
}
diff --git a/src/badge/badgeElements.ts b/src/badge/badgeElements.ts
index d29be3a..b61bc3d 100644
--- a/src/badge/badgeElements.ts
+++ b/src/badge/badgeElements.ts
@@ -3,6 +3,7 @@ import { formatNumber } from '../utils/formatNumber';
import { COLORS } from './colors';
import { timeAgo } from '../utils/timeAgo';
import { FONTS } from './fonts';
+import { InstallMode } from '../installMode';
export interface BadgeElements {
npmLogo: TextElement;
@@ -19,8 +20,11 @@ export interface TextElement {
color: string;
}
-export function getBadgeElements(pkg: PackageInfo): BadgeElements {
- return {
+export function getBadgeElements(
+ pkg: PackageInfo,
+ installMode?: InstallMode
+): BadgeElements {
+ const result: BadgeElements = {
npmLogo: {
text: 'npm',
font: FONTS.npm,
@@ -56,4 +60,14 @@ export function getBadgeElements(pkg: PackageInfo): BadgeElements {
color: COLORS.darkGrey,
},
};
+
+ if (installMode === 'global') {
+ result.installCommand.text = `npm install -g ${pkg.name}`;
+ }
+
+ if (installMode === 'npx') {
+ result.installCommand.text = `npx ${pkg.name}`;
+ }
+
+ return result;
}
diff --git a/src/badge/drawBadge.ts b/src/badge/drawBadge.ts
index d8f1763..cca5222 100644
--- a/src/badge/drawBadge.ts
+++ b/src/badge/drawBadge.ts
@@ -4,6 +4,7 @@ import { initFonts } from './fonts';
import { getBadgeElements } from './badgeElements';
import { drawText, getTextSizes } from './text';
import { COLORS } from './colors';
+import { InstallMode } from '../installMode';
const BORDER_WIDTH = 2;
const PADDING = 9;
@@ -23,12 +24,15 @@ initFonts();
| M 1,000 weekly downloads updated 5 months ago |
+---------------------------------------------------+
*/
-export function drawBadge(pkg: PackageInfo): PNGStream {
+export function drawBadge(
+ pkg: PackageInfo,
+ installMode?: InstallMode
+): PNGStream {
const canvas = new Canvas(0, 0);
const ctx = canvas.getContext('2d');
ctx.antialias = 'subpixel';
- const elems = getBadgeElements(pkg);
+ const elems = getBadgeElements(pkg, installMode);
const sizes = getTextSizes(ctx, elems);
const pkgInfoX = NPM_LOGO_X + sizes.npmLogo.width + LOGO_SPACING_RIGHT;
diff --git a/src/index.ts b/src/index.ts
index 55e67ff..77c4d0b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,6 +2,7 @@ import express from 'express';
import { getPackageInfo } from './packageInfo';
import { drawBadge } from './badge/drawBadge';
import { packageNameMiddleware } from './packageNameMiddleware';
+import { parseInstallMode } from './installMode';
const app = express();
app.use(express.static('_site'));
@@ -9,8 +10,9 @@ app.use(express.static('_site'));
app.get('/npm/*', packageNameMiddleware, async function (req, res, next) {
getPackageInfo(req.packageName)
.then((pkg) => {
+ const { mode } = req.query;
res.type('image/png');
- drawBadge(pkg).pipe(res);
+ drawBadge(pkg, parseInstallMode(mode)).pipe(res);
})
.catch(next);
});
diff --git a/src/installMode.ts b/src/installMode.ts
new file mode 100644
index 0000000..281c1c5
--- /dev/null
+++ b/src/installMode.ts
@@ -0,0 +1,9 @@
+export type InstallMode = 'install' | 'global' | 'npx';
+
+const validModes: InstallMode[] = ['install', 'global', 'npx'];
+
+export function parseInstallMode(mode?: unknown): InstallMode | undefined {
+ if (typeof mode === 'string' && validModes.includes(mode as InstallMode)) {
+ return mode as InstallMode;
+ }
+}