diff --git a/webapp/channels/build/emoji/make_emojis.mjs b/webapp/channels/build/emoji/make_emojis.mjs index 244ed0e462..b8ecb8e8b4 100755 --- a/webapp/channels/build/emoji/make_emojis.mjs +++ b/webapp/channels/build/emoji/make_emojis.mjs @@ -13,14 +13,13 @@ * npm run make-emojis -- --help */ -/* eslint-disable no-console */ - import path from 'node:path'; import * as fsPromise from 'node:fs/promises'; import * as fs from 'node:fs'; import * as url from 'node:url'; import yargs from 'yargs'; +import chalk from 'chalk'; import jsonData from 'emoji-datasource/emoji.json'; import jsonCategories from 'emoji-datasource/categories.json'; @@ -31,10 +30,6 @@ const EMOJI_SIZE_PADDED = EMOJI_SIZE + 2; // 1px per side const EMOJI_DEFAULT_SKIN = 'default'; const endResults = []; -const errorLogColor = '\x1b[31m%s\x1b[0m'; -const warnLogColor = '\x1b[33m%s\x1b[0m'; -const successLogColor = '\x1b[32m%s\x1b[0m'; - const currentDir = path.dirname(url.fileURLToPath(import.meta.url)); const rootDir = path.resolve(currentDir, '..', '..', '..', '..'); const serverRootDir = path.resolve(rootDir, 'server'); @@ -54,12 +49,48 @@ const argv = yargs(process.argv.slice(1)). const argsExcludedEmojiFile = argv['excluded-emoji-file']; +function log(level = '', text) { + if (level === 'info') { + // eslint-disable-next-line no-console + console.log(chalk.cyan(`[INFO]: ${text}`)); + } else if (level === 'warn') { + // eslint-disable-next-line no-console + console.log(chalk.yellow(`[WARN]: ${text}`)); + } else if (level === 'error') { + // eslint-disable-next-line no-console + console.error(chalk.red(`[ERRO]: ${text}`)); + } else if (level === 'success') { + // eslint-disable-next-line no-console + console.log(chalk.green(`[SUCC]: ${text}`)); + } else { + // eslint-disable-next-line no-console + console.log(text); + } +} + function writeToFileAndPrint(fileName, filePath, data) { const promise = fsPromise.writeFile(filePath, data, writeOptions); promise.then(() => { - console.log(successLogColor, `${fileName} generated successfully in ${filePath}\n`); + log('info', `"${fileName}" generated successfully in "${filePath}"`); + }).catch((err) => { + log('error', `Failed to generate "${fileName}": ${err}`); }); + + return promise; +} + +function copyFileAndPrint(source, destination, fileName, print = true) { + const promise = fsPromise.copyFile(source, destination); + + promise.then(() => { + if (print) { + log('info', `"${fileName}" copied successfully to "${destination}"`); + } + }).catch((err) => { + log('error', `Failed to copy "${fileName}": ${err}`); + }); + return promise; } @@ -73,24 +104,36 @@ const emojiImagesDir = path.resolve(webappRootDir, 'channels', 'src', 'images', const readDirPromise = fsPromise.readdir(emojiDataSourceDir); endResults.push(readDirPromise); readDirPromise.then((images) => { - console.log(`Copying ${images.length} emoji images, this might take a while\n`); - for (const imageFile of images) { - endResults.push( - fsPromise.copyFile(path.join(emojiDataSourceDir, imageFile), path.join(emojiImagesDir, imageFile)). - catch((err) => console.log(errorLogColor, `[ERROR] Failed to copy ${imageFile}: ${err}`))); + endResults.push(copyFileAndPrint(path.join(emojiDataSourceDir, imageFile), path.join(emojiImagesDir, imageFile), imageFile, false)); } }); +// Missing emojis from Apple emoji set ["medical_symbol", "male_sign", and "female_sign"] +// @see https://github.com/iamcal/emoji-data#image-sources +const missingEmojis = ['2640-fe0f', '2642-fe0f', '2695-fe0f']; + +// Copy the missing from google emoji set +const missingEmojiDataSourceDir = path.resolve(webappRootDir, `node_modules/emoji-datasource-google/img/google/${EMOJI_SIZE}/`); +const readMissingDirPromise = fsPromise.readdir(missingEmojiDataSourceDir); +endResults.push(readMissingDirPromise); +readMissingDirPromise.then(() => { + for (const missingEmoji of missingEmojis) { + endResults.push( + copyFileAndPrint(path.join(missingEmojiDataSourceDir, `${missingEmoji}.png`), path.join(emojiImagesDir, `${missingEmoji}.png`), `Missed ${missingEmoji}`)); + } +}); + +// Copy mattermost emoji image const webappImagesDir = path.resolve(webappRootDir, 'channels', 'src', 'images'); -fsPromise.copyFile(path.resolve(webappImagesDir, 'icon64x64.png'), path.resolve(webappImagesDir, 'emoji/mattermost.png')); +endResults.push(copyFileAndPrint(path.resolve(webappImagesDir, 'icon64x64.png'), path.resolve(webappImagesDir, 'emoji/mattermost.png'), 'mattermost-emoji')); const sheetSource = path.resolve(webappRootDir, `node_modules/emoji-datasource-apple/img/apple/sheets/${EMOJI_SIZE}.png`); const sheetAbsoluteFile = path.resolve(webappRootDir, 'channels', 'src', 'images/emoji-sheets/apple-sheet.png'); const sheetFile = 'images/emoji-sheets/apple-sheet.png'; // Copy sheet image -fsPromise.copyFile(sheetSource, sheetAbsoluteFile).catch((err) => console.log(errorLogColor, `[ERROR] Failed to copy sheet file: ${err}`)); +endResults.push(copyFileAndPrint(sheetSource, sheetAbsoluteFile, 'emoji-sheet')); // we'll load it as a two dimensional array so we can generate a Map out of it const emojiIndicesByAlias = []; @@ -129,7 +172,7 @@ if (argsExcludedEmojiFile) { fs.readFileSync(path.normalize(argsExcludedEmojiFile), 'utf-8').split(/\r?\n/).forEach((line) => { excludedEmoji.push(line); }); - console.log(warnLogColor, `\n[WARNING] The following emoji(s) will be excluded from the webapp: \n${excludedEmoji}\n`); + log('warn', `The following emoji(s) will be excluded from the webapp: \n${excludedEmoji}\n`); } // Remove unwanted emoji @@ -454,11 +497,13 @@ ${cssEmojis.join('\n')} const emojispriteDir = path.resolve(webappRootDir, 'channels', 'src', 'sass', 'components', '_emojisprite.scss'); endResults.push(writeToFileAndPrint('_emojisprite.scss', emojispriteDir, cssRules)); +log('', '\n'); +log('info', 'Running "make-emojis" script...'); Promise.all(endResults).then(() => { - console.log(warnLogColor, '\n[WARNING] Remember to npm run \'i18n-extract\' as categories might have changed.'); - console.log(warnLogColor, '[WARNING] Remember to run `gofmt -w ./server/public/model/emoji_data.go` from the root of the repository.'); - console.log(successLogColor, '\n[SUCCESS] make-emojis script completed successfully.'); + log('warn', 'Remember to npm run "i18n-extract" as categories might have changed.'); + log('warn', 'Remember to run "gofmt -w ./server/public/model/emoji_data.go" from the root of the repository.'); + log('success', 'make-emojis script completed successfully.'); }).catch((err) => { control.abort(); // cancel any other file writing - console.log(errorLogColor, `[ERROR] There was an error while running make-emojis script: ${err}`); + log('error', `There was an error while running make-emojis script: ${err}`); }); diff --git a/webapp/channels/package.json b/webapp/channels/package.json index 17786e8442..6fe42fd9f5 100644 --- a/webapp/channels/package.json +++ b/webapp/channels/package.json @@ -34,8 +34,6 @@ "css-vars-ponyfill": "2.4.8", "date-fns": "2.29.3", "dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f", - "emoji-datasource": "6.1.1", - "emoji-datasource-apple": "6.0.1", "emoji-regex": "10.2.1", "exif2css": "1.3.0", "fast-deep-equal": "3.1.3", @@ -157,6 +155,9 @@ "bundle-loader": "0.2.0", "copy-webpack-plugin": "11.0.0", "dotenv-webpack": "8.0.1", + "emoji-datasource": "6.1.1", + "emoji-datasource-apple": "6.1.1", + "emoji-datasource-google": "6.1.1", "enzyme": "3.11.0", "enzyme-adapter-react-17-updated": "1.0.2", "enzyme-to-json": "3.6.2", diff --git a/webapp/channels/src/images/emoji/2640-fe0f.png b/webapp/channels/src/images/emoji/2640-fe0f.png new file mode 100644 index 0000000000..2c134435b3 Binary files /dev/null and b/webapp/channels/src/images/emoji/2640-fe0f.png differ diff --git a/webapp/channels/src/images/emoji/2642-fe0f.png b/webapp/channels/src/images/emoji/2642-fe0f.png new file mode 100644 index 0000000000..e465b825d6 Binary files /dev/null and b/webapp/channels/src/images/emoji/2642-fe0f.png differ diff --git a/webapp/channels/src/images/emoji/2695-fe0f.png b/webapp/channels/src/images/emoji/2695-fe0f.png new file mode 100644 index 0000000000..4254a42d3c Binary files /dev/null and b/webapp/channels/src/images/emoji/2695-fe0f.png differ diff --git a/webapp/package-lock.json b/webapp/package-lock.json index f9d308e4d8..328598747f 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -3408,8 +3408,6 @@ "css-vars-ponyfill": "2.4.8", "date-fns": "2.29.3", "dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f", - "emoji-datasource": "6.1.1", - "emoji-datasource-apple": "6.0.1", "emoji-regex": "10.2.1", "exif2css": "1.3.0", "fast-deep-equal": "3.1.3", @@ -3531,6 +3529,9 @@ "bundle-loader": "0.2.0", "copy-webpack-plugin": "11.0.0", "dotenv-webpack": "8.0.1", + "emoji-datasource": "6.1.1", + "emoji-datasource-apple": "6.1.1", + "emoji-datasource-google": "6.1.1", "enzyme": "3.11.0", "enzyme-adapter-react-17-updated": "1.0.2", "enzyme-to-json": "3.6.2", @@ -16907,12 +16908,20 @@ "node_modules/emoji-datasource": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/emoji-datasource/-/emoji-datasource-6.1.1.tgz", - "integrity": "sha512-fbS3QJpzGHhujvBULSKXcvsYmVg+1ldfI3VVXG3jnFuniZtkp7rz/OcTcQjbp3m43BYxmiJgKmaoOUPxXQupRQ==" + "integrity": "sha512-fbS3QJpzGHhujvBULSKXcvsYmVg+1ldfI3VVXG3jnFuniZtkp7rz/OcTcQjbp3m43BYxmiJgKmaoOUPxXQupRQ==", + "dev": true }, "node_modules/emoji-datasource-apple": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/emoji-datasource-apple/-/emoji-datasource-apple-6.0.1.tgz", - "integrity": "sha512-Aqj3Km5e4Q8an0cOASP0T1S/+StnIrPQc9Y7Mg2x2LtkwvmoVQO3UaaF9Cj8yi4o8yOPc6GoIKeg95WJTzWzhw==" + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-datasource-apple/-/emoji-datasource-apple-6.1.1.tgz", + "integrity": "sha512-qe3STGOaMR0/7iD9XxkrAh94+bsnIN1aD1Odb+odg+dhbUAk1idsxO6cLYE5trUHTRflwYCh2//n0cSv7k5y6w==", + "dev": true + }, + "node_modules/emoji-datasource-google": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-datasource-google/-/emoji-datasource-google-6.1.1.tgz", + "integrity": "sha512-hsKsajOC1uE8N7grzFg85ujjL+g7mAeMpMwOG/Fi47oYiXbrJsExwAKXDkqVp2FhOFSZMFDu+GfZUW+04YDYRA==", + "dev": true }, "node_modules/emoji-mart": { "version": "3.0.1", @@ -47865,12 +47874,20 @@ "emoji-datasource": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/emoji-datasource/-/emoji-datasource-6.1.1.tgz", - "integrity": "sha512-fbS3QJpzGHhujvBULSKXcvsYmVg+1ldfI3VVXG3jnFuniZtkp7rz/OcTcQjbp3m43BYxmiJgKmaoOUPxXQupRQ==" + "integrity": "sha512-fbS3QJpzGHhujvBULSKXcvsYmVg+1ldfI3VVXG3jnFuniZtkp7rz/OcTcQjbp3m43BYxmiJgKmaoOUPxXQupRQ==", + "dev": true }, "emoji-datasource-apple": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/emoji-datasource-apple/-/emoji-datasource-apple-6.0.1.tgz", - "integrity": "sha512-Aqj3Km5e4Q8an0cOASP0T1S/+StnIrPQc9Y7Mg2x2LtkwvmoVQO3UaaF9Cj8yi4o8yOPc6GoIKeg95WJTzWzhw==" + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-datasource-apple/-/emoji-datasource-apple-6.1.1.tgz", + "integrity": "sha512-qe3STGOaMR0/7iD9XxkrAh94+bsnIN1aD1Odb+odg+dhbUAk1idsxO6cLYE5trUHTRflwYCh2//n0cSv7k5y6w==", + "dev": true + }, + "emoji-datasource-google": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-datasource-google/-/emoji-datasource-google-6.1.1.tgz", + "integrity": "sha512-hsKsajOC1uE8N7grzFg85ujjL+g7mAeMpMwOG/Fi47oYiXbrJsExwAKXDkqVp2FhOFSZMFDu+GfZUW+04YDYRA==", + "dev": true }, "emoji-mart": { "version": "3.0.1", @@ -53297,8 +53314,9 @@ "date-fns": "2.29.3", "dotenv-webpack": "8.0.1", "dynamic-virtualized-list": "github:mattermost/dynamic-virtualized-list#1c330717d6778315a40e70137ace38247c6a1d0f", - "emoji-datasource": "6.1.1", - "emoji-datasource-apple": "6.0.1", + "emoji-datasource": "6", + "emoji-datasource-apple": "6", + "emoji-datasource-google": "6.1.1", "emoji-regex": "10.2.1", "enzyme": "3.11.0", "enzyme-adapter-react-17-updated": "1.0.2",