From 37c43712d1f48caf123f25e7cf6fff9a78b8cb33 Mon Sep 17 00:00:00 2001 From: Bastian Ike Date: Tue, 13 Sep 2022 11:18:36 +0200 Subject: [PATCH] chore(codestyle): cleanup and reformat --- .eslintrc | 2 +- .npmrc | 1 + dist_scripts/scripts/buildRadar.js | 2 +- dist_scripts/scripts/generateJson/radar.js | 18 +- dist_scripts/scripts/paths.js | 2 +- package-lock.json | 389 +++++++++++++++++- package.json | 6 +- prettier.config.js | 1 + scripts/buildRadar.ts | 6 +- scripts/createStaticFiles.ts | 2 +- scripts/generateJson.ts | 2 +- scripts/generateJson/radar.ts | 80 ++-- scripts/paths.ts | 2 +- src/components/App.tsx | 21 +- src/components/Badge/Badge.tsx | 3 +- src/components/Branding/Branding.tsx | 4 +- src/components/Chart/Axes.tsx | 64 ++- src/components/Chart/BlipPoints.tsx | 221 +++++----- src/components/Chart/BlipShapes.tsx | 97 ++--- src/components/Chart/QuadrantRings.tsx | 148 ++++--- src/components/Chart/RadarChart.tsx | 140 ++++--- src/components/EditButton/EditButton.tsx | 18 +- src/components/Fadeable/Fadeable.tsx | 3 +- src/components/Footer/Footer.tsx | 16 +- src/components/FooterEnd/FooterEnd.tsx | 16 +- src/components/Header/Header.tsx | 11 +- .../HeadlineGroup/HeadlineGroup.tsx | 3 +- src/components/HeroHeadline/HeroHeadline.tsx | 1 + src/components/Item/Item.tsx | 7 +- src/components/ItemList/ItemList.tsx | 3 +- src/components/ItemRevision/ItemRevision.tsx | 4 +- .../ItemRevisions/ItemRevisions.tsx | 16 +- src/components/Link/Link.tsx | 1 + src/components/LogoLink/LogoLink.tsx | 6 +- src/components/PageHelp/PageHelp.tsx | 56 ++- src/components/PageIndex/PageIndex.tsx | 27 +- src/components/PageItem/PageItem.tsx | 41 +- src/components/PageItem/useAnimations.tsx | 11 +- .../PageItemMobile/PageItemMobile.tsx | 23 +- src/components/PageOverview/PageOverview.tsx | 21 +- src/components/PageQuadrant/PageQuadrant.tsx | 12 +- src/components/QuadrantGrid/QuadrantGrid.tsx | 28 +- .../QuadrantSection/QuadrantSection.tsx | 11 +- src/components/RadarGrid/RadarGrid.tsx | 18 +- src/components/Router.tsx | 14 +- src/components/Search/Search.tsx | 7 +- src/components/SetTitle.tsx | 1 + src/components/SocialLink/SocialLink.tsx | 10 +- src/config.ts | 16 +- src/context/MessagesContext/index.tsx | 3 +- src/date.test.tsx | 7 +- src/date.ts | 6 +- src/index.tsx | 3 +- src/model.ts | 36 +- src/sanitize.test.tsx | 15 +- src/sanitize.ts | 20 +- 56 files changed, 1142 insertions(+), 560 deletions(-) create mode 100644 .npmrc diff --git a/.eslintrc b/.eslintrc index f298005..cce7ecc 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,3 @@ { - "extends": ["react-app", "react-app/jest"] + "extends": ["react-app", "react-app/jest", "prettier"] } diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..cffe8cd --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +save-exact=true diff --git a/dist_scripts/scripts/buildRadar.js b/dist_scripts/scripts/buildRadar.js index ea05df7..7325e86 100755 --- a/dist_scripts/scripts/buildRadar.js +++ b/dist_scripts/scripts/buildRadar.js @@ -24,8 +24,8 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -var fs = __importStar(require("fs-extra")); var child_process_1 = require("child_process"); +var fs = __importStar(require("fs-extra")); var paths = __importStar(require("./paths")); // Do this as the first thing so that any code reading it knows the right env. process.env.BABEL_ENV = "production"; diff --git a/dist_scripts/scripts/generateJson/radar.js b/dist_scripts/scripts/generateJson/radar.js index 657660f..e45ae79 100644 --- a/dist_scripts/scripts/generateJson/radar.js +++ b/dist_scripts/scripts/generateJson/radar.js @@ -83,16 +83,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createRadar = void 0; -var fs_extra_1 = require("fs-extra"); -var fs_1 = require("fs"); -var path = __importStar(require("path")); var front_matter_1 = __importDefault(require("front-matter")); -// @ts-ignore esModuleInterop is activated in tsconfig.scripts.json, but IDE typescript uses default typescript config -var marked_1 = require("marked"); +var fs_1 = require("fs"); +var fs_extra_1 = require("fs-extra"); var highlight_js_1 = __importDefault(require("highlight.js")); -var file_1 = require("./file"); +var marked_1 = require("marked"); +var path = __importStar(require("path")); var model_1 = require("../../src/model"); var paths_1 = require("../paths"); +var file_1 = require("./file"); marked_1.marked.setOptions({ highlight: function (code) { return highlight_js_1.default.highlightAuto(code).value; }, }); @@ -180,7 +179,7 @@ var createItems = function (revisions) { return __assign(__assign({}, items), (_a = {}, _a[revision.name] = addRevisionToItem(items[revision.name], revision), _a)); }, {}); return Object.values(itemMap) - .map(function (item) { return (__assign(__assign({}, item), { "title": item.title || item.name })); }) + .map(function (item) { return (__assign(__assign({}, item), { title: item.title || item.name })); }) .sort(function (x, y) { return (x.name > y.name ? 1 : -1); }); }; var ignoreEmptyRevisionBody = function (revision, item) { @@ -208,7 +207,10 @@ var addRevisionToItem = function (item, revision) { return newItem; }; var revisionCreatesNewHistoryEntry = function (revision, item) { - return revision.body.trim() !== "" || (typeof revision.ring !== "undefined" && revision.ring !== item.ring) || (typeof revision.quadrant !== "undefined" && revision.quadrant !== item.quadrant); + return (revision.body.trim() !== "" || + (typeof revision.ring !== "undefined" && revision.ring !== item.ring) || + (typeof revision.quadrant !== "undefined" && + revision.quadrant !== item.quadrant)); }; var flagItem = function (items, allReleases) { return items.map(function (item) { diff --git a/dist_scripts/scripts/paths.js b/dist_scripts/scripts/paths.js index ad61d9d..1635c3d 100644 --- a/dist_scripts/scripts/paths.js +++ b/dist_scripts/scripts/paths.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.appNodeModules = exports.appYarnLock = exports.appPublic = exports.appBuild = exports.appRdJson = exports.templateNodeModules = exports.templateBuild = exports.template = exports.radarJson = void 0; -var path_1 = require("path"); var fs_1 = require("fs"); +var path_1 = require("path"); exports.radarJson = "rd.json"; var appDirectory = (0, fs_1.realpathSync)(process.cwd()); var resolveApp = function (relativePath) { diff --git a/package-lock.json b/package-lock.json index c71720c..4bc3bbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aoe_technology_radar", - "version": "3.3.2", + "version": "3.3.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "aoe_technology_radar", - "version": "3.3.2", + "version": "3.3.3", "license": "Apache-2.0", "dependencies": { "@apideck/better-ajv-errors": "0.3.6", @@ -15,7 +15,6 @@ "@types/d3": "7.4.0", "@types/fs-extra": "9.0.13", "@types/jest": "29.0.1", - "@types/node": "17.0.33", "@types/react": "18.0.19", "@types/react-dom": "18.0.6", "@types/sanitize-html": "2.6.2", @@ -48,9 +47,14 @@ "aoe_technology_radar-generateJson": "dist_scripts/scripts/generateJson.js" }, "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "3.3.0", + "@types/marked": "4.0.7", + "@types/node": "18.7.17", "@typescript-eslint/parser": "5.37.0", "eslint": "8.23.1", + "eslint-config-prettier": "8.5.0", "eslint-config-react-app": "7.0.1", + "eslint-plugin-prettier": "4.2.1", "eslint-plugin-react": "7.31.8", "yallist": "4.0.0" } @@ -3319,6 +3323,141 @@ "node": ">= 6" } }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.3.0.tgz", + "integrity": "sha512-1y44bVZuIN0RsS3oIiGd5k8Vm3IZXYZnp4VsP2Z/S5L9WAOw43HE2clso66M2S/dDeJ+8sKPqnHsEfh39Vjs3w==", + "dev": true, + "dependencies": { + "@babel/core": "7.17.8", + "@babel/generator": "7.17.7", + "@babel/parser": "7.17.8", + "@babel/traverse": "7.17.3", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "4.17.21" + }, + "peerDependencies": { + "prettier": "2.x" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/core": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/parser": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz", + "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -3916,15 +4055,21 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "node_modules/@types/marked": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", + "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz", - "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==" + "version": "18.7.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz", + "integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -7292,6 +7437,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-config-react-app": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", @@ -7483,6 +7640,27 @@ "node": ">=6.0" } }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.31.8", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", @@ -7958,6 +8136,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -9589,6 +9773,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, "node_modules/jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", @@ -12942,6 +13132,34 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -18345,6 +18563,109 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, + "@trivago/prettier-plugin-sort-imports": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.3.0.tgz", + "integrity": "sha512-1y44bVZuIN0RsS3oIiGd5k8Vm3IZXYZnp4VsP2Z/S5L9WAOw43HE2clso66M2S/dDeJ+8sKPqnHsEfh39Vjs3w==", + "dev": true, + "requires": { + "@babel/core": "7.17.8", + "@babel/generator": "7.17.7", + "@babel/parser": "7.17.8", + "@babel/traverse": "7.17.3", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "4.17.21" + }, + "dependencies": { + "@babel/core": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "requires": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/parser": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz", + "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ==", + "dev": true + }, + "@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true + } + } + }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -18901,15 +19222,21 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/marked": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", + "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "@types/node": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz", - "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==" + "version": "18.7.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz", + "integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==" }, "@types/parse-json": { "version": "4.0.0", @@ -21450,6 +21777,13 @@ } } }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "requires": {} + }, "eslint-config-react-app": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", @@ -21599,6 +21933,15 @@ } } }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-plugin-react": { "version": "7.31.8", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", @@ -21861,6 +22204,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -23013,6 +23362,12 @@ } } }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, "jest": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", @@ -25338,6 +25693,22 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "peer": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", diff --git a/package.json b/package.json index 865f0da..ad0a624 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "@types/d3": "7.4.0", "@types/fs-extra": "9.0.13", "@types/jest": "29.0.1", - "@types/node": "17.0.33", "@types/react": "18.0.19", "@types/react-dom": "18.0.6", "@types/sanitize-html": "2.6.2", @@ -57,9 +56,14 @@ "yaml": "2.1.1" }, "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "3.3.0", + "@types/marked": "4.0.7", + "@types/node": "18.7.17", "@typescript-eslint/parser": "5.37.0", "eslint": "8.23.1", + "eslint-config-prettier": "8.5.0", "eslint-config-react-app": "7.0.1", + "eslint-plugin-prettier": "4.2.1", "eslint-plugin-react": "7.31.8", "yallist": "4.0.0" }, diff --git a/prettier.config.js b/prettier.config.js index a0e1f4c..0d1b82b 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,4 +1,5 @@ module.exports = { + importOrder: ["^[./]"], importOrderSeparation: true, importOrderSortSpecifiers: true, }; diff --git a/scripts/buildRadar.ts b/scripts/buildRadar.ts index 81d86a0..c23f4bb 100644 --- a/scripts/buildRadar.ts +++ b/scripts/buildRadar.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node - -import * as fs from "fs-extra"; import { spawn } from "child_process"; +import * as fs from "fs-extra"; + import * as paths from "./paths"; // Do this as the first thing so that any code reading it knows the right env. @@ -52,7 +52,7 @@ const buildTemplate = () => { buildTemplate().then(() => { fs.copySync(paths.templateBuild, paths.appBuild); - fs.ensureDirSync(paths.appPublic) + fs.ensureDirSync(paths.appPublic); fs.copySync(paths.appPublic, paths.appBuild); console.log(`${paths.appBuild} was created and can be deployed.`); }); diff --git a/scripts/createStaticFiles.ts b/scripts/createStaticFiles.ts index 8db21cc..e47c164 100644 --- a/scripts/createStaticFiles.ts +++ b/scripts/createStaticFiles.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node +import { copyFileSync, existsSync, mkdirSync, readFileSync } from "fs"; -import { copyFileSync, mkdirSync, existsSync, readFileSync } from "fs"; import { createRadar } from "./generateJson/radar"; // Do this as the first thing so that any code reading it knows the right env. diff --git a/scripts/generateJson.ts b/scripts/generateJson.ts index 6d16043..5c7abdb 100644 --- a/scripts/generateJson.ts +++ b/scripts/generateJson.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node - import * as fs from "fs-extra"; + import * as paths from "./paths"; // Do this as the first thing so that any code reading it knows the right env. diff --git a/scripts/generateJson/radar.ts b/scripts/generateJson/radar.ts index f43f1cc..381ff06 100644 --- a/scripts/generateJson/radar.ts +++ b/scripts/generateJson/radar.ts @@ -1,32 +1,39 @@ -import { readFile } from "fs-extra"; -import { readFileSync } from "fs"; -import * as path from "path"; import frontMatter from "front-matter"; -// @ts-ignore esModuleInterop is activated in tsconfig.scripts.json, but IDE typescript uses default typescript config -import { marked } from "marked"; +import { readFileSync } from "fs"; +import { readFile } from "fs-extra"; import highlight from "highlight.js"; +import { marked } from "marked"; +import * as path from "path"; -import { radarPath, getAllMarkdownFiles } from "./file"; -import { Item, Revision, ItemAttributes, Radar, FlagType } from "../../src/model"; +import { + FlagType, + Item, + ItemAttributes, + Radar, + Revision, +} from "../../src/model"; import { appBuild } from "../paths"; +import { getAllMarkdownFiles, radarPath } from "./file"; import type { ConfigData } from "../../src/config"; -type FMAttributes = ItemAttributes; - marked.setOptions({ highlight: (code: any) => highlight.highlightAuto(code).value, }); export const createRadar = async (): Promise => { const fileNames = await getAllMarkdownFiles(radarPath()); - const revisions: (Revision|undefined)[] = await createRevisionsFromFiles(fileNames); - const filterdRevisions : Revision[] = revisions.filter(r => r !== undefined) as Revision[]; + const revisions: (Revision | undefined)[] = await createRevisionsFromFiles( + fileNames + ); + const filterdRevisions: Revision[] = revisions.filter( + (r) => r !== undefined + ) as Revision[]; const allReleases = getAllReleases(filterdRevisions); const items = createItems(filterdRevisions); const flaggedItems = flagItem(items, allReleases); - items.forEach(item => checkAttributes(item.name, item)) + items.forEach((item) => checkAttributes(item.name, item)); return { items: flaggedItems, @@ -34,7 +41,7 @@ export const createRadar = async (): Promise => { }; }; -const checkAttributes = (fileName: string, attributes: FMAttributes) => { +const checkAttributes = (fileName: string, attributes: ItemAttributes) => { const rawConf = readFileSync(path.resolve(appBuild, "config.json"), "utf-8"); const config = JSON.parse(rawConf) as ConfigData; @@ -61,31 +68,29 @@ const checkAttributes = (fileName: string, attributes: FMAttributes) => { } else { return attributes; } - }; const createRevisionsFromFiles = (fileNames: string[]) => { const publicUrl = process.env.PUBLIC_URL; return Promise.all( - fileNames.map( - (fileName) => - readFile(fileName, "utf8").then(data => { - const fm = frontMatter(data); - let html = marked(fm.body.replace(/\]\(\//g, `](${publicUrl}/`)); - html = html.replace( - /a href="http/g, - 'a target="_blank" rel="noopener noreferrer" href="http' - ); - const attributes = checkAttributes(fileName, fm.attributes); - if (attributes) { - return { - ...itemInfoFromFilename(fileName), - ...attributes, - fileName, - body: html, - } as Revision; - } - }) + fileNames.map((fileName) => + readFile(fileName, "utf8").then((data) => { + const fm = frontMatter(data); + let html = marked(fm.body.replace(/\]\(\//g, `](${publicUrl}/`)); + html = html.replace( + /a href="http/g, + 'a target="_blank" rel="noopener noreferrer" href="http' + ); + const attributes = checkAttributes(fileName, fm.attributes); + if (attributes) { + return { + ...itemInfoFromFilename(fileName), + ...attributes, + fileName, + body: html, + } as Revision; + } + }) ) ); }; @@ -120,7 +125,7 @@ const createItems = (revisions: Revision[]) => { ); return Object.values(itemMap) - .map((item) => ({ ...item, "title": item.title || item.name })) + .map((item) => ({ ...item, title: item.title || item.name })) .sort((x, y) => (x.name > y.name ? 1 : -1)); }; @@ -162,7 +167,12 @@ const addRevisionToItem = ( }; const revisionCreatesNewHistoryEntry = (revision: Revision, item: Item) => { - return revision.body.trim() !== "" || (typeof revision.ring !== "undefined" && revision.ring !== item.ring) || (typeof revision.quadrant !== "undefined" && revision.quadrant !== item.quadrant); + return ( + revision.body.trim() !== "" || + (typeof revision.ring !== "undefined" && revision.ring !== item.ring) || + (typeof revision.quadrant !== "undefined" && + revision.quadrant !== item.quadrant) + ); }; const flagItem = (items: Item[], allReleases: string[]) => diff --git a/scripts/paths.ts b/scripts/paths.ts index eb4c5ed..53089db 100644 --- a/scripts/paths.ts +++ b/scripts/paths.ts @@ -1,5 +1,5 @@ -import { resolve } from "path"; import { realpathSync } from "fs"; +import { resolve } from "path"; export const radarJson = "rd.json"; const appDirectory = realpathSync(process.cwd()); diff --git a/src/components/App.tsx b/src/components/App.tsx index e474a75..407db5a 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,19 +1,20 @@ -import React from "react"; import classNames from "classnames"; -import Header from "./Header/Header"; -import Footer from "./Footer/Footer"; -import Router from "./Router"; +import React from "react"; import { BrowserRouter, - Routes, - Route, Navigate, - useParams, + Route, + Routes, useLocation, + useParams, } from "react-router-dom"; -import { Item } from "../model"; -import { Messages, MessagesProvider } from "../context/MessagesContext"; + import { ConfigData } from "../config"; +import { Messages, MessagesProvider } from "../context/MessagesContext"; +import { Item } from "../model"; +import Footer from "./Footer/Footer"; +import Header from "./Header/Header"; +import Router from "./Router"; const useFetch = (url: string): D | undefined => { const [data, setData] = React.useState(); @@ -35,7 +36,7 @@ const useFetch = (url: string): D | undefined => { const useQuery = () => new URLSearchParams(useLocation().search); const usePage = (params: Record) => { - return (params['*'] || '').replace(".html", ""); + return (params["*"] || "").replace(".html", ""); }; const RouterWithPageParam = ({ diff --git a/src/components/Badge/Badge.tsx b/src/components/Badge/Badge.tsx index 79a97ca..2a1ab18 100644 --- a/src/components/Badge/Badge.tsx +++ b/src/components/Badge/Badge.tsx @@ -1,5 +1,6 @@ -import React, { MouseEventHandler } from "react"; import classNames from "classnames"; +import React, { MouseEventHandler } from "react"; + import "./badge.scss"; type BadgeProps = { diff --git a/src/components/Branding/Branding.tsx b/src/components/Branding/Branding.tsx index 0f27050..fece251 100644 --- a/src/components/Branding/Branding.tsx +++ b/src/components/Branding/Branding.tsx @@ -1,6 +1,8 @@ -import React from "react"; import classNames from "classnames"; +import React from "react"; + import "./branding.scss"; + type BrandingProps = { logoContent: React.ReactNode; modifier?: "backlink" | "logo" | "content" | "footer"; diff --git a/src/components/Chart/Axes.tsx b/src/components/Chart/Axes.tsx index 2440721..125814b 100644 --- a/src/components/Chart/Axes.tsx +++ b/src/components/Chart/Axes.tsx @@ -1,46 +1,44 @@ -import React, { useRef, useLayoutEffect } from 'react'; import * as d3 from "d3"; +import React, { useLayoutEffect, useRef } from "react"; export const YAxis: React.FC<{ - scale: d3.ScaleLinear + scale: d3.ScaleLinear; }> = ({ scale }) => { + const ref = useRef(null); - const ref = useRef(null); + useLayoutEffect(() => { + if (ref.current == null) { + return; + } + const axisGenerator = d3.axisLeft(scale).ticks(6); + d3.select(ref.current) + .attr("class", "y-axis") + .call(axisGenerator) + .call((g) => g.selectAll(".tick text").remove()) + .call((g) => g.selectAll(".tick line").remove()) + .call((g) => g.selectAll(".domain").remove()); + }, [scale]); - useLayoutEffect(() => { - if (ref.current == null) { - return - } - const axisGenerator = d3.axisLeft(scale).ticks(6); - d3.select(ref.current) - .attr('class', 'y-axis') - .call(axisGenerator) - .call(g => g.selectAll('.tick text').remove()) - .call(g => g.selectAll('.tick line').remove()) - .call(g => g.selectAll('.domain').remove()); - }, [scale]); - - return ; + return ; }; export const XAxis: React.FC<{ - scale: d3.ScaleLinear + scale: d3.ScaleLinear; }> = ({ scale }) => { + const ref = useRef(null); - const ref = useRef(null); + useLayoutEffect(() => { + if (ref.current == null) { + return; + } + const axisGenerator = d3.axisBottom(scale).ticks(6); + d3.select(ref.current) + .attr("class", "x-axis") + .call(axisGenerator) + .call((g) => g.selectAll(".tick text").remove()) + .call((g) => g.selectAll(".tick line").remove()) + .call((g) => g.selectAll(".domain").remove()); + }, [scale]); - useLayoutEffect(() => { - if (ref.current == null) { - return - } - const axisGenerator = d3.axisBottom(scale).ticks(6); - d3.select(ref.current) - .attr('class', 'x-axis') - .call(axisGenerator) - .call(g => g.selectAll('.tick text').remove()) - .call(g => g.selectAll('.tick line').remove()) - .call(g => g.selectAll('.domain').remove()); - }, [scale]); - - return ; + return ; }; diff --git a/src/components/Chart/BlipPoints.tsx b/src/components/Chart/BlipPoints.tsx index f0fa82a..e88d022 100644 --- a/src/components/Chart/BlipPoints.tsx +++ b/src/components/Chart/BlipPoints.tsx @@ -1,126 +1,147 @@ -import React from 'react'; -import { ScaleLinear } from 'd3'; -import { FlagType, Item, Blip, Point } from '../../model'; -import Link from '../Link/Link'; -import { NewBlip, ChangedBlip, DefaultBlip } from './BlipShapes'; -import { ConfigData } from '../../config'; +import { ScaleLinear } from "d3"; +import React from "react"; + +import { ConfigData } from "../../config"; +import { Blip, FlagType, Item, Point } from "../../model"; +import Link from "../Link/Link"; +import { ChangedBlip, DefaultBlip, NewBlip } from "./BlipShapes"; /* See https://medium.com/create-code/build-a-radar-diagram-with-d3-js-9db6458a9248 for a good explanation of formulas used to calculate various things in this component */ -function generateCoordinates(blip: Blip, xScale: ScaleLinear, yScale: ScaleLinear, config: ConfigData): Point { - const pi = Math.PI, - ringRadius = config.chartConfig.ringsAttributes[blip.ringPosition].radius, - previousRingRadius = blip.ringPosition === 0 ? 0 : config.chartConfig.ringsAttributes[blip.ringPosition - 1].radius, - ringPadding = 0.7; +function generateCoordinates( + blip: Blip, + xScale: ScaleLinear, + yScale: ScaleLinear, + config: ConfigData +): Point { + const pi = Math.PI, + ringRadius = config.chartConfig.ringsAttributes[blip.ringPosition].radius, + previousRingRadius = + blip.ringPosition === 0 + ? 0 + : config.chartConfig.ringsAttributes[blip.ringPosition - 1].radius, + ringPadding = 0.7; - // radian between 0 and 90 degrees - const randomDegree = ((Math.random() * 90) * pi) / 180; - // random distance from the centre of the radar, but within given ring. Also, with some "padding" so the points don't touch ring borders. - const radius = randomBetween(previousRingRadius + ringPadding, ringRadius - ringPadding); - /* + // radian between 0 and 90 degrees + const randomDegree = (Math.random() * 90 * pi) / 180; + // random distance from the centre of the radar, but within given ring. Also, with some "padding" so the points don't touch ring borders. + const radius = randomBetween( + previousRingRadius + ringPadding, + ringRadius - ringPadding + ); + /* Multiples of PI/2. To apply the calculated position to the specific quadrant. Order here is counter-clockwise, so we need to "invert" quadrant positions (i.e. swap 2 with 4) */ - const shift = pi * [1, 4, 3, 2][blip.quadrantPosition - 1] / 2; + const shift = (pi * [1, 4, 3, 2][blip.quadrantPosition - 1]) / 2; - return { - x: xScale(Math.cos(randomDegree + shift) * radius), - y: yScale(Math.sin(randomDegree + shift) * radius) - }; -}; + return { + x: xScale(Math.cos(randomDegree + shift) * radius), + y: yScale(Math.sin(randomDegree + shift) * radius), + }; +} -function randomBetween (min: number, max: number): number { - return Math.random() * (max - min) + min; -}; +function randomBetween(min: number, max: number): number { + return Math.random() * (max - min) + min; +} function distanceBetween(point1: Point, point2: Point): number { - const a = point2.x - point1.x; - const b = point2.y - point1.y; - return Math.sqrt((a * a) + (b * b)); -}; + const a = point2.x - point1.x; + const b = point2.y - point1.y; + return Math.sqrt(a * a + b * b); +} -function renderBlip(blip: Blip, index: number, config: ConfigData): JSX.Element { - const props = { - blip, - className: 'blip', - fill: blip.colour, - 'data-background-color': blip.colour, - 'data-text-color': blip.txtColour, - 'data-tip': blip.title, - key: index - } - switch (blip.flag) { - case FlagType.new: - return ; - case FlagType.changed: - return ; - default: - return ; - } -}; +function renderBlip( + blip: Blip, + index: number, + config: ConfigData +): JSX.Element { + const props = { + blip, + className: "blip", + fill: blip.colour, + "data-background-color": blip.colour, + "data-text-color": blip.txtColour, + "data-tip": blip.title, + key: index, + }; + switch (blip.flag) { + case FlagType.new: + return ; + case FlagType.changed: + return ; + default: + return ; + } +} const BlipPoints: React.FC<{ - items: Item[] - xScale:ScaleLinear - yScale:ScaleLinear - config:ConfigData -}> = ({items, xScale, yScale, config}) => { + items: Item[]; + xScale: ScaleLinear; + yScale: ScaleLinear; + config: ConfigData; +}> = ({ items, xScale, yScale, config }) => { + const blips: Blip[] = items.reduce((list: Blip[], item: Item) => { + if (!item.ring || !item.quadrant) { + // skip the blip if it doesn't have a ring or quadrant assigned + return list; + } + const quadrantConfig = config.quadrantsMap[item.quadrant]; + if (!quadrantConfig) { + return list; + } - const blips: Blip[] = items.reduce((list: Blip[], item: Item) => { - if (!item.ring || !item.quadrant) { - // skip the blip if it doesn't have a ring or quadrant assigned - return list; - } - const quadrantConfig = config.quadrantsMap[item.quadrant]; - if (!quadrantConfig) { - return list; - } + let blip: Blip = { + ...item, + quadrantPosition: quadrantConfig.position, + ringPosition: config.rings.findIndex((r) => r === item.ring), + colour: quadrantConfig.colour, + txtColour: quadrantConfig.txtColour, + coordinates: { x: 0, y: 0 }, + }; - let blip: Blip = { ...item, - quadrantPosition: quadrantConfig.position, - ringPosition: config.rings.findIndex(r => r === item.ring), - colour: quadrantConfig.colour, - txtColour: quadrantConfig.txtColour, - coordinates: {x: 0, y: 0}, - }; - - let point: Point; - let counter = 1; - let distanceBetweenCheck: boolean; - do { - const localpoint = generateCoordinates(blip, xScale, yScale, config); - point = localpoint - counter++; - /* + let point: Point; + let counter = 1; + let distanceBetweenCheck: boolean; + do { + const localpoint = generateCoordinates(blip, xScale, yScale, config); + point = localpoint; + counter++; + /* Generate position of the new blip until it has a satisfactory distance to every other blip (so that they don't touch each other) and quadrant borders (so that they don't overlap quadrants) This feels pretty inefficient, but good enough for now. */ - distanceBetweenCheck = list.some(b => distanceBetween(localpoint, b.coordinates) < config.chartConfig.blipSize + config.chartConfig.blipSize / 2) - } while (counter < 100 - && (Math.abs(point.x - xScale(0)) < 15 - || Math.abs(point.y - yScale(0)) < 15 - || distanceBetweenCheck - )); - - blip.coordinates = point; - - list.push(blip); - return list; - }, []); - - return ( - - {blips.map((blip, index) => ( - - {renderBlip(blip, index, config)} - - ))} - + distanceBetweenCheck = list.some( + (b) => + distanceBetween(localpoint, b.coordinates) < + config.chartConfig.blipSize + config.chartConfig.blipSize / 2 + ); + } while ( + counter < 100 && + (Math.abs(point.x - xScale(0)) < 15 || + Math.abs(point.y - yScale(0)) < 15 || + distanceBetweenCheck) ); + + blip.coordinates = point; + + list.push(blip); + return list; + }, []); + + return ( + + {blips.map((blip, index) => ( + + {renderBlip(blip, index, config)} + + ))} + + ); }; -export default BlipPoints; \ No newline at end of file +export default BlipPoints; diff --git a/src/components/Chart/BlipShapes.tsx b/src/components/Chart/BlipShapes.tsx index 47d8910..29942d8 100644 --- a/src/components/Chart/BlipShapes.tsx +++ b/src/components/Chart/BlipShapes.tsx @@ -1,64 +1,65 @@ -import React from 'react'; -import { ConfigData } from '../../config'; -import { Blip } from '../../model'; +import React from "react"; + +import { ConfigData } from "../../config"; +import { Blip } from "../../model"; type VisualBlipProps = { - className: string, - fill: string, - 'data-background-color': string, - 'data-text-color': string, - 'data-tip': string, - key: number -} + className: string; + fill: string; + "data-background-color": string; + "data-text-color": string; + "data-tip": string; + key: number; +}; export const ChangedBlip: React.FC< - {blip: Blip, config: ConfigData} & VisualBlipProps -> = ({blip, config, ...props}) => { - const centeredX = blip.coordinates.x - config.chartConfig.blipSize/2, - centeredY = blip.coordinates.y - config.chartConfig.blipSize/2; + { blip: Blip; config: ConfigData } & VisualBlipProps +> = ({ blip, config, ...props }) => { + const centeredX = blip.coordinates.x - config.chartConfig.blipSize / 2, + centeredY = blip.coordinates.y - config.chartConfig.blipSize / 2; - return ( - - ); + return ( + + ); }; export const NewBlip: React.FC< - {blip: Blip, config: ConfigData} & VisualBlipProps -> = ({blip, config, ...props}) => { - const centeredX = blip.coordinates.x - config.chartConfig.blipSize/2, - centeredY = blip.coordinates.y - config.chartConfig.blipSize/2; + { blip: Blip; config: ConfigData } & VisualBlipProps +> = ({ blip, config, ...props }) => { + const centeredX = blip.coordinates.x - config.chartConfig.blipSize / 2, + centeredY = blip.coordinates.y - config.chartConfig.blipSize / 2; - /* + /* The below is a predefined path of a triangle with rounded corners. I didn't find any more human friendly way of doing this as all examples I found have tons of lines of code e.g. https://observablehq.com/@perlmonger42/interactive-rounded-corners-on-svg-polygons-using-d3-js */ - return ( - - ); + return ( + + ); }; export const DefaultBlip: React.FC< - {blip: Blip, config: ConfigData} & VisualBlipProps -> = ({blip, config, ...props}) => { - return ( - - ); -}; \ No newline at end of file + { blip: Blip; config: ConfigData } & VisualBlipProps +> = ({ blip, config, ...props }) => { + return ( + + ); +}; diff --git a/src/components/Chart/QuadrantRings.tsx b/src/components/Chart/QuadrantRings.tsx index b4e6e2a..f520c8f 100644 --- a/src/components/Chart/QuadrantRings.tsx +++ b/src/components/Chart/QuadrantRings.tsx @@ -1,74 +1,92 @@ -import React from 'react'; -import * as d3 from 'd3'; -import { QuadrantConfig } from '../../model'; -import { ConfigData } from '../../config'; +import * as d3 from "d3"; +import React from "react"; -function arcPath(quadrantPosition: number, ringPosition: number, xScale: d3.ScaleLinear, config: ConfigData) { - const startAngle = quadrantPosition === 1 ? - 3 * Math.PI / 2 - : (quadrantPosition - 2) * Math.PI / 2 - const endAngle = quadrantPosition === 1 ? - 4 * Math.PI / 2 - : (quadrantPosition -1) * Math.PI / 2 - const arcAttrs = config.chartConfig.ringsAttributes[ringPosition], - ringRadiusPx = xScale(arcAttrs.radius) - xScale(0), - arc = d3.arc(); +import { ConfigData } from "../../config"; +import { QuadrantConfig } from "../../model"; - return arc({ - innerRadius: ringRadiusPx - arcAttrs.arcWidth, - outerRadius: ringRadiusPx, - startAngle, - endAngle - }) || undefined; +function arcPath( + quadrantPosition: number, + ringPosition: number, + xScale: d3.ScaleLinear, + config: ConfigData +) { + const startAngle = + quadrantPosition === 1 + ? (3 * Math.PI) / 2 + : ((quadrantPosition - 2) * Math.PI) / 2; + const endAngle = + quadrantPosition === 1 + ? (4 * Math.PI) / 2 + : ((quadrantPosition - 1) * Math.PI) / 2; + const arcAttrs = config.chartConfig.ringsAttributes[ringPosition], + ringRadiusPx = xScale(arcAttrs.radius) - xScale(0), + arc = d3.arc(); + + return ( + arc({ + innerRadius: ringRadiusPx - arcAttrs.arcWidth, + outerRadius: ringRadiusPx, + startAngle, + endAngle, + }) || undefined + ); } const QuadrantRings: React.FC<{ - quadrant: QuadrantConfig - xScale: d3.ScaleLinear - config: ConfigData -}> = ({ quadrant, xScale, config}) => { - // order from top-right clockwise - const gradientAttributes = [ - {x: 0, y: 0, cx: 1, cy: 1, r: 1}, - {x: xScale(0), y: 0, cx: 0, cy: 1, r: 1}, - {x: xScale(0), y: xScale(0), cx: 0, cy: 0, r: 1}, - {x: 0, y: xScale(0), cx: 1, cy: 0, r: 1} - ]; - const gradientId = `${quadrant.position}-radial-gradient`, - quadrantSize = config.chartConfig.size / 2; + quadrant: QuadrantConfig; + xScale: d3.ScaleLinear; + config: ConfigData; +}> = ({ quadrant, xScale, config }) => { + // order from top-right clockwise + const gradientAttributes = [ + { x: 0, y: 0, cx: 1, cy: 1, r: 1 }, + { x: xScale(0), y: 0, cx: 0, cy: 1, r: 1 }, + { x: xScale(0), y: xScale(0), cx: 0, cy: 0, r: 1 }, + { x: 0, y: xScale(0), cx: 1, cy: 0, r: 1 }, + ]; + const gradientId = `${quadrant.position}-radial-gradient`, + quadrantSize = config.chartConfig.size / 2; - return ( - - {/* Definition of the quadrant gradient */} - - - - - - + return ( + + {/* Definition of the quadrant gradient */} + + + + + + - {/* Gradient background area */} - + + {/* Rings' arcs */} + {Array.from(config.rings).map((ringPosition, index) => ( + + ))} + + ); +}; - {/* Rings' arcs */} - {Array.from(config.rings).map((ringPosition, index) => ( - - ))} - - - ); - } - - export default QuadrantRings; \ No newline at end of file +export default QuadrantRings; diff --git a/src/components/Chart/RadarChart.tsx b/src/components/Chart/RadarChart.tsx index 031f2d6..f4cbd2a 100644 --- a/src/components/Chart/RadarChart.tsx +++ b/src/components/Chart/RadarChart.tsx @@ -1,77 +1,109 @@ -import React from 'react'; import * as d3 from "d3"; -import ReactTooltip from 'react-tooltip'; -import { Item } from '../../model'; -import { YAxis, XAxis } from './Axes'; -import QuadrantRings from './QuadrantRings'; -import BlipPoints from './BlipPoints'; +import React from "react"; +import ReactTooltip from "react-tooltip"; -import './chart.scss'; -import { ConfigData } from '../../config'; +import { ConfigData } from "../../config"; +import { Item } from "../../model"; +import { XAxis, YAxis } from "./Axes"; +import BlipPoints from "./BlipPoints"; +import QuadrantRings from "./QuadrantRings"; +import "./chart.scss"; const RingLabel: React.FC<{ - ring: string - xScale: d3.ScaleLinear - yScale: d3.ScaleLinear - config: ConfigData -}> = ({ring, xScale, yScale, config}) => { - const ringIndex = config.rings.findIndex(r => r === ring) + ring: string; + xScale: d3.ScaleLinear; + yScale: d3.ScaleLinear; + config: ConfigData; +}> = ({ ring, xScale, yScale, config }) => { + const ringIndex = config.rings.findIndex((r) => r === ring); - const ringRadius = config.chartConfig.ringsAttributes[ringIndex].radius, - previousRingRadius = ringIndex === 0 ? 0 : config.chartConfig.ringsAttributes[ringIndex - 1].radius, + const ringRadius = config.chartConfig.ringsAttributes[ringIndex].radius, + previousRingRadius = + ringIndex === 0 + ? 0 + : config.chartConfig.ringsAttributes[ringIndex - 1].radius, + // middle point in between two ring arcs + distanceFromCentre = + previousRingRadius + (ringRadius - previousRingRadius) / 2; - // middle point in between two ring arcs - distanceFromCentre = previousRingRadius + (ringRadius - previousRingRadius) / 2; - - return ( - - {/* Right hand-side label */} - - {ring} - - {/* Left hand-side label */} - - {ring} - - - ); + return ( + + {/* Right hand-side label */} + + {ring} + + {/* Left hand-side label */} + + {ring} + + + ); }; const RadarChart: React.FC<{ - items: Item[] - config: ConfigData + items: Item[]; + config: ConfigData; }> = ({ items, config }) => { - - const xScale = d3.scaleLinear() + const xScale = d3 + .scaleLinear() .domain(config.chartConfig.scale) .range([0, config.chartConfig.size]); - const yScale = d3.scaleLinear() + const yScale = d3 + .scaleLinear() .domain(config.chartConfig.scale) .range([config.chartConfig.size, 0]); return ( -
- - - - - - - +
+ + + + + + + - {Object.values(config.quadrantsMap).map((value, index) => ( - - ))} + {Object.values(config.quadrantsMap).map((value, index) => ( + + ))} - {Array.from(config.rings).map((ring: string, index) => ( - - ))} + {Array.from(config.rings).map((ring: string, index) => ( + + ))} - + - +
- ); -} + ); +}; export default RadarChart; diff --git a/src/components/EditButton/EditButton.tsx b/src/components/EditButton/EditButton.tsx index a5eb1cb..c6c4e53 100644 --- a/src/components/EditButton/EditButton.tsx +++ b/src/components/EditButton/EditButton.tsx @@ -1,16 +1,28 @@ import React from "react"; + import { Item } from "../../model"; import "./editButton.scss"; type EditButtonProps = { baseUrl: string; - item: Item & { release? : string } + item: Item & { release?: string }; title?: string; }; -export default function EditButton({baseUrl, item, title}: React.PropsWithChildren) { +export default function EditButton({ + baseUrl, + item, + title, +}: React.PropsWithChildren) { const href = `${baseUrl}/${item.release}/${item.name}.md`; return ( - {title || 'Edit'} + + {title || "Edit"} + ); } diff --git a/src/components/Fadeable/Fadeable.tsx b/src/components/Fadeable/Fadeable.tsx index 1926023..8f7d402 100644 --- a/src/components/Fadeable/Fadeable.tsx +++ b/src/components/Fadeable/Fadeable.tsx @@ -1,5 +1,6 @@ -import React, { useState, useEffect } from "react"; import classNames from "classnames"; +import React, { useEffect, useState } from "react"; + import "./fadeable.scss"; type FadeableProps = { diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx index 243319a..91129d3 100644 --- a/src/components/Footer/Footer.tsx +++ b/src/components/Footer/Footer.tsx @@ -1,12 +1,13 @@ -import React from "react"; import classNames from "classnames"; +import React from "react"; + +import { assetUrl, getItemPageNames, isMobileViewport } from "../../config"; +import { useMessages } from "../../context/MessagesContext"; +import { Item } from "../../model"; +import { sanitize } from "../../sanitize"; import Branding from "../Branding/Branding"; import FooterEnd from "../FooterEnd/FooterEnd"; -import { assetUrl, getItemPageNames, isMobileViewport } from "../../config"; -import { Item } from "../../model"; import "./footer.scss"; -import { useMessages } from "../../context/MessagesContext"; -import { sanitize } from "../../sanitize"; interface Props { items: Item[]; @@ -35,7 +36,10 @@ const Footer: React.FC = ({ items, pageName }) => { /> } > -
+
)} diff --git a/src/components/FooterEnd/FooterEnd.tsx b/src/components/FooterEnd/FooterEnd.tsx index 3278b61..3db57db 100644 --- a/src/components/FooterEnd/FooterEnd.tsx +++ b/src/components/FooterEnd/FooterEnd.tsx @@ -1,15 +1,21 @@ -import React from "react"; import classNames from "classnames"; +import React from "react"; + +import { useMessages } from "../../context/MessagesContext"; import SocialLink from "../SocialLink/SocialLink"; import "./footerend.scss"; -import { useMessages } from "../../context/MessagesContext"; interface Props { modifier?: "in-sidebar"; } const FooterEnd: React.FC = ({ modifier }) => { - const { socialLinksLabel, socialLinks, legalInformationLink, legalInformationLabel } = useMessages(); + const { + socialLinksLabel, + socialLinks, + legalInformationLink, + legalInformationLabel, + } = useMessages(); return (
= ({ modifier }) => { {socialLinks && ( <>
-

{socialLinksLabel ?? 'Follow us:' }

+

{socialLinksLabel ?? "Follow us:"}

{socialLinks.map(({ href, iconName }) => ( @@ -40,7 +46,7 @@ const FooterEnd: React.FC = ({ modifier }) => { target="_blank" rel="noopener noreferrer" > - {legalInformationLabel || 'Legal Information'} + {legalInformationLabel || "Legal Information"}

diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index e3a2b32..030dfb3 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,13 +1,14 @@ -import React, { useState, useRef } from "react"; import classNames from "classnames"; +import qs from "query-string"; +import React, { useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import { radarNameShort } from "../../config"; +import { useMessages } from "../../context/MessagesContext"; import Branding from "../Branding/Branding"; import Link from "../Link/Link"; import LogoLink from "../LogoLink/LogoLink"; import Search from "../Search/Search"; -import { radarNameShort } from "../../config"; -import { useNavigate } from "react-router-dom"; -import qs from "query-string"; -import { useMessages } from "../../context/MessagesContext"; export default function Header({ pageName }: { pageName: string }) { const [searchOpen, setSearchOpen] = useState(false); diff --git a/src/components/HeadlineGroup/HeadlineGroup.tsx b/src/components/HeadlineGroup/HeadlineGroup.tsx index 9864c52..3fc815e 100644 --- a/src/components/HeadlineGroup/HeadlineGroup.tsx +++ b/src/components/HeadlineGroup/HeadlineGroup.tsx @@ -1,5 +1,6 @@ -import React from "react"; import classNames from "classnames"; +import React from "react"; + import "./headline-group.scss"; interface Props { diff --git a/src/components/HeroHeadline/HeroHeadline.tsx b/src/components/HeroHeadline/HeroHeadline.tsx index 7421b2f..ccfc664 100644 --- a/src/components/HeroHeadline/HeroHeadline.tsx +++ b/src/components/HeroHeadline/HeroHeadline.tsx @@ -1,4 +1,5 @@ import React from "react"; + import "./hero-headline.scss"; interface Props { diff --git a/src/components/Item/Item.tsx b/src/components/Item/Item.tsx index 5f5aa90..c67c090 100644 --- a/src/components/Item/Item.tsx +++ b/src/components/Item/Item.tsx @@ -1,8 +1,9 @@ -import React from "react"; import classNames from "classnames"; -import Link from "../Link/Link"; -import Flag from "../Flag/Flag"; +import React from "react"; + import { Item as mItem } from "../../model"; +import Flag from "../Flag/Flag"; +import Link from "../Link/Link"; import "./item.scss"; type Props = { diff --git a/src/components/ItemList/ItemList.tsx b/src/components/ItemList/ItemList.tsx index eb4d468..1cdebee 100644 --- a/src/components/ItemList/ItemList.tsx +++ b/src/components/ItemList/ItemList.tsx @@ -1,6 +1,7 @@ import React from "react"; + +import { featuredOnly, Item as mItem, nonFeaturedOnly } from "../../model"; import Item from "../Item/Item"; -import { featuredOnly, nonFeaturedOnly, Item as mItem } from "../../model"; import "./item-list.scss"; type ItemListProps = { diff --git a/src/components/ItemRevision/ItemRevision.tsx b/src/components/ItemRevision/ItemRevision.tsx index 58853d3..fdb06e5 100644 --- a/src/components/ItemRevision/ItemRevision.tsx +++ b/src/components/ItemRevision/ItemRevision.tsx @@ -1,13 +1,13 @@ -import Badge from "../Badge/Badge"; import { formatRelease } from "../../date"; import { Revision } from "../../model"; +import Badge from "../Badge/Badge"; export default function ItemRevision({ revision, dateFormat, }: { revision: Revision; - dateFormat?: string + dateFormat?: string; }) { return (
diff --git a/src/components/ItemRevisions/ItemRevisions.tsx b/src/components/ItemRevisions/ItemRevisions.tsx index b6978e2..e4e9424 100644 --- a/src/components/ItemRevisions/ItemRevisions.tsx +++ b/src/components/ItemRevisions/ItemRevisions.tsx @@ -1,25 +1,31 @@ +import { useMessages } from "../../context/MessagesContext"; +import { Revision } from "../../model"; import HeadlineGroup from "../HeadlineGroup/HeadlineGroup"; import ItemRevision from "../ItemRevision/ItemRevision"; -import { Revision } from "../../model"; import "./item-revisions.scss"; -import { useMessages } from "../../context/MessagesContext"; export default function ItemRevisions({ revisions, dateFormat, }: { revisions: Revision[]; - dateFormat?: string + dateFormat?: string; }) { const { revisionsText } = useMessages(); return (
-

{revisionsText ?? 'Revisions:'}

+

+ {revisionsText ?? "Revisions:"} +

{revisions.map((revision) => ( - + ))}
); diff --git a/src/components/Link/Link.tsx b/src/components/Link/Link.tsx index 32d0a7b..1424c26 100644 --- a/src/components/Link/Link.tsx +++ b/src/components/Link/Link.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Link as RLink } from "react-router-dom"; + import "./link.scss"; type LinkProps = { diff --git a/src/components/LogoLink/LogoLink.tsx b/src/components/LogoLink/LogoLink.tsx index bd0f1cc..996c4f2 100644 --- a/src/components/LogoLink/LogoLink.tsx +++ b/src/components/LogoLink/LogoLink.tsx @@ -1,8 +1,10 @@ -import React from "react"; import classNames from "classnames"; -import Link from "../Link/Link"; +import React from "react"; + import { assetUrl, radarNameShort } from "../../config"; +import Link from "../Link/Link"; import "./logo-link.scss"; + export default function LogoLink({ small = false }: { small?: boolean }) { return ( = ({ leaving, onLeave }) => { const { pageHelp } = useMessages(); if (pageHelp) { - const { paragraphs, quadrants, rings, sourcecodeLink, headlinePrefix, quadrantsPreDescription, ringsPreDescription } = pageHelp; - const title = `${headlinePrefix || 'How to use the'} ${radarName}`; + const { + paragraphs, + quadrants, + rings, + sourcecodeLink, + headlinePrefix, + quadrantsPreDescription, + ringsPreDescription, + } = pageHelp; + const title = `${headlinePrefix || "How to use the"} ${radarName}`; return ( - + {title}
{paragraphs.map(({ headline, values }) => ( - -

{headline}

- {values.map((element, index) => { - return ( -

- ) - }) - } -
+ +

{headline}

+ {values.map((element, index) => { + return ( +

+ ); + })} +
))}

{quadrantsPreDescription ?? "The quadrants are:"}

    {quadrants.map(({ name, description }) => (
  • - {name}: + {name}:{" "} +
  • ))}
-

{ringsPreDescription ?? "Each of the items is classified in one of these rings:"}

+

+ {ringsPreDescription ?? + "Each of the items is classified in one of these rings:"} +

    {rings.map(({ name, description }) => (
  • - {name}: + {name}:{" "} +
  • ))}
diff --git a/src/components/PageIndex/PageIndex.tsx b/src/components/PageIndex/PageIndex.tsx index b54c1f9..eab116d 100644 --- a/src/components/PageIndex/PageIndex.tsx +++ b/src/components/PageIndex/PageIndex.tsx @@ -1,13 +1,14 @@ +import { MomentInput } from "moment"; + +import { ConfigData, radarName, radarNameShort } from "../../config"; +import { useMessages } from "../../context/MessagesContext"; import { formatRelease } from "../../date"; -import { featuredOnly, Item, HomepageOption } from "../../model"; +import { HomepageOption, Item, featuredOnly } from "../../model"; +import Fadeable from "../Fadeable/Fadeable"; import HeroHeadline from "../HeroHeadline/HeroHeadline"; import QuadrantGrid from "../QuadrantGrid/QuadrantGrid"; -import RadarGrid from '../RadarGrid/RadarGrid'; -import Fadeable from "../Fadeable/Fadeable"; +import RadarGrid from "../RadarGrid/RadarGrid"; import SetTitle from "../SetTitle"; -import { ConfigData, radarName, radarNameShort } from "../../config"; -import { MomentInput } from "moment"; -import { useMessages } from "../../context/MessagesContext"; type PageIndexProps = { leaving: boolean; @@ -25,12 +26,16 @@ export default function PageIndex({ releases, }: PageIndexProps) { const { pageIndex } = useMessages(); - const publishedLabel = pageIndex?.publishedLabel || 'Published'; + const publishedLabel = pageIndex?.publishedLabel || "Published"; const newestRelease = releases.slice(-1)[0]; const numberOfReleases = releases.length; - const showChart = config.homepageContent === HomepageOption.chart || config.homepageContent === HomepageOption.both; - const showColumns = config.homepageContent === HomepageOption.columns || config.homepageContent === HomepageOption.both; + const showChart = + config.homepageContent === HomepageOption.chart || + config.homepageContent === HomepageOption.both; + const showColumns = + config.homepageContent === HomepageOption.columns || + config.homepageContent === HomepageOption.both; return ( @@ -39,9 +44,7 @@ export default function PageIndex({ {radarName}
- {showChart && ( - - )} + {showChart && } {showColumns && ( )} diff --git a/src/components/PageItem/PageItem.tsx b/src/components/PageItem/PageItem.tsx index af895fb..08e2922 100644 --- a/src/components/PageItem/PageItem.tsx +++ b/src/components/PageItem/PageItem.tsx @@ -1,19 +1,17 @@ import React from "react"; + +import { ConfigData, translate } from "../../config"; +import { useMessages } from "../../context/MessagesContext"; +import { Item, groupByQuadrants } from "../../model"; import Badge from "../Badge/Badge"; import EditButton from "../EditButton/EditButton"; -import ItemList from "../ItemList/ItemList"; -import Link from "../Link/Link"; import FooterEnd from "../FooterEnd/FooterEnd"; -import SetTitle from "../SetTitle"; +import ItemList from "../ItemList/ItemList"; import ItemRevisions from "../ItemRevisions/ItemRevisions"; -import { useAnimations } from "./useAnimations"; +import Link from "../Link/Link"; +import SetTitle from "../SetTitle"; import "./item-page.scss"; -import { ConfigData, translate } from "../../config"; -import { - groupByQuadrants, - Item, -} from "../../model"; -import { useMessages } from "../../context/MessagesContext"; +import { useAnimations } from "./useAnimations"; const getItem = (pageName: string, items: Item[]) => { const [quadrantName, itemName] = pageName.split("/"); @@ -35,9 +33,15 @@ type Props = { onLeave: () => void; }; -const PageItem: React.FC = ({ pageName, items, config, leaving, onLeave }) => { +const PageItem: React.FC = ({ + pageName, + items, + config, + leaving, + onLeave, +}) => { const { pageItem } = useMessages(); - const quadrantOverview = pageItem?.quadrantOverview || 'Quadrant Overview'; + const quadrantOverview = pageItem?.quadrantOverview || "Quadrant Overview"; const itemsInRing = getItemsInRing(pageName, items); @@ -48,7 +52,13 @@ const PageItem: React.FC = ({ pageName, items, config, leaving, onLeave } }); const item = getItem(pageName, items); - const editButton = config.editLink ? : null + const editButton = config.editLink ? ( + + ) : null; return ( <> @@ -119,7 +129,10 @@ const PageItem: React.FC = ({ pageName, items, config, leaving, onLeave } dangerouslySetInnerHTML={{ __html: item.body }} /> {item.revisions.length > 1 && ( - + )}
diff --git a/src/components/PageItem/useAnimations.tsx b/src/components/PageItem/useAnimations.tsx index 9d6f27e..64af4e3 100644 --- a/src/components/PageItem/useAnimations.tsx +++ b/src/components/PageItem/useAnimations.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState, useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; + import { Animation, AnimationStates, @@ -13,18 +14,14 @@ interface Props { onLeave: () => void; } -export const useAnimations = ({ - itemsInRing, - leaving, - onLeave, -}: Props) => { +export const useAnimations = ({ itemsInRing, leaving, onLeave }: Props) => { type AnimationConfig = { background: Animation; navHeader: Animation; text: Animation; items: Animation[]; footer: Animation; - } + }; type AnimationNames = keyof AnimationConfig; diff --git a/src/components/PageItemMobile/PageItemMobile.tsx b/src/components/PageItemMobile/PageItemMobile.tsx index 4b8c9a8..9b39ff5 100644 --- a/src/components/PageItemMobile/PageItemMobile.tsx +++ b/src/components/PageItemMobile/PageItemMobile.tsx @@ -1,13 +1,12 @@ +import { ConfigData, translate } from "../../config"; +import { Item, groupByQuadrants } from "../../model"; import Badge from "../Badge/Badge"; import EditButton from "../EditButton/EditButton"; -import ItemList from "../ItemList/ItemList"; -import Link from "../Link/Link"; import Fadeable from "../Fadeable/Fadeable"; -import SetTitle from "../SetTitle"; +import ItemList from "../ItemList/ItemList"; import ItemRevisions from "../ItemRevisions/ItemRevisions"; - -import { ConfigData, translate } from "../../config"; -import { groupByQuadrants, Item } from "../../model"; +import Link from "../Link/Link"; +import SetTitle from "../SetTitle"; type PageItemMobileProps = { pageName: string; @@ -40,7 +39,13 @@ export default function PageItemMobile({ const item = getItem(pageName, items); const itemsInRing = getItemsInRing(pageName, items); - const editButton = config.editLink ? : null + const editButton = config.editLink ? ( + + ) : null; return ( @@ -50,7 +55,9 @@ export default function PageItemMobile({
-

{translate(config, item.quadrant)}

+

+ {translate(config, item.quadrant)} +

{item.title}

diff --git a/src/components/PageOverview/PageOverview.tsx b/src/components/PageOverview/PageOverview.tsx index afaa667..bcc75a8 100644 --- a/src/components/PageOverview/PageOverview.tsx +++ b/src/components/PageOverview/PageOverview.tsx @@ -1,15 +1,16 @@ -import { useState, useEffect } from "react"; -import HeadlineGroup from "../HeadlineGroup/HeadlineGroup"; -import HeroHeadline from "../HeroHeadline/HeroHeadline"; -import Badge from "../Badge/Badge"; -import Link from "../Link/Link"; -import Search from "../Search/Search"; -import Fadeable from "../Fadeable/Fadeable"; -import SetTitle from "../SetTitle"; -import Flag from "../Flag/Flag"; -import { groupByFirstLetter, Item } from "../../model"; +import { useEffect, useState } from "react"; + import { ConfigData, translate } from "../../config"; import { useMessages } from "../../context/MessagesContext"; +import { Item, groupByFirstLetter } from "../../model"; +import Badge from "../Badge/Badge"; +import Fadeable from "../Fadeable/Fadeable"; +import Flag from "../Flag/Flag"; +import HeadlineGroup from "../HeadlineGroup/HeadlineGroup"; +import HeroHeadline from "../HeroHeadline/HeroHeadline"; +import Link from "../Link/Link"; +import Search from "../Search/Search"; +import SetTitle from "../SetTitle"; const containsSearchTerm = (text = "", term = "") => { // TODO search refinement diff --git a/src/components/PageQuadrant/PageQuadrant.tsx b/src/components/PageQuadrant/PageQuadrant.tsx index 311c307..6c9d533 100644 --- a/src/components/PageQuadrant/PageQuadrant.tsx +++ b/src/components/PageQuadrant/PageQuadrant.tsx @@ -1,12 +1,12 @@ import React from "react"; -import HeroHeadline from "../HeroHeadline/HeroHeadline"; -import HeadlineGroup from "../HeadlineGroup/HeadlineGroup"; -import QuadrantSection from "../QuadrantSection/QuadrantSection"; -import Fadeable from "../Fadeable/Fadeable"; -import SetTitle from "../SetTitle"; import { ConfigData, translate } from "../../config"; -import { featuredOnly, groupByQuadrants, Item } from "../../model"; +import { Item, featuredOnly, groupByQuadrants } from "../../model"; +import Fadeable from "../Fadeable/Fadeable"; +import HeadlineGroup from "../HeadlineGroup/HeadlineGroup"; +import HeroHeadline from "../HeroHeadline/HeroHeadline"; +import QuadrantSection from "../QuadrantSection/QuadrantSection"; +import SetTitle from "../SetTitle"; type PageQuadrantProps = { leaving: boolean; diff --git a/src/components/QuadrantGrid/QuadrantGrid.tsx b/src/components/QuadrantGrid/QuadrantGrid.tsx index 65faf27..b2c2efd 100644 --- a/src/components/QuadrantGrid/QuadrantGrid.tsx +++ b/src/components/QuadrantGrid/QuadrantGrid.tsx @@ -1,21 +1,39 @@ import React from "react"; -import { groupByQuadrants, Item, Group } from "../../model"; + import { ConfigData } from "../../config"; +import { Group, Item, groupByQuadrants } from "../../model"; import QuadrantSection from "../QuadrantSection/QuadrantSection"; import "./quadrant-grid.scss"; -const renderQuadrant = (quadrantName: string, groups: Group, config: ConfigData) => { + +const renderQuadrant = ( + quadrantName: string, + groups: Group, + config: ConfigData +) => { return (
- +
); }; -export default function QuadrantGrid({ items, config }: { items: Item[], config: ConfigData }) { +export default function QuadrantGrid({ + items, + config, +}: { + items: Item[]; + config: ConfigData; +}) { const groups = groupByQuadrants(items); return (
- {Object.keys(config.quadrants).map((quadrantName: string) => renderQuadrant(quadrantName, groups, config))} + {Object.keys(config.quadrants).map((quadrantName: string) => + renderQuadrant(quadrantName, groups, config) + )}
); } diff --git a/src/components/QuadrantSection/QuadrantSection.tsx b/src/components/QuadrantSection/QuadrantSection.tsx index 3cd6dca..f14ebe4 100644 --- a/src/components/QuadrantSection/QuadrantSection.tsx +++ b/src/components/QuadrantSection/QuadrantSection.tsx @@ -1,10 +1,11 @@ -import { translate, ConfigData } from "../../config"; -import Badge from "../Badge/Badge"; -import Link from "../Link/Link"; -import ItemList from "../ItemList/ItemList"; -import Flag from "../Flag/Flag"; +import { ConfigData, translate } from "../../config"; import { Group } from "../../model"; +import Badge from "../Badge/Badge"; +import Flag from "../Flag/Flag"; +import ItemList from "../ItemList/ItemList"; +import Link from "../Link/Link"; import "./quadrant-section.scss"; + const renderList = ( ringName: string, quadrantName: string, diff --git a/src/components/RadarGrid/RadarGrid.tsx b/src/components/RadarGrid/RadarGrid.tsx index 2b814a0..b71dcf2 100644 --- a/src/components/RadarGrid/RadarGrid.tsx +++ b/src/components/RadarGrid/RadarGrid.tsx @@ -1,10 +1,10 @@ import React from "react"; -import RadarChart from "../Chart/RadarChart"; + import { ConfigData } from "../../config"; import { Item, QuadrantConfig } from "../../model"; - -import "./radar-grid.scss"; +import RadarChart from "../Chart/RadarChart"; import Link from "../Link/Link"; +import "./radar-grid.scss"; const QuadrantLabel: React.FC<{ quadrantConfig: QuadrantConfig; @@ -19,7 +19,10 @@ const QuadrantLabel: React.FC<{ ]; return ( -
+
Quadrant {quadrantConfig.position} @@ -65,7 +68,12 @@ const RadarGrid: React.FC<{ items: Item[]; config: ConfigData }> = ({
{Object.entries(config.quadrantsMap).map(([name, quadrant], index) => ( - + ))}
diff --git a/src/components/Router.tsx b/src/components/Router.tsx index 287543c..cae6bc3 100644 --- a/src/components/Router.tsx +++ b/src/components/Router.tsx @@ -1,13 +1,13 @@ -import { useState, useEffect } from "react"; +import { useEffect, useState } from "react"; -import PageIndex from "./PageIndex/PageIndex"; -import PageOverview from "./PageOverview/PageOverview"; -import PageHelp from "./PageHelp/PageHelp"; -import PageQuadrant from "./PageQuadrant/PageQuadrant"; -import PageItem from "./PageItem/PageItem"; -import PageItemMobile from "./PageItemMobile/PageItemMobile"; import { ConfigData, getItemPageNames, isMobileViewport } from "../config"; import { Item } from "../model"; +import PageHelp from "./PageHelp/PageHelp"; +import PageIndex from "./PageIndex/PageIndex"; +import PageItem from "./PageItem/PageItem"; +import PageItemMobile from "./PageItemMobile/PageItemMobile"; +import PageOverview from "./PageOverview/PageOverview"; +import PageQuadrant from "./PageQuadrant/PageQuadrant"; type RouterProps = { pageName: string; diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx index 66bdf9c..1c7db56 100644 --- a/src/components/Search/Search.tsx +++ b/src/components/Search/Search.tsx @@ -1,6 +1,7 @@ -import React, { FormEvent } from "react"; -import { useMessages } from "../../context/MessagesContext"; import classNames from "classnames"; +import React, { FormEvent } from "react"; + +import { useMessages } from "../../context/MessagesContext"; import "./search.scss"; type SearchProps = { @@ -52,7 +53,7 @@ function Search( {closable && ( diff --git a/src/components/SetTitle.tsx b/src/components/SetTitle.tsx index 25ae7ac..feec9be 100644 --- a/src/components/SetTitle.tsx +++ b/src/components/SetTitle.tsx @@ -1,4 +1,5 @@ import { useEffect } from "react"; + import { radarName } from "../config"; type SetTitleProps = { diff --git a/src/components/SocialLink/SocialLink.tsx b/src/components/SocialLink/SocialLink.tsx index 9374c81..c8c96c8 100644 --- a/src/components/SocialLink/SocialLink.tsx +++ b/src/components/SocialLink/SocialLink.tsx @@ -1,13 +1,13 @@ import React from "react"; import { + FaExternalLinkAlt, FaFacebookF, - FaTwitter, - FaLinkedinIn, - FaXing, - FaYoutube, FaGithub, FaInstagram, - FaExternalLinkAlt + FaLinkedinIn, + FaTwitter, + FaXing, + FaYoutube, } from "react-icons/fa"; const icons = { diff --git a/src/config.ts b/src/config.ts index 56c4cd8..f52817b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,4 +1,4 @@ -import {Item, HomepageOption, QuadrantConfig} from './model'; +import { HomepageOption, Item, QuadrantConfig } from "./model"; export interface ConfigData { tags?: string[]; @@ -7,17 +7,17 @@ export interface ConfigData { showEmptyRings: boolean; quadrantsMap: { [quadrant: string]: QuadrantConfig }; chartConfig: { - size: number, - scale: number[], - blipSize: number, - ringsAttributes: {radius: number, arcWidth: number}[] + size: number; + scale: number[]; + blipSize: number; + ringsAttributes: { radius: number; arcWidth: number }[]; }; homepageContent: HomepageOption; dateFormat?: string; editLink?: { - radarLink: string, - title?: string - } + radarLink: string; + title?: string; + }; } export const radarName = diff --git a/src/context/MessagesContext/index.tsx b/src/context/MessagesContext/index.tsx index f8cac91..46984b7 100644 --- a/src/context/MessagesContext/index.tsx +++ b/src/context/MessagesContext/index.tsx @@ -1,4 +1,5 @@ -import { createContext, FC, useContext } from "react"; +import { FC, createContext, useContext } from "react"; + import { Props as SocialLink } from "../../components/SocialLink/SocialLink"; interface Quadrant { diff --git a/src/date.test.tsx b/src/date.test.tsx index efde281..d22ac15 100644 --- a/src/date.test.tsx +++ b/src/date.test.tsx @@ -1,11 +1,14 @@ import moment from "moment"; + import { formatRelease } from "./date"; describe("formatRelease", () => { it("should format a date object using default output format", () => { - expect(formatRelease(moment('2022-01-05'))).toEqual('January 2022') + expect(formatRelease(moment("2022-01-05"))).toEqual("January 2022"); }); it("should format a date object using a custom output format", () => { - expect(formatRelease(moment('2022-01-05'), 'DD.MM.YYYY')).toEqual('05.01.2022') + expect(formatRelease(moment("2022-01-05"), "DD.MM.YYYY")).toEqual( + "05.01.2022" + ); }); }); diff --git a/src/date.ts b/src/date.ts index 97d7219..00c40b7 100644 --- a/src/date.ts +++ b/src/date.ts @@ -3,5 +3,7 @@ import moment from "moment"; const isoDateToMoment = (isoDate: moment.MomentInput) => moment(isoDate, "YYYY-MM-DD"); -export const formatRelease = (isoDate: moment.MomentInput, format: string = "MMMM YYYY") => - isoDateToMoment(isoDate).format(format); +export const formatRelease = ( + isoDate: moment.MomentInput, + format: string = "MMMM YYYY" +) => isoDateToMoment(isoDate).format(format); diff --git a/src/index.tsx b/src/index.tsx index 1928713..d917c49 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; -import App from "./components/App"; import { createRoot } from "react-dom/client"; + +import App from "./components/App"; import "./index.scss"; const container = document.getElementById("root")!; diff --git a/src/model.ts b/src/model.ts index 3e01c3e..ffe3094 100644 --- a/src/model.ts +++ b/src/model.ts @@ -1,7 +1,7 @@ export enum HomepageOption { chart = "chart", columns = "columns", - both = "both" + both = "both", } export type ItemAttributes = { @@ -14,9 +14,9 @@ export type ItemAttributes = { }; export enum FlagType { - new = 'new', - changed = 'changed', - default = 'default' + new = "new", + changed = "changed", + default = "default", } export type Item = ItemAttributes & { @@ -28,12 +28,12 @@ export type Item = ItemAttributes & { }; export type Blip = Item & { - quadrantPosition: number - ringPosition: number - colour: string - txtColour: string - coordinates: Point -} + quadrantPosition: number; + ringPosition: number; + colour: string; + txtColour: string; + coordinates: Point; +}; export type Revision = ItemAttributes & { body: string; @@ -46,11 +46,11 @@ export type Quadrant = { }; export type QuadrantConfig = { - colour: string, - txtColour: string, - position: number, - description: string -} + colour: string; + txtColour: string; + position: number; + description: string; +}; export type Radar = { items: Item[]; @@ -67,9 +67,9 @@ export const nonFeaturedOnly = (items: Item[]) => items.filter((item) => !item.featured); export type Point = { - x: number, - y: number -} + x: number; + y: number; +}; export const groupByQuadrants = (items: Item[]): Group => items.reduce( diff --git a/src/sanitize.test.tsx b/src/sanitize.test.tsx index dacd947..fc6e4cb 100644 --- a/src/sanitize.test.tsx +++ b/src/sanitize.test.tsx @@ -2,17 +2,22 @@ import { sanitize } from "./sanitize"; describe("sanitize", () => { it("should sanitize the string input to HTML output", () => { - let res = sanitize('foo'); + let res = sanitize("foo"); expect(res.__html).toEqual("foo"); res = sanitize('Example.org'); - expect(res.__html).toEqual("Example.org"); + expect(res.__html).toEqual('Example.org'); }); it("should not sanitize not allowed tags", () => { - let res = sanitize('Before After'); + let res = sanitize( + 'Before After' + ); expect(res.__html).toEqual("Before After"); }); it("should accept options for rendering", () => { - let res = sanitize('Example.org', { allowedAttributes: { a: ['href']}}); - expect(res.__html).toEqual("Example.org"); + let res = sanitize( + 'Example.org', + { allowedAttributes: { a: ["href"] } } + ); + expect(res.__html).toEqual('Example.org'); }); }); diff --git a/src/sanitize.ts b/src/sanitize.ts index 6c01e77..f97cd76 100644 --- a/src/sanitize.ts +++ b/src/sanitize.ts @@ -1,15 +1,15 @@ -import sanitizeHtml from 'sanitize-html'; +import sanitizeHtml from "sanitize-html"; const defaultSanitizeOptions = { - allowedTags: ['b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'], + allowedTags: ["b", "i", "em", "strong", "a", "ul", "ol", "li"], allowedAttributes: { - 'a': ['href', 'target'] - } -} + a: ["href", "target"], + }, +}; -export const sanitize = (dirty: string, options: sanitizeHtml.IOptions = defaultSanitizeOptions) => ({ - __html: sanitizeHtml( - dirty, - options - ) +export const sanitize = ( + dirty: string, + options: sanitizeHtml.IOptions = defaultSanitizeOptions +) => ({ + __html: sanitizeHtml(dirty, options), });