├── .browserslistrc ├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .lintstagedrc.js ├── .npmignore ├── .npmrc ├── .prettierignore ├── .versionrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── changelog.config.js ├── commitlint.config.js ├── craco.config.js ├── husky.config.js ├── package.json ├── postcss.config.js ├── prettier.config.js ├── public ├── favicons │ ├── favicon.svg │ ├── logo.svg │ ├── logo192.png │ ├── logo512.png │ └── logocra.svg ├── images │ └── image-public.jpg ├── index.html ├── manifest.json └── robots.txt ├── scripts ├── craco │ ├── craco-babel.js │ ├── craco-module.js │ ├── craco-plugin--analyze.js │ └── craco-plugin--less.js └── ssl │ ├── .gitignore │ └── README.md ├── src ├── App.tsx ├── assets │ └── images │ │ └── image.jpg ├── components │ ├── AppRouter │ │ ├── AppRouter.tsx │ │ └── styles.module.less │ ├── ErrorBoundary │ │ ├── ErrorBoundary.tsx │ │ └── styles.module.less │ ├── FooterNav │ │ ├── FooterNav.tsx │ │ └── style.module.less │ ├── HeaderNavbar │ │ ├── HeaderNavbar.tsx │ │ └── style.module.less │ ├── HtmlMeta │ │ ├── HtmlMeta.tsx │ │ └── style.module.less │ ├── HugeIcon │ │ ├── HugeIcon.tsx │ │ └── style.module.less │ ├── LazyLoadingSpin │ │ ├── LazyLoadingSpin.tsx │ │ └── style.module.less │ ├── LoadingSpinner │ │ ├── LoadingSpinner.tsx │ │ ├── _spinner.svg │ │ └── styles.module.less │ ├── PageWrapper │ │ ├── PageWrapper.tsx │ │ └── styles.module.less │ └── index.tsx ├── configs │ ├── app.config.ts │ ├── env.ts │ ├── index.ts │ └── pkg.config.ts ├── constants │ ├── index.ts │ └── style.constant.ts ├── hooks │ ├── index.ts │ └── useDarkMode.tsx ├── index.tsx ├── interfaces │ ├── config.interface.ts │ ├── index.ts │ ├── jsx.interface.ts │ └── router.interface.ts ├── layouts │ ├── MasterLayout │ │ ├── MasterLayout.tsx │ │ └── styles.module.less │ └── index.tsx ├── page-components │ ├── about │ │ ├── About │ │ │ ├── About.tsx │ │ │ └── styles.module.less │ │ └── AboutName │ │ │ ├── AboutName.tsx │ │ │ └── styles.module.less │ ├── error │ │ └── Error404 │ │ │ ├── Error404.tsx │ │ │ └── styles.module.less │ ├── home │ │ └── Home │ │ │ ├── Home.tsx │ │ │ └── styles.module.less │ └── test │ │ ├── Test │ │ ├── Test.tsx │ │ ├── _css.css │ │ ├── _less.less │ │ ├── image-dir--css.jpg │ │ ├── image-dir--less-module.jpg │ │ ├── image-dir--less.jpg │ │ ├── image-dir.jpg │ │ └── styles.module.less │ │ └── TestLazyLoadingSpin │ │ ├── TestLazyLoadingSpin.tsx │ │ └── styles.module.less ├── react-app-env.d.ts ├── reportWebVitals.ts ├── routes │ ├── _fn.tsx │ ├── error.route.tsx │ ├── index.tsx │ ├── master.route.tsx │ └── test.route.tsx ├── setupTests.ts └── styles │ ├── _sync-vars-to-root.js │ ├── animate.less │ ├── global.less │ ├── mixin.less │ ├── variables-css.less │ └── variables.less ├── tsconfig.extend.json ├── tsconfig.json ├── typings ├── custom-typings.d.ts ├── global.d.ts └── index.d.ts └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | >0.3% 2 | not ie 11 3 | not dead 4 | not op_mini all 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | charset = utf-8 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # `.env.local` always overrides the defaults set. 2 | # see more https://create-react-app.dev/docs/adding-custom-environment-variables 3 | REACT_APP_NAME=mkr 4 | 5 | SKIP_PREFLIGHT_CHECK=true 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .idea 3 | .vscode/* 4 | /typings 5 | CHANGELOG.md 6 | 7 | /_cache 8 | /cache 9 | 10 | /.build 11 | /_build 12 | /build 13 | 14 | /.dist 15 | /_dist 16 | /dist 17 | 18 | /.deploy 19 | /_deploy 20 | /deploy 21 | 22 | /_documents 23 | /public 24 | /static 25 | /src/assets 26 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | module.exports = { 3 | // https://github.com/qcolate/web-configs/blob/master/packages/eslint-config/react.js 4 | // extends: ['airbnb', 'airbnb-typescript', 'prettier'], 5 | extends: ['@qcolate/eslint-config'], 6 | env: { 7 | browser: true, 8 | es2021: true, 9 | jest: true, 10 | }, 11 | globals: { 12 | __DEV__: true, 13 | __PROD__: true, 14 | }, 15 | // 16 | // 0 (off) / 1 (warn) / 2 (error) 17 | rules: { 18 | 'max-len': [ 19 | 2, 20 | { 21 | code: 80, // (default 80) enforces a maximum line length 22 | ignoreComments: true, // ignores all trailing comments and comments on their own line 23 | ignoreTrailingComments: true, // ignores only trailing comments 24 | // ignoreUrls: true, // ignores lines that contain a URL 25 | // tabWidth: 4, // (default 4) specifies the character width for tab characters 26 | // comments: 80, // enforces a maximum line length for comments; defaults to value of code 27 | // ignorePattern: true, // ignores lines matching a regular expression; can only match a single line and need to be double escaped when written in YAML or JSON 28 | // ignoreStrings: true, // ignores lines that contain a double-quoted or single-quoted string 29 | // ignoreTemplateLiterals: true, // ignores lines that contain a template literal 30 | // ignoreRegExpLiterals: true, // ignores lines that contain a RegExp literal 31 | }, 32 | ], 33 | 'spaced-comment': 0, 34 | 'no-restricted-exports': 0, 35 | 'react/function-component-definition': 0, 36 | 'react/no-namespace': 0, 37 | 'react/prefer-exact-props': 0, 38 | 'react/no-arrow-function-lifecycle': 0, 39 | 'react/no-invalid-html-attribute': 0, 40 | 'react/jsx-no-constructed-context-values': 0, 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Automatically normalize line endings for all text-based files 2 | # http://git-scm.com/docs/gitattributes#_end_of_line_conversion 3 | * text=auto 4 | 5 | # For the following file types, normalize line endings to LF on 6 | # checkin and prevent conversion to CRLF when they are checked out 7 | # (this is required in order to prevent newline related issues like, 8 | # for example, after the build script is run) 9 | .* text eol=lf 10 | *.html text eol=lf 11 | *.css text eol=lf 12 | *.less text eol=lf 13 | *.styl text eol=lf 14 | *.scss text eol=lf 15 | *.sass text eol=lf 16 | *.sss text eol=lf 17 | *.js text eol=lf 18 | *.jsx text eol=lf 19 | *.ts text eol=lf 20 | *.tsx text eol=lf 21 | *.json text eol=lf 22 | *.md text eol=lf 23 | *.mjs text eol=lf 24 | *.sh text eol=lf 25 | *.svg text eol=lf 26 | *.txt text eol=lf 27 | *.xml text eol=lf 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | /.eslintcache 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | *~ 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env* 31 | .env.local 32 | .env.development.local 33 | .env.test.local 34 | .env.production.local 35 | !.env.example 36 | !.env 37 | !.env.development 38 | !.env.test 39 | !.env.production 40 | 41 | # vercel 42 | .vercel 43 | /.vercel 44 | .now 45 | /.now 46 | 47 | # compiled 48 | .cache 49 | /.cache 50 | /_cache 51 | /cache 52 | 53 | .build 54 | /.build 55 | /_build 56 | 57 | .dist 58 | /.dist 59 | /_dist 60 | /dist 61 | 62 | .deploy 63 | /.deploy 64 | /_deploy 65 | /deploy 66 | 67 | node_modules 68 | 69 | # docker 70 | .docker 71 | _docker_data 72 | docker_data 73 | tsconfig.tsbuildinfo 74 | 75 | # Lols 76 | logs 77 | *.log 78 | 79 | # IDEs 80 | .idea 81 | .project 82 | .classpath 83 | .c9 84 | *.launch 85 | .settings 86 | *.sublime-workspace 87 | .vscode/* 88 | !.vscode/settings.json 89 | !.vscode/tasks.json 90 | !.vscode/launch.json 91 | !.vscode/extensions.json 92 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | # https://github.com/conventional-changelog/commitlint 5 | yarn commitlint --edit $1 6 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | #https://github.com/azz/pretty-quick 5 | yarn pretty-quick --staged 6 | 7 | # https://github.com/okonet/lint-staged#configuration. 8 | yarn lint-staged 9 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'src/**/*.(ts|js)?(x)': ['prettier --write', 'eslint'], 3 | // 'packages/**/*.(css|less)': ['prettier --write', 'stylelint"', 'git add'], 4 | }; 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmrc 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | // registry=https://registry.npmjs.org 2 | registry=http://registry.npmmirror.com 3 | disturl=http://npmmirror.com/dist 4 | 5 | // pnpm config 6 | shamefully-hoist=true 7 | 8 | chromedriver-cdnurl=http://npmmirror.com/mirrors/chromedriver 9 | sharp_binary_host=http://npmmirror.com/mirrors/sharp 10 | sharp_libvips_binary_host=http://npmmirror.com/mirrors/sharp-libvips 11 | couchbase-binary-host-mirror=http://npmmirror.com/mirrors/couchbase/v{version} 12 | debug-binary-host-mirror=http://npmmirror.com/mirrors/node-inspector 13 | electron-mirror=http://npmmirror.com/mirrors/electron/ 14 | flow-bin-binary-host-mirror=http://npmmirror.com/mirrors/flow/v 15 | fse-binary-host-mirror=http://npmmirror.com/mirrors/fsevents 16 | fuse-bindings-binary-host-mirror=http://npmmirror.com/mirrors/fuse-bindings/v{version} 17 | git4win-mirror=http://npmmirror.com/mirrors/git-for-windows 18 | gl-binary-host-mirror=http://npmmirror.com/mirrors/gl/v{version} 19 | grpc-node-binary-host-mirror=http://npmmirror.com/mirrors 20 | hackrf-binary-host-mirror=http://npmmirror.com/mirrors/hackrf/v{version} 21 | leveldown-binary-host-mirror=http://npmmirror.com/mirrors/leveldown/v{version} 22 | leveldown-hyper-binary-host-mirror=http://npmmirror.com/mirrors/leveldown-hyper/v{version} 23 | mknod-binary-host-mirror=http://npmmirror.com/mirrors/mknod/v{version} 24 | node-sqlite3-binary-host-mirror=http://npmmirror.com/mirrors 25 | node-tk5-binary-host-mirror=http://npmmirror.com/mirrors/node-tk5/v{version} 26 | nodegit-binary-host-mirror=http://npmmirror.com/mirrors/nodegit/v{version}/ 27 | operadriver-cdnurl=http://npmmirror.com/mirrors/operadriver 28 | phantomjs-cdnurl=http://npmmirror.com/mirrors/phantomjs 29 | profiler-binary-host-mirror=http://npmmirror.com/mirrors/node-inspector/ 30 | puppeteer-download-host=http://npmmirror.com/mirrors 31 | python-mirror=http://npmmirror.com/mirrors/python 32 | rabin-binary-host-mirror=http://npmmirror.com/mirrors/rabin/v{version} 33 | sass-binary-site=http://npmmirror.com/mirrors/node-sass 34 | sodium-prebuilt-binary-host-mirror=http://npmmirror.com/mirrors/sodium-prebuilt/v{version} 35 | sqlite3-binary-site=http://npmmirror.com/mirrors/sqlite3 36 | utf-8-validate-binary-host-mirror=http://npmmirror.com/mirrors/utf-8-validate/v{version} 37 | utp-native-binary-host-mirror=http://npmmirror.com/mirrors/utp-native/v{version} 38 | zmq-prebuilt-binary-host-mirror=http://npmmirror.com/mirrors/zmq-prebuilt/v{version} 39 | electron_mirror=http://npmmirror.com/mirrors/electron/ 40 | ELECTRON_BUILDER_BINARIES_MIRROR=http://npmmirror.com/mirrors/electron-builder-binaries/ 41 | PRISMA_BINARIES_MIRROR=http://npmmirror.com/mirrors/prisma/ 42 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.md 3 | 4 | /tsconfig.json 5 | /tsconfig.extend.json 6 | -------------------------------------------------------------------------------- /.versionrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | types: [ 3 | { type: 'feat', section: 'Features' }, 4 | { type: 'fix', section: 'Bug Fixes' }, 5 | { type: 'perf', section: 'Performance' }, 6 | { type: 'refactor', section: 'Refactor' }, 7 | { type: 'chore', hidden: true }, 8 | { type: 'docs', hidden: true }, 9 | { type: 'style', hidden: true }, 10 | { type: 'test', hidden: true }, 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.4.1](https://github.com/SolidZORO/mkr/compare/v0.4.0...v0.4.1) (2021-12-23) 6 | 7 | ## [0.4.0](https://github.com/SolidZORO/mkr/compare/v0.3.0...v0.4.0) (2021-12-23) 8 | 9 | 10 | ### Features 11 | 12 | * update next-plugin-antd-less 1.7.0 ([37b698e](https://github.com/SolidZORO/mkr/commit/37b698ee660d154d8f4c85255472dbd54462684f)) 13 | 14 | ## [0.3.0](https://github.com/SolidZORO/mkr/compare/v0.2.0...v0.3.0) (2021-12-20) 15 | 16 | 17 | ### Features 18 | 19 | * update to CRA v5.0.0 ([e523bb5](https://github.com/SolidZORO/mkr/commit/e523bb5c2aedd4de477beb8c8a8ccf78ebbc9163)) 20 | * update to React Router v6.0.0 ([676eb9d](https://github.com/SolidZORO/mkr/commit/676eb9d631dfe19e77e05ab55530384d11c6e6d2)) 21 | 22 | 23 | ### Bug Fixes 24 | 25 | * compatible CRA and Next.js ([e31109a](https://github.com/SolidZORO/mkr/commit/e31109a5d00f310443fbbad8ee06f5910ccd4e3b)) 26 | 27 | 28 | ### Refactor 29 | 30 | * use eslint-config-qcolate ([c941c37](https://github.com/SolidZORO/mkr/commit/c941c37cf6578475237c75f5ea8e93a4665ecc5b)) 31 | 32 | ### [0.2.2](https://github.com/SolidZORO/mkr/compare/v0.2.1...v0.2.2) (2021-12-20) 33 | 34 | 35 | ### Features 36 | 37 | * update to CRA v5.0.0 ([e523bb5](https://github.com/SolidZORO/mkr/commit/e523bb5c2aedd4de477beb8c8a8ccf78ebbc9163)) 38 | * update to React Router v6.0.0 ([676eb9d](https://github.com/SolidZORO/mkr/commit/676eb9d631dfe19e77e05ab55530384d11c6e6d2)) 39 | 40 | 41 | ### Bug Fixes 42 | 43 | * compatible CRA and Next.js ([e31109a](https://github.com/SolidZORO/mkr/commit/e31109a5d00f310443fbbad8ee06f5910ccd4e3b)) 44 | 45 | ### [0.2.1](https://github.com/SolidZORO/mkr/compare/v0.2.0...v0.2.1) (2021-08-21) 46 | 47 | 48 | ### Refactor 49 | 50 | * use eslint-config-qcolate ([c941c37](https://github.com/SolidZORO/mkr/commit/c941c37cf6578475237c75f5ea8e93a4665ecc5b)) 51 | 52 | ## [0.2.0](https://github.com/SolidZORO/mkr/compare/v0.1.3...v0.2.0) (2021-07-02) 53 | 54 | ### [0.1.3](https://github.com/SolidZORO/mkr/compare/v0.1.2...v0.1.3) (2021-07-02) 55 | 56 | 57 | ### Features 58 | 59 | * add configs ([a100117](https://github.com/SolidZORO/mkr/commit/a100117f913d69c6032b54aa5774b945f516f7f7)) 60 | * new file structure ([228000d](https://github.com/SolidZORO/mkr/commit/228000df27bb09fb817854a6e596ec9869cd5056)) 61 | * use next-plugin-antd-less hot reload less var supported ([b16c8ef](https://github.com/SolidZORO/mkr/commit/b16c8ef9eab71b4acfbf7f17f47ba9e0521c1ce0)) 62 | 63 | 64 | ### Refactor 65 | 66 | * add animate.less ([df60f9b](https://github.com/SolidZORO/mkr/commit/df60f9bd9fac0a65c1dada1e6f9428f6883e8337)) 67 | * edit withAntdLess pluginOptions ([39b4ac2](https://github.com/SolidZORO/mkr/commit/39b4ac283cab73fb88442af62db1b5d3c54296a4)) 68 | * update deps ([9d47b8c](https://github.com/SolidZORO/mkr/commit/9d47b8cb77e9ecc9e36e54b6af1920cf6b22d795)) 69 | * update deps ([240fc04](https://github.com/SolidZORO/mkr/commit/240fc0461cda3277e5d1562426be8366abe5c567)) 70 | * update next-plugin-antd-less ([2bf9f13](https://github.com/SolidZORO/mkr/commit/2bf9f13d1378d8ebbd09312cf51e840b7e4f69fa)) 71 | * use next-plugin-antd-less 1.2.0 ([7f13ee7](https://github.com/SolidZORO/mkr/commit/7f13ee7afef43e17979098801447c7526f7452c9)) 72 | 73 | ### [0.1.2](https://github.com/SolidZORO/mkr/compare/v0.1.1...v0.1.2) (2021-03-23) 74 | 75 | 76 | ### Bug Fixes 77 | 78 | * fix Error404 lazy loader ([1f92a9e](https://github.com/SolidZORO/mkr/commit/1f92a9e5607de16edb6b494d26aa8defbab4a970)) 79 | * fixed scripts error ([dcd7ded](https://github.com/SolidZORO/mkr/commit/dcd7dedef4b8272e70fe1fb4bb760fdcf2e103d4)) 80 | 81 | 82 | ### Refactor 83 | 84 | * all less files [@import](https://github.com/import) use `/src/...` path ([fa5f503](https://github.com/SolidZORO/mkr/commit/fa5f5037fed74cbf760c119c3507ec02fa31ce00)) 85 | 86 | ### 0.1.1 (2021-01-10) 87 | 88 | 89 | ### Refactor 90 | 91 | * remove all export default ([e926365](https://github.com/SolidZORO/mkr/commit/e9263652227846b263637cd1bb11795573ee93a0)) 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Jason Feng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 7 | 12 | 17 |
18 | 19 | 20 | 21 | ## mkr ([demo](https://mkr.vercel.app/)) 22 | 23 | A Simple **CSR** Scaffolding for React Projects w/ [CRA](https://create-react-app.dev/) and [Typescript](https://www.typescriptlang.org/). 24 | 25 | `Less` is supported by [next-plugin-antd-less](https://github.com/SolidZORO/next-plugin-antd-less). 26 | 27 | If you need SSR, you can use [mkn](https://github.com/SolidZORO/mkn). 28 | 29 | 30 | © [MIT](https://github.com/SolidZORO/mkr/blob/master/LICENSE) 31 | -------------------------------------------------------------------------------- /changelog.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | disableEmoji: false, 3 | maxMessageLength: 64, 4 | minMessageLength: 3, 5 | }; 6 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /craco.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len, no-param-reassign, import/no-extraneous-dependencies, @typescript-eslint/no-unused-vars, arrow-body-style, no-new */ 2 | const path = require('path'); 3 | 4 | const cracoBabel = require('./scripts/craco/craco-babel'); 5 | const cracoPluginAnalyze = require('./scripts/craco/craco-plugin--analyze'); 6 | const cracoPluginLess = require('./scripts/craco/craco-plugin--less'); 7 | const cracoModule = require('./scripts/craco/craco-module'); 8 | 9 | module.exports = { 10 | babel: cracoBabel, 11 | plugins: [cracoPluginAnalyze, cracoPluginLess, cracoModule], 12 | webpack: { 13 | alias: { '@': path.resolve(__dirname, 'src/') }, 14 | }, 15 | jest: { 16 | configure: { moduleNameMapper: { '^@(.*)$': '/src$1' } }, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /husky.config.js: -------------------------------------------------------------------------------- 1 | const tasks = (arr) => arr.join(' && '); 2 | 3 | module.exports = { 4 | hooks: { 5 | 'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS', 6 | 'pre-commit': tasks([ 7 | // https://github.com/azz/pretty-quick 8 | 'pretty-quick --staged', 9 | // https://github.com/okonet/lint-staged#configuration. 10 | 'lint-staged', 11 | ]), 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mkr", 3 | "description": "Make React Project w/ CRA(CRAco) and Typescript", 4 | "version": "0.4.1", 5 | "license": "MIT", 6 | "author": "Jason Feng ", 7 | "private": true, 8 | "scripts": { 9 | "-------------------------------- LINT ----": "----", 10 | "format": "prettier --write src/**/*.ts{,x}", 11 | "tsc-check": "tsc -v && tsc --noEmit", 12 | "lint": "tsc --noEmit && eslint src/**/*.ts{,x}", 13 | "fix": "yarn lint --fix && yarn format", 14 | "-------------------------------- TOOL ----": "----", 15 | "nuke": "rimraf build && rimraf build && rimraf yarn.lock && rimraf node_modules && yarn", 16 | "clear": "rimraf build", 17 | "versionup": "standard-version -r patch", 18 | "versionup:minor": "standard-version -r minor", 19 | "versionup:major": "standard-version -r major", 20 | "versionup:init": "standard-version --first-release", 21 | "build-icon": "node src/assets/react-icons-ext/_builder/build.js", 22 | "prepare": "husky install", 23 | "eject": "react-scripts eject", 24 | "dev-debug": "yarn dev | cat", 25 | "build-debug": "yarn build | cat", 26 | "vvv": "yarn analyze", 27 | "-------------------------------- DEV ----": "----", 28 | "dev": "GENERATE_SOURCEMAP=false yarn start", 29 | "devs": "GENERATE_SOURCEMAP=false HTTPS=true PORT=4433 SSL_CRT_FILE=scripts/ssl/cert.crt SSL_KEY_FILE=scripts/ssl/cert.key craco start", 30 | "start": "GENERATE_SOURCEMAP=false craco start", 31 | "test": "craco test", 32 | "analyze": "GENERATE_SOURCEMAP=false NODE_ENV=production yarn build --analyze", 33 | "serve": "yarn build && serve -s build", 34 | "-------------------------------- DEBUG ----": "----", 35 | "debug-serve": "craco build --optimizationless && serve -s build", 36 | "debug-build": "craco build --optimizationless", 37 | "-------------------------------- PROD ----": "----", 38 | "build": "GENERATE_SOURCEMAP=false craco build" 39 | }, 40 | "dependencies": { 41 | "@loadable/component": "^5.15.2", 42 | "antd": "^4.17.4", 43 | "classnames": "^2.3.1", 44 | "history": "^5.2.0", 45 | "less-loader": "^10.2.0", 46 | "lodash": "^4.17.21", 47 | "react": "^17.0.2", 48 | "react-dom": "^17.0.2", 49 | "react-helmet-async": "^1.2.2", 50 | "react-icons": "^4.3.1", 51 | "react-router": "^6.2.1", 52 | "react-router-dom": "^6.2.1", 53 | "web-vitals": "^2.1.2" 54 | }, 55 | "devDependencies": { 56 | "@babel/plugin-proposal-decorators": "^7.16.5", 57 | "@commitlint/config-conventional": "^15.0.0", 58 | "@craco/craco": "^6.4.3", 59 | "@qcolate/eslint-config": "^1.4.1", 60 | "@types/classnames": "^2.3.1", 61 | "@types/eslint-plugin-prettier": "^3.1.0", 62 | "@types/loadable__component": "^5.13.4", 63 | "@types/lodash": "^4.14.178", 64 | "@types/node": "^17.0.4", 65 | "@types/prettier": "^2.4.2", 66 | "@types/react": "^17.0.38", 67 | "@types/react-dom": "^17.0.11", 68 | "@typescript-eslint/eslint-plugin": "^5.8.0", 69 | "@typescript-eslint/parser": "^5.8.0", 70 | "babel-plugin-add-react-displayname": "^0.0.5", 71 | "babel-plugin-import": "^1.13.3", 72 | "babel-plugin-lodash": "^3.3.4", 73 | "commitlint": "^15.0.0", 74 | "craco-alias": "^3.0.1", 75 | "eslint": "^8.5.0", 76 | "eslint-config-airbnb": "^19.0.2", 77 | "eslint-config-airbnb-base": "^15.0.0", 78 | "eslint-config-airbnb-typescript": "^16.1.0", 79 | "eslint-config-prettier": "^8.3.0", 80 | "eslint-import-resolver-typescript": "^2.5.0", 81 | "eslint-loader": "^4.0.2", 82 | "eslint-plugin-import": "^2.25.3", 83 | "eslint-plugin-jest": "^25.3.0", 84 | "eslint-plugin-jsx-a11y": "^6.5.1", 85 | "eslint-plugin-prettier": "^4.0.0", 86 | "eslint-plugin-react": "^7.28.0", 87 | "eslint-plugin-react-hooks": "^4.3.0", 88 | "husky": "^7.0.4", 89 | "lint-staged": "^12.1.3", 90 | "lodash-webpack-plugin": "^0.11.6", 91 | "module-resolver": "^1.0.0", 92 | "next-plugin-antd-less": "^1.7.0", 93 | "prettier": "^2.5.1", 94 | "pretty-quick": "^3.1.3", 95 | "react-scripts": "^5.0.0", 96 | "typescript": "^4.5.4", 97 | "webpack-bundle-analyzer": "^4.5.0" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | module.exports = { 3 | plugins: { 4 | autoprefixer: { flexbox: 'no-2009' }, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 80, 3 | singleQuote: true, 4 | bracketSpacing: true, 5 | trailingComma: 'all', 6 | }; 7 | -------------------------------------------------------------------------------- /public/favicons/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/favicons/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/favicons/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/public/favicons/logo192.png -------------------------------------------------------------------------------- /public/favicons/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/public/favicons/logo512.png -------------------------------------------------------------------------------- /public/favicons/logocra.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 79 | 80 | -------------------------------------------------------------------------------- /public/images/image-public.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/public/images/image-public.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 19 | 20 | 29 | mkr (React) 30 | 31 | 32 | 33 |
34 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mkr", 3 | "short_name": "mkr", 4 | "description": "mkr (React)", 5 | "orientation": "portrait", 6 | "start_url": ".", 7 | "display": "standalone", 8 | "theme_color": "#ffffff", 9 | "background_color": "#ffffff", 10 | "icons": [ 11 | { 12 | "src": "favicons/logo192.png", 13 | "type": "image/png", 14 | "sizes": "192x192", 15 | "purpose": "maskable" 16 | }, 17 | { 18 | "src": "favicons/logo512.png", 19 | "type": "image/png", 20 | "sizes": "512x512" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /scripts/craco/craco-babel.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | ['@babel/plugin-proposal-decorators', { legacy: true }], 4 | ['add-react-displayname'], 5 | ['lodash'], 6 | [ 7 | 'import', 8 | { 9 | libraryName: 'antd', 10 | libraryDirectory: 'lib', 11 | style: true, 12 | }, 13 | 'antd', 14 | ], 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /scripts/craco/craco-module.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len, no-param-reassign, import/no-extraneous-dependencies, @typescript-eslint/no-unused-vars */ 2 | module.exports = { 3 | plugin: { 4 | overrideWebpackConfig: ({ webpackConfig }) => { 5 | // webpackConfig.optimization.splitChunks.name = true; 6 | 7 | const __PROD__ = process.env.NODE_ENV === 'production'; 8 | 9 | // if (__PROD__) { 10 | // webpackConfig.devtool = false; 11 | // } 12 | 13 | // speed up compilation 14 | if (process.argv.includes('--debug')) { 15 | webpackConfig.plugins = webpackConfig.plugins.filter( 16 | (p) => 17 | !['ESLintWebpackPlugin', 'ForkTsCheckerWebpackPlugin'].includes( 18 | p.constructor.name, 19 | ), 20 | ); 21 | 22 | webpackConfig.devtool = false; 23 | webpackConfig.optimization.minimize = false; 24 | webpackConfig.optimization.minimizer = []; 25 | 26 | console.log(webpackConfig); 27 | // process.exit(0); 28 | } 29 | 30 | return webpackConfig; 31 | }, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /scripts/craco/craco-plugin--analyze.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len, no-param-reassign, import/no-extraneous-dependencies, @typescript-eslint/no-unused-vars */ 2 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); 3 | 4 | module.exports = { 5 | plugin: { 6 | overrideWebpackConfig: ({ webpackConfig }) => { 7 | if (process.argv.includes('--analyze')) { 8 | // eslint-disable-next-line no-new 9 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()); 10 | } 11 | 12 | return webpackConfig; 13 | }, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /scripts/craco/craco-plugin--less.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const cracoPluginLess = require('next-plugin-antd-less/overrideWebpackConfig'); 3 | 4 | module.exports = { 5 | plugin: cracoPluginLess, 6 | options: { 7 | // modifyVars: { 8 | // '@THEME--DARK': 'theme-dark', 9 | // }, 10 | lessVarsFilePath: './src/styles/variables.less', 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /scripts/ssl/.gitignore: -------------------------------------------------------------------------------- 1 | *.crt 2 | *.key 3 | -------------------------------------------------------------------------------- /scripts/ssl/README.md: -------------------------------------------------------------------------------- 1 | ## use HTTPS (Guide ONLY for macOS) 2 | 3 | - `brew install mkcert` 4 | 5 | - `mkcert -install` 6 | 7 | - `mkcert -cert-file cert.crt -key-file cert.key localhost ::1 127.0.0.1 192.168.169.99` 8 | 9 | ip `192.168.169.99` is my WLAN ip, pls replace to yourself. 10 | 11 | signature completed, move `cert.crt` and `cert.key` to this dir. 12 | 13 | CRA [HTTPS Guider](https://create-react-app.dev/docs/using-https-in-development/). 14 | 15 | and then `yarn devs` start, more detailed pls see `package.json`. 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter as Router } from 'react-router-dom'; 3 | import { HelmetProvider } from 'react-helmet-async'; 4 | import { Spin } from 'antd'; 5 | 6 | import { AppRouter, ErrorBoundary, LoadingSpinner } from '@/components'; 7 | 8 | Spin.setDefaultIndicator(); 9 | 10 | export const App = () => ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | -------------------------------------------------------------------------------- /src/assets/images/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/assets/images/image.jpg -------------------------------------------------------------------------------- /src/components/AppRouter/AppRouter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import { Route, Routes } from 'react-router-dom'; 4 | 5 | import { errorRoute, masterRoute, testRoute } from '@/routes'; 6 | import { ICompBaseProps } from '@/interfaces'; 7 | import { Error404 } from '@/page-components/error/Error404/Error404'; 8 | 9 | import styles from './styles.module.less'; 10 | 11 | interface IProps extends ICompBaseProps {} 12 | 13 | export const AppRouter: React.FC = (props) => { 14 | return ( 15 |
28 | 29 | null} /> 30 | } /> 31 | 32 | {masterRoute} 33 | {testRoute} 34 | {errorRoute} 35 | 36 |
37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /src/components/AppRouter/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | } 5 | 6 | .comp-style--transition { 7 | width: 100%; 8 | height: 100%; 9 | } 10 | 11 | // DARK-MODE--COMP 12 | .comp-wrapper--alwaysDarkMode, 13 | :global(.@{THEME--DARK}) .comp-wrapper { 14 | } 15 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from 'antd'; 3 | import { RiRefreshLine } from 'react-icons/ri'; 4 | 5 | import styles from './styles.module.less'; 6 | 7 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 8 | interface IProps {} 9 | 10 | interface IState { 11 | hasError: boolean; 12 | errorInfo: any; 13 | } 14 | 15 | // const CATCH_HAS_REFRESH_URL_PARAM = '____ErrorBoundary'; 16 | 17 | export class ErrorBoundary extends React.Component { 18 | static getDerivedStateFromError() { 19 | return { hasError: true }; 20 | } 21 | 22 | constructor(props: IProps) { 23 | super(props); 24 | this.state = { 25 | hasError: false, 26 | errorInfo: {}, 27 | }; 28 | } 29 | 30 | componentDidCatch(err: Error) { 31 | this.setState({ errorInfo: err.message }); 32 | } 33 | 34 | // eslint-disable-next-line class-methods-use-this 35 | onRefresh = () => { 36 | window.location.href = '/'; 37 | // window.location.reload(); 38 | }; 39 | 40 | render() { 41 | if (this.state.hasError) { 42 | return ( 43 |
44 |
45 |
46 | Page Load Error 47 |
48 | 49 | 57 | 58 |
59 |
60 |                 {JSON.stringify(this.state.errorInfo)}
61 |               
62 |
63 |
64 |
65 | ); 66 | } 67 | 68 | return this.props.children; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .error-boundary-comp-wrapper { 4 | position: relative; 5 | display: flex; 6 | flex: 1; 7 | height: 100vh; 8 | align-items: center; 9 | justify-content: center; 10 | background-color: #fff; 11 | } 12 | 13 | .error-boundary-container { 14 | text-align: center; 15 | justify-content: center; 16 | width: 85%; 17 | } 18 | 19 | .title { 20 | display: flex; 21 | font-size: 1.6rem; 22 | align-items: center; 23 | justify-content: center; 24 | 25 | strong { 26 | font-weight: 400; 27 | margin-left: 10px; 28 | } 29 | } 30 | 31 | .error-info { 32 | opacity: 0.5; 33 | position: fixed; 34 | bottom: 50px; 35 | left: 0; 36 | right: 0; 37 | width: 90%; 38 | padding: 15px; 39 | margin: 0 auto; 40 | font-family: var(--code-family); 41 | font-size: 80%; 42 | display: block; 43 | max-width: 640px; 44 | text-align: center; 45 | border-radius: 5px; 46 | border: 1px dashed #ccc; 47 | 48 | pre { 49 | margin-bottom: 0; 50 | } 51 | 52 | code { 53 | font-family: var(--code-family); 54 | line-height: 1.2; 55 | } 56 | } 57 | 58 | .refresh-button { 59 | margin-top: 20px; 60 | display: inline-flex; 61 | place-items: center; 62 | border-radius: 5px; 63 | 64 | span, 65 | svg { 66 | line-height: 1; 67 | } 68 | 69 | svg { 70 | font-size: 120%; 71 | margin-right: 3px; 72 | } 73 | } 74 | 75 | // DARK-MODE--COMP 76 | body .error-boundary-comp-wrapper--alwaysDarkMode, 77 | :global(.@{THEME--DARK}) .error-boundary-comp-wrapper { 78 | .title, 79 | .error-info { 80 | color: #fff; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/components/FooterNav/FooterNav.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | 4 | import { ICompBaseProps } from '@/interfaces'; 5 | import { config } from '@/configs'; 6 | 7 | import styles from './style.module.less'; 8 | 9 | interface IProps extends ICompBaseProps {} 10 | 11 | const fmtVer = (v: string) => v.replace('^', '').replace('~', ''); 12 | const deps = [ 13 | { k: 'react', v: fmtVer(config.pkg.dependencies.react) }, 14 | { k: 'antd', v: fmtVer(config.pkg.dependencies.antd) }, 15 | { k: 'craco', v: fmtVer(config.pkg.devDependencies['@craco/craco']) }, 16 | ]; 17 | 18 | export const FooterNav: React.FC = (props) => { 19 | return ( 20 |
29 |
30 | © {new Date().getFullYear()} 31 | 36 | {config.app.NAME} 37 | {' '} 38 | by {config.pkg.author.split(' ')[0]} 39 |
40 | 41 |
42 | {deps.map((d) => ( 43 |
44 | {d.k} 45 | {d.v} 46 |
47 | ))} 48 |
49 |
50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /src/components/FooterNav/style.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | @import '/src/styles/mixin.less'; 3 | 4 | .comp-wrapper { 5 | display: flex; 6 | justify-content: center; 7 | flex-direction: column; 8 | text-align: center; 9 | margin-bottom: 20px; 10 | } 11 | 12 | .copyright { 13 | display: block; 14 | font-size: 12px; 15 | line-height: 1; 16 | transform: scale(0.95); 17 | 18 | strong { 19 | font-weight: 400; 20 | //font-size: 12px; 21 | } 22 | 23 | span { 24 | } 25 | 26 | a { 27 | display: inline-block; 28 | padding: 0 3px; 29 | } 30 | } 31 | 32 | .deps { 33 | .font-size-10px(); 34 | margin-top: 15px; 35 | display: flex; 36 | justify-content: center; 37 | transform-origin: center; 38 | color: #fff; 39 | 40 | .dep { 41 | margin: 0 5px; 42 | 43 | strong { 44 | font-weight: 400; 45 | } 46 | 47 | sup { 48 | transform: scale(0.7); 49 | display: inline-block; 50 | } 51 | } 52 | } 53 | 54 | // DARK-MODE--COMP 55 | .comp-wrapper--alwaysDarkMode, 56 | :global(.@{THEME--DARK}) .comp-wrapper { 57 | color: var(--text-color--dark); 58 | 59 | a { 60 | color: var(--text-color--dark); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/components/HeaderNavbar/HeaderNavbar.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import { Button } from 'antd'; 4 | import { Link, useLocation } from 'react-router-dom'; 5 | import { FiMoon, FiPercent, FiTriangle } from 'react-icons/fi'; 6 | import { ICompBaseProps } from '@/interfaces'; 7 | 8 | import styles from './style.module.less'; 9 | 10 | interface IProps extends ICompBaseProps {} 11 | 12 | export const HeaderNavbar: React.FC = (props) => { 13 | const { pathname } = useLocation(); 14 | 15 | const navs = [ 16 | { to: '/', icon: , exact: true }, 17 | { to: '/about', icon: , exact: true }, 18 | { to: '/about/darkmode', icon: , exact: true }, 19 | ]; 20 | 21 | return ( 22 |
31 | {navs.map((nav) => ( 32 | 39 | 42 | 43 | ))} 44 |
45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /src/components/HeaderNavbar/style.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | display: flex; 5 | text-align: center; 6 | justify-content: center; 7 | margin-top: 50px; 8 | } 9 | 10 | .nav-button { 11 | display: inline-block; 12 | margin: 0 13px; 13 | border-radius: 50px; 14 | padding: 6px 27px; 15 | text-align: center; 16 | height: auto; 17 | line-height: 1; 18 | border: 2px solid var(--primary-color); 19 | color: var(--primary-color); 20 | 21 | // for Desktop 22 | @media (min-width: @screen-sm) { 23 | margin: 0 20px; 24 | } 25 | 26 | svg { 27 | font-size: 20px; 28 | } 29 | } 30 | 31 | .nav-link { 32 | } 33 | 34 | .nav-link--active { 35 | .nav-button { 36 | background-color: var(--primary-color); 37 | color: #fff; 38 | } 39 | } 40 | 41 | // DARK-MODE--COMP 42 | .comp-wrapper--alwaysDarkMode, 43 | :global(.@{THEME--DARK}) .comp-wrapper { 44 | .nav-button { 45 | border-color: var(--gray-color--dark); 46 | color: var(--gray-color--dark); 47 | } 48 | 49 | .nav-link--active { 50 | .nav-button { 51 | border-color: var(--primary-color--dark); 52 | background-color: transparent; 53 | color: var(--text-color--dark); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/components/HtmlMeta/HtmlMeta.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Helmet } from 'react-helmet-async'; 3 | 4 | import { config } from '@/configs'; 5 | import { ICompBaseProps } from '@/interfaces'; 6 | 7 | interface IProps extends ICompBaseProps { 8 | title: React.ReactNode; 9 | disableSiteName?: boolean; 10 | } 11 | 12 | export const HtmlMeta: React.FC = (props) => { 13 | const siteName = props.disableSiteName ? '' : ` - ${config.app.NAME}`; 14 | 15 | return ( 16 | 17 | 18 | {props.title || ''} 19 | {siteName} 20 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /src/components/HtmlMeta/style.module.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/components/HtmlMeta/style.module.less -------------------------------------------------------------------------------- /src/components/HugeIcon/HugeIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | 4 | import { ICompBaseProps } from '@/interfaces'; 5 | 6 | import styles from './style.module.less'; 7 | 8 | interface IProps extends ICompBaseProps { 9 | icon: any; 10 | } 11 | 12 | export const HugeIcon: React.FC = (props) => { 13 | return ( 14 |
23 | {props.icon} 24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /src/components/HugeIcon/style.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | transition: all 0.3s; 5 | 6 | svg { 7 | transition: all 0.3s; 8 | font-size: 150px; 9 | } 10 | } 11 | 12 | // DARK-MODE--COMP 13 | .comp-wrapper--alwaysDarkMode, 14 | :global(.@{THEME--DARK}) .comp-wrapper { 15 | svg { 16 | transition: all 0.3s; 17 | color: var(--text-color--dark); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/LazyLoadingSpin/LazyLoadingSpin.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import { Spin } from 'antd'; 4 | import { SpinProps } from 'antd/lib/spin'; 5 | 6 | import styles from './style.module.less'; 7 | 8 | interface IProps extends SpinProps { 9 | fullscreen?: boolean; 10 | delay?: number; 11 | // 12 | className?: string; 13 | style?: React.CSSProperties; 14 | alwaysDarkMode?: boolean; 15 | } 16 | 17 | export const LazyLoadingSpin: React.FC = (props) => { 18 | return ( 19 | 32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /src/components/LazyLoadingSpin/style.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: fixed; 5 | right: 10px; 6 | top: 10px; 7 | } 8 | 9 | .comp-wrapper--fullscreen { 10 | position: unset; 11 | right: unset; 12 | top: unset; 13 | display: flex; 14 | justify-content: center; 15 | place-items: center; 16 | height: 100%; 17 | } 18 | 19 | // DARK-MODE--COMP 20 | .comp-wrapper--alwaysDarkMode, 21 | :global(.@{THEME--DARK}) .comp-wrapper { 22 | } 23 | -------------------------------------------------------------------------------- /src/components/LoadingSpinner/LoadingSpinner.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cx from 'classnames'; 3 | import { Spin } from 'antd'; 4 | import { SpinProps, SpinSize } from 'antd/lib/spin'; 5 | 6 | import { ICompBaseProps } from '@/interfaces'; 7 | 8 | // import { CgSpinner as Spinner } from 'react-icons/cg'; 9 | import { ReactComponent as Spinner } from './_spinner.svg'; 10 | 11 | import styles from './styles.module.less'; 12 | 13 | interface IProps extends ICompBaseProps, SpinProps { 14 | fullscreen?: boolean; 15 | spinning?: boolean; 16 | size?: SpinSize; 17 | tip?: string; 18 | delay?: number; 19 | lazy?: boolean; 20 | // 21 | iconClassName?: string; 22 | } 23 | 24 | export const LoadingSpinner: React.FC = (props) => { 25 | LoadingSpinner.displayName = 'LoadingSpinner'; 26 | 27 | const iconSize = props.size || 'default'; 28 | 29 | return ( 30 |
43 | } 52 | /> 53 |
54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /src/components/LoadingSpinner/_spinner.svg: -------------------------------------------------------------------------------- 1 | 8 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /src/components/LoadingSpinner/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | @import '/src/styles/mixin.less'; 3 | 4 | .comp-wrapper { 5 | z-index: 99; 6 | display: flex; 7 | justify-content: center; 8 | place-items: center; 9 | text-align: center; 10 | .fade-in-opacity(); 11 | } 12 | 13 | .comp-wrapper--lazy { 14 | position: absolute; 15 | right: 0; 16 | top: 0; 17 | justify-content: flex-end; 18 | place-items: flex-end; 19 | padding: 5px; 20 | } 21 | 22 | .comp-wrapper--fullscreen { 23 | height: 95vh; 24 | } 25 | 26 | .spin { 27 | } 28 | 29 | .spin-size--small { 30 | svg { 31 | @w: 20px; 32 | width: @w; 33 | height: @w; 34 | } 35 | } 36 | 37 | .spin-size--default { 38 | svg { 39 | margin: -11px !important; 40 | 41 | @w: 24px; 42 | width: @w; 43 | height: @w; 44 | } 45 | } 46 | 47 | .spin-size--large { 48 | svg { 49 | @w: 36px; 50 | width: @w; 51 | height: @w; 52 | } 53 | } 54 | 55 | // DARK-MODE--COMP 56 | .comp-wrapper--alwaysDarkMode, 57 | :global(.@{THEME--DARK}) .comp-wrapper { 58 | color: var(--primary-color); 59 | } 60 | -------------------------------------------------------------------------------- /src/components/PageWrapper/PageWrapper.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | 4 | import { ICompBaseProps } from '@/interfaces'; 5 | 6 | import styles from './styles.module.less'; 7 | 8 | interface IProps extends ICompBaseProps { 9 | children: React.ReactNode; 10 | } 11 | 12 | export const PageWrapper: React.FC = (props) => { 13 | return ( 14 |
23 | {props.children} 24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /src/components/PageWrapper/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: relative; 5 | } 6 | 7 | // DARK-MODE--COMP 8 | .comp-wrapper--alwaysDarkMode, 9 | :global(.@{THEME--DARK}) .comp-wrapper { 10 | } 11 | -------------------------------------------------------------------------------- /src/components/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len, import/no-cycle */ 2 | export { LazyLoadingSpin } from './LazyLoadingSpin/LazyLoadingSpin'; 3 | export { HeaderNavbar } from './HeaderNavbar/HeaderNavbar'; 4 | export { HtmlMeta } from './HtmlMeta/HtmlMeta'; 5 | export { PageWrapper } from './PageWrapper/PageWrapper'; 6 | export { FooterNav } from './FooterNav/FooterNav'; 7 | export { HugeIcon } from './HugeIcon/HugeIcon'; 8 | export { LoadingSpinner } from './LoadingSpinner/LoadingSpinner'; 9 | export { AppRouter } from './AppRouter/AppRouter'; 10 | export { ErrorBoundary } from './ErrorBoundary/ErrorBoundary'; 11 | -------------------------------------------------------------------------------- /src/configs/app.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | import { __env__ } from './env'; 4 | 5 | export const app = { 6 | __DEV__: process.env.NODE_ENV !== 'production', 7 | // 8 | NAME: __env__.REACT_APP_NAME, 9 | }; 10 | -------------------------------------------------------------------------------- /src/configs/env.ts: -------------------------------------------------------------------------------- 1 | import { IDotEnv } from '@/interfaces'; 2 | 3 | // @ts-ignore 4 | export const __env__: IDotEnv = process.env as IDotEnv; 5 | -------------------------------------------------------------------------------- /src/configs/index.ts: -------------------------------------------------------------------------------- 1 | import { app } from './app.config'; 2 | import { pkg } from './pkg.config'; 3 | 4 | export const config = { 5 | app, 6 | pkg, 7 | }; 8 | 9 | // @ts-ignore 10 | window.__APP_CONFIG__ = config; 11 | 12 | export * from './env'; 13 | -------------------------------------------------------------------------------- /src/configs/pkg.config.ts: -------------------------------------------------------------------------------- 1 | import p from '../../package.json'; 2 | 3 | export const pkg = { 4 | name: p.name, 5 | version: p.version, 6 | author: p.author, 7 | dependencies: { 8 | react: p.dependencies.react, 9 | antd: p.dependencies.antd, 10 | }, 11 | devDependencies: { 12 | '@craco/craco': p.devDependencies['@craco/craco'], 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './style.constant'; 2 | -------------------------------------------------------------------------------- /src/constants/style.constant.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | // setting theme 4 | export const CSS_THEME_DARK = getComputedStyle(document.documentElement)?.getPropertyValue('--THEME--DARK').trim() || 'theme-dark'; // prettier-ignore 5 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { useDarkMode } from './useDarkMode'; 2 | -------------------------------------------------------------------------------- /src/hooks/useDarkMode.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | import { CSS_THEME_DARK } from '@/constants'; 4 | 5 | export function useDarkMode() { 6 | useEffect(() => { 7 | const htmlEl = document?.documentElement; 8 | 9 | if (CSS_THEME_DARK && htmlEl) { 10 | htmlEl.classList.add(CSS_THEME_DARK); 11 | } 12 | 13 | // eslint-disable-next-line consistent-return 14 | return () => { 15 | htmlEl.classList.remove(CSS_THEME_DARK); 16 | }; 17 | }, []); 18 | } 19 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import { App } from '@/App'; 5 | import { reportWebVitals } from '@/reportWebVitals'; 6 | 7 | import '@/styles/global.less'; 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root'), 14 | ); 15 | 16 | // If you want to start measuring performance in your app, pass a function 17 | // to log results (for example: reportWebVitals(console.log)) 18 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 19 | reportWebVitals(); 20 | -------------------------------------------------------------------------------- /src/interfaces/config.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IDotEnv { 2 | PUBLIC_URL: string; 3 | // 4 | REACT_APP_NAME: string; 5 | } 6 | 7 | export interface IBuild { 8 | MODE: string; 9 | VERSION: string; 10 | VERSION_DASH: string; 11 | VERSION_NUMBER: string; 12 | VERSION_HASH: string; 13 | BUILDTIME: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export * from './router.interface'; 2 | export * from './config.interface'; 3 | 4 | export type { ICompBaseProps, IPageBaseProps } from './jsx.interface'; 5 | -------------------------------------------------------------------------------- /src/interfaces/jsx.interface.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { IRouteProps } from '@/interfaces/router.interface'; 3 | 4 | export interface IPageBaseProps { 5 | routeProps?: IRouteProps; 6 | // 7 | className?: string; 8 | style?: React.CSSProperties; 9 | alwaysDarkMode?: boolean; 10 | } 11 | 12 | export interface ICompBaseProps { 13 | className?: string; 14 | style?: React.CSSProperties; 15 | alwaysDarkMode?: boolean; 16 | } 17 | -------------------------------------------------------------------------------- /src/interfaces/router.interface.ts: -------------------------------------------------------------------------------- 1 | export interface IRouteItem { 2 | name: string; 3 | path: string; 4 | // 5 | when?: 'forward' | 'back' | 'always'; // default 'forward' 6 | auth?: boolean; 7 | exact?: boolean; 8 | icon?: any; 9 | children?: IRouteItem[]; 10 | bodyClassName?: string; 11 | alwaysDarkMode?: boolean; 12 | LazyComp?: any; 13 | } 14 | 15 | // declare type ILocation = Pick; 16 | 17 | export interface IRouteProps extends IRouteItem {} 18 | -------------------------------------------------------------------------------- /src/layouts/MasterLayout/MasterLayout.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | 4 | import { FooterNav, HeaderNavbar } from '@/components'; 5 | 6 | import styles from './styles.module.less'; 7 | 8 | export interface IProps { 9 | children: React.ReactNode; 10 | // 11 | disableHeader?: boolean; 12 | disableFooter?: boolean; 13 | } 14 | 15 | export const MasterLayout: React.FC = (props) => ( 16 |
23 | {props.disableHeader ? null : ( 24 |
25 | 26 |
27 | )} 28 | 29 |
32 | {props.children} 33 |
34 | 35 | {props.disableFooter ? null : ( 36 |
37 | 38 |
39 | )} 40 |
41 | ); 42 | -------------------------------------------------------------------------------- /src/layouts/MasterLayout/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | height: 100%; 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | .layout-header { 10 | } 11 | 12 | .layout-container { 13 | flex: 1; 14 | } 15 | 16 | .layout-footer { 17 | } 18 | 19 | // DARK-MODE--COMP 20 | .comp-wrapper--alwaysDarkMode, 21 | :global(.@{THEME--DARK}) .comp-wrapper { 22 | } 23 | -------------------------------------------------------------------------------- /src/layouts/index.tsx: -------------------------------------------------------------------------------- 1 | export { MasterLayout } from './MasterLayout/MasterLayout'; 2 | -------------------------------------------------------------------------------- /src/page-components/about/About/About.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | import { FiPercent } from 'react-icons/fi'; 4 | 5 | import { IPageBaseProps } from '@/interfaces'; 6 | import { HtmlMeta, HugeIcon, PageWrapper } from '@/components'; 7 | 8 | import styles from './styles.module.less'; 9 | 10 | interface IProps extends IPageBaseProps {} 11 | 12 | export const About: React.FC = (props) => { 13 | return ( 14 | 23 | 24 | 25 | } /> 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/page-components/about/About/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | @import '/src/styles/mixin.less'; 3 | 4 | .comp-wrapper { 5 | position: relative; 6 | height: 100%; 7 | display: flex; 8 | justify-content: center; 9 | place-items: center; 10 | // 11 | // just test less file aliase 12 | //.just-a-bgc(); 13 | } 14 | 15 | // DARK-MODE--COMP 16 | .comp-wrapper--alwaysDarkMode, 17 | :global(.@{THEME--DARK}) .comp-wrapper { 18 | } 19 | -------------------------------------------------------------------------------- /src/page-components/about/AboutName/AboutName.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | import { useParams } from 'react-router-dom'; 4 | import { FiMoon } from 'react-icons/fi'; 5 | 6 | import { IPageBaseProps } from '@/interfaces'; 7 | import { useDarkMode } from '@/hooks'; 8 | import { HtmlMeta, HugeIcon, PageWrapper } from '@/components'; 9 | 10 | import styles from './styles.module.less'; 11 | 12 | interface IProps extends IPageBaseProps {} 13 | 14 | export const AboutName: React.FC = (props) => { 15 | useDarkMode(); 16 | 17 | const { name } = useParams<{ name?: string }>(); 18 | 19 | return ( 20 | 29 | 30 | 31 | } className={styles['huge-icon']} /> 32 | 33 |
34 | {name} 35 |
36 |
37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /src/page-components/about/AboutName/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | //position: relative; 5 | height: 100%; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | place-items: center; 10 | } 11 | 12 | .huge-icon { 13 | display: block; 14 | } 15 | 16 | .params-info { 17 | display: block; 18 | text-align: center; 19 | color: #999; 20 | padding-top: 20px; 21 | 22 | em, 23 | code { 24 | display: block; 25 | } 26 | 27 | em { 28 | font-style: normal; 29 | } 30 | 31 | code { 32 | } 33 | } 34 | 35 | // DARK-MODE--COMP 36 | .comp-wrapper--alwaysDarkMode, 37 | :global(.@{THEME--DARK}) .comp-wrapper { 38 | .params-info { 39 | color: #888; 40 | font-size: small; 41 | font-weight: 400; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/page-components/error/Error404/Error404.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | 4 | import { IPageBaseProps } from '@/interfaces'; 5 | import { HtmlMeta, PageWrapper } from '@/components'; 6 | 7 | import styles from './styles.module.less'; 8 | 9 | interface IProps extends IPageBaseProps {} 10 | 11 | export const Error404: React.FC = (props) => { 12 | return ( 13 | 22 | 23 | 24 |

Error 404

25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/page-components/error/Error404/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: relative; 5 | height: 100%; 6 | display: flex; 7 | justify-content: center; 8 | place-items: center; 9 | } 10 | 11 | // DARK-MODE--COMP 12 | .comp-wrapper--alwaysDarkMode, 13 | :global(.@{THEME--DARK}) .comp-wrapper { 14 | } 15 | -------------------------------------------------------------------------------- /src/page-components/home/Home/Home.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | import { FiTriangle } from 'react-icons/fi'; 4 | 5 | import { IPageBaseProps } from '@/interfaces'; 6 | import { HtmlMeta, HugeIcon, PageWrapper } from '@/components'; 7 | 8 | import styles from './styles.module.less'; 9 | 10 | interface IProps extends IPageBaseProps {} 11 | 12 | export const Home: React.FC = (props) => { 13 | return ( 14 | 23 | 24 | 25 | } /> 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/page-components/home/Home/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: relative; 5 | height: 100%; 6 | display: flex; 7 | justify-content: center; 8 | place-items: center; 9 | } 10 | 11 | // DARK-MODE--COMP 12 | .comp-wrapper--alwaysDarkMode, 13 | :global(.@{THEME--DARK}) .comp-wrapper { 14 | } 15 | -------------------------------------------------------------------------------- /src/page-components/test/Test/Test.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | 4 | import { IPageBaseProps } from '@/interfaces'; 5 | import { HtmlMeta, PageWrapper } from '@/components'; 6 | 7 | import styles from './styles.module.less'; 8 | 9 | import './_css.css'; 10 | import './_less.less'; 11 | 12 | interface IProps extends IPageBaseProps {} 13 | 14 | export const Test: React.FC = (props) => ( 15 | 16 | 17 | 18 |
css
19 |
20 |
less
21 |
22 |
less module
23 | 24 |
TEST LESS
25 |
TEST CSS
26 |
27 | ); 28 | -------------------------------------------------------------------------------- /src/page-components/test/Test/_css.css: -------------------------------------------------------------------------------- 1 | .test--css { 2 | background-color: blue; 3 | color: red; 4 | } 5 | 6 | .image-bg--css { 7 | width: 200px; 8 | height: 200px; 9 | background-image: url('./image-dir--css.jpg'); 10 | } 11 | -------------------------------------------------------------------------------- /src/page-components/test/Test/_less.less: -------------------------------------------------------------------------------- 1 | .test--less { 2 | background-color: yellow; 3 | color: red; 4 | } 5 | 6 | .image-bg--less { 7 | width: 200px; 8 | height: 200px; 9 | background-image: url('./image-dir--less.jpg'); 10 | } 11 | -------------------------------------------------------------------------------- /src/page-components/test/Test/image-dir--css.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/page-components/test/Test/image-dir--css.jpg -------------------------------------------------------------------------------- /src/page-components/test/Test/image-dir--less-module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/page-components/test/Test/image-dir--less-module.jpg -------------------------------------------------------------------------------- /src/page-components/test/Test/image-dir--less.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/page-components/test/Test/image-dir--less.jpg -------------------------------------------------------------------------------- /src/page-components/test/Test/image-dir.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SolidZORO/mkr/ad998080bf1049ffb69bf6c7cc239f9266c5c1ae/src/page-components/test/Test/image-dir.jpg -------------------------------------------------------------------------------- /src/page-components/test/Test/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: relative; 5 | height: 100%; 6 | display: flex; 7 | justify-content: center; 8 | place-items: center; 9 | flex-direction: column; 10 | } 11 | 12 | .image-bg--less-module { 13 | display: table; 14 | margin: 0 auto; 15 | width: 200px; 16 | height: 200px; 17 | background-image: url('./image-dir--less-module.jpg'); 18 | } 19 | 20 | // DARK-MODE--COMP 21 | .comp-wrapper--always-dark-mode, 22 | :global(.@{THEME--DARK}) .comp-wrapper { 23 | } 24 | -------------------------------------------------------------------------------- /src/page-components/test/TestLazyLoadingSpin/TestLazyLoadingSpin.tsx: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import React from 'react'; 3 | 4 | import { IPageBaseProps } from '@/interfaces'; 5 | import { HtmlMeta, LazyLoadingSpin, PageWrapper } from '@/components'; 6 | 7 | import styles from './styles.module.less'; 8 | 9 | interface IProps extends IPageBaseProps {} 10 | 11 | export const TestLazyLoadingSpin: React.FC = (props) => { 12 | return ( 13 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/page-components/test/TestLazyLoadingSpin/styles.module.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | .comp-wrapper { 4 | position: relative; 5 | height: 100%; 6 | display: flex; 7 | justify-content: center; 8 | place-items: center; 9 | } 10 | 11 | // DARK-MODE--COMP 12 | .comp-wrapper--alwaysDarkMode, 13 | :global(.@{THEME--DARK}) .comp-wrapper { 14 | } 15 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | export const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/routes/_fn.tsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import lazyLib from '@loadable/component'; 4 | 5 | import { IRouteItem } from '@/interfaces'; 6 | 7 | import { LoadingSpinner } from '@/components'; 8 | 9 | export const lazy = (component: any) => 10 | lazyLib(component, { fallback: }); 11 | 12 | export const routeKey = (route: IRouteItem) => 13 | route.children ? `group-${route.name}` : route.path; 14 | 15 | export interface IRouteRender { 16 | route: any; 17 | layoutComp: React.ReactNode; 18 | } 19 | 20 | export const routeRender = (opts: IRouteRender) => { 21 | const routeProps = _.omit(opts?.route, ['LazyComp', 'icon']); 22 | 23 | return ( 24 | // @ts-ignore 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/routes/error.route.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import React from 'react'; 3 | import { Route } from 'react-router-dom'; 4 | 5 | import { IRouteItem } from '@/interfaces'; 6 | import { Error404 } from '@/page-components/error/Error404/Error404'; 7 | 8 | import { routeKey } from './_fn'; 9 | 10 | const errorRouteList: IRouteItem[] = [ 11 | { 12 | name: 'Error404', 13 | path: '/*', 14 | LazyComp: Error404, 15 | exact: true, 16 | }, 17 | ]; 18 | 19 | export const errorRoute = errorRouteList.map((route) => ( 20 | } 27 | /> 28 | )); 29 | -------------------------------------------------------------------------------- /src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './master.route'; 2 | export * from './error.route'; 3 | export * from './test.route'; 4 | -------------------------------------------------------------------------------- /src/routes/master.route.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import React from 'react'; 3 | import { Route } from 'react-router-dom'; 4 | 5 | import { IRouteItem } from '@/interfaces'; 6 | import { Home } from '@/page-components/home/Home/Home'; 7 | import { MasterLayout } from '@/layouts'; 8 | 9 | import { lazy, routeKey } from './_fn'; 10 | 11 | const masterRouteList: IRouteItem[] = [ 12 | { 13 | name: 'AboutDarkMode', 14 | path: '/about/:name', 15 | LazyComp: lazy(() => import(/* webpackChunkName: 'AboutDarkMode' */ '@/page-components/about/AboutName/AboutName' ).then((m) => ({ default: m.AboutName }))), // prettier-ignore 16 | }, 17 | { 18 | name: 'About', 19 | path: '/about', 20 | LazyComp: lazy(() => import(/* webpackChunkName: 'About' */ '@/page-components/about/About/About' ).then((m) => ({ default: m.About }))), // prettier-ignore 21 | exact: true, 22 | }, 23 | { 24 | name: 'Home', 25 | path: '/', 26 | LazyComp: Home, 27 | exact: true, 28 | }, 29 | ]; 30 | 31 | export const masterRoute = masterRouteList.map((route) => ( 32 | 37 | 38 | 39 | } 40 | /> 41 | )); 42 | -------------------------------------------------------------------------------- /src/routes/test.route.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | import React from 'react'; 3 | import { Route } from 'react-router-dom'; 4 | 5 | import { IRouteItem } from '@/interfaces'; 6 | 7 | import { lazy, routeKey } from './_fn'; 8 | 9 | const testRouteList: IRouteItem[] = [ 10 | { 11 | name: 'Test', 12 | path: '/test', 13 | LazyComp: lazy(() => import(/* webpackChunkName: 'Test' */ '@/page-components/test/Test/Test' ).then((m) => ({ default: m.Test }))), // prettier-ignore 14 | }, 15 | { 16 | name: 'TestLazyLoadingSpin', 17 | path: '/test/lazy-loading-spin', 18 | LazyComp: lazy(() => import(/* webpackChunkName: 'TestLazyLoadingSpin' */ '@/page-components/test/TestLazyLoadingSpin/TestLazyLoadingSpin' ).then((m) => ({ default: m.TestLazyLoadingSpin }))), // prettier-ignore 19 | }, 20 | ]; 21 | 22 | export const testRoute = testRouteList.map((route) => ( 23 | } 27 | /> 28 | )); 29 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/styles/_sync-vars-to-root.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | // const mkdirp = require('mkdirp'); 3 | 4 | // Avoid too long formatting 5 | const vars = fs.readFileSync('./variables.less', 'utf-8').replace(/,\n/g, ','); 6 | 7 | const matchs = vars.match(/^@.*/gm); 8 | 9 | // eslint-disable-next-line array-callback-return,consistent-return 10 | const allVars = matchs.map((m) => { 11 | const mv = m.match(/^@(.*?):.*;/m); 12 | // eslint-disable-next-line @typescript-eslint/prefer-optional-chain 13 | if (mv && mv[1]) return mv[1]; 14 | }); 15 | 16 | const HEADER = `@import '/src/styles/variables.less'; 17 | 18 | :root { 19 | `; 20 | 21 | const FOOTER = `} 22 | `; 23 | 24 | let CONTENT = ''; 25 | 26 | allVars.forEach((v) => { 27 | // --screen-md: @screen-md; 28 | if (!v) return; 29 | 30 | CONTENT += ` --${v}: @${v};\n`; 31 | }); 32 | 33 | fs.writeFileSync('variables-css.less', `${HEADER}${CONTENT}${FOOTER}`); 34 | -------------------------------------------------------------------------------- /src/styles/animate.less: -------------------------------------------------------------------------------- 1 | @keyframes infiniteRotating { 2 | 0% { 3 | transform: rotate(0deg); 4 | } 5 | 100% { 6 | transform: rotate(359deg); 7 | } 8 | } 9 | 10 | @keyframes fadeInOpacity { 11 | 0% { 12 | opacity: 0; 13 | } 14 | 15 | 100% { 16 | opacity: 1; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/styles/global.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | @import '/src/styles/variables-css.less'; 3 | @import '/src/styles/animate.less'; 4 | 5 | html, 6 | body { 7 | width: 100%; 8 | } 9 | 10 | html { 11 | text-size-adjust: 100%; 12 | } 13 | 14 | body { 15 | font-size: 14px; 16 | background-color: var(--primary-color-bg); 17 | } 18 | 19 | html, 20 | body, 21 | #root, 22 | #__next, 23 | .app { 24 | height: 100%; 25 | } 26 | 27 | .theme-dark { 28 | background-color: var(--primary-color-bg--dark); 29 | transition: all 0.5s; 30 | 31 | body { 32 | background-color: var(--primary-color-bg--dark); 33 | transition: all 0.5s; 34 | } 35 | } 36 | 37 | .g-icon-spin { 38 | @s: 0.6s; 39 | -webkit-animation: infiniteRotating @s infinite linear; 40 | animation: infiniteRotating @s infinite linear; 41 | } 42 | 43 | .rcicon { 44 | line-height: 1; 45 | display: inline-block; 46 | vertical-align: -3px; 47 | font-size: 16px; 48 | } 49 | 50 | .g-rcicon { 51 | } 52 | -------------------------------------------------------------------------------- /src/styles/mixin.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/animate.less'; 2 | 3 | .just-a-bgc() { 4 | background-color: yellow; 5 | } 6 | 7 | .font-size-11px() { 8 | font-size: 12px; 9 | transform-origin: 0; 10 | transform: scale(0.9); 11 | } 12 | 13 | .font-size-10px() { 14 | font-size: 12px; 15 | transform-origin: 0; 16 | transform: scale(0.8); 17 | } 18 | 19 | .fade-in-opacity() { 20 | animation-name: fadeInOpacity; 21 | animation-iteration-count: 1; 22 | animation-timing-function: ease; 23 | animation-duration: 1s; 24 | } 25 | -------------------------------------------------------------------------------- /src/styles/variables-css.less: -------------------------------------------------------------------------------- 1 | @import '/src/styles/variables.less'; 2 | 3 | :root { 4 | --THEME--DARK: @THEME--DARK; 5 | --font-family: @font-family; 6 | --primary-color: @primary-color; 7 | --primary-color--dark: @primary-color--dark; 8 | --primary-color-bg: @primary-color-bg; 9 | --primary-color-bg--dark: @primary-color-bg--dark; 10 | --text-color: @text-color; 11 | --text-color--dark: @text-color--dark; 12 | --gray-color: @gray-color; 13 | --gray-color--dark: @gray-color--dark; 14 | --border-radius-base: @border-radius-base; 15 | --border-radius-sm: @border-radius-sm; 16 | } 17 | -------------------------------------------------------------------------------- /src/styles/variables.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | // 4 | // PROJECT 5 | // ----------------------------------------- 6 | // https://lesscss.org/#escaping 7 | @THEME--DARK: ~'theme-dark'; 8 | 9 | // Font 10 | @font-family: 'Chinese Quote', 'Segoe UI', Roboto, -apple-system, 11 | BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 12 | 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 13 | 'Segoe UI Emoji', 'Segoe UI Symbol'; 14 | 15 | // Colors 16 | @primary-color: #04f; 17 | @primary-color--dark: #ffff; 18 | 19 | @primary-color-bg: #fff; 20 | @primary-color-bg--dark: #111; 21 | 22 | @text-color: #111; 23 | @text-color--dark: #eee; 24 | 25 | @gray-color: #cbcbcb; 26 | @gray-color--dark: #8f8f8f; 27 | 28 | // Border 29 | //@border-radius-base: 4px; 30 | @border-radius-base: 4px; 31 | @border-radius-sm: 2px; 32 | -------------------------------------------------------------------------------- /tsconfig.extend.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["./src/*"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.extend.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "target": "es6", 6 | "module": "esnext", 7 | "moduleResolution": "node", 8 | "lib": [ 9 | "dom", 10 | "dom.iterable", 11 | "esnext" 12 | ], 13 | "allowJs": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "esModuleInterop": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "allowSyntheticDefaultImports": true, 22 | "noEmit": true, 23 | "experimentalDecorators": true, 24 | "emitDecoratorMetadata": true, 25 | "jsx": "react-jsx" 26 | }, 27 | "include": [ 28 | "src", 29 | "typings", 30 | "global.d.ts" 31 | ], 32 | "exclude": [ 33 | "node_modules" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /typings/custom-typings.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.css'; 3 | declare module '*.less'; 4 | declare module '*.scss'; 5 | declare module '*.sass'; 6 | declare module '*.styl'; 7 | declare module '*.json'; 8 | 9 | declare module '*.png'; 10 | declare module '*.jpg'; 11 | declare module '*.jpeg'; 12 | declare module '*.svg'; 13 | declare module '*.gif'; 14 | declare module '*.ico'; 15 | -------------------------------------------------------------------------------- /typings/global.d.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | declare global { 3 | interface Window { 4 | NoCaptcha: any; 5 | } 6 | } 7 | 8 | declare namespace NodeJS { 9 | interface Process { 10 | browser: boolean; 11 | } 12 | } 13 | 14 | declare const __DEV__: boolean; 15 | 16 | declare module 'colorthief/*'; 17 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /// 3 | --------------------------------------------------------------------------------