Add ts-packages for shared Typescript packages using yarn workspaces
@@ -35,4 +35,5 @@ contracts/mixnet/Justfile
|
||||
contracts/mixnet/Makefile
|
||||
validator-config
|
||||
*.patch
|
||||
validator-api-config.toml
|
||||
validator-api-config.toml
|
||||
dist
|
||||
@@ -28,6 +28,8 @@ Wallet build instructions are also available on [our docs site](https://nymtech.
|
||||
|
||||
There's a `.env.sample-dev` file provided which you can rename to `.env` if you want convenient logging, backtrace, or other environment variables pre-set. The `.env` file is ignored so you don't need to worry about checking it in.
|
||||
|
||||
For Typescript components, please see [ts-packages](./ts-packages).
|
||||
|
||||
### Developer chat
|
||||
|
||||
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
||||
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,13 @@
|
||||
<svg width="300" height="300" viewBox="0 0 296 296" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M148 296C229.738 296 296 229.738 296 148C296 66.2619 229.738 0 148 0C66.2619 0 0 66.2619 0 148C0 229.738 66.2619 296 148 296Z" fill="url(#paint0_linear_113_1244)"/>
|
||||
<path d="M148 285.875C224.147 285.875 285.875 224.146 285.875 148C285.875 71.8536 224.147 10.1248 148 10.1248C71.8538 10.1248 10.125 71.8536 10.125 148C10.125 224.146 71.8538 285.875 148 285.875Z" fill="#121725"/>
|
||||
<path d="M88.8829 120.143H88.7169V120.281V168.637L68.3289 120.226L68.3012 120.143H68.1905H56.6272H43.653H43.5146V120.281V175.719V175.857H43.653H56.6272H56.7655V175.719V127.28L77.2365 175.774L77.2642 175.857H77.3748H88.8829H101.829H101.968V175.719V120.281V120.143H101.829H88.8829Z" fill="white"/>
|
||||
<path d="M252.347 120.143H227.616H227.477L227.45 120.253L214.78 168.858L202.082 120.253L202.054 120.143H201.944H177.157H176.991V120.281V175.719V175.857H177.157H190.104H190.242V175.719V127.667L202.774 175.747L202.801 175.857H202.94H226.564H226.675L226.703 175.747L239.234 127.667V175.719V175.857H239.373H252.347H252.485V175.719V120.281V120.143H252.347Z" fill="white"/>
|
||||
<path d="M155.663 120.143H155.58L155.552 120.198L139.812 147.557L123.988 120.198L123.96 120.143H123.877H108.911H108.635L108.773 120.364L133.145 162.579V175.719V175.857H133.283H146.257H146.396V175.719V162.579L170.767 120.364L170.905 120.143H170.629H155.663Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_113_1244" x1="0" y1="148" x2="296" y2="148" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#FC1D60"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,6 @@
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('./OpenSans-VariableFont_wdth,wght.ttf') format('truetype-variations'),
|
||||
url('./OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype-variations');
|
||||
font-weight: 100 1000;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
|
||||
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#F51473"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 714 B |
@@ -0,0 +1,13 @@
|
||||
<svg width="300" height="300" viewBox="0 0 296 296" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M148 296C229.738 296 296 229.738 296 148C296 66.2619 229.738 0 148 0C66.2619 0 0 66.2619 0 148C0 229.738 66.2619 296 148 296Z" fill="url(#paint0_linear_113_1244)"/>
|
||||
<path d="M148 285.875C224.147 285.875 285.875 224.146 285.875 148C285.875 71.8536 224.147 10.1248 148 10.1248C71.8538 10.1248 10.125 71.8536 10.125 148C10.125 224.146 71.8538 285.875 148 285.875Z" fill="#121725"/>
|
||||
<path d="M88.8829 120.143H88.7169V120.281V168.637L68.3289 120.226L68.3012 120.143H68.1905H56.6272H43.653H43.5146V120.281V175.719V175.857H43.653H56.6272H56.7655V175.719V127.28L77.2365 175.774L77.2642 175.857H77.3748H88.8829H101.829H101.968V175.719V120.281V120.143H101.829H88.8829Z" fill="white"/>
|
||||
<path d="M252.347 120.143H227.616H227.477L227.45 120.253L214.78 168.858L202.082 120.253L202.054 120.143H201.944H177.157H176.991V120.281V175.719V175.857H177.157H190.104H190.242V175.719V127.667L202.774 175.747L202.801 175.857H202.94H226.564H226.675L226.703 175.747L239.234 127.667V175.719V175.857H239.373H252.347H252.485V175.719V120.281V120.143H252.347Z" fill="white"/>
|
||||
<path d="M155.663 120.143H155.58L155.552 120.198L139.812 147.557L123.988 120.198L123.96 120.143H123.877H108.911H108.635L108.773 120.364L133.145 162.579V175.719V175.857H133.283H146.257H146.396V175.719V162.579L170.767 120.364L170.905 120.143H170.629H155.663Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_113_1244" x1="0" y1="148" x2="296" y2="148" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.09375" stop-color="#FB6E4E"/>
|
||||
<stop offset="1" stop-color="#FC1D60"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="210" height="56" viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M45.8829 0.142822H45.7169V0.28114V48.637L25.3289 0.225818L25.3012 0.142822H25.1905H13.6272H0.652966H0.514648V0.28114V55.7189V55.8572H0.652966H13.6272H13.7655V55.7189V7.28002L34.2365 55.7742L34.2642 55.8572H34.3748H45.8829H58.8294H58.9677V55.7189V0.28114V0.142822H58.8294H45.8829Z" fill="white"/>
|
||||
<path d="M209.347 0.142822H184.616H184.477L184.45 0.253483L171.78 48.8583L159.082 0.253483L159.054 0.142822H158.944H134.157H133.991V0.28114V55.7189V55.8572H134.157H147.104H147.242V55.7189V7.66731L159.774 55.7466L159.801 55.8572H159.94H183.564H183.675L183.703 55.7466L196.234 7.66731V55.7189V55.8572H196.373H209.347H209.485V55.7189V0.28114V0.142822H209.347Z" fill="white"/>
|
||||
<path d="M112.663 0.142822H112.58L112.552 0.198153L96.8116 27.5574L80.988 0.198153L80.9604 0.142822H80.8774H65.9114H65.6348L65.7731 0.364136L90.1447 42.5787V55.7189V55.8572H90.283H103.257H103.396V55.7189V42.5787L127.767 0.364136L127.905 0.142822H127.629H112.663Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="white"/>
|
||||
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="#070B15"/>
|
||||
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="#141521"/>
|
||||
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="white"/>
|
||||
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="#141521"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -89,12 +89,6 @@
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"packages": [
|
||||
"ts-packages/*"
|
||||
],
|
||||
"version": "0.0.0"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "@nymproject/nymsphere",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "Apache 2.0",
|
||||
"workspaces": [
|
||||
"ts-packages/*",
|
||||
"nym-wallet"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "lerna run --scope @nymproject/mui-theme --scope @nymproject/react build --stream"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lerna": "^4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# See http://editorconfig.org/
|
||||
# EditorConfig helps developers define and maintain consistent coding styles
|
||||
# between different editors and IDEs. The EditorConfig project consists of a
|
||||
# file format for defining coding styles and a collection of text editor plugins
|
||||
# that enable editors to read the file format and adhere to defined styles.
|
||||
# EditorConfig files are easily readable and they work nicely with version
|
||||
# control systems.
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"@nymproject/eslint-config-react-typescript"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# Nym Typescript (and Javascript) packages
|
||||
|
||||
This directory has shared Typescript (and Javascript) libraries using `yarn workspaces`.
|
||||
|
||||
## Why `ts-packages`?
|
||||
|
||||
Naming stuff is hard. The `ts-` part means Typescript, because this monorepo also contains Rust crates. So we needed some way to indicate: "put your Typescript here".
|
||||
|
||||
Now you know! So, please, put your Typescript here. And your Javascript.
|
||||
|
||||
## How does it work?
|
||||
|
||||
In the root of this repository is [package.json](../package.json) that specifies an array of globs for packages that are shared:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "@nymproject/nymsphere",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "Apache 2.0",
|
||||
"workspaces": ["ts-packages/*", "nym-wallet"] <-------
|
||||
}
|
||||
```
|
||||
|
||||
There are some caveats:
|
||||
|
||||
- this only works with `yarn` and not `npm`
|
||||
- `yarn` creates a single `node_modules` in the root for shared dependencies
|
||||
- packages that use shared packages, need to be in a path specified in `workspaces`
|
||||
- local packages take precedence over published packages on `npm`
|
||||
|
||||
## Building
|
||||
|
||||
From the [root of the repository](../README.md) run:
|
||||
|
||||
```
|
||||
yarn
|
||||
yarn build
|
||||
```
|
||||
|
||||
This will build all libraries.
|
||||
|
||||
Now you can try out [react-webpack-with-theme-example](./react-webpack-with-theme-example) by running:
|
||||
|
||||
```
|
||||
cd ts-packages/react-webpack-with-theme-example
|
||||
yarn start
|
||||
```
|
||||
|
||||
Our React components have a Storybook in [react-components](./react-components):
|
||||
|
||||
```
|
||||
cd ts-packages/react-components
|
||||
yarn storybook
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 2019,
|
||||
sourceType: 'module',
|
||||
},
|
||||
globals: {
|
||||
Atomics: 'readonly',
|
||||
SharedArrayBuffer: 'readonly',
|
||||
},
|
||||
plugins: ['react', 'react-hooks', 'jsx-a11y', 'prettier', 'jest'],
|
||||
extends: ['plugin:react/recommended', 'airbnb', 'prettier', 'plugin:jest/recommended', 'plugin:jest/style'],
|
||||
ignorePatterns: ['dist/**/*', 'dist'],
|
||||
rules: {
|
||||
'jest/prefer-strict-equal': 'error',
|
||||
'jest/prefer-to-have-length': 'warn',
|
||||
'prettier/prettier': 'error',
|
||||
'import/prefer-default-export': 'off',
|
||||
'react/prop-types': 'off',
|
||||
'react/jsx-filename-extension': 'off',
|
||||
'react/jsx-props-no-spreading': 'off',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['**/*.test.[jt]s', '**/*.spec.[jt]s', '**/*.test.[jt]sx', '**/*.spec.[jt]sx'],
|
||||
},
|
||||
],
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'ignorePackages',
|
||||
{
|
||||
ts: 'never',
|
||||
tsx: 'never',
|
||||
js: 'never',
|
||||
jsx: 'never',
|
||||
},
|
||||
],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: '**/*.+(ts|tsx)',
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: ['plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'no-use-before-define': [0],
|
||||
'@typescript-eslint/no-use-before-define': [1],
|
||||
'import/no-unresolved': 0,
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['**/*.test.ts', '**/*.spec.ts', '**/*.test.tsx', '**/*.spec.tsx'],
|
||||
},
|
||||
],
|
||||
quotes: 'off',
|
||||
'@typescript-eslint/quotes': [
|
||||
2,
|
||||
'single',
|
||||
{
|
||||
avoidEscape: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': [2, { argsIgnorePattern: '^_' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
'root-import': {
|
||||
rootPathPrefix: '@',
|
||||
rootPathSuffix: 'src',
|
||||
extensions: ['.js', '.ts', '.tsx', '.jsx', '.mdx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"name": "@nymproject/eslint-config-react-typescript",
|
||||
"description": "Import the default eslint config for nym",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "index.js",
|
||||
"peerDependencies": {
|
||||
"react": "17",
|
||||
"react-dom": "17",
|
||||
"eslint": ">= 8",
|
||||
"@typescript-eslint/eslint-plugin": ">= 5",
|
||||
"@typescript-eslint/parser": ">= 5",
|
||||
"eslint-config-airbnb": ">= 19",
|
||||
"eslint-config-prettier": ">= 8",
|
||||
"eslint-import-resolver-root-import": ">= 1",
|
||||
"eslint-plugin-import": ">= 2",
|
||||
"eslint-plugin-jest": ">= 26.1.1",
|
||||
"eslint-plugin-jsx-a11y": ">= 6",
|
||||
"eslint-plugin-prettier": ">= 4",
|
||||
"eslint-plugin-react": ">= 7",
|
||||
"eslint-plugin-react-hooks": ">= 4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"typescript": "^4.6.2",
|
||||
"ts-jest": "^27.0.5",
|
||||
"jest": "^27.1.0",
|
||||
"babel-plugin-root-import": "^5.1.0"
|
||||
},
|
||||
"eslintConfig" : {
|
||||
"plugins": ["prettier"],
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error"
|
||||
},
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": false,
|
||||
"es6": false,
|
||||
"node": true
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint *.js",
|
||||
"lint:fix": "eslint *.js --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@nymproject/mui-theme",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"peerDependencies": {
|
||||
"react": "17",
|
||||
"react-dom": "17",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"prettier": "^2.5.1",
|
||||
"typescript": "^4.6.2",
|
||||
"ts-jest": "^27.0.5",
|
||||
"jest": "^27.1.0",
|
||||
"babel-plugin-root-import": "^5.1.0",
|
||||
"@types/react": "^17.0.34",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build": "tsc --noEmit false",
|
||||
"watch": "tsc --noEmit false -w",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// defines the OpenSans font and processes the font files with Webpack
|
||||
import '@assets/fonts/fonts.css';
|
||||
|
||||
export * from './theme';
|
||||
@@ -0,0 +1,152 @@
|
||||
import { PaletteMode } from '@mui/material';
|
||||
import { PaletteOptions } from '@mui/material/styles';
|
||||
|
||||
/**
|
||||
* This interface defines a palette used across Nym for branding
|
||||
*/
|
||||
export interface NymPalette {
|
||||
highlight: string;
|
||||
|
||||
status: {
|
||||
success: string;
|
||||
info: string;
|
||||
};
|
||||
|
||||
light: string;
|
||||
dark: string;
|
||||
|
||||
muted: {
|
||||
onDarkBg: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface defines the palette for a light or dark mode variant
|
||||
*/
|
||||
export interface NymPaletteVariant {
|
||||
mode: PaletteMode;
|
||||
background: {
|
||||
main: string;
|
||||
paper: string;
|
||||
};
|
||||
text: {
|
||||
main: string;
|
||||
};
|
||||
topNav: {
|
||||
background: string;
|
||||
};
|
||||
nav: {
|
||||
text: string;
|
||||
background: string;
|
||||
hover: string;
|
||||
};
|
||||
mixnodes: {
|
||||
status: {
|
||||
active: string;
|
||||
standby: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The Nym palette.
|
||||
*
|
||||
* IMPORTANT: do not export this constant, always use the MUI `useTheme` hook to get the correct
|
||||
* colours for dark/light mode.
|
||||
*/
|
||||
export const nymPalette: NymPalette = {
|
||||
/** emphasises important elements */
|
||||
highlight: '#FB6E4E',
|
||||
|
||||
/** statuses */
|
||||
status: {
|
||||
success: '#21D073',
|
||||
info: '#60D7EF',
|
||||
},
|
||||
|
||||
/** light and dark base values */
|
||||
light: '#F4F6F8',
|
||||
dark: '#121726',
|
||||
|
||||
/** muted on backgrounds */
|
||||
muted: {
|
||||
onDarkBg: '#666B77',
|
||||
},
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Dark mode variant
|
||||
*/
|
||||
export const darkMode: NymPaletteVariant = {
|
||||
mode: 'dark',
|
||||
background: {
|
||||
main: nymPalette.dark,
|
||||
paper: '#242C3D',
|
||||
},
|
||||
text: {
|
||||
main: '#F2F2F2',
|
||||
},
|
||||
topNav: {
|
||||
background: '#111826',
|
||||
},
|
||||
nav: {
|
||||
text: '#F2F2F2',
|
||||
background: '#242C3D',
|
||||
hover: '#111826',
|
||||
},
|
||||
mixnodes: {
|
||||
status: {
|
||||
active: '#20D073',
|
||||
standby: '#5FD7EF',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Light mode variant
|
||||
*/
|
||||
export const lightMode: NymPaletteVariant = {
|
||||
mode: 'light',
|
||||
background: {
|
||||
main: '#F2F2F2',
|
||||
paper: '#FFFFFF',
|
||||
},
|
||||
text: {
|
||||
main: '#121726',
|
||||
},
|
||||
topNav: {
|
||||
background: '#111826',
|
||||
},
|
||||
nav: {
|
||||
text: '#F2F2F2',
|
||||
background: '#242C3D',
|
||||
hover: '#111826',
|
||||
},
|
||||
mixnodes: {
|
||||
status: {
|
||||
active: '#1CBB67',
|
||||
standby: '#55C1D7',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Map a Nym palette variant onto the MUI palette
|
||||
*/
|
||||
export const variantToMUIPalette = (variant: NymPaletteVariant): PaletteOptions => ({
|
||||
text: {
|
||||
primary: variant.text.main,
|
||||
},
|
||||
primary: {
|
||||
main: nymPalette.highlight,
|
||||
contrastText: '#fff',
|
||||
},
|
||||
background: {
|
||||
default: variant.background.main,
|
||||
paper: variant.background.paper,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as React from 'react';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import { CssBaseline, PaletteMode } from '@mui/material';
|
||||
import { getDesignTokens } from './theme';
|
||||
|
||||
/**
|
||||
* Provides the theme for the Nym Components by reacting to the light/dark mode choice.
|
||||
*
|
||||
*/
|
||||
export const NymThemeProvider: React.FC<{ mode: PaletteMode }> = ({ mode, children }) => {
|
||||
const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode]);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export type { NymPalette, NymPaletteVariant } from './common';
|
||||
export type { NymTheme, NymPaletteWithExtensions, NymPaletteWithExtensionsOptions } from './theme';
|
||||
@@ -0,0 +1,85 @@
|
||||
import { darkMode, nymPalette, NymPaletteVariant } from './common';
|
||||
|
||||
/**
|
||||
* A palette definition only for the Network Explorer that extends the Nym palette
|
||||
*/
|
||||
|
||||
export interface NetworkExplorerPalette {
|
||||
networkExplorer: {
|
||||
map: {
|
||||
stroke: string;
|
||||
fills: string[];
|
||||
};
|
||||
background: {
|
||||
tertiary: string;
|
||||
};
|
||||
topNav: {
|
||||
background: string;
|
||||
socialIcons: string;
|
||||
appBar: string;
|
||||
};
|
||||
nav: {
|
||||
selected: {
|
||||
main: string;
|
||||
nested: string;
|
||||
};
|
||||
background: string;
|
||||
hover: string;
|
||||
text: string;
|
||||
};
|
||||
footer: {
|
||||
socialIcons: string;
|
||||
};
|
||||
mixnodes: {
|
||||
status: {
|
||||
active: string;
|
||||
standby: string;
|
||||
inactive: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Nym palette specific to the Network Explorer
|
||||
*
|
||||
* IMPORTANT: do not export this constant, always use the MUI `useTheme` hook to get the correct
|
||||
* colours for dark/light mode.
|
||||
*/
|
||||
export const networkExplorerPalette = (variant: NymPaletteVariant): NetworkExplorerPalette => ({
|
||||
networkExplorer: {
|
||||
/** world map styles */
|
||||
map: {
|
||||
stroke: '#333333',
|
||||
fills: ['rgba(255,255,255,0.2)', '#EFEFEF', '#FBE7E1', '#F7D1C6', '#F09379'],
|
||||
},
|
||||
background: {
|
||||
tertiary: variant.mode === 'light' ? '#F4F8FA' : '#323C51',
|
||||
},
|
||||
/** left nav styles */
|
||||
nav: {
|
||||
selected: {
|
||||
main: '#111826',
|
||||
nested: '#3C4558',
|
||||
},
|
||||
background: variant.nav.background,
|
||||
hover: variant.nav.hover,
|
||||
text: variant.nav.text,
|
||||
},
|
||||
topNav: {
|
||||
...variant.topNav,
|
||||
appBar: '#080715',
|
||||
socialIcons: '#F2F2F2',
|
||||
},
|
||||
footer: {
|
||||
socialIcons: variant.mode === 'light' ? nymPalette.muted.onDarkBg : darkMode.text.main,
|
||||
},
|
||||
mixnodes: {
|
||||
status: {
|
||||
active: variant.mixnodes.status.active,
|
||||
standby: variant.mixnodes.status.standby,
|
||||
inactive: variant.text.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,132 @@
|
||||
import { createTheme, Palette, PaletteOptions, ThemeOptions } from '@mui/material/styles';
|
||||
import { PaletteMode } from '@mui/material';
|
||||
import { darkMode, lightMode, nymPalette, NymPalette, variantToMUIPalette } from './common';
|
||||
import { NymWalletPalette, nymWalletPallete } from './wallet';
|
||||
import { networkExplorerPalette, NetworkExplorerPalette } from './network-explorer';
|
||||
|
||||
/**
|
||||
* To use the theme, copy the file in `../../template/mui-theme.d.ts` into `src/typings/mui-theme.d.ts` in your project.
|
||||
*
|
||||
* This will augment the types for `Theme` from `@mui/material/styles` with Nym theme types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* "Namespace" in MUI palette for Nym that is a union of the base palette and product palettes
|
||||
*/
|
||||
export interface NymPaletteWithExtensions {
|
||||
nym: NymPalette & NymWalletPalette & NetworkExplorerPalette;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add anything Nym specific to the MUI theme.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface NymTheme {
|
||||
palette: Palette & NymPaletteWithExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type use by MUI's `createTheme` method
|
||||
*/
|
||||
export type NymPaletteWithExtensionsOptions = Partial<NymPaletteWithExtensions>;
|
||||
|
||||
/**
|
||||
* Returns the Nym palette for light mode.
|
||||
*/
|
||||
const createLightModePalette = (): PaletteOptions & NymPaletteWithExtensionsOptions => ({
|
||||
nym: {
|
||||
...nymPalette,
|
||||
...nymWalletPallete(lightMode),
|
||||
...networkExplorerPalette(lightMode),
|
||||
},
|
||||
...variantToMUIPalette(lightMode),
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the Nym palette for dark mode.
|
||||
*/
|
||||
const createDarkModePalette = (): PaletteOptions & NymPaletteWithExtensionsOptions => ({
|
||||
nym: {
|
||||
...nymPalette,
|
||||
...nymWalletPallete(darkMode),
|
||||
...networkExplorerPalette(darkMode),
|
||||
},
|
||||
...variantToMUIPalette(darkMode),
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the theme options to be passed to `createTheme`.
|
||||
*
|
||||
* Based on pattern from https://mui.com/customization/dark-mode/#dark-mode-with-custom-palette.
|
||||
*
|
||||
* @param mode The theme mode: 'light' or 'dark'
|
||||
*/
|
||||
export const getDesignTokens = (mode: PaletteMode): ThemeOptions => {
|
||||
// first, create the palette from user's choice of light or dark mode
|
||||
const { palette } = createTheme({
|
||||
palette: {
|
||||
mode,
|
||||
...(mode === 'light' ? createLightModePalette() : createDarkModePalette()),
|
||||
},
|
||||
});
|
||||
|
||||
// then customise theme and components
|
||||
return {
|
||||
typography: {
|
||||
fontFamily: [
|
||||
'Open Sans',
|
||||
'sans-serif',
|
||||
'BlinkMacSystemFont',
|
||||
'Roboto',
|
||||
'Oxygen',
|
||||
'Ubuntu',
|
||||
'Helvetica Neue',
|
||||
].join(','),
|
||||
fontSize: 14,
|
||||
fontWeightRegular: 500,
|
||||
button: {
|
||||
textTransform: 'none',
|
||||
fontWeight: '600',
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
transitions: {
|
||||
duration: {
|
||||
shortest: 150,
|
||||
shorter: 200,
|
||||
short: 250,
|
||||
standard: 300,
|
||||
complex: 375,
|
||||
enteringScreen: 225,
|
||||
leavingScreen: 195,
|
||||
},
|
||||
easing: {
|
||||
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
sizeLarge: {
|
||||
height: 55,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiStepIcon: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
'&.Mui-completed': {
|
||||
color: nymPalette.status.success,
|
||||
},
|
||||
'&.Mui-active': {
|
||||
color: nymPalette.dark,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
palette,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NymPaletteVariant } from './common';
|
||||
|
||||
/**
|
||||
* This interface defines a palette used by the Nym wallet
|
||||
*/
|
||||
export interface NymWalletPalette {
|
||||
wallet: {
|
||||
fee: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const nymWalletPallete = (_variant: NymPaletteVariant): NymWalletPalette => ({
|
||||
wallet: {
|
||||
fee: '#967FF0',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable no-shadow,@typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-interface,import/no-extraneous-dependencies */
|
||||
import { Theme, ThemeOptions, Palette, PaletteOptions } from '@mui/material/styles';
|
||||
import { PaletteMode } from '@mui/material';
|
||||
|
||||
/**
|
||||
* If you are unfamiliar with Material UI theming, please read the following first:
|
||||
* - https://mui.com/customization/theming/
|
||||
* - https://mui.com/customization/palette/
|
||||
* - https://mui.com/customization/dark-mode/#dark-mode-with-custom-palette
|
||||
*
|
||||
* This file adds typings to the theme using Typescript's module augmentation.
|
||||
*
|
||||
* Read the following if you are unfamiliar with module augmentation and declaration merging. Then
|
||||
* look at the recommendations from Material UI docs for implementation:
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
|
||||
* - https://mui.com/customization/palette/#adding-new-colors
|
||||
*
|
||||
*
|
||||
* IMPORTANT:
|
||||
*
|
||||
* The type augmentation must match MUI's definitions. So, notice the use of `interface` rather than
|
||||
* `type Foo = { ... }` - this is necessary to merge the definitions.
|
||||
*/
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
import {
|
||||
NymTheme,
|
||||
NymPalette,
|
||||
NymPaletteWithExtensions,
|
||||
NymPaletteWithExtensionsOptions,
|
||||
} from '@nymproject/mui-theme';
|
||||
|
||||
/**
|
||||
* This augments the definitions of the MUI Theme with the Nym theme, as well as
|
||||
* a partial `ThemeOptions` type used by `createTheme`
|
||||
*
|
||||
* IMPORTANT: only add extensions to the interfaces above, do not modify the lines below
|
||||
*/
|
||||
interface Theme extends NymTheme {}
|
||||
interface ThemeOptions extends Partial<NymTheme> {}
|
||||
interface Palette extends NymPaletteWithExtensions {}
|
||||
interface PaletteOptions extends NymPaletteWithExtensionsOptions {}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
"stories": [
|
||||
"../src/**/*.stories.mdx",
|
||||
"../src/**/*.stories.@(js|jsx|ts|tsx)"
|
||||
],
|
||||
"addons": [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions"
|
||||
],
|
||||
"framework": "@storybook/react",
|
||||
"core": {
|
||||
"builder": "webpack5"
|
||||
},
|
||||
webpackFinal: async (config, { configType }) => {
|
||||
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
|
||||
// You can change the configuration based on that.
|
||||
// 'PRODUCTION' is used when building the static version of storybook.
|
||||
|
||||
config.module.rules.forEach(rule => {
|
||||
// look for SVG import rule and replace
|
||||
// NOTE: the rule before modification is /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
|
||||
if(rule.test?.toString().includes('svg')) {
|
||||
rule.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
|
||||
}
|
||||
});
|
||||
|
||||
// handle asset loading with this
|
||||
config.module.rules.unshift({
|
||||
test: /\.svg(\?.*)?$/i,
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ['@svgr/webpack'],
|
||||
});
|
||||
|
||||
config.resolve.extensions = ['.tsx', '.ts', '.js'];
|
||||
config.resolve.plugins = [new TsconfigPathsPlugin()];
|
||||
|
||||
// Return the altered config
|
||||
return config;
|
||||
},
|
||||
features: {
|
||||
emotionAlias: false,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "@nymproject/react",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"peerDependencies": {
|
||||
"@mui/material": ">= 5",
|
||||
"@mui/styles": ">= 5",
|
||||
"@mui/system": ">= 5",
|
||||
"@nymproject/mui-theme": "1",
|
||||
"react": "17",
|
||||
"react-dom": "17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@mui/system": "^5.0.1",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@storybook/addon-actions": "^6.4.19",
|
||||
"@storybook/addon-essentials": "^6.4.19",
|
||||
"@storybook/addon-interactions": "^6.4.19",
|
||||
"@storybook/addon-links": "^6.4.19",
|
||||
"@storybook/builder-webpack5": "^6.4.19",
|
||||
"@storybook/manager-webpack5": "^6.4.19",
|
||||
"@storybook/react": "^6.4.19",
|
||||
"@storybook/testing-library": "^0.0.9",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@types/react": "^17.0.39",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
"babel-plugin-root-import": "^5.1.0",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"jest": "^27.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^27.0.5",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"build": "tsc --noEmit false",
|
||||
"watch": "tsc --noEmit false -w",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"storybook:build": "build-storybook"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './logo';
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface LogoProps {
|
||||
height?: number | string;
|
||||
width?: number | string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import Logo from '@assets/logo/logo-circle.svg';
|
||||
import { LogoProps } from './LogoProps';
|
||||
|
||||
export const NymLogo: React.FC<LogoProps> = ({ height, width }) => <Logo height={height} width={width} />;
|
||||
@@ -0,0 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import Wordmark from '@assets/logo/logo-wordmark.svg';
|
||||
import { LogoProps } from './LogoProps';
|
||||
|
||||
export const NymWordmark: React.FC<LogoProps> = ({ height, width }) => <Wordmark height={height} width={width} />;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './NymLogo';
|
||||
export * from './NymWordmark';
|
||||
@@ -0,0 +1 @@
|
||||
export * from './useIsMounted';
|
||||
@@ -0,0 +1,14 @@
|
||||
import { useRef, useEffect, useCallback } from 'react';
|
||||
|
||||
export function useIsMounted(): () => boolean {
|
||||
const ref = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = true;
|
||||
return () => {
|
||||
ref.current = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return useCallback(() => ref.current, [ref]);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './components';
|
||||
export * from './hooks';
|
||||
export { Playground } from './playground';
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Button, Stack } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
|
||||
export const PlaygroundButtons: React.FC = () => (
|
||||
<Stack spacing={2} direction="row">
|
||||
<Button variant="text">Text</Button>
|
||||
<Button variant="contained">Contained</Button>
|
||||
<Button variant="outlined">Outlined</Button>
|
||||
</Stack>
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
|
||||
const label = { inputProps: { 'aria-label': 'Checkbox demo' } };
|
||||
|
||||
export const PlaygroundCheckboxes: React.FC = function () {
|
||||
return (
|
||||
<div>
|
||||
<Checkbox {...label} defaultChecked />
|
||||
<Checkbox {...label} />
|
||||
<Checkbox {...label} disabled />
|
||||
<Checkbox {...label} disabled checked />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as React from 'react';
|
||||
|
||||
const CONTENT = 'The quick brown fox jumped over the white fence';
|
||||
|
||||
const WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000];
|
||||
|
||||
export const PlaygroundFonts: React.FC = () => (
|
||||
<div style={{ fontFamily: 'Open Sans' }}>
|
||||
{WEIGHTS.map((fontWeight) => (
|
||||
<div key={`weight-${fontWeight}`}>
|
||||
<div style={{ fontWeight, fontSize: '30px' }}>{CONTENT}</div>
|
||||
<div>
|
||||
<code>Font weight: {fontWeight}</code>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { PlaygroundButtons } from './buttons';
|
||||
import { PlaygroundCheckboxes } from './checkboxes';
|
||||
import { PlaygroundBasicSwitches } from './switches';
|
||||
import { PlaygroundFonts } from './fonts';
|
||||
|
||||
export const Playground: React.FC = () => (
|
||||
<>
|
||||
<h2>Buttons</h2>
|
||||
<PlaygroundButtons />
|
||||
|
||||
<h2>Checkboxes</h2>
|
||||
<PlaygroundCheckboxes />
|
||||
|
||||
<h2>Switches</h2>
|
||||
<PlaygroundBasicSwitches />
|
||||
|
||||
<h2>Fonts</h2>
|
||||
<PlaygroundFonts />
|
||||
</>
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import Switch from '@mui/material/Switch';
|
||||
|
||||
const label = { inputProps: { 'aria-label': 'Switch demo' } };
|
||||
|
||||
export const PlaygroundBasicSwitches: React.FC = function () {
|
||||
return (
|
||||
<div>
|
||||
<Switch {...label} defaultChecked />
|
||||
<Switch {...label} />
|
||||
<Switch {...label} disabled defaultChecked />
|
||||
<Switch {...label} disabled />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
import { NymLogo } from '../components';
|
||||
|
||||
<Meta title="Introduction" />
|
||||
|
||||
<NymLogo height={100} />
|
||||
|
||||
# Nym Design System
|
||||
|
||||
This is the Nym design system.
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { ComponentMeta } from '@storybook/react';
|
||||
import { Box } from '@mui/material';
|
||||
import { NymLogo, NymWordmark } from '../components';
|
||||
|
||||
export default {
|
||||
title: 'Logo/Nym Logo',
|
||||
component: NymLogo,
|
||||
} as ComponentMeta<typeof NymLogo>;
|
||||
|
||||
export function Logo() {
|
||||
return <NymLogo height={250} />;
|
||||
}
|
||||
|
||||
export function Wordmark() {
|
||||
return (
|
||||
<div style={{ background: '#888', padding: '2rem' }}>
|
||||
<NymWordmark height={250} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import * as React from 'react';
|
||||
import { ComponentMeta } from '@storybook/react';
|
||||
import { NymThemeProvider } from '@nymproject/mui-theme';
|
||||
import { Playground } from '../playground';
|
||||
|
||||
export default {
|
||||
title: 'Playground',
|
||||
component: Playground,
|
||||
} as ComponentMeta<typeof Playground>;
|
||||
|
||||
export function LightMode() {
|
||||
return (
|
||||
<NymThemeProvider mode="light">
|
||||
<Playground />
|
||||
</NymThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function DarkMode() {
|
||||
return (
|
||||
<NymThemeProvider mode="dark">
|
||||
<Playground />
|
||||
</NymThemeProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* eslint-disable no-shadow,@typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-interface,import/no-extraneous-dependencies */
|
||||
import { Theme, ThemeOptions, Palette, PaletteOptions } from '@mui/material/styles';
|
||||
import { NymTheme, NymPaletteWithExtensions, NymPaletteWithExtensionsOptions } from '@nymproject/mui-theme';
|
||||
|
||||
/**
|
||||
* If you are unfamiliar with Material UI theming, please read the following first:
|
||||
* - https://mui.com/customization/theming/
|
||||
* - https://mui.com/customization/palette/
|
||||
* - https://mui.com/customization/dark-mode/#dark-mode-with-custom-palette
|
||||
*
|
||||
* This file adds typings to the theme using Typescript's module augmentation.
|
||||
*
|
||||
* Read the following if you are unfamiliar with module augmentation and declaration merging. Then
|
||||
* look at the recommendations from Material UI docs for implementation:
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
|
||||
* - https://mui.com/customization/palette/#adding-new-colors
|
||||
*
|
||||
*
|
||||
* IMPORTANT:
|
||||
*
|
||||
* The type augmentation must match MUI's definitions. So, notice the use of `interface` rather than
|
||||
* `type Foo = { ... }` - this is necessary to merge the definitions.
|
||||
*/
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
/**
|
||||
* This augments the definitions of the MUI Theme with the Nym theme, as well as
|
||||
* a partial `ThemeOptions` type used by `createTheme`
|
||||
*
|
||||
* IMPORTANT: only add extensions to the interfaces above, do not modify the lines below
|
||||
*/
|
||||
interface Theme extends NymTheme {}
|
||||
interface ThemeOptions extends Partial<NymTheme> {}
|
||||
interface Palette extends NymPaletteWithExtensions {}
|
||||
interface PaletteOptions extends NymPaletteWithExtensionsOptions {}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
declare module '*.jpeg' {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
declare module '*.json' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
declare module '*.png' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
declare module '*.svg' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true,
|
||||
"outDir": "./dist",
|
||||
"declarationDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"src/stories",
|
||||
"**/*.stories.*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/react"]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"name": "@nymproject/react-webpack-with-theme-example",
|
||||
"description": "An example project that uses React, Webpack, Typescript and the Nym theme + components library",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"@mui/material": "^5.0.1",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@nymproject/mui-theme" : "^1.0.0",
|
||||
"@nymproject/react" : "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.14.5",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@nymproject/eslint-config-react-typescript": "^1.0.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/react": "^17.0.34",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-root-import": "^5.1.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"dotenv-webpack": "^7.0.3",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.29.2",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"favicons": "^6.2.2",
|
||||
"favicons-webpack-plugin": "^5.0.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.1",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"jest": "^27.1.0",
|
||||
"mini-css-extract-plugin": "^2.2.2",
|
||||
"prettier": "^2.5.1",
|
||||
"react-refresh-typescript": "^2.0.3",
|
||||
"style-loader": "^3.2.1",
|
||||
"ts-jest": "^27.0.5",
|
||||
"ts-loader": "^9.2.5",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"typescript": "^4.6.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.64.3",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.5.0",
|
||||
"webpack-favicons": "^1.3.8",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --progress --port 3000",
|
||||
"build": "webpack build --progress --config webpack.prod.js",
|
||||
"build:dev": "webpack build --progress",
|
||||
"build:serve": "npx serve dist",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"tsc": "tsc",
|
||||
"tsc:watch": "tsc --watch",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import * as React from 'react';
|
||||
import { Box, Container, Grid, Typography } from '@mui/material';
|
||||
import { NymLogo, Playground } from '@nymproject/react';
|
||||
import { NymThemeProvider } from '@nymproject/mui-theme';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { ThemeToggle } from './ThemeToggle';
|
||||
import { AppContextProvider, useAppContext } from './context';
|
||||
|
||||
export const App: React.FC = () => (
|
||||
<AppContextProvider>
|
||||
<AppTheme>
|
||||
<Content />
|
||||
</AppTheme>
|
||||
</AppContextProvider>
|
||||
);
|
||||
|
||||
export const AppTheme: React.FC = ({ children }) => {
|
||||
const { mode } = useAppContext();
|
||||
|
||||
return <NymThemeProvider mode={mode}>{children}</NymThemeProvider>;
|
||||
};
|
||||
|
||||
export const Content: React.FC = () => {
|
||||
const { mode } = useAppContext();
|
||||
const theme = useTheme();
|
||||
|
||||
const swatches: Record<string, string> = {
|
||||
'palette.primary.main': theme.palette.primary.main,
|
||||
'palette.secondary.main': theme.palette.secondary.main,
|
||||
'palette.info.main': theme.palette.info.main,
|
||||
'palette.success.main': theme.palette.success.main,
|
||||
'palette.text.primary': theme.palette.text.primary,
|
||||
'theme.palette.nym.networkExplorer.mixnodes.status.active':
|
||||
theme.palette.nym.networkExplorer.mixnodes.status.active,
|
||||
'theme.palette.nym.networkExplorer.mixnodes.status.standby':
|
||||
theme.palette.nym.networkExplorer.mixnodes.status.standby,
|
||||
};
|
||||
|
||||
return (
|
||||
<Container sx={{ py: 4 }}>
|
||||
<Box display="flex" flexDirection="row-reverse" pb={2}>
|
||||
<ThemeToggle />
|
||||
</Box>
|
||||
<NymLogo height={50} />
|
||||
<h1>Example App</h1>
|
||||
<Box mb={10}>
|
||||
<Typography sx={{ color: (theme) => theme.palette.nym.networkExplorer.mixnodes.status.active }}>
|
||||
This is an example app that uses React, Typescript, Webpack and the Nym theme + components.
|
||||
</Typography>
|
||||
<h4>Some colours from the theme (mode = {mode}) are:</h4>
|
||||
<Grid container spacing={2}>
|
||||
{Object.keys(swatches).map((key) => (
|
||||
<Grid item key={key}>
|
||||
<Box display="flex" alignItems="center">
|
||||
<svg height="50px" width="50px">
|
||||
<rect width="100%" height="100%" fill={swatches[key]} />
|
||||
</svg>
|
||||
<Typography mx={2}>
|
||||
<code>{swatches[key]}</code>
|
||||
<br />
|
||||
<code>{key}</code>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
<h1>Component playground</h1>
|
||||
<Playground />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import { Button, Typography } from '@mui/material';
|
||||
import DarkModeIcon from '@mui/icons-material/DarkMode';
|
||||
import LightModeIcon from '@mui/icons-material/LightMode';
|
||||
import { useAppContext } from './context';
|
||||
|
||||
export const ThemeToggle: React.FC = () => {
|
||||
const { mode, toggleMode } = useAppContext();
|
||||
return (
|
||||
<Button variant="outlined" color="secondary" onClick={toggleMode} sx={{ display: 'flex', alignItems: 'centre' }}>
|
||||
{mode === 'dark' ? (
|
||||
<DarkModeIcon sx={{ color: (theme) => theme.palette.text.secondary }} />
|
||||
) : (
|
||||
<LightModeIcon sx={{ color: (theme) => theme.palette.text.secondary }} />
|
||||
)}
|
||||
<Typography ml={1} color={(theme) => theme.palette.primary.light}>
|
||||
Switch to {mode === 'dark' ? 'light mode' : 'dark mode'}
|
||||
</Typography>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { PaletteMode } from '@mui/material';
|
||||
import * as React from 'react';
|
||||
|
||||
interface State {
|
||||
mode: PaletteMode;
|
||||
toggleMode: () => void;
|
||||
}
|
||||
|
||||
const AppContext = React.createContext<State | undefined>(undefined);
|
||||
|
||||
export const useAppContext = (): State => {
|
||||
const context = React.useContext<State | undefined>(AppContext);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('Please include a `import { AppContextProvider } from "./context"` before using this hook');
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
export const AppContextProvider: React.FC = ({ children }) => {
|
||||
// light/dark mode
|
||||
const [mode, setMode] = React.useState<PaletteMode>('dark');
|
||||
|
||||
const value = React.useMemo<State>(
|
||||
() => ({
|
||||
mode,
|
||||
toggleMode: () => setMode((prevMode) => (prevMode !== 'light' ? 'light' : 'dark')),
|
||||
}),
|
||||
[mode],
|
||||
);
|
||||
|
||||
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Nym Example with React, Typescript, Webpack</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { App } from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('app'));
|
||||
@@ -0,0 +1,13 @@
|
||||
import React, { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { App } from '../App';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(() => {
|
||||
render(<App />);
|
||||
});
|
||||
it('should render without exploding', () => {
|
||||
const { container } = render(<App />);
|
||||
expect(container.firstChild).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
/* eslint-disable no-shadow,@typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-interface,import/no-extraneous-dependencies */
|
||||
import { Theme, ThemeOptions, Palette, PaletteOptions } from '@mui/material/styles';
|
||||
import { NymTheme, NymPaletteWithExtensions, NymPaletteWithExtensionsOptions } from '@nymproject/mui-theme';
|
||||
|
||||
/**
|
||||
* If you are unfamiliar with Material UI theming, please read the following first:
|
||||
* - https://mui.com/customization/theming/
|
||||
* - https://mui.com/customization/palette/
|
||||
* - https://mui.com/customization/dark-mode/#dark-mode-with-custom-palette
|
||||
*
|
||||
* This file adds typings to the theme using Typescript's module augmentation.
|
||||
*
|
||||
* Read the following if you are unfamiliar with module augmentation and declaration merging. Then
|
||||
* look at the recommendations from Material UI docs for implementation:
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
||||
* - https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
|
||||
* - https://mui.com/customization/palette/#adding-new-colors
|
||||
*
|
||||
*
|
||||
* IMPORTANT:
|
||||
*
|
||||
* The type augmentation must match MUI's definitions. So, notice the use of `interface` rather than
|
||||
* `type Foo = { ... }` - this is necessary to merge the definitions.
|
||||
*/
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
/**
|
||||
* This augments the definitions of the MUI Theme with the Nym theme, as well as
|
||||
* a partial `ThemeOptions` type used by `createTheme`
|
||||
*
|
||||
* IMPORTANT: only add extensions to the interfaces above, do not modify the lines below
|
||||
*/
|
||||
interface Theme extends NymTheme {}
|
||||
interface ThemeOptions extends Partial<NymTheme> {}
|
||||
interface Palette extends NymPaletteWithExtensions {}
|
||||
interface PaletteOptions extends NymPaletteWithExtensionsOptions {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist",
|
||||
"declaration": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build",
|
||||
"dist",
|
||||
"**/*.stories.*",
|
||||
"**/*.test.*",
|
||||
"**/*.spec.*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
const path = require('path');
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const { webpackCommon } = require('@nymproject/webpack');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(webpackCommon(__dirname), {
|
||||
entry: path.resolve(__dirname, 'src/index.tsx'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const webpack = require('webpack');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const ReactRefreshTypeScript = require('react-refresh-typescript');
|
||||
const commonConfig = require('./webpack.common');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(commonConfig, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
options: {
|
||||
getCustomTransformers: () => ({
|
||||
before: [ReactRefreshTypeScript()],
|
||||
}),
|
||||
// `ts-loader` does not work with HMR unless `transpileOnly` is used.
|
||||
// If you need type checking, `ForkTsCheckerWebpackPlugin` is an alternative.
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new ReactRefreshWebpackPlugin(),
|
||||
|
||||
// this can be included automatically by the dev server, however build mode fails if missing
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
],
|
||||
|
||||
target: 'web',
|
||||
|
||||
devServer: {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
historyApiFallback: true,
|
||||
},
|
||||
|
||||
// recommended for faster rebuild
|
||||
optimization: {
|
||||
runtimeChunk: true,
|
||||
removeAvailableModules: false,
|
||||
removeEmptyChunks: false,
|
||||
splitChunks: false,
|
||||
},
|
||||
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
buildDependencies: {
|
||||
// restart on config change
|
||||
config: ['./webpack.config.js'],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const commonConfig = require('./webpack.common');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(commonConfig, {
|
||||
mode: 'production',
|
||||
|
||||
// TODO: no source maps, add back
|
||||
devtool: false,
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [`...`, new CssMinimizerPlugin()],
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].[contenthash].css',
|
||||
}),
|
||||
],
|
||||
output: {
|
||||
pathinfo: false,
|
||||
filename: '[name].[contenthash].js',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": false,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"jsx": "react-jsx",
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@assets/*": ["../assets/*"]
|
||||
},
|
||||
},
|
||||
"exclude": [
|
||||
"jest.config.js",
|
||||
"webpack.config.js",
|
||||
"webpack.prod.js",
|
||||
"webpack.common.js",
|
||||
"node_modules",
|
||||
"**/node_modules",
|
||||
"dist",
|
||||
"**/dist",
|
||||
"scripts",
|
||||
"jest",
|
||||
"__tests__",
|
||||
"**/__tests__",
|
||||
"__jest__",
|
||||
"**/__jest__",
|
||||
"config/*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"root": true,
|
||||
"plugins": ["prettier"],
|
||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error"
|
||||
},
|
||||
"env": {
|
||||
"browser": false,
|
||||
"es6": true,
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
const webpackDevConfig = require('./webpack.dev');
|
||||
const webpackProdConfig = require('./webpack.prod');
|
||||
const webpackCommon = require('./webpack.common');
|
||||
|
||||
module.exports = {
|
||||
webpackCommon,
|
||||
webpackDevConfig,
|
||||
webpackProdConfig,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@nymproject/webpack",
|
||||
"description": "Provides default Webpack 5 config and dependencies",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"main": "index.js",
|
||||
"peerDependencies": {
|
||||
"react": "17",
|
||||
"react-dom": "17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.14.5",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"dotenv-webpack": "^7.0.3",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"favicons": "^6.2.2",
|
||||
"favicons-webpack-plugin": "^5.0.2",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.1",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"prettier": "^2.5.1",
|
||||
"style-loader": "^3.2.1",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.64.3",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.5.0",
|
||||
"webpack-favicons": "^1.3.8",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint *.js",
|
||||
"lint:fix": "eslint *.js --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const WebpackFavicons = require('webpack-favicons');
|
||||
const Dotenv = require('dotenv-webpack');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Creates the default Webpack config
|
||||
* @param baseDir The base directory path, e.g. pass `__dirname` of the webpack config file using this method
|
||||
*/
|
||||
module.exports = (baseDir) => ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [{ loader: 'ts-loader', options: { transpileOnly: true } }],
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.svg$/i,
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ['@svgr/webpack'],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|md)$/i,
|
||||
// More information here https://webpack.js.org/guides/asset-modules/
|
||||
type: 'asset',
|
||||
},
|
||||
{
|
||||
// See https://webpack.js.org/guides/asset-management/#loading-fonts
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.ya?ml$/,
|
||||
type: 'json',
|
||||
use: 'yaml-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
plugins: [new TsconfigPathsPlugin()],
|
||||
alias: {
|
||||
'react/jsx-runtime': require.resolve('react/jsx-runtime'),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
// new CleanWebpackPlugin(),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(baseDir, 'src/index.html'),
|
||||
}),
|
||||
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
mode: 'write-references',
|
||||
diagnosticOptions: {
|
||||
semantic: true,
|
||||
syntactic: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
new WebpackFavicons({
|
||||
src: path.resolve(__dirname, '../../assets/favicon/favicon.svg'), // the asset directory is relative to THIS file
|
||||
}),
|
||||
|
||||
new Dotenv(),
|
||||
],
|
||||
output: {
|
||||
path: path.resolve(baseDir, 'dist'),
|
||||
publicPath: '/',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
const { merge } = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
/**
|
||||
* Creates the default Webpack dev config
|
||||
* @param baseDir The base directory path, e.g. pass `__dirname` of the webpack config file using this method
|
||||
*/
|
||||
module.exports = (baseDir) =>
|
||||
merge(common, {
|
||||
mode: 'development',
|
||||
entry: path.resolve(baseDir, '/src/index'),
|
||||
devServer: {
|
||||
port: 9000,
|
||||
compress: true,
|
||||
historyApiFallback: true,
|
||||
hot: true,
|
||||
client: {
|
||||
overlay: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
const path = require('path');
|
||||
const { default: merge } = require('webpack-merge');
|
||||
const common = require('./webpack.common');
|
||||
|
||||
/**
|
||||
* Creates the default Webpack prod config
|
||||
* @param baseDir The base directory path, e.g. pass `__dirname` of the webpack config file using this method
|
||||
*/
|
||||
module.exports = (baseDir) =>
|
||||
merge(common, {
|
||||
mode: 'production',
|
||||
node: {
|
||||
__dirname: false,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [{ loader: 'ts-loader', options: { transpileOnly: true, configFile: 'tsconfig.prod.json' } }],
|
||||
exclude: [/node_modules/, '**/*.stories.*', '**/*.test.*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
entry: path.resolve(baseDir, 'src/index'),
|
||||
});
|
||||