diff --git a/app/soapbox/custom.js b/app/soapbox/custom.js new file mode 100644 index 000000000..31f565ed7 --- /dev/null +++ b/app/soapbox/custom.js @@ -0,0 +1,11 @@ +/** + * Functions for dealing with custom build configuration. + */ + +/** Require a custom JSON file if it exists */ +export const custom = (filename, fallback = {}) => { + const context = require.context('custom', false, /\.json$/); + const path = `./${filename}.json`; + + return context.keys().includes(path) ? context(path) : fallback; +}; diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index 0516ef02d..44621a322 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -4,6 +4,12 @@ import { createSelector } from 'reselect'; import gte from 'semver/functions/gte'; import lt from 'semver/functions/lt'; +import { custom } from 'soapbox/custom'; + +// Import custom overrides, if exists +const overrides = custom('features'); + +// Truthy array convenience function const any = arr => arr.some(Boolean); // For uglification @@ -16,7 +22,7 @@ export const getFeatures = createSelector([instance => instance], instance => { const features = instance.getIn(['pleroma', 'metadata', 'features'], ImmutableList()); const federation = instance.getIn(['pleroma', 'metadata', 'federation'], ImmutableMap()); - return { + return Object.assign({ bookmarks: any([ v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), @@ -93,7 +99,7 @@ export const getFeatures = createSelector([instance => instance], instance => { v.software === MASTODON && gte(v.compatVersion, '3.2.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), ]), - }; + }, overrides); }); export const parseVersion = version => { diff --git a/babel.config.js b/babel.config.js index b9f7954d1..0791d27f4 100644 --- a/babel.config.js +++ b/babel.config.js @@ -57,6 +57,9 @@ module.exports = (api) => { ]); break; case 'test': + config.plugins.push(...[ + 'transform-require-context', + ]); envOptions.modules = 'commonjs'; break; } diff --git a/docs/development/build-config.md b/docs/development/build-config.md index e5083b8a0..a5f9a741b 100644 --- a/docs/development/build-config.md +++ b/docs/development/build-config.md @@ -1,5 +1,45 @@ # Build Configuration +Soapbox supports compile-time customizations in the form of environment variables and a gitignored `custom/` directory. + +## `custom/` directory + +You can place files into the `custom/` directory to customize the Soapbox build. + +### Custom locales (`custom/locales/*.json`) + +It is possible to override locale messages by creating a file for each language, eg `custom/locales/en.json`. +In this file, add only the messages you want to be overridden. +For example: + +```json +{ + "account.posts": "Poasts", + "account.posts_with_replies": "Poasts & Replies", + "compose.submit_success": "Your poast was sent!", + "compose_form.publish": "Poast" +} +``` + +These messages will be merged into the language file shipped with Soapbox. + +### Feature overrides (`custom/features.json`) + +You can create a file called `custom/features.json` to disable version-checking and force some features on or off. +For example: + +```json +{ + "bookmarks": false, + "lists": false, + "quotePosts": true +} +``` + +See `app/soapbox/utils/features.js` for the full list of features. + +## Environment variables + When compiling Soapbox FE, environment variables may be passed to change the build itself. For example: diff --git a/package.json b/package.json index 5b9b1d9ac..dcdca8734 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "babel-plugin-preval": "^5.0.0", "babel-plugin-react-intl": "^7.5.20", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", + "babel-plugin-transform-require-context": "^0.1.1", "blurhash": "^1.0.0", "bootstrap-icons": "^1.5.0", "bowser": "^2.11.0", diff --git a/yarn.lock b/yarn.lock index 3623eb0ff..36ed26b5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1141,6 +1141,15 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/template@7", "@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/template@^7.15.4", "@babel/template@^7.3.3": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" @@ -1150,15 +1159,6 @@ "@babel/parser" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" @@ -2579,6 +2579,13 @@ babel-plugin-transform-react-remove-prop-types@^0.4.24: resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== +babel-plugin-transform-require-context@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-require-context/-/babel-plugin-transform-require-context-0.1.1.tgz#319b545ca83080b5062776b46cc9b8b346fea9a6" + integrity sha512-4ceqYOtzgmq4/QsB8dP7pUrUOCjY/jrRYdt7YkIOWHxtGDQbcf6YZDyLCiPQf6KsEIcIbSQiTRXOsbLiuJfgNQ== + dependencies: + "@babel/template" "7" + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b"