2023-08-08 06:38:52 +02:00
|
|
|
import process from 'node:process';
|
2022-09-25 03:04:58 +02:00
|
|
|
import chalk from 'chalk';
|
2023-05-03 04:16:53 +02:00
|
|
|
import { input, confirm, checkbox } from '@inquirer/prompts';
|
2022-09-25 03:04:58 +02:00
|
|
|
import getRelativeLuminance from 'get-relative-luminance';
|
|
|
|
import {
|
|
|
|
URL_REGEX,
|
|
|
|
collator,
|
|
|
|
getIconsDataString,
|
|
|
|
titleToSlug,
|
|
|
|
normalizeColor,
|
2023-04-19 15:23:13 +02:00
|
|
|
} from '../sdk.mjs';
|
2023-04-30 11:53:03 +02:00
|
|
|
import { getJsonSchemaData, writeIconsData } from './utils.js';
|
2022-09-25 03:04:58 +02:00
|
|
|
|
|
|
|
const hexPattern = /^#?[a-f0-9]{3,8}$/i;
|
|
|
|
|
|
|
|
const iconsData = JSON.parse(await getIconsDataString());
|
2022-09-28 04:11:27 +02:00
|
|
|
const jsonSchema = await getJsonSchemaData();
|
2022-09-25 03:04:58 +02:00
|
|
|
|
|
|
|
const titleValidator = (text) => {
|
|
|
|
if (!text) return 'This field is required';
|
|
|
|
if (
|
|
|
|
iconsData.icons.find(
|
|
|
|
(x) => x.title === text || titleToSlug(x.title) === titleToSlug(text),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return 'This icon title or slug already exist';
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
const hexValidator = (text) =>
|
2023-08-08 06:38:52 +02:00
|
|
|
hexPattern.test(text) || 'This should be a valid hex code';
|
2022-09-25 03:04:58 +02:00
|
|
|
|
|
|
|
const sourceValidator = (text) =>
|
2023-08-08 06:38:52 +02:00
|
|
|
URL_REGEX.test(text) || 'This should be a secure URL';
|
2022-09-25 03:04:58 +02:00
|
|
|
|
|
|
|
const hexTransformer = (text) => {
|
|
|
|
const color = normalizeColor(text);
|
|
|
|
const luminance = hexPattern.test(text)
|
|
|
|
? getRelativeLuminance.default(`#${color}`)
|
|
|
|
: -1;
|
2023-06-10 17:33:26 +02:00
|
|
|
if (luminance === -1) return text.toUpperCase();
|
|
|
|
return chalk.bgHex(`#${color}`).hex(luminance < 0.4 ? '#fff' : '#000')(
|
|
|
|
text.toUpperCase(),
|
|
|
|
);
|
2022-09-25 03:04:58 +02:00
|
|
|
};
|
|
|
|
|
2022-09-28 04:11:27 +02:00
|
|
|
const aliasesTransformer = (text) =>
|
|
|
|
text
|
|
|
|
.split(',')
|
|
|
|
.map((x) => chalk.cyan(x))
|
|
|
|
.join(',');
|
|
|
|
|
|
|
|
const aliasesChoices = Object.entries(
|
|
|
|
jsonSchema.definitions.brand.properties.aliases.properties,
|
|
|
|
)
|
|
|
|
.filter(([k]) => ['aka', 'old'].includes(k))
|
|
|
|
.map(([k, v]) => ({ name: `${k}: ${v.description}`, value: k }));
|
|
|
|
|
2022-09-25 03:04:58 +02:00
|
|
|
const getIconDataFromAnswers = (answers) => ({
|
|
|
|
title: answers.title,
|
2023-09-24 20:36:55 +02:00
|
|
|
hex: normalizeColor(answers.hex),
|
2022-09-25 03:04:58 +02:00
|
|
|
source: answers.source,
|
|
|
|
...(answers.hasGuidelines ? { guidelines: answers.guidelines } : {}),
|
|
|
|
...(answers.hasLicense
|
|
|
|
? {
|
|
|
|
license: {
|
|
|
|
type: answers.licenseType,
|
|
|
|
...(answers.licenseUrl ? { url: answers.licenseUrl } : {}),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
: {}),
|
2022-09-28 04:11:27 +02:00
|
|
|
...(answers.hasAliases
|
|
|
|
? {
|
|
|
|
aliases: aliasesChoices.reduce((previous, current) => {
|
|
|
|
const promptKey = `${current.value}AliasesList`;
|
|
|
|
if (answers[promptKey])
|
|
|
|
return {
|
|
|
|
...previous,
|
|
|
|
[current.value]: answers[promptKey]
|
|
|
|
.split(',')
|
|
|
|
.map((x) => x.trim()),
|
|
|
|
};
|
|
|
|
return previous;
|
|
|
|
}, {}),
|
|
|
|
}
|
|
|
|
: {}),
|
2022-09-25 03:04:58 +02:00
|
|
|
});
|
|
|
|
|
2023-05-03 04:16:53 +02:00
|
|
|
const answers = {};
|
|
|
|
|
|
|
|
answers.title = await input({
|
|
|
|
message: 'Title',
|
|
|
|
validate: titleValidator,
|
|
|
|
});
|
|
|
|
|
|
|
|
answers.hex = await input({
|
|
|
|
message: 'Hex',
|
|
|
|
validate: hexValidator,
|
|
|
|
transformer: hexTransformer,
|
|
|
|
});
|
|
|
|
|
|
|
|
answers.source = await input({
|
|
|
|
message: 'Source',
|
|
|
|
validate: sourceValidator,
|
|
|
|
});
|
|
|
|
|
|
|
|
answers.hasGuidelines = await confirm({
|
|
|
|
message: 'The icon has brand guidelines?',
|
|
|
|
});
|
|
|
|
|
|
|
|
if (answers.hasGuidelines) {
|
|
|
|
answers.guidelines = await input({
|
2022-09-25 03:04:58 +02:00
|
|
|
message: 'Guidelines',
|
|
|
|
validate: sourceValidator,
|
2023-05-03 04:16:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
answers.hasLicense = await confirm({
|
|
|
|
message: 'The icon has brand license?',
|
|
|
|
});
|
|
|
|
|
|
|
|
if (answers.hasLicense) {
|
|
|
|
answers.licenseType = await input({
|
2022-09-25 03:04:58 +02:00
|
|
|
message: 'License type',
|
|
|
|
validate: (text) => Boolean(text),
|
2023-05-03 04:16:53 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
answers.licenseUrl = await input({
|
|
|
|
message: 'License URL' + chalk.reset(' (optional)'),
|
2022-09-25 03:04:58 +02:00
|
|
|
validate: (text) => !Boolean(text) || sourceValidator(text),
|
2023-05-03 04:16:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
answers.hasAliases = await confirm({
|
|
|
|
message: 'This icon has brands aliases?',
|
|
|
|
default: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (answers.hasAliases) {
|
|
|
|
answers.aliasesTypes = await checkbox({
|
2022-09-28 04:11:27 +02:00
|
|
|
message: 'What types of aliases do you want to add?',
|
|
|
|
choices: aliasesChoices,
|
2023-05-03 04:16:53 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
for (const x of aliasesChoices) {
|
|
|
|
if (!answers?.aliasesTypes?.includes(x.value)) continue;
|
|
|
|
answers[`${x.value}AliasesList`] = await input({
|
|
|
|
message: x.value + chalk.reset(' (separate with commas)'),
|
|
|
|
validate: (text) => Boolean(text),
|
|
|
|
transformer: aliasesTransformer,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
answers.confirmToAdd = await confirm({
|
|
|
|
message: [
|
|
|
|
'About to write to simple-icons.json',
|
|
|
|
chalk.reset(JSON.stringify(getIconDataFromAnswers(answers), null, 4)),
|
|
|
|
chalk.reset('Is this OK?'),
|
|
|
|
].join('\n\n'),
|
|
|
|
});
|
|
|
|
|
2022-09-25 03:04:58 +02:00
|
|
|
const icon = getIconDataFromAnswers(answers);
|
|
|
|
|
2022-09-28 04:11:27 +02:00
|
|
|
if (answers.confirmToAdd) {
|
2022-09-25 03:04:58 +02:00
|
|
|
iconsData.icons.push(icon);
|
|
|
|
iconsData.icons.sort((a, b) => collator.compare(a.title, b.title));
|
|
|
|
await writeIconsData(iconsData);
|
|
|
|
} else {
|
|
|
|
console.log('Aborted.');
|
|
|
|
process.exit(1);
|
|
|
|
}
|