From 16d8de38b74c298fda27c22c804850a999183d57 Mon Sep 17 00:00:00 2001 From: Vijay A Date: Sat, 21 Aug 2021 09:03:32 +0530 Subject: chore: move build-time js files out of 'src' and into 'scripts' so that they not packaged into final deployable artefact --- scripts/add-crowdin-contributors.js | 81 +++++++++++++++++++++++++++++++ scripts/build-theme-info.js | 97 +++++++++++++++++++++++++++++++++++++ scripts/link-readme.js | 63 ++++++++++++++++++++++++ scripts/theme/default/legacy.js | 38 +++++++++++++++ 4 files changed, 279 insertions(+) create mode 100644 scripts/add-crowdin-contributors.js create mode 100644 scripts/build-theme-info.js create mode 100644 scripts/link-readme.js create mode 100644 scripts/theme/default/legacy.js (limited to 'scripts') diff --git a/scripts/add-crowdin-contributors.js b/scripts/add-crowdin-contributors.js new file mode 100644 index 000000000..05e377a94 --- /dev/null +++ b/scripts/add-crowdin-contributors.js @@ -0,0 +1,81 @@ +/** + * Add CrowdIn Contributors to AllContributors list + * + * This script will add CrowdIn Contributors to the list of all contributors. + * As the CrowdIn API doesn't give good access to the data needed, this script + * requires you to manually execute a script on the members page of CrowdIn + * and paste its output into this script. + * + * Usage: + * 1. Open https://crowdin.com/project/getferdi/settings#members + * 2. Open the console and execute the script below: + +const members = []; +// All elements containing members +const membersEl = [...document.querySelectorAll('.ps-members-name')]; +// Remove the first 4 contributors as they are already in the list +for (let i = 0; i < 4; i += 1) { + membersEl.shift(); +} +membersEl.forEach((el) => { + const text = el.innerText; + let picture = el.querySelector('img').getAttribute('src'); + picture = picture.replace(/\?.+/, ''); + + // Check if the text includes a separate username + if (text.includes('(')) { + const username = /(?<=\()\w*(?=\))/.exec(text)[0]; + const name = /^.*(?= \()/.exec(text)[0]; + + if (username) { + members.push({ + name: name || username, + login: username, + avatar_url: picture, + }); + return; + } + } + members.push({ + name: text, + login: text, + avatar_url: picture, + }); +}); + +// Output data to console +console.clear(); +console.log(JSON.stringify(members)); + + * 3. Paste the output of the script (JSON Array) below to set 'list' to that value + * 4. Execute this script using 'node scripts/add-crowdin-contributors.js' + * 5. Regenerate the README table using the CLI ('all-contributors generate') + * Please check if the generated data is ok and no data is lost. +*/ +const list = []; + +const fs = require('fs-extra'); +const path = require('path'); +const allContributors = require('all-contributors-cli'); + +const infoPath = path.join(__dirname, '..', '..', '.all-contributorsrc'); + +(async () => { + const info = await fs.readJSON(infoPath); + + for (const user of list) { + // eslint-disable-next-line no-await-in-loop + info.contributors = await allContributors.addContributorWithDetails({ + ...user, + contributions: ['translation'], + profile: `https://crowdin.com/profile/${user.login}`, + options: { + contributors: info.contributors, + }, + }); + } + + fs.writeJSON(infoPath, info, { + spaces: 2, + }); +})(); diff --git a/scripts/build-theme-info.js b/scripts/build-theme-info.js new file mode 100644 index 000000000..4058be942 --- /dev/null +++ b/scripts/build-theme-info.js @@ -0,0 +1,97 @@ +/** + * Script to get information on which selectors use the brand color. + * This is needed to provide the accent color feature - the feature will create CSS rules + * to overwrite the color of these selectors. + */ +const css = require('css'); +const fs = require('fs-extra'); +const path = require('path'); +const theme = require('@meetfranz/theme'); + +// Colors that should be replaced with the accent color +const accentColors = [ + theme.DEFAULT_ACCENT_COLOR.toLowerCase(), + '#7367f0', + '#5e50ee', +]; + +const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css'); +const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json'); + +// Parse and extract the rules from a CSS stylesheet file +async function getRulesFromCssFile(file) { + const cssSrc = (await fs.readFile(file)).toString(); + const cssTree = css.parse(cssSrc); + + return cssTree.stylesheet.rules; +} + +/** + * Get all selectors from a list of parsed CSS rules that set any property to one of the specified + * values. + * + * This function will output an object in this format: + * { + * 'property-name': [ array of selectors ] + * } + * + * e.g. + * { + * 'background-color': [ + * '.background', + * '.input-dark' + * ] + * } + * + * @param {Array} rules Rules as outputted by the `css` module + * @param {Array} values Array of values that should be searched for + */ +function getSelectorsDeclaringValues(rules, values) { + const output = {}; + + rules.forEach((rule) => { + if (rule.declarations) { + rule.declarations.forEach((declaration) => { + if (declaration.type === 'declaration' + && values.includes(declaration.value.toLowerCase())) { + if (!output[declaration.property]) { + output[declaration.property] = []; + } + output[declaration.property] = output[declaration.property].concat(rule.selectors); + } + }); + } + }); + + return output; +} + +async function generateThemeInfo() { + if (!await fs.pathExists(cssFile)) { + console.log('Please make sure to build the project first.'); + return; + } + + // Read and parse css bundle + const rules = await getRulesFromCssFile(cssFile); + + console.log(`Found ${rules.length} rules`); + + // Get rules specifying the brand colors + const brandRules = getSelectorsDeclaringValues(rules, accentColors); + + console.log(`Found ${Object.keys(brandRules).join(', ')} properties that set color to brand color`); + + // Join array of declarations into a single string + Object.keys(brandRules).forEach((rule) => { + brandRules[rule] = brandRules[rule].join(', '); + }); + + // Write object with theme info to file + fs.writeFile( + outputFile, + JSON.stringify(brandRules), + ); +} + +generateThemeInfo(); diff --git a/scripts/link-readme.js b/scripts/link-readme.js new file mode 100644 index 000000000..1e47cddf8 --- /dev/null +++ b/scripts/link-readme.js @@ -0,0 +1,63 @@ +/** + * Script that automatically creates links to issues and users inside README.md + * + * e.g. "#123" => "[#123](https://github.com/getferdi/ferdi/issues/123)" + * and "franz/#123" => "[franz#123](https://github.com/meetfranz/franz/issues/123)" + * and "@abc" => "[@abc](https://github.com/abc)" + */ + +const fs = require('fs-extra'); +const path = require('path'); + +console.log('Linking issues and PRs in README.md'); + +const readmepath = path.join(__dirname, '..', '..', 'README.md'); + +// Read README.md +let readme = fs.readFileSync(readmepath, 'utf-8'); + +let replacements = 0; + +// Replace Franz issues +// Regex matches strings that don't begin with a "[", i.e. are not already linked +// followed by a "franz#" and digits to indicate +// a GitHub issue, and not ending with a "]" +readme = readme.replace(/(? { + const issueNr = match.replace('franz#', ''); + replacements += 1; + return `[franz#${issueNr}](https://github.com/meetfranz/franz/issues/${issueNr})`; +}); + +// Replace external issues +// Regex matches strings that don't begin with a "[", followed a repo name in the format "user/repo" +// followed by a "#" and digits to indicate a GitHub issue, and not ending with a "]" +readme = readme.replace(/(? { + const issueNr = match.replace(/\D/g, ''); + const repo = match.replace(/#\d+/g, ''); + replacements += 1; + return `[${repo}#${issueNr}](https://github.com/${repo}/issues/${issueNr})`; +}); + +// Replace Ferdi issues +// Regex matches strings that don't begin with a "[", i.e. are not already linked and +// don't begin with "franz", i.e. are not Franz issues, followed by a "#" and digits to indicate +// a GitHub issue, and not ending with a "]" +readme = readme.replace(/(? { + const issueNr = match.replace('#', ''); + replacements += 1; + return `[#${issueNr}](https://github.com/getferdi/ferdi/issues/${issueNr})`; +}); + +// Link GitHub users +// Regex matches strings that don't begin with a "[", i.e. are not already linked +// followed by a "@" and at least one word character and not ending with a "]" +readme = readme.replace(/(? { + const username = match.replace('@', ''); + replacements += 1; + return `[@${username}](https://github.com/${username})`; +}); + +// Write to file +fs.writeFileSync(readmepath, readme); + +console.log(`Added ${replacements} strings`); diff --git a/scripts/theme/default/legacy.js b/scripts/theme/default/legacy.js new file mode 100644 index 000000000..015dca756 --- /dev/null +++ b/scripts/theme/default/legacy.js @@ -0,0 +1,38 @@ +/* legacy config, injected into sass at build time */ +export const themeBrandPrimary = '#7266F0'; +export const themeBrandSuccess = '#5cb85c'; +export const themeBrandInfo = '#5bc0de'; +export const themeBrandWarning = '#FF9F00'; +export const themeBrandDanger = '#d9534f'; + +export const themeGrayDark = '#373a3c'; +export const themeGray = '#55595c'; +export const themeGrayLight = '#818a91'; +export const themeGrayLighter = '#eceeef'; +export const themeGrayLightest = '#f7f7f9'; + +export const themeBorderRadius = '6px'; +export const themeBorderRadiusSmall = '3px'; + +export const themeSidebarWidth = '68px'; + +export const themeTextColor = themeGrayDark; + +export const themeTransitionTime = '.5s'; + +export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)'; + +export const darkThemeBlack = '#1A1A1A'; + +export const darkThemeGrayDarkest = '#1E1E1E'; +export const darkThemeGrayDarker = '#2D2F31'; +export const darkThemeGrayDark = '#383A3B'; + +export const darkThemeGray = '#47494B'; + +export const darkThemeGrayLight = '#515355'; +export const darkThemeGrayLighter = '#8a8b8b'; +export const darkThemeGrayLightest = '#FFFFFF'; + +export const darkThemeGraySmoke = '#CED0D1'; +export const darkThemeTextColor = '#FFFFFF'; -- cgit v1.2.3-54-g00ecf