commit c5e5ecf5769352ea55d8c66b0501a7ccfd7625b1 Author: srgooglo <38926803+srgooglo@users.noreply.github.com> Date: Fri Jan 31 16:59:15 2020 +0100 core release diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7e3649ac --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +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 + +[Makefile] +indent_style = tab diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..96a82dff --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +src/**/*-test.js +src/public +src/routes/chart/ECharts/theme +src/routes/chart/highCharts/mapdata +src/locales/_build/ +src/locales/**/*.js +docs/**/*.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..e71ebc80 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,8 @@ +{ + "extends": "react-app", + "rules": { + "jsx-a11y/href-no-hash": "off", + "no-console": "warn", + "valid-jsdoc": "warn" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..e33f72bd --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +coverage +dist +node_modules +npm-debug.log +yarn-error.log +yarn.lock +package-lock.json + +# ide +.idea + +# Mac General +.DS_Store +.AppleDouble +.LSOverride + +# umi +.umi +.umi-production + +# jslingui +src/locales/_build +src/locales/**/*.js +recover/ + +.env +.env +.env +sockets/rs_develop diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..1e879f7a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +*.svg +*.ejs +.DS_Store +.umi +.umi-production +src/locales/**/*.json \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..36301bc5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "es5" +} diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 00000000..b533bdd6 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,9 @@ +{ + "extends": ["stylelint-config-standard", "stylelint-config-prettier"], + "rules": { + "declaration-empty-line-before": null, + "no-descending-specificity": null, + "selector-pseudo-class-no-unknown": null, + "selector-pseudo-element-colon-notation": null + } +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..4789d27f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: node_js +node_js: + - node +script: + - npm run build +before_install: + - | + if [ "$TRAVIS_BRANCH" = "develop" ]; then + for prefixed_envvar in ${!DEV_*}; do + eval export ${prefixed_envvar#DEV_}="${!prefixed_envvar}" + done + elif [ "$TRAVIS_BRANCH" = "master" ]; then + for prefixed_envvar in ${!PROD_*}; do + eval export ${prefixed_envvar#PROD_}="${!prefixed_envvar}" + done + else + for prefixed_envvar in ${!TEST_*}; do + eval export ${prefixed_envvar#TEST_}="${!prefixed_envvar}" + done + fi + - openssl aes-256-cbc -K $encrypted_18b2305b78c9_key -iv $encrypted_18b2305b78c9_iv -in config/id_rsa.enc -out ~/.ssh/id_rsa -d + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $HOST\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + - yarn global add now +after_script: + - scp -o stricthostkeychecking=no -r ./dist root@$HOST:$BUILD_DIR + - cd ./docs && now -A $DOC_NOW_CONFIG -t $NOW_TOKEN && now alias -A $DOC_NOW_CONFIG -t $NOW_TOKEN diff --git a/.umirc.js b/.umirc.js new file mode 100644 index 00000000..e721f8fc --- /dev/null +++ b/.umirc.js @@ -0,0 +1,92 @@ +// https://umijs.org/config/ +import { resolve } from 'path'; +import { i18n } from './config/ycore.config.js'; +export default { + ignoreMomentLocale: true, + targets: { + ie: 9, + }, + treeShaking: true, + plugins: [ + [ + 'umi-plugin-react', + { + dva: { + immer: true, + hmr: true, + }, + antd: true, + dynamicImport: { + webpackChunkName: true, + loadingComponent: './components/Loader/Loader', + }, + routes: { + exclude: [ + /model\.(j|t)sx?$/, + /service\.(j|t)sx?$/, + /models\//, + /components\//, + /services\//, + ], + update: routes => { + if (!i18n) return routes; + const newRoutes = []; + + for (const item of routes[0].routes) { + newRoutes.push(item); + + if (item.path) { + newRoutes.push( + Object.assign({}, item, { + path: `/:lang(${i18n.languages.map(item => item.key).join('|')})` + item.path, + }) + ); + } + } + + routes[0].routes = newRoutes; + return routes; + }, + }, + dll: false, + pwa: { + manifestOptions: { + srcPath: 'manifest.json', + }, + }, + hd: false, + }, + ], + ], + // Theme for antd + // https://ant.design/docs/react/customize-theme + theme: './config/theme.config.js', + // Webpack Configuration + alias: { + sockets: resolve(__dirname, './sockets'), + ycore: resolve(__dirname, './src/ycore_worker.tsx'), + ycstyle: resolve(__dirname, './src/ycore_style.scss'), + api: resolve(__dirname, './src/services/'), + components: resolve(__dirname, './src/components'), + widgets: resolve(__dirname, './src/widgets'), + config: resolve(__dirname, './config/ycore.config.js'), + models: resolve(__dirname, './src/models'), + routes: resolve(__dirname, './src/routes'), + services: resolve(__dirname, './src/services'), + themes: resolve(__dirname, './src/themes'), + utils: resolve(__dirname, './src/utils'), + }, + extraBabelPresets: ['@lingui/babel-preset-react'], + extraBabelPlugins: [ + [ + 'import', + { + libraryName: 'lodash', + libraryDirectory: '', + camel2DashComponentName: false, + }, + 'lodash', + ], + ], +}; + diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/config/id_rsa.enc b/config/id_rsa.enc new file mode 100644 index 00000000..5c41e85f Binary files /dev/null and b/config/id_rsa.enc differ diff --git a/config/keys.js b/config/keys.js new file mode 100644 index 00000000..7fe55a49 --- /dev/null +++ b/config/keys.js @@ -0,0 +1,3 @@ +module.exports = { + secretOrKey: "secret" +}; \ No newline at end of file diff --git a/config/theme.config.js b/config/theme.config.js new file mode 100644 index 00000000..6a454e54 --- /dev/null +++ b/config/theme.config.js @@ -0,0 +1,8 @@ +const fs = require('fs') +const path = require('path') +const lessToJs = require('less-vars-to-js') + +module.exports = () => { + const themePath = path.join(__dirname, '../src/themes/default.less') + return lessToJs(fs.readFileSync(themePath, 'utf8')) +} diff --git a/config/ycore.config.js b/config/ycore.config.js new file mode 100644 index 00000000..b7f15b62 --- /dev/null +++ b/config/ycore.config.js @@ -0,0 +1,69 @@ +module.exports = { + siteName: 'Comty', + copyright: 'RageStudio©', + logoPath: '/logo.svg', + FullLogoPath: '/full_logo.svg', + apiPrefix: '/api/v1', + fixedHeader: true, // sticky primary layout header + + App_Config: { + InitRes: { width: 1000, height: 900}, + InitOpenConsole: true, + }, + + /* Layout configuration, specify which layout to use for route. */ + layouts: [ + { + name: 'primary', + include: [/.*/], + exclude: [/\/login/, /\/socket\/(.*)/, /\/publics/, /\/authorize/], + }, + ], + yConfig: { + // Disused Variables, exported from yCoreWorker + // Global Server Key (Requiered for RS-YIBTP), Not autogenerated, must be included on. (Recommended not modify this constants) + server_key: "f706b0a535b6c2d36545c4137a0a3a26853ea8b5-1223c9ba7923152cae28e5a2e7501b2b-50600768", + openwheater_apiKey:'2acf34be0b8f033b89ba4de1e674d42a', + }, + Endpoints: { + auth_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/auth", + get_servicesHandler: 'https://api.ragestudio.net/RS-YIBTP/rs/servicesHandler', + get_modhandler: "https://api.ragestudio.net/RS-YIBTP/rs/modHandler", + get_subscriptionHandler: "https://api.ragestudio.net/RS-YIBTP/rs/subscriptionHandler", + get_marketplace_global: "https://api.ragestudio.net/RS-YIBTP/rs/marketplaceHandler?access_token=", + get_config_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/get-site-settings?access_token=", + get_userData_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/get-user-data?access_token=", + update_userData_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/update-user-data?access_token=", + removeToken: "https://api.ragestudio.net/RS-YIBTP/yid/delete-access-token?access_token=", + register_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/create-account", + resetPassword_endpoint: "https://api.ragestudio.net/RS-YIBTP/yid/send-reset-password-email?access_token=", + logotype_uri: 'https://api.ragestudio.net/branding/svg/STUDIO-JETBLACK-Generic_template.png', + }, + DevOptions: { + defaultSettings: [{id: 'strict_lightMode', value: false}, {id: 'force_collapse', value: false}, {id: 'force_showDevLogs', value: true}], + + // Global Behaviors + InfiniteLoading: false, + InfiniteLogin: false, + InfiniteRegister: false, + DisableLogin: false, + DisableRegister: true, + DisablePasswordRecover: true, + // Activating this, the logs must be trowed + ShowFunctionsLogs: true, + StrictLightMode: false + }, + /* I18n configuration, `languages` and `defaultLanguage` are required currently. */ + i18n: { + /* Countrys flags: https://www.flaticon.com/packs/countrys-flags */ + languages: [ + { + key: 'en', + title: 'English', + }, + ], + defaultLanguage: 'en', + }, + } + + diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..c52ac835 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + testURL: 'http://localhost:8000', +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 00000000..5668584c --- /dev/null +++ b/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "Comty", + "start_url": ".", + "display": "standalone", + "background_color": "white", + "description": "RageStudio users dashboard", + "icons": [ + { + "src": "logo.svg" + } + ] +} diff --git a/mock/_utils.js b/mock/_utils.js new file mode 100644 index 00000000..deeb2000 --- /dev/null +++ b/mock/_utils.js @@ -0,0 +1,40 @@ +/** + * Query objects that specify keys and values in an array where all values are objects. + * @param {array} array An array where all values are objects, like [{key:1},{key:2}]. + * @param {string} key The key of the object that needs to be queried. + * @param {string} value The value of the object that needs to be queried. + * @return {object|undefined} Return frist object when query success. + */ +export function queryArray(array, key, value) { + if (!Array.isArray(array)) { + return + } + return array.filter(_ => _[key] === value) +} + +export function randomNumber(min, max) { + return Math.floor(Math.random() * (max - min) + min) +} + +export const Constant = { + ApiPrefix: '/api/v1', + NotFound: { + message: 'Not Found', + documentation_url: '', + }, + Color: { + green: '#64ea91', + blue: '#8fc9fb', + purple: '#d897eb', + red: '#f69899', + yellow: '#f8c82e', + peach: '#f797d6', + borderBase: '#e5e5e5', + borderSplit: '#f4f4f4', + grass: '#d6fbb5', + sky: '#c1e0fc', + }, +} + +export Mock from 'mockjs' +export qs from 'qs' diff --git a/mock/route.js b/mock/route.js new file mode 100644 index 00000000..3d8f1cdf --- /dev/null +++ b/mock/route.js @@ -0,0 +1,152 @@ +import { + Constant +} from './_utils' +const { + ApiPrefix +} = Constant + +const database = [ + + // DASHBOARD SECTION + { + id: '1', + icon: 'home', + name: 'Main', + route: '/main', + }, + + // ACCOUNT SECTION + { + id: '2', + breadcrumbParentId: '1', + name: 'Account', + icon: 'user', + }, + { + id: '21', + breadcrumbParentId: '2', + menuParentId: '2', + name: 'YulioID™', + icon: 'user', + route: '/account', + }, + { + id: '22', + breadcrumbParentId: '2', + menuParentId: '2', + name: 'YulioPay™', + icon: 'wallet', + route: '/wallet', + }, + { + id: '23', + breadcrumbParentId: '2', + menuParentId: '2', + name: 'Vault', + icon: 'save', + route: '/account', + }, + + + // RESOURCES SECTION + { + id: '3', + breadcrumbParentId: '1', + name: 'Resources', + icon: 'compass', + }, + { + id: '31', + breadcrumbParentId: '3', + menuParentId: '3', + name: 'Marketplace', + icon: 'shopping-cart', + route: '/resources/marketplace', + }, + { + id: '32', + breadcrumbParentId: '3', + menuParentId: '3', + name: 'Apps', + icon: 'desktop', + route: '/resources/apps', + }, + { + id: '33', + breadcrumbParentId: '3', + menuParentId: '3', + name: 'Download Manager', + icon: 'build', + route: '/resources/dl', + }, + { + id: '34', + breadcrumbParentId: '3', + menuParentId: '3', + name: 'Other Services', + icon: 'compass', + route: '/resources/otherservices', + }, + + // CloudStudio + { + id: '4', + breadcrumbParentId: '1', + name: 'Cloud Studio', + icon: 'cloud', + }, + { + id: '42', + breadcrumbParentId: '4', + menuParentId: '4', + name: 'Workspaces', + icon: 'deployment-unit', + route: '/changelogs', + }, + { + id: '43', + breadcrumbParentId: '4', + menuParentId: '4', + name: 'Cloud Computing', + icon: 'cloud-server', + route: '/help', + }, + { + id: '44', + breadcrumbParentId: '4', + menuParentId: '4', + name: 'GIT', + icon: 'branches', + route: '/about', + }, + // Project Manager + { + id: '5', + breadcrumbParentId: '1', + name: 'Project Manager', + icon: 'team', + }, + { + id: '51', + breadcrumbParentId: '5', + menuParentId: '5', + name: 'Project Manager', + icon: 'reconciliation', + route: '/help', + }, + { + id: '52', + breadcrumbParentId: '5', + menuParentId: '5', + name: 'Teams', + icon: 'team', + route: '/changelogs', + }, + +] + +module.exports = { + [`GET ${ApiPrefix}/routes`](req, res) { + res.status(200).json(database) + }, +} \ No newline at end of file diff --git a/mock/user.js b/mock/user.js new file mode 100644 index 00000000..12006d3d --- /dev/null +++ b/mock/user.js @@ -0,0 +1,52 @@ +import { Mock, Constant, qs, randomAvatar } from './_utils' +import bcrypt from 'bcryptjs'; +import jwt from 'jsonwebtoken'; +import keys from '../config/keys.js'; + +const { ApiPrefix } = Constant +const queryArray = (array, key, keyAlias = 'key') => { + if (!(array instanceof Array)) { + return null + } + let data + + for (let item of array) { + if (item[keyAlias] === key) { + data = item + break + } + } + + if (data) { + return data + } + return null +} +const NOTFOUND = { + message: 'API Route Not Found', + documentation_url: 'http://localhost:8000/request', +} + +module.exports = { + [`POST ${ApiPrefix}/user/login`](req, res) { + var ExpireTime = '1556952' + const now = new Date() + now.setDate(now.getDate() + 1) + const { UserID, UserToken } = req.body + const frame = { UserID, UserToken, deadline: now.getTime()} + jwt.sign( + frame, + keys.secretOrKey, + { expiresIn: ExpireTime }, + (err, token) => { + res.cookie('token', token, { maxAge: ExpireTime, httpOnly: false }), + res.json({ success: true, token: token }) + } + ) + }, + + [`GET ${ApiPrefix}/user/logout`](req, res) { + res.clearCookie('token') + res.status(200).end() + }, +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..43dcfa23 --- /dev/null +++ b/package.json @@ -0,0 +1,151 @@ +{ + "name": "comty-development", + "version": "0.1.1", + "description": "", + "main": "index.js", + "author": "", + "license": "ISC", + "dependencies": { + "@ant-design/pro-layout": "^4.9.11", + "@lingui/react": "^2.9.0", + "ant-design-pro": "^2.3.2", + "antd": "^3.26.3", + "autoprefixer": "7.1.6", + "axios": "^0.18.0", + "babel-core": "7.0.0-bridge.0", + "bcryptjs": "^2.4.3", + "body-parser": "^1.19.0", + "chart.js": "^2.9.3", + "classnames": "^2.2.6", + "concurrently": "^5.0.2", + "cryptr": "^4.0.2", + "dns": "^0.2.2", + "dotenv": "^8.2.0", + "draftjs-to-html": "^0.8.4", + "draftjs-to-markdown": "^0.5.1", + "dva-model-extend": "^0.1.2", + "enquire-js": "^0.2.1", + "highcharts-exporting": "^0.1.7", + "highcharts-more": "^0.1.7", + "immutability-helper": "^3.0.1", + "is-empty": "^1.2.0", + "jquery": "^3.4.1", + "js-cookie": "^2.2.1", + "json-format": "^1.0.1", + "jsonwebtoken": "^8.5.1", + "lodash": "^4.17.15", + "md5": "^2.2.1", + "moment": "^2.24.0", + "node-sass": "^4.13.1", + "nprogress": "^0.2.0", + "os-utils": "0.0.14", + "passport": "^0.4.1", + "passport-auth0": "^1.3.1", + "passport-jwt": "^4.0.0", + "path-to-regexp": "^2.4.0", + "prop-types": "^15.7.0", + "qs": "^6.9.0", + "radium": "^0.26.0", + "rc-tween-one": "^2.6.8", + "react-animations": "^1.0.0", + "react-bootstrap": "^0.32.4", + "react-chartjs": "^1.2.0", + "react-chat-elements": "^10.1.1", + "react-countup": "^4.3.0", + "react-dazzle": "^1.4.0", + "react-detect-offline": "^2.4.0", + "react-draft-wysiwyg": "^1.14.1", + "react-fullscreen-crossbrowser": "^1.0.9", + "react-helmet": "^5.2.0", + "react-highcharts": "^16.1.0", + "react-iframe": "^1.8.0", + "react-modal": "^3.11.1", + "react-new-window": "^0.1.2", + "react-notifications": "^1.4.3", + "react-perfect-scrollbar": "^1.4.2", + "react-responsive": "^8.0.1", + "react-router": "^5.1.2", + "react-scripts": "2.1.1", + "react-select-country-list": "^2.0.1", + "react-server-status": "^1.1.1", + "react-sound": "^1.2.0", + "recompose": "^0.30.0", + "simple-oauth2": "^3.1.0", + "socket.io-client": "^2.1.1", + "store": "^2.0.12", + "stripe": "^7.14.0", + "ts-cookies": "^1.0.0", + "uifx": "^1.0.8", + "umi-plugin-datahub": "^3.2.1", + "universal-cookie": "^4.0.2", + "validator": "^12.1.0", + "websocket": "^1.0.31" + }, + "devDependencies": { + "electron-builder": "^20.43.0", + "electron-devtools-installer": "^2.2.4", + "electron-reload": "^1.4.0", + "rimraf": "^2.6.3", + "wait-on": "^3.2.0", + "@lingui/babel-preset-react": "^2.9.0", + "@lingui/cli": "^2.9.0", + "@lingui/loader": "^2.9.0", + "@types/react": "^16.9.16", + "babel-eslint": "^10.0.3", + "babel-plugin-dev-expression": "^0.2.2", + "babel-plugin-import": "^1.13.0", + "babel-plugin-macros": "^2.8.0", + "babel-plugin-module-resolver": "^3.2.0", + "cross-env": "^5.2.1", + "electron": "^7.1.8", + "eslint": "^5.15.0", + "eslint-config-react-app": "^3.0.5", + "eslint-plugin-flowtype": "^3.13.0", + "eslint-plugin-import": "^2.19.1", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.17.0", + "husky": "^1.3.0", + "less-vars-to-js": "^1.3.0", + "lint-staged": "^8.1.0", + "mockjs": "^1.1.0", + "module": "^1.2.5", + "now": "^16.7.0", + "prettier": "^1.16.0", + "stylelint": "^9.10.0", + "stylelint-config-prettier": "^5.3.0", + "stylelint-config-standard": "^18.2.0", + "typescript": "^3.7.3", + "umi": "^2.12.7", + "umi-plugin-react": "^1.14.10" + }, + "lingui": { + "fallbackLocale": "en", + "sourceLocale": "en", + "localeDir": "src/locales", + "srcPathDirs": [ + "src/pages", + "src/layouts", + "src/components", + "src/layouts" + ], + "format": "minimal", + "extractBabelOptions": { + "presets": [ + "umi/babel" + ] + } + }, + "scripts": { + "app-dev": "concurrently \"npm run start\" \"wait-on http://localhost:8000 && npm run electron-dev\"", + "electron-dev": "cross-env NODE_ENV=development electron .", + "tsc:w": "tsc -w", + "analyze": "cross-env ANALYZE=1 umi build", + "build": "umi build", + "start": "umi dev", + "test": "cross-env BABELRC=none umi test", + "prettier": "prettier --write 'src/**/*.{js,less}'", + "add-locale": "lingui add-locale", + "extract": "lingui extract", + "trans": "lingui extract --clean && node ./scripts/translate.js" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..5c41e85f Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/full_logo.svg b/public/full_logo.svg new file mode 100644 index 00000000..6f64918f --- /dev/null +++ b/public/full_logo.svg @@ -0,0 +1,39 @@ +<svg id="Capa_2" data-name="Capa 2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1391.17 234.17"> + <defs> + <style> + .cls-1 { + fill: #fff; + } + + .cls-2 { + fill: #00fea1; + } + + .cls-3 { + fill: #00a079; + } + </style> + <symbol id="TM" data-name="TM" viewBox="0 0 46.03 24.05"> + <path class="cls-1" d="M19.68.52a1.31,1.31,0,0,1,.42,1,1.31,1.31,0,0,1-.42,1A1.7,1.7,0,0,1,18.53,3H11.7l0,19.43a1.54,1.54,0,0,1-.48,1.18A1.71,1.71,0,0,1,10,24a1.72,1.72,0,0,1-1.18-.45,1.51,1.51,0,0,1-.5-1.17l0-19.44H1.57C.52,2.93,0,2.46,0,1.53S.52.13,1.57.13l17,0A1.68,1.68,0,0,1,19.68.52Zm25.93,0A1.65,1.65,0,0,1,46,1.66l0,20.77a1.73,1.73,0,0,1-.39,1.21,1.44,1.44,0,0,1-1.07.41,1.37,1.37,0,0,1-1.06-.42,1.7,1.7,0,0,1-.39-1.2l0-16L36.32,19.34a1.64,1.64,0,0,1-1.57,1.11,1.61,1.61,0,0,1-1.51-1.12L26.48,6.67l0,15.73A1.61,1.61,0,0,1,26,23.61a1.63,1.63,0,0,1-1.12.41,1.39,1.39,0,0,1-1.07-.42,1.7,1.7,0,0,1-.39-1.2l0-20.78A1.58,1.58,0,0,1,23.91.45,1.59,1.59,0,0,1,25.09,0c.6,0,1.1.39,1.51,1.18l8.21,15.69L43,1.2A1.81,1.81,0,0,1,44.52,0,1.42,1.42,0,0,1,45.61.48Z"/> + </symbol> + <symbol id="Nuevo_símbolo" data-name="Nuevo símbolo" viewBox="0 0 822.09 126.19"> + <g> + <path class="cls-1" d="M1.67,123.38A5.16,5.16,0,0,1,0,119.5V6.34A5.16,5.16,0,0,1,1.67,2.46,5.81,5.81,0,0,1,5.81.88H40q29.4,0,45.5,16t16.1,45.93q0,29.92-16.1,46T40,125H5.81A5.81,5.81,0,0,1,1.67,123.38Zm37.75-7.92q50.7,0,50.69-52.63,0-52.44-50.69-52.45H10.91V115.46Z"/> + <path class="cls-1" d="M183.65,45.58q7.66,8.1,7.66,24.47v50.16a5.55,5.55,0,0,1-1.41,4,5.77,5.77,0,0,1-7.74,0,5.55,5.55,0,0,1-1.41-4V109.65A27.59,27.59,0,0,1,170,121.88a30.31,30.31,0,0,1-16.19,4.31,34.05,34.05,0,0,1-15.13-3.34,26.68,26.68,0,0,1-10.83-9.33,23.42,23.42,0,0,1-4-13.2q0-9.51,4.93-14.78T145.2,78q11.43-2.3,31.85-2.29h3.7V69.17q0-11.62-4.75-17t-15-5.36a48.54,48.54,0,0,0-24.82,6.86l-2.73,1.85A7,7,0,0,1,129.71,57a3.67,3.67,0,0,1-2.9-1.32,4.75,4.75,0,0,1-1.15-3.25q0-3.87,6.16-7.57a55.22,55.22,0,0,1,13.73-5.46,60.17,60.17,0,0,1,15-1.93Q176,37.49,183.65,45.58Zm-10.2,63.54q7.29-7.74,7.3-19.71V83.6h-3.34q-16.9,0-25.88,1.41t-12.67,4.84q-3.69,3.44-3.69,9.94A15.4,15.4,0,0,0,140.8,112a20.56,20.56,0,0,0,13.9,4.84Q166.15,116.86,173.45,109.12Z"/> + <path class="cls-1" d="M232.4,124.17a46.44,46.44,0,0,1-12.58-5.55,21.46,21.46,0,0,1-4.66-4,5.92,5.92,0,0,1-1.32-3.78,4.2,4.2,0,0,1,1.14-3,3.59,3.59,0,0,1,2.73-1.23q1.57,0,5.45,2.64a57.52,57.52,0,0,0,10.48,5.45,37,37,0,0,0,13.46,2.11q10.38,0,16.19-3.78a12.16,12.16,0,0,0,5.81-10.82,11,11,0,0,0-2.11-7,16.9,16.9,0,0,0-7-4.75,85.62,85.62,0,0,0-14.08-4q-15.68-3.51-22.27-9.06T217,62.66a22.14,22.14,0,0,1,8.8-18.22q8.8-6.94,22.88-6.95a48.33,48.33,0,0,1,13.12,1.76,33.53,33.53,0,0,1,10.82,5.1q6.17,4.23,6.16,8.27a4.55,4.55,0,0,1-1.14,3.08A3.52,3.52,0,0,1,274.91,57c-1.18,0-3-.93-5.46-2.81A53.7,53.7,0,0,0,260,48.84a30,30,0,0,0-11.88-2q-9.16,0-14.61,4.13a13.3,13.3,0,0,0-5.46,11.18,11.41,11.41,0,0,0,1.85,6.69,15,15,0,0,0,6.34,4.66,72.14,72.14,0,0,0,12.93,4q12.15,2.82,18.66,6T277.2,91Q280,95.4,280,102.26,280,113,271,119.59t-24,6.6A53,53,0,0,1,232.4,124.17Z"/> + <path class="cls-1" d="M374.17,70.58v49.8a5.51,5.51,0,0,1-1.41,4,5.05,5.05,0,0,1-3.87,1.5,5.14,5.14,0,0,1-5.45-5.46V71.28q0-12.68-5.11-18.48T342.14,47q-12.67,0-20.33,7.75T314.16,75.5v44.88a5.51,5.51,0,0,1-1.41,4,5.05,5.05,0,0,1-3.87,1.5,5.15,5.15,0,0,1-5.46-5.46V5.46a5.32,5.32,0,0,1,1.5-4,5.32,5.32,0,0,1,4-1.5,5.05,5.05,0,0,1,3.87,1.5,5.51,5.51,0,0,1,1.41,4v48.4a28.2,28.2,0,0,1,11.7-12.15,35.69,35.69,0,0,1,17.51-4.22Q374.17,37.49,374.17,70.58Z"/> + <path class="cls-1" d="M462.17,42.94a36.27,36.27,0,0,1,13.38,15.4q4.74,9.94,4.75,23.15,0,13.38-4.75,23.49a36.62,36.62,0,0,1-13.38,15.67,36,36,0,0,1-19.89,5.54,34.47,34.47,0,0,1-17.95-4.49,28.13,28.13,0,0,1-11.44-13.11v11.62a5.55,5.55,0,0,1-1.41,4,5.08,5.08,0,0,1-3.87,1.49,5.14,5.14,0,0,1-5.46-5.45V5.46a5.32,5.32,0,0,1,1.5-4,5.35,5.35,0,0,1,4-1.5,5.05,5.05,0,0,1,3.87,1.5,5.51,5.51,0,0,1,1.41,4V55.09A28.13,28.13,0,0,1,424.33,42a34.47,34.47,0,0,1,17.95-4.49A36.47,36.47,0,0,1,462.17,42.94Zm-.44,64.42q7.49-9.33,7.48-25.87t-7.48-25.61q-7.49-9.06-21-9.06-13.38,0-20.59,9.15t-7.22,25.87q0,16.72,7.3,25.78t20.68,9.07Q454.25,116.69,461.73,107.36Z"/> + <path class="cls-1" d="M516.29,120.74a36.65,36.65,0,0,1-13.82-15.49q-4.92-10-4.92-23.41t4.92-23.41a36.65,36.65,0,0,1,13.82-15.49,41.79,41.79,0,0,1,41.27,0,35.88,35.88,0,0,1,13.82,15.49q4.83,10,4.84,23.41t-4.84,23.41a35.88,35.88,0,0,1-13.82,15.49,41.79,41.79,0,0,1-41.27,0Zm41.45-13q7.39-9,7.39-25.87,0-16.55-7.48-25.78T537,46.82q-13.38,0-20.77,9.24t-7.39,25.78q0,16.89,7.21,25.87t20.77,9Q550.35,116.69,557.74,107.71Z"/> + <path class="cls-1" d="M655.86,45.58q7.65,8.1,7.65,24.47v50.16a5.55,5.55,0,0,1-1.41,4,5.77,5.77,0,0,1-7.74,0,5.55,5.55,0,0,1-1.41-4V109.65a27.62,27.62,0,0,1-10.73,12.23,30.37,30.37,0,0,1-16.2,4.31,34.08,34.08,0,0,1-15.13-3.34,26.75,26.75,0,0,1-10.83-9.33,23.5,23.5,0,0,1-4-13.2q0-9.51,4.93-14.78T617.4,78q11.45-2.3,31.86-2.29H653V69.17q0-11.62-4.75-17t-15-5.36a48.51,48.51,0,0,0-24.81,6.86c-.36.24-1.27.85-2.73,1.85A7.1,7.1,0,0,1,601.91,57,3.67,3.67,0,0,1,599,55.7a4.74,4.74,0,0,1-1.14-3.25q0-3.87,6.15-7.57a55.38,55.38,0,0,1,13.73-5.46,60.28,60.28,0,0,1,15-1.93Q648.2,37.49,655.86,45.58Zm-10.21,63.54q7.3-7.74,7.3-19.71V83.6h-3.34q-16.89,0-25.87,1.41t-12.68,4.84q-3.69,3.44-3.69,9.94A15.4,15.4,0,0,0,613,112a20.59,20.59,0,0,0,13.91,4.84Q638.34,116.86,645.65,109.12Z"/> + <path class="cls-1" d="M736,38.72a4.11,4.11,0,0,1,1.41,3.52c0,2.93-1.76,4.58-5.28,4.93l-5.28.53q-12.5,1.23-18.57,9a28.54,28.54,0,0,0-6.07,18.13v45.58a5.48,5.48,0,0,1-1.41,4.05,5.23,5.23,0,0,1-3.87,1.41,5.55,5.55,0,0,1-4-1.41,5.29,5.29,0,0,1-1.5-4.05V43.3a5.29,5.29,0,0,1,1.5-4,5.55,5.55,0,0,1,4-1.41,5,5,0,0,1,3.7,1.41,5.26,5.26,0,0,1,1.4,3.87V54.56Q709.27,39.42,728.81,38l2.46-.18C733.5,37.72,735.08,38,736,38.72Z"/> + <path class="cls-1" d="M820.59,1.5a5.32,5.32,0,0,1,1.5,4V120.21a5.14,5.14,0,0,1-5.46,5.45,5.08,5.08,0,0,1-3.87-1.49,5.55,5.55,0,0,1-1.41-4V108.59a28.19,28.19,0,0,1-11.44,13.11A34.49,34.49,0,0,1,782,126.19a36,36,0,0,1-19.89-5.54A36.62,36.62,0,0,1,748.69,105q-4.74-10.11-4.75-23.49,0-13.2,4.75-23.15A35.39,35.39,0,0,1,782,37.49,34.49,34.49,0,0,1,799.91,42a28.19,28.19,0,0,1,11.44,13.11V5.46a5.51,5.51,0,0,1,1.41-4A5.05,5.05,0,0,1,816.63,0,5.35,5.35,0,0,1,820.59,1.5ZM804.05,107.62q7.29-9.06,7.3-25.78T804.13,56q-7.21-9.15-20.59-9.15-13.54,0-20.94,9.06t-7.39,25.61q0,16.73,7.39,26t20.77,9.24Q796.73,116.69,804.05,107.62Z"/> + </g> + </symbol> + </defs> + <title>rDashboard-White-TM-T3</title> + <use id="TM-3" data-name="TM" width="46.03" height="24.05" transform="translate(1345.14 73.61)" xlink:href="#TM"/> + <use id="Dashboard_TEXT" data-name="Dashboard TEXT" width="822.09" height="126.19" transform="translate(514.02 89.17)" xlink:href="#Nuevo_símbolo"/> + <path id="RLayer" class="cls-2" d="M664.53,480.3c-1.79-11.1-9.16-47.71-42.06-77.06a144,144,0,0,0-39.93-25.5C567,371.55,545.3,369,540,369c-88.56,0-173.41-.11-262-.17L381.87,480h-154l267,123H585c7.28-.46,27.63,0,45-18,9.86-10.21,12.63-15.37,19.17-25.65h0A119.92,119.92,0,0,0,664.53,480.3Z" transform="translate(-222 -368.83)"/> + <polygon id="T1" class="cls-3" points="160 111.17 273 234.17 0 111.17 160 111.17"/> + <path class="cls-2" d="M227.92,480" transform="translate(-222 -368.83)"/> +</svg> diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 00000000..e00195f0 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,16 @@ +<svg id="Capa_2" data-name="Capa 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 443.92 234.17"> + <defs> + <style> + .cls-1 { + fill: #00fea1; + } + + .cls-2 { + fill: #00a079; + } + </style> + </defs> + <title>RDSeries-T3</title> + <path id="RLayer" class="cls-1" d="M664.53,480.3c-1.79-11.1-9.16-47.71-42.06-77.06a144,144,0,0,0-39.93-25.5C567,371.55,545.3,369,540,369c-88.56,0-173.41-.11-262-.17L381.87,480h-154l.31.44c6,2.26,11.16,5.59,16.79,8.5a180.69,180.69,0,0,0,17.5,7.61c12.18,4.74,24.6,8.82,37.06,12.71,12.1,3.77,23.86,7.24,34.95,13.52.86.49,1.73.94,2.61,1.41,3.95.9,7.77,2.71,11.51,4.13,5.34,2,10.55,4.33,15.78,6.59a273.69,273.69,0,0,1,30.79,15.39,302.11,302.11,0,0,0,31.68,16.38c5.45,2.42,10.91,4.91,16.14,7.77l.22.12a5.2,5.2,0,0,1,6.31,1.78c1.79,2.5,7.26,4.21,9.86,5.84,3.74,2.36,7.78,4.18,11.47,6.62a99.34,99.34,0,0,0,11.11,6,16.43,16.43,0,0,1,4.28,2.86,19.8,19.8,0,0,1,1.64,1.77,20.81,20.81,0,0,1,5.7,3l1.24.56H585c7.28-.46,27.63,0,45-18,9.86-10.21,12.63-15.37,19.17-25.65h0A119.92,119.92,0,0,0,664.53,480.3Z" transform="translate(-222 -368.83)"/> + <polygon id="T1" class="cls-2" points="160 111.17 273 234.17 0 111.17 160 111.17"/> +</svg> diff --git a/service-worker.js b/service-worker.js new file mode 100644 index 00000000..2283ff9c --- /dev/null +++ b/service-worker.js @@ -0,0 +1,135 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read http://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit http://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } +} diff --git a/setupTests.js b/setupTests.js new file mode 100644 index 00000000..330f214a --- /dev/null +++ b/setupTests.js @@ -0,0 +1,6 @@ +const Enzyme = require('enzyme'); +// this is where we reference the adapter package we installed +// earlier +const EnzymeAdapter = require('enzyme-adapter-react-16'); +// This sets up the adapter to be used by Enzyme +Enzyme.configure({ adapter: new EnzymeAdapter() }); \ No newline at end of file diff --git a/src/components/CoreLoader/index.js b/src/components/CoreLoader/index.js new file mode 100644 index 00000000..e335b7cb --- /dev/null +++ b/src/components/CoreLoader/index.js @@ -0,0 +1,31 @@ +import React from 'react' +import style from './styles.less' +class CoreLoader extends React.PureComponent { + render(){ + const { type } = this.props; + if ( type == 'circle') { + return ( + <div> + <div className={style.loader}> + <svg viewBox="0 0 80 80"> + <circle id="test" cx="40" cy="40" r="32"></circle> + </svg> + </div> + </div> + ); + } + if ( type == 'box') { + return( + <div> + <div className={style.loader}> + <svg viewBox="0 0 80 80"> + <rect x="8" y="8" width="64" height="64"></rect> + </svg> + </div> + </div> + ) + } + return null; + } +} +export default CoreLoader; \ No newline at end of file diff --git a/src/components/CoreLoader/styles.less b/src/components/CoreLoader/styles.less new file mode 100644 index 00000000..0257ce86 --- /dev/null +++ b/src/components/CoreLoader/styles.less @@ -0,0 +1,137 @@ +.loader { + --path: #2F3545; + // OLDDOT => --dot: #5628EE; + --dot: rgb(0, 254, 161); + --duration: 3s; + width: 44px; + height: 44px; + position: relative; + &:before { + content: ''; + width: 6px; + height: 6px; + border-radius: 50%; + position: absolute; + display: block; + background: var(--dot); + top: 37px; + left: 19px; + transform: translate(-18px, -18px); + animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + } + svg { + display: block; + width: 100%; + height: 100%; + rect, + polygon, + circle { + fill: none; + stroke: var(--path); + stroke-width: 10px; + stroke-linejoin: round; + stroke-linecap: round; + } + polygon { + stroke-dasharray: 145 (221 - 145) 145 (221 - 145); + stroke-dashoffset: 0; + animation: pathTriangle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + } + rect { + stroke-dasharray: (256 / 4 * 3) (256 / 4) (256 / 4 * 3) (256 / 4); + stroke-dashoffset: 0; + animation: pathRect 3s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + } + circle { + stroke-dasharray: (200 / 4 * 3) (200 / 4) (200 / 4 * 3) (200 / 4); + stroke-dashoffset: 75; + animation: pathCircle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite; + } + } +} + +@keyframes pathTriangle { + 33% { + stroke-dashoffset: 74; + } + 66% { + stroke-dashoffset: 147; + } + 100% { + stroke-dashoffset: 221; + } +} + +@keyframes dotTriangle { + 33% { + transform: translate(0, 0); + } + 66% { + transform: translate(10px, -18px); + } + 100% { + transform: translate(-10px, -18px); + } +} + +@keyframes pathRect { + 25% { + stroke-dashoffset: 64; + } + 50% { + stroke-dashoffset: 128; + } + 75% { + stroke-dashoffset: 192; + } + 100% { + stroke-dashoffset: 256; + } +} + +@keyframes dotRect { + 25% { + transform: translate(0, 0); + } + 50% { + transform: translate(18px, -18px); + } + 75% { + transform: translate(0, -36px); + } + 100% { + transform: translate(-18px, -18px); + } +} + +@keyframes pathCircle { + 25% { + stroke-dashoffset: 125; + } + 50% { + stroke-dashoffset: 175; + } + 75% { + stroke-dashoffset: 225; + } + 100% { + stroke-dashoffset: 275; + } +} + +.loader { + display: inline-block; + margin: 0 16px; +} + +html { + -webkit-font-smoothing: antialiased; +} + +* { + box-sizing: border-box; + &:before, + &:after { + box-sizing: border-box; + } +} diff --git a/src/components/DropOption/DropOption.js b/src/components/DropOption/DropOption.js new file mode 100644 index 00000000..99e7d12c --- /dev/null +++ b/src/components/DropOption/DropOption.js @@ -0,0 +1,34 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Dropdown, Button, Icon, Menu } from 'antd' + +const DropOption = ({ + onMenuClick, + menuOptions = [], + buttonStyle, + dropdownProps, +}) => { + const menu = menuOptions.map(item => ( + <Menu.Item key={item.key}>{item.name}</Menu.Item> + )) + return ( + <Dropdown overlay= { + <Menu onClick={onMenuClick}>{menu}</Menu> + } {...dropdownProps}> + + <Button style={{ border: 'none', ...buttonStyle }}> + <Icon style={{ marginRight: 2 }} type="bars" /> + <Icon type="down" /> + </Button> + </Dropdown> + ) +} + +DropOption.propTypes = { + onMenuClick: PropTypes.func, + menuOptions: PropTypes.array.isRequired, + buttonStyle: PropTypes.object, + dropdownProps: PropTypes.object, +} + +export default DropOption diff --git a/src/components/DropOption/package.json b/src/components/DropOption/package.json new file mode 100644 index 00000000..0a1dc405 --- /dev/null +++ b/src/components/DropOption/package.json @@ -0,0 +1,6 @@ +{ + "name": "DropOption", + "version": "0.0.0", + "private": true, + "main": "./DropOption.js" +} diff --git a/src/components/Editor/Editor.js b/src/components/Editor/Editor.js new file mode 100644 index 00000000..3d002511 --- /dev/null +++ b/src/components/Editor/Editor.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { Editor } from 'react-draft-wysiwyg'; +import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'; +import styles from './Editor.less'; + +const DraftEditor = props => { + return ( + <Editor + toolbarClassName={ styles.toolbar } + wrapperClassName={ styles.wrapper } + editorClassName={ styles.editor } + {...props} + /> + ) +} + +export default DraftEditor diff --git a/src/components/Editor/Editor.less b/src/components/Editor/Editor.less new file mode 100644 index 00000000..2cea380a --- /dev/null +++ b/src/components/Editor/Editor.less @@ -0,0 +1,106 @@ +.wrapper { + height: 500px; + + :global { + .rdw-dropdownoption-default { + padding: 6px; + } + + .rdw-dropdown-optionwrapper { + box-sizing: content-box; + width: 100%; + border-radius: 0 0 2px 2px; + &:hover { + box-shadow: none; + } + } + + .rdw-inline-wrapper { + flex-wrap: wrap; + margin-bottom: 0; + + .rdw-option-wrapper { + margin-bottom: 6px; + } + } + + .rdw-option-active { + box-shadow: 1px 1px 0 #e8e8e8 inset; + } + + .rdw-colorpicker-option { + box-shadow: none; + } + + .rdw-colorpicker-modal, + .rdw-embedded-modal, + .rdw-emoji-modal, + .rdw-image-modal, + .rdw-link-modal { + box-shadow: 4px 4px 40px rgba(0, 0, 0, 0.05); + } + + .rdw-colorpicker-modal, + .rdw-embedded-modal, + .rdw-link-modal { + height: auto; + } + + .rdw-emoji-modal { + width: 214px; + } + + .rdw-colorpicker-modal { + width: auto; + } + + .rdw-embedded-modal-btn, + .rdw-image-modal-btn, + .rdw-link-modal-btn { + height: 32px; + margin-top: 12px; + } + + .rdw-embedded-modal-input, + .rdw-embedded-modal-size-input, + .rdw-link-modal-input { + padding: 2px 6px; + height: 32px; + } + + .rdw-dropdown-selectedtext { + color: #000; + } + + .rdw-dropdown-wrapper, + .rdw-option-wrapper { + min-width: 36px; + transition: all 0.2s ease; + height: 30px; + + &:active { + box-shadow: 1px 1px 0 #e8e8e8 inset; + } + + &:hover { + box-shadow: 1px 1px 0 #e8e8e8; + } + } + + .rdw-dropdown-wrapper { + min-width: 60px; + } + + .rdw-editor-main { + box-sizing: border-box; + } + } + + .editor { + border: 1px solid #f1f1f1; + padding: 5px; + border-radius: 2px; + height: auto; + min-height: 200px; + } +} diff --git a/src/components/Editor/package.json b/src/components/Editor/package.json new file mode 100644 index 00000000..80696262 --- /dev/null +++ b/src/components/Editor/package.json @@ -0,0 +1,6 @@ +{ + "name": "Editor", + "version": "0.0.0", + "private": true, + "main": "./Editor.js" +} diff --git a/src/components/FilterItem/FilterItem.js b/src/components/FilterItem/FilterItem.js new file mode 100644 index 00000000..6cb14136 --- /dev/null +++ b/src/components/FilterItem/FilterItem.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './FilterItem.less'; + +const FilterItem = ({ label = '', children }) => { + const labelArray = label.split('') + return ( + <div className={ styles.filterItem }> + { + labelArray.length > 0 ? ( + <div className={ styles.labelWrap }> + {labelArray.map((item, index) => ( + <span className="labelText" key={ index }> + { item } + </span> + ))} + </div> + ) : ('') + } + <div className={ styles.item }>{ children }</div> + </div> + ) +} + +FilterItem.propTypes = { + label: PropTypes.string, + children: PropTypes.element.isRequired, +} + +export default FilterItem diff --git a/src/components/FilterItem/FilterItem.less b/src/components/FilterItem/FilterItem.less new file mode 100644 index 00000000..c2e98ec5 --- /dev/null +++ b/src/components/FilterItem/FilterItem.less @@ -0,0 +1,17 @@ +.filterItem { + display: flex; + justify-content: space-between; + + .labelWrap { + width: 64px; + line-height: 28px; + margin-right: 12px; + justify-content: space-between; + display: flex; + overflow: hidden; + } + + .item { + flex: 1; + } +} diff --git a/src/components/FilterItem/package.json b/src/components/FilterItem/package.json new file mode 100644 index 00000000..04c7d8a3 --- /dev/null +++ b/src/components/FilterItem/package.json @@ -0,0 +1,6 @@ +{ + "name": "FilterItem", + "version": "0.0.0", + "private": true, + "main": "./FilterItem.js" +} diff --git a/src/components/Layout/Control.js b/src/components/Layout/Control.js new file mode 100644 index 00000000..ea4e9887 --- /dev/null +++ b/src/components/Layout/Control.js @@ -0,0 +1,65 @@ +import React from 'react' +import * as antd from 'antd' +import * as ycore from 'ycore' +import styles from './Control.less' + +import Radium, {StyleRoot}from 'radium'; +import { fadeInUp, bounceOutDown } from 'react-animations' +const animationStyles = { + fadeInUp: { + animation: 'x 0.5s', + animationName: Radium.keyframes(fadeInUp, 'fadeInUp') + }, + bounceOutDown: { + animation: 'x 1s', + animationName: Radium.keyframes(bounceOutDown, 'bounceOutDown') + } +} + +export function SetControls(e){ + window.ControlComponent.DummySetControls(e); + return +} +export function CloseControls(){ + window.ControlComponent.DummyCloseControls(); + return +} + +class Control extends React.Component { + constructor(props){ + super(props) + window.ControlComponent = this; + this.state = { + Show: false, + FadeIN: true, + } + } + DummySetControls = (e) =>{ + ycore.DevOptions.ShowFunctionsLogs? console.log('Controls recived => ', e) : null + if (this.state.Show == false) { + this.setState({ FadeIN: true }) + } + this.setState({Show: true, RenderFragment: e}) + } + DummyCloseControls(){ + ycore.DevOptions.ShowFunctionsLogs? console.log('Closing Control Bar...') : null + this.setState({FadeIN: false}) + setTimeout(() => this.setState({ Show: false, RenderFragment: null}), 1000) + } + + render(){ + const {RenderFragment, Show, FadeIN} = this.state + return( + Show? ( + <StyleRoot> + <div style={FadeIN? animationStyles.fadeInUp : animationStyles.bounceOutDown }> + <antd.Card bordered={false} className={styles.ControlCard}> + <React.Fragment>{RenderFragment} </React.Fragment> + </antd.Card> + </div> + </StyleRoot> + ) : null + ) + } +} +export default Control; diff --git a/src/components/Layout/Control.less b/src/components/Layout/Control.less new file mode 100644 index 00000000..261448f2 --- /dev/null +++ b/src/components/Layout/Control.less @@ -0,0 +1,21 @@ +.ControlCard{ + background-color: rgba(0, 0, 0, 0.1); + width: auto; + max-width: 60%; + padding: 0 5px 0 5px; + margin: 0 0 0 50%; + height: auto; + position: absolute; + z-index: 10000; + bottom: 0; + text-align: center; + :global { + .ant-card-body { + padding: 5px; + } + .ant-btn { + background-color: rgba(0, 0, 0, 0.1); + margin: 3px; + } + } +} \ No newline at end of file diff --git a/src/components/Layout/Header.js b/src/components/Layout/Header.js new file mode 100644 index 00000000..d63de26b --- /dev/null +++ b/src/components/Layout/Header.js @@ -0,0 +1,144 @@ +import React, { PureComponent, Fragment } from 'react' +import { Menu, Icon, Layout, Avatar, Popover, Badge, List, Switch, Tooltip } from 'antd' +import { Trans, withI18n } from '@lingui/react' +import { Ellipsis } from 'ant-design-pro' +import classnames from 'classnames' +import PropTypes from 'prop-types' +import styles from './Header.less' +import * as ycore from 'ycore' +import router from 'umi/router' +import moment from 'moment' +import Bread from './Bread' + + +let userData = ycore.SDCP() + + + + +@withI18n() +class Header extends PureComponent { + + isDarkMode = () => { + const {theme} = this.props + if (theme == "light") { + return false; + } + return true; + } + render() { + const { + i18n, + fixed, + theme, + collapsed, + newRouteList, + notifications, + onCollapseChange, + onAllNotificationsRead, + } = this.props + + + + + const menuContent = ( + <Popover + placement="bottomRight" + trigger="click" + key="notifications" + overlayClassName={styles.notificationPopover} + getPopupContainer={() => document.querySelector('#layoutHeader')} + content={ + <div className={styles.notification}> + <List + itemLayout="horizontal" + dataSource={notifications} + locale={{ + emptyText: <Trans>You have viewed all notifications.</Trans>, + }} + renderItem={item => ( + <List.Item className={styles.notificationItem}> + <List.Item.Meta + title={ + <Ellipsis tooltip lines={1}> + {' '} + {item.title}{' '} + </Ellipsis> + } + description={moment(item.date).fromNow()} + /> + <Icon + style={{ fontSize: 10, color: '#ccc' }} + type="right" + theme="outlined" + /> + </List.Item> + )} + /> + {notifications.length ? ( + <div + onClick={onAllNotificationsRead} + className={styles.clearButton} + > + <Trans>Clear notifications</Trans> + </div> + ) : null} + </div> + } + > + <Badge + count={notifications.length} + dot + offset={[-10, 10]} + className={styles.iconButton} + > + <Icon className={styles.iconFont} type="bell" /> + </Badge> + </Popover> + ) + + return ( + <Layout.Header + style={{ padding: 0 }} + className={classnames(styles.header, { + [styles.fixed]: fixed, + [styles.collapsed]: collapsed, + })} + id={this.isDarkMode()? styles.header_dark : styles.header_light} + > + <div className={styles.button} onClick={onCollapseChange.bind(this, !collapsed)} > + <Icon + style={{ fontSize: '23px' }} + type={classnames({ + 'pic-right': collapsed, + 'pic-center': !collapsed, + })} + /> + </div> + <div className={styles.bread}><Bread theme={theme} routeList={newRouteList} /></div> + <div className={styles.rightContainer}> + <Tooltip title={'Search'}><a target="_blank" href="" rel="noopener noreferrer"><Icon type="search" className={styles.iconButton} style={{ fontSize: '18px' }} /></a></Tooltip> + <Tooltip title={'Help'}><a target="_blank" href="" rel="noopener noreferrer"><Icon type="question-circle-o" className={styles.iconButton} style={{ fontSize: '18px' }} /></a></Tooltip> + {menuContent} + + </div> + + </Layout.Header> + ) + } +} + +Header.propTypes = { + fixed: PropTypes.bool, + menus: PropTypes.array, + theme: PropTypes.string, + newRouteList: PropTypes.array, + collapsed: PropTypes.bool, + onSignOut: PropTypes.func, + notifications: PropTypes.array, + onThemeChange: PropTypes.func, + onCollapseChange: PropTypes.func, + onAllNotificationsRead: PropTypes.func, +} + +export default Header diff --git a/src/components/Layout/Header.less b/src/components/Layout/Header.less new file mode 100644 index 00000000..c0c68236 --- /dev/null +++ b/src/components/Layout/Header.less @@ -0,0 +1,195 @@ +@import '~themes/vars.less'; + +.bread { + float: left; +} + +.darkmode_btn { + margin-bottom: 8px; + height: 40px; + line-height: 40px; + margin-top: 4px; + padding: 0 16px; + overflow: hidden; + font-size: 13px; + text-overflow: ellipsis; +} + +#header_dark{ + background-color: @DarkMode-backgroud_container; + color: @DarkMode-color; + transition: background-color 200ms linear; + +} +#header_light{ + background-color: @LightMode-backgroud; + color: @LightMode-color; + transition: background-color 200ms linear; + +} + +.header { + padding: 0; + position: relative; + display: flex; + justify-content: space-between; + height: 64px; + z-index: 9; + align-items: center; + + &.fixed { + position: fixed; + top: 0; + width: ~'calc(100% - 370px)'; + z-index: 10; + transition: width 0.2s; + + &.collapsed { + width: ~'calc(100% - 115px)'; + } + } + + :global { + .ant-menu-submenu-title { + height: 40px; + } + + + .ant-menu-horizontal { + line-height: 40px; + + &>.ant-menu-submenu:hover { + color: @primary-color; + background-color: @hover-color; + } + } + + .ant-menu { + border-bottom: none; + height: 40px; + } + + .ant-menu-horizontal>.ant-menu-submenu { + top: 0; + margin-top: 0; + } + + .ant-menu-horizontal>.ant-menu-item, + .ant-menu-horizontal>.ant-menu-submenu { + border-bottom: none; + } + + .ant-menu-horizontal>.ant-menu-item-active, + .ant-menu-horizontal>.ant-menu-item-open, + .ant-menu-horizontal>.ant-menu-item-selected, + .ant-menu-horizontal>.ant-menu-item:hover, + .ant-menu-horizontal>.ant-menu-submenu-active, + .ant-menu-horizontal>.ant-menu-submenu-open, + .ant-menu-horizontal>.ant-menu-submenu-selected, + .ant-menu-horizontal>.ant-menu-submenu:hover { + border-bottom: none; + } + } + + .rightContainer { + display: flex; + align-items: center; + } + + .button { + width: 40px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 18px; + cursor: pointer; + transition: @transition-ease-in; + + &:hover { + color: @primary-color; + background-color: @hover-color; + } + } +} + + + +.iconButton { + color: #b2b0c7; + width: 48px; + height: 48px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 24px; + cursor: pointer; + .background-hover(); + + &:hover { + .iconFont { + color: @primary-color; + } + } + + &+.iconButton { + margin-left: 8px; + } + + .iconFont { + color: #b2b0c7; + font-size: 24px; + } +} +.search { + padding: 0 12px; + &:hover { + background: transparent; + } +} +.avatar { + margin:~'calc((64px - 24px) / 4.4)'0; + margin-right: 8px; + color: @primary-color; + vertical-align: top; + background: rgba(255, 255, 255, 0.85); +} + +.notification { + padding: 24px 0; + + .notificationItem { + transition: all 0.3s; + padding: 12px 24px; + cursor: pointer; + + &:hover { + background-color: @hover-color; + } + } + + .clearButton { + text-align: center; + height: 48px; + line-height: 48px; + cursor: pointer; + .background-hover(); + } +} + +.notificationPopover { + :global { + .ant-popover-inner-content { + padding: 0; + } + + .ant-popover-arrow { + display: none; + } + + .ant-list-item-content { + flex: 0; + margin-left: 16px; + } + } +} + diff --git a/src/components/Layout/L_Sider.js b/src/components/Layout/L_Sider.js new file mode 100644 index 00000000..ac6c7dae --- /dev/null +++ b/src/components/Layout/L_Sider.js @@ -0,0 +1,95 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import { Icon, Switch, Layout, Tag, Divider} from 'antd' +import { withI18n, Trans } from '@lingui/react' +import ScrollBar from '../ScrollBar' +import { config } from 'utils' +import styles from './L_Sider.less' +import { ycore_worker, DevOptions } from 'ycore'; +import SiderMenu from './Menu.js' +import { CustomMenu } from './local_components' + +@withI18n() +class L_Sider extends PureComponent { + + StrictMode = () =>{ + const { theme } = this.props; + if (DevOptions.StrictLightMode == false) { + return "dark" + } + if (DevOptions.StrictLightMode == true && theme == "light") { + return "light" + } + if (DevOptions.StrictLightMode == true && theme == "dark") { + return "dark" + } + } + + render() { + const { + i18n, + menus, + theme, + isMobile, + collapsed, + onThemeChange, + onCollapseChange, + } = this.props + + return ( + <div className={styles.siderhandler}> + <Layout.Sider + width={215} + style={{ height: '100%' }} + theme={this.StrictMode()} + // style={{ backgroundColor: '#2d2d2d' }} + breakpoint="lg" + trigger={null} + collapsible + collapsed={collapsed} + onBreakpoint={isMobile ? null : onCollapseChange} + className={styles.sider} + > + <div className={styles.brand}> + {collapsed? <div className={styles.logo}><img className={styles.logocollapsed} src={config.logoPath} /></div> : <div className={styles.logo}><img className={styles.logonotcollapsed} src={config.logoPath} /></div> } + </div> + + <div className={styles.menuContainer}> + <ScrollBar + options={{ + // Disabled horizontal scrolling, https://github.com/utatti/perfect-scrollbar#options + suppressScrollX: true, + }} + > + <SiderMenu + menus={menus} + theme={this.StrictMode()} + isMobile={isMobile} + collapsed={collapsed} + onCollapseChange={onCollapseChange} + /> + <CustomMenu + menus={menus} + theme={this.StrictMode()} + isMobile={isMobile} + collapsed={collapsed} + onCollapseChange={onCollapseChange} + /> + </ScrollBar> + </div> + </Layout.Sider> + </div> + ) + } +} + +L_Sider.propTypes = { + menus: PropTypes.array, + theme: PropTypes.string, + isMobile: PropTypes.bool, + collapsed: PropTypes.bool, + onThemeChange: PropTypes.func, + onCollapseChange: PropTypes.func, +} + +export default L_Sider diff --git a/src/components/Layout/L_Sider.less b/src/components/Layout/L_Sider.less new file mode 100644 index 00000000..a9c429e9 --- /dev/null +++ b/src/components/Layout/L_Sider.less @@ -0,0 +1,138 @@ +@import '~themes/vars.less'; +@import (inline) './fonty.css'; + +.siderhandler { + overflow-x: hidden; + height: 100vh; + bottom: 0; + :global { + letter-spacing: 0.6px; + font-weight: 500; + font-size: 1.4447884416924666vh; + .ant-layout-sider-dark { + background-color: @DarkMode-backgroud; + color: @DarkMode-color; + -webkit-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + } + .ant-layout-sider-light { + background-color: @LightMode-backgroud; + color: @LightMode-color; + -webkit-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.05); + } + .ant-menu-dark { + background-color: @DarkMode-backgroud; + color: @DarkMode-color; + -webkit-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + -moz-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + :global{ + color: @DarkMode-color; + } + } + .ant-menu-light { + background-color: @LightMode-backgroud; + color: @LightMode-color; + -webkit-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + -moz-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + } + .ant-menu-dark .ant-menu-inline .ant-menu-sub { + -webkit-box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + -moz-box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + background-color: @DarkMode-backgroud; + } + .ant-menu-light .ant-menu-inline .ant-menu-sub { + -webkit-box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + -moz-box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + box-shadow: 0px 27px 29px -18px rgba(23, 23, 23, 0); + background-color: @LightMode-backgroud; + } + .ant-menu-dark .ant-menu-item::after { + border-right: 3px solid #00FEA1; + } + .ant-menu-light .ant-menu-item::after { + border-right: 3px solid #00FEA1; + } + .ant-menu-dark .ant-menu-item-selected { + background: rgb(80, 78, 82); + } + .ant-menu-light .ant-menu-item-selected { + background: rgb(219, 219, 219); + } + .ant-layout-sider-children { + display: flex; + flex-direction: column; + justify-content: space-between; + } + + } +} + +.sider { + .brand { + z-index: 1; + height: 70px; + display: flex; + align-items: center; + justify-content: center; + padding: 0 23px; + .logo { + display: flex; + align-items: center; + justify-content: center; + .logocollapsed{ + width: 68px; + transition: width 0.1s; + } + .logonotcollapsed { + width: 90px; + transition: width 0.1s; + } + } + } + .menuContainer { + height: ~'calc(100vh - 120px)'; + overflow-x: hidden; + flex: 1; + &::-webkit-scrollbar-thumb { + background-color: transparent; + } + &:hover { + &::-webkit-scrollbar-thumb { + background-color: rgba(59, 59, 59, 0.2); + } + } + :global { + .ant-menu-inline .ant-menu-item { + font-size: 14px; + } + .ant-menu-dark .ant-menu-item a { + color: @DarkMode-color; + } + .ant-menu-light .ant-menu-item a { + color: @LightMode-color; + } + .ant-menu-item a:hover { + color: #00FEA1; + } + } + } +} + + +@keyframes fadeLeftIn { + 0% { + transform: translateX(5px); + opacity: 0; + } + + 100% { + transform: translateX(0); + opacity: 1; + } +} \ No newline at end of file diff --git a/src/components/Layout/Menu.js b/src/components/Layout/Menu.js new file mode 100644 index 00000000..975217da --- /dev/null +++ b/src/components/Layout/Menu.js @@ -0,0 +1,132 @@ +import React, { PureComponent, Fragment } from 'react' +import PropTypes from 'prop-types' +import { Menu, Icon } from 'antd' +import Navlink from 'umi/navlink' +import withRouter from 'umi/withRouter' +import {SDCP} from 'ycore' +import { + arrayToTree, + queryAncestors, + pathMatchRegexp, + addLangPrefix, +} from 'utils' +import store from 'store' +import styles from './Menu.less' + + +const { SubMenu } = Menu + + +@withRouter +class SiderMenu extends PureComponent { + state = { + openKeys: store.get('openKeys') || [], + } + + onOpenChange = openKeys => { + const { menus } = this.props + const rootSubmenuKeys = menus.filter(_ => !_.menuParentId).map(_ => _.id) + + const latestOpenKey = openKeys.find( + key => this.state.openKeys.indexOf(key) === -1 + ) + + let newOpenKeys = openKeys + if (rootSubmenuKeys.indexOf(latestOpenKey) !== -1) { + newOpenKeys = latestOpenKey ? [latestOpenKey] : [] + } + + this.setState({ + openKeys: newOpenKeys, + }) + store.set('openKeys', newOpenKeys) + } + + generateMenus = data => { + return data.map(item => { + if (item.children) { + return ( + <SubMenu + key={item.id} + className={styles.SubMenuItems} + title={ + <Fragment> + {item.icon && <Icon type={item.icon} />} + <span className={styles.SubItemTitle}>{item.name}</span> + </Fragment> + } + > + {this.generateMenus(item.children)} + </SubMenu> + ) + } + return ( + <Menu.Item key={item.id} > + <Navlink to={addLangPrefix(item.route) || '#'}> + {item.icon && <Icon type={item.icon} />} + <span>{item.name}</span> + </Navlink> + </Menu.Item> + ) + }) + } + + render() { + const { + collapsed, + theme, + menus, + location, + isMobile, + onCollapseChange, + } = this.props + + // Generating tree-structured data for menu content. + const menuTree = arrayToTree(menus, 'id', 'menuParentId') + + // Find a menu that matches the pathname. + const currentMenu = menus.find( + _ => _.route && pathMatchRegexp(_.route, location.pathname) + ) + + // Find the key that should be selected according to the current menu. + const selectedKeys = currentMenu + ? queryAncestors(menus, currentMenu, 'menuParentId').map(_ => _.id) + : [] + + const menuProps = collapsed + ? {} + : { + openKeys: this.state.openKeys, + } + + return ( + <Menu + theme={theme} + mode="inline" + onOpenChange={this.onOpenChange} + selectedKeys={selectedKeys} + onClick={ + isMobile + ? () => { + onCollapseChange(true) + } + : undefined + } + {...menuProps} + > + {this.generateMenus(menuTree)} + </Menu> + ) + } +} + +SiderMenu.propTypes = { + menus: PropTypes.array, + theme: PropTypes.string, + isMobile: PropTypes.bool, + collapsed: PropTypes.bool, + onCollapseChange: PropTypes.func, +} + +export default SiderMenu diff --git a/src/components/Layout/Menu.less b/src/components/Layout/Menu.less new file mode 100644 index 00000000..6ac1c673 --- /dev/null +++ b/src/components/Layout/Menu.less @@ -0,0 +1,5 @@ +@import '~themes/vars.less'; + +.SubItemTitle { + font-size: 14px; +} \ No newline at end of file diff --git a/src/components/Layout/R_Sider.js b/src/components/Layout/R_Sider.js new file mode 100644 index 00000000..0e59f1a2 --- /dev/null +++ b/src/components/Layout/R_Sider.js @@ -0,0 +1,125 @@ +import React, { PureComponent, StrictMode } from 'react' +import PropTypes from 'prop-types' +import { Icon, Switch, Layout, Tag, Divider, Drawer, Avatar, Menu} from 'antd' +import { withI18n, Trans } from '@lingui/react' +import classNames from 'classnames' +import router from 'umi/router' +import { SDCP, LogoutCall, DevOptions} from 'ycore' + +import styles from './R_Sider.less' + +let userData = SDCP() + +@withI18n() +class R_Sider extends PureComponent { + constructor(props) { + super(props); + this.state = { + isHover: false + }; + this.hover = this.hover.bind(this); + } + hover(e) { + this.setState({ + isHover: !this.state.isHover + }); + } + handleClickMenu = e => { + e.key === 'SignOut' && LogoutCall() + e.key === 'settingpage' && router.push('/settings') + e.key === 'accountpage' && router.push('/account') + } + Balancer() { + const { collapsed, } = this.props; + const { isHover } = this.state; + if (collapsed == false) { + return false + } + if (isHover == false ){ + if (collapsed == true) { + return true + } + return true + }else{ + return false + } + + } + StrictMode = () =>{ + const { theme } = this.props; + if (DevOptions.StrictLightMode == false) { + return "dark" + } + if (DevOptions.StrictLightMode == true && theme == "light") { + return "light" + } + if (DevOptions.StrictLightMode == true && theme == "dark") { + return "dark" + } + } + render() { + const { theme, onThemeChange} = this.props; + + return ( + <div className={styles.siderwrapper}> + <Layout.Sider + collapsedWidth="30" + theme={this.StrictMode()} + width="140" + collapsed={this.Balancer()} + className={styles.sider} + style={this.Balancer()? {backgroundColor: 'rgba(0, 0, 0, 0.1)'} : null} + onMouseEnter={this.hover} + onMouseLeave={this.hover} + > + + <div className={styles.siderhead}> + <Avatar size={this.Balancer()? "small" : "large"} shape={this.Balancer()? "circle" : "square"} src={userData.avatar} className={styles.avatar} /> + {this.Balancer()? null : <span>{userData.username}</span>} + </div> + {this.Balancer()? <div style={{ height: "100%", textAlign: "center" }} ><Icon onClick={this.hover} type="left" style={{ color: "#2F2E30", position: "absolute", bottom: "50%" }} /></div> : + <div className={styles.sidercontainer}> + <Menu className={styles.menuItems} mode="vertical" onClick={this.handleClickMenu}> + <Menu.Item key="accountpage"> + <Icon type="idcard" /> + <Trans>Account</Trans> + </Menu.Item> + <Menu.Item key="settingpage"> + <Icon type="setting" /> + <Trans>Settings</Trans> + </Menu.Item> + <Menu.Item key="LightMode" disabled={false}> + <Icon type="bg-colors" /> + <Switch + onChange={onThemeChange.bind( + this, + theme === 'light' ? 'dark' : 'light' + )} + checkedChildren="Dark" + unCheckedChildren="Light" + defaultChecked={theme === 'dark'} + /> + </Menu.Item> + <Menu.Item key="SignOut" className={styles.SignOut} > + <Icon type="logout" style={{ color: 'red' }} /> + <Trans>Logout</Trans> + </Menu.Item> + </Menu> + </div> + } + </Layout.Sider> + </div> + ) + } +} + +R_Sider.propTypes = { + menus: PropTypes.array, + theme: PropTypes.string, + isMobile: PropTypes.bool, + collapsed: PropTypes.bool, + onThemeChange: PropTypes.func, + onCollapseChange: PropTypes.func, +} + +export default R_Sider diff --git a/src/components/Layout/R_Sider.less b/src/components/Layout/R_Sider.less new file mode 100644 index 00000000..3977545f --- /dev/null +++ b/src/components/Layout/R_Sider.less @@ -0,0 +1,131 @@ +@import '~themes/vars.less'; +@import (inline) './fonty.css'; + +@LDarkMode-backgroud: rgba(47, 46, 48, 0.74); +@LLightMode-backgroud: #fff; + +@LDarkMode-color: #fff; +@LLightMode-color: #2F2E30; + +.siderwrapper { + height: 100%; + right: 0; + position: absolute; + :global { + .ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left { + :hover { + color: #00FEA1; + } + border-right: 1px solid transparent; + } + .ant-layout-sider-dark { + background-color: @LDarkMode-backgroud; + color: @DarkMode-color; + } + .ant-layout-sider-light { + background-color: @LightMode-backgroud; + color: @LightMode-color; + } + } +} +.sider { + height: 100%; + z-index: 50; + :global { + .ant-menu-sub { + font-size: 14px; + -webkit-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + -moz-box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + box-shadow: 13px 4px 34px 0px rgba(0, 0, 0, 0.005); + } + .ant-menu-dark { + background-color: @LDarkMode-backgroud; + color: @LDarkMode-color; + } + .ant-menu-light { + background-color: @LLightMode-backgroud; + color: @LLightMode-color; + } + } + .siderhead{ + font-family: 'Source Sans Pro', sans-serif; + display: flex; + align-items: center; + justify-content: center; + ::first-letter{ + margin-left: 7px; + } + height: 60px; + font-size: 17px; + } + .sidercontainer{ + width: 100%; + display: flex; + align-items: center; + justify-content: center; + } + .menuItems{ + background-color: transparent; + color: @LDarkMode-color; + margin-bottom: 8px; + width: 100%; + text-align: center; + animation: fadein 0.5s; + :global { + .ant-menu-item-selected{ + background-color: rgba(82, 82, 82, 0.562); + } + } + + } + .SignOut{ + margin-bottom: 7px; + bottom: 0; + position: absolute; + width: 100%; + } + .menuContainer { + height: ~'calc(100vh - 120px)'; + overflow-x: hidden; + flex: 1; + + &::-webkit-scrollbar-thumb { + background-color: transparent; + } + + &:hover { + &::-webkit-scrollbar-thumb { + background-color: rgba(59, 59, 59, 0.2); + } + } + + :global { + .ant-menu-inline .ant-menu-item { + font-size: 14px; + font-family: 'Source Sans Pro', sans-serif; + } + + .ant-menu-dark .ant-menu-item a { + color: rgb(197, 197, 197); + } + + .ant-menu-item a:hover { + color: #00FEA1; + } + + } + + } +} + +@keyframes fadeLeftIn { + 0% { + transform: translateX(5px); + opacity: 0; + } + + 100% { + transform: translateX(0); + opacity: 1; + } +} \ No newline at end of file diff --git a/src/components/Layout/fonty.css b/src/components/Layout/fonty.css new file mode 100644 index 00000000..4fb67951 --- /dev/null +++ b/src/components/Layout/fonty.css @@ -0,0 +1,4 @@ +@import url('https://fonts.googleapis.com/css?family=Alata&display=swap'); +@import url('https://fonts.googleapis.com/css?family=Poppins:300,300i,500,500i,700'); +@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap'); +@import url('https://fonts.googleapis.com/css?family=Kulim+Park&display=swap'); \ No newline at end of file diff --git a/src/components/Layout/index.js b/src/components/Layout/index.js new file mode 100644 index 00000000..78dfdc90 --- /dev/null +++ b/src/components/Layout/index.js @@ -0,0 +1,7 @@ +import Header from './Header' +import Bread from './Bread' +import L_Sider from './L_Sider' +import R_Sider from './R_Sider' +import Control from './Control' + +export { Header, Bread, L_Sider, R_Sider, Control } diff --git a/src/components/Layout/local_components/CustomMenu/index.js b/src/components/Layout/local_components/CustomMenu/index.js new file mode 100644 index 00000000..2d17f50a --- /dev/null +++ b/src/components/Layout/local_components/CustomMenu/index.js @@ -0,0 +1,132 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Menu, Icon, Button, Divider, Tooltip, message } from 'antd' +import Navlink from 'umi/navlink' +import withRouter from 'umi/withRouter' +import { arrayToTree, addLangPrefix} from 'utils' +import store from 'store' +import styles from './style.less' + +@withRouter +class CustomMenu extends React.Component { + constructor(props){ + super(props) + this.state = { + pins: store.get('pins') || [], + EditMode: false + } + this.HandleEditMode = this.HandleEditMode.bind(this); + } + SetDefaultPins(){ + this.setState({ pins: [{id: "1", icon: "bug", name: "Debug", route: "/debug"}, {id: "2", icon: "fire", name: "Empty Pin", route: ""}] }) + } + DeletePin = (item) => { + const items = this.state.pins.filter(pin => pin.id !== item.id); + this.setState({ pins: items }); + message.success(`Deleted ${item.name} of your pins...`) + } + HandleEditMode(){ + if (this.state.EditMode == true) { + store.set('pins', this.state.pins) + message.success('Changes have been saved successfully') + } + this.setState({ EditMode: !this.state.EditMode }) + } + + generateMenus = data => { + const { EditMode } = this.state; + return data.map(item => { + if (EditMode == true) { + return ( + <div className={styles.RemovePin} key={item.id}> + <Button className={styles.RemovePin} onClick={ () => this.DeletePin(item)} type='dashed'> + <Icon type="delete" style={{ color: 'rgb(245, 48, 48)' }} /> + <span>{item.name}</span> + </Button> + </div> + + ) + }else { + return ( + <Menu.Item key={item.id} > + <Navlink to={addLangPrefix(item.route) || '#'}> + {item.icon && <Icon type={item.icon} />} + <span>{item.name}</span> + </Navlink> + </Menu.Item> + ) + } + } + ) + } + + componentDidUpdate(){ + const { EditMode } = this.state; + const { collapsed } = this.props; + if (EditMode == true && collapsed){ + this.HandleEditMode() + } + } + isDarkMode = () => { + const { theme } = this.props + if (theme == "light") { + return false; + } + return true; + } + render() { + const { + collapsed, + theme, + isMobile, + onCollapseChange, + } = this.props + const { pins, EditMode } = this.state; + // Generating tree-structured data for menu content. + const menuTree = arrayToTree(pins, 'id', 'menuParentId') + const menuProps = collapsed + ? {} + : { + openKeys: this.state.openKeys, + } + return ( + <Menu + theme={theme} + mode="inline" + onClick={ + isMobile + ? () => { + onCollapseChange(true) + } + : undefined + } + {...menuProps} + > + <div className={styles.DividerZT}><Divider dashed className={ styles.DividerZT } style={{ margin: '15px 0 5px 0' }} /></div> + {collapsed? null : <div className={styles.EditBTN}> + <Button className={EditMode? styles.edit_pins_active : styles.edit_pins} onClick={this.HandleEditMode} id={this.isDarkMode()? styles.edit_btn_dark : styles.edit_btn_light} type="link"> + <span className={styles.circle}><Icon className={EditMode? styles.icon_active : styles.icon} type={EditMode? "save" : "pushpin"}/> </span> + <span className={styles.button_text}>{EditMode? 'Save' : 'Edit pins'}</span> + </Button> + + </div>} + + + {this.generateMenus(menuTree)} + + {EditMode? (pins.length < 1)? <div style={{ marginTop: '15px', textAlign: 'center', }} ><Button type='ghost' style={{ width: 'auto' }} onClick={() => this.SetDefaultPins()}>Set Default Pins</Button></div> : null : (pins.length < 1)? <Icon style={{ marginTop: '15px', width: '100%', fontSize: '20px', color: '#666' }} type="unordered-list" /> : null } + + </Menu> + ) + } +} + +CustomMenu.propTypes = { + menus: PropTypes.array, + theme: PropTypes.string, + isMobile: PropTypes.bool, + collapsed: PropTypes.bool, + onCollapseChange: PropTypes.func, +} + +export default CustomMenu diff --git a/src/components/Layout/local_components/CustomMenu/style.less b/src/components/Layout/local_components/CustomMenu/style.less new file mode 100644 index 00000000..fe716c1b --- /dev/null +++ b/src/components/Layout/local_components/CustomMenu/style.less @@ -0,0 +1,181 @@ +@import '~themes/vars.less'; + + +#edit_btn_dark { + background-color: @DarkMode-backgroud; + color: @DarkMode-color; +} +#edit_btn_light { + background-color: @LightMode-backgroud; + color: @LightMode-color; +} + +.SubItemTitle { + font-size: 14px; +} + +.SubMenuItems { + z-index: 98; +} + +@keyframes fadein { + from { opacity: 0; } + to { opacity: 1; } +} + +.RemovePin { + color: #6b686e; + margin-bottom: 8px; + width: 100%; + text-align: left; + font-size: 14px; + background: transparent; + border-color: transparent; + animation: fadein 0.5s; + :hover { + color: rgb(245, 48, 48); + border-left-style: solid; + } + :global { + .ant-btn:hover, + .ant-btn:focus, + .ant-btn:active, + .ant-btn.active { + border-width: 1px 1px 1px 25px; + width: 85%; + background: transparent; + transform: translate(10px, 0px); + border-color: rgb(245, 48, 48); + color: #fff; + + } + } +} + +.EditBTN { +@bg: #f3f8fa; +@white: #fff; +@black: #282936; + +.transition(@property: all, @duration: 0.45s, @ease: cubic-bezier(0.65,0,.076,1)) { + transition: @property @duration @ease; +} + +button { + position: relative; + display: inline-block; + outline: none; + border: 0; + vertical-align: middle; + background: transparent; + padding: 0; + + &.edit_pins { + width: 12rem; + height: auto; + .circle { + .transition(all, 0.45s, cubic-bezier(0.65,0,.076,1)); + position: relative; + display: block; + margin: 0; + width: 2rem; + height: 2rem; + background: transparent; + border-radius: 0rem; + .icon { + .transition(all, 0.45s, cubic-bezier(0.65, 0, .076, 1)); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: none; + padding: 0.45rem 0; + margin: 0 0 0 1.85rem; + font-weight: 500; + line-height: 1.6; + text-align: center; + } + } + + .button_text { + .transition(all, 0.45s, cubic-bezier(0.65,0,.076,1)); + position: absolute; + top: 0; + left: 0; + right: 1; + bottom: 0; + padding: 0.45rem 0; + margin: 0 0 0 1.85rem; + font-weight: 500; + line-height: 1.6; + text-align: center; + text-transform: uppercase; + } + } + + &.edit_pins_active { + width: 12rem; + height: auto; + .circle { + position: relative; + width: 100%; + height: 2rem; + + .icon_active { + position: absolute; + padding: 0.45rem 0; + font-weight: 500; + line-height: 1.9; + text-align: center; + } + } + + .button_text { + transform: translate(25px,0); + position: absolute; + top: 0; + left: 0; + right: 1; + bottom: 0; + padding: 0.45rem 0; + margin: 0 0 0 1.85rem; + + font-weight: 500; + line-height: 1.6; + text-align: center; + text-transform: uppercase; + } + } + + .circle_btn_light { + background-color: @LightMode-backgroud; + color: @LightMode-color; + } + &:hover { + .circle { + background-color: @white; + width: 100%; + .icon { + color: @black; + display: block; + transform: translate(1rem, 0); + } + } + .button_text { + transform: translate(25px,0); + color: @black; + } + } +} + +} + +.DividerZT { + z-index: 99; + transform: translate(0px, -3px); + border-width: 2px 5px 0; + border-color: rgba(236, 236, 236, 0.24); + } + + \ No newline at end of file diff --git a/src/components/Layout/local_components/HeaderSearch/index.less b/src/components/Layout/local_components/HeaderSearch/index.less new file mode 100644 index 00000000..8f40cc7f --- /dev/null +++ b/src/components/Layout/local_components/HeaderSearch/index.less @@ -0,0 +1,32 @@ +@import '~antd/es/style/themes/default.less'; + +.headerSearch { + :global(.anticon-search) { + font-size: 16px; + cursor: pointer; + } + .input { + width: 0; + background: transparent; + border-radius: 0; + transition: width 0.3s, margin-left 0.3s; + :global(.ant-select-selection) { + background: transparent; + } + input { + padding-right: 0; + padding-left: 0; + border: 0; + box-shadow: none !important; + } + &, + &:hover, + &:focus { + border-bottom: 1px solid @border-color-base; + } + &.show { + width: 210px; + margin-left: 8px; + } + } +} diff --git a/src/components/Layout/local_components/HeaderSearch/index.tsx b/src/components/Layout/local_components/HeaderSearch/index.tsx new file mode 100644 index 00000000..4c297d11 --- /dev/null +++ b/src/components/Layout/local_components/HeaderSearch/index.tsx @@ -0,0 +1,147 @@ +import { AutoComplete, Icon, Input } from 'antd'; +import { AutoCompleteProps, DataSourceItemType } from 'antd/es/auto-complete'; +import React, { Component } from 'react'; + +import classNames from 'classnames'; +import debounce from 'lodash/debounce'; +var styles = require('./index.less') + +export interface HeaderSearchProps {1 + onPressEnter: (value: string) => void; + onSearch: (value: string) => void; + onChange: (value: string) => void; + onVisibleChange: (b: boolean) => void; + className: string; + placeholder: string; + defaultActiveFirstOption: boolean; + dataSource: DataSourceItemType[]; + defaultOpen: boolean; + open?: boolean; + defaultValue?: string; +} + +interface HeaderSearchState { + value?: string; + searchMode: boolean; +} + +export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSearchState> { + static defaultProps = { + defaultActiveFirstOption: false, + onPressEnter: () => {}, + onSearch: () => {}, + onChange: () => {}, + className: '', + placeholder: '', + dataSource: [], + defaultOpen: false, + onVisibleChange: () => {}, + }; + + static getDerivedStateFromProps(props: HeaderSearchProps) { + if ('open' in props) { + return { + searchMode: props.open, + }; + } + return null; + } + + private inputRef: Input | null = null; + + constructor(props: HeaderSearchProps) { + super(props); + this.state = { + searchMode: props.defaultOpen, + value: props.defaultValue, + }; + // this.debouncePressEnter = debounce(this.debouncePressEnter, 500, { + // leading: true, + // trailing: false, + // }); + } + + // onKeyDown = (e: React.KeyboardEvent) => { + // if (e.key === 'Enter') { + // this.debouncePressEnter(); + // } + // }; + + // onChange: AutoCompleteProps['onChange'] = value => { + // if (typeof value === 'string') { + // const { onSearch, onChange } = this.props; + // this.setState({ value }); + // if (onSearch) { + // onSearch(value); + // } + // if (onChange) { + // onChange(value); + // } + // } + // }; + + // enterSearchMode = () => { + // const { onVisibleChange } = this.props; + // onVisibleChange(true); + // this.setState({ searchMode: true }, () => { + // const { searchMode } = this.state; + // if (searchMode && this.inputRef) { + // this.inputRef.focus(); + // } + // }); + // }; + + // leaveSearchMode = () => { + // this.setState({ + // searchMode: false, + // }); + // }; + + // debouncePressEnter = () => { + // const { onPressEnter } = this.props; + // const { value } = this.state; + // onPressEnter(value || ''); + // }; + + render() { + const { className, defaultValue, placeholder, open, ...restProps } = this.props; + const { searchMode, value } = this.state; + delete restProps.defaultOpen; // for rc-select not affected + const inputClass = classNames(styles.input, { + [styles.show]: searchMode, + }); + + return ( + <span + className={classNames(className, styles.headerSearch)} + // onClick={this.enterSearchMode} + onTransitionEnd={({ propertyName }) => { + if (propertyName === 'width' && !searchMode) { + const { onVisibleChange } = this.props; + onVisibleChange(searchMode); + } + }} + > + <Icon type="search" key="Icon" /> + <AutoComplete + key="AutoComplete" + {...restProps} + className={inputClass} + value={value} + // onChange={this.onChange} + > + <Input + // ref={node => { + // this.inputRef = node; + // }} + defaultValue={defaultValue} + aria-label={placeholder} + placeholder={placeholder} + // onKeyDown={this.onKeyDown} + // onBlur={this.leaveSearchMode} + /> + </AutoComplete> + </span> + ); + } +} diff --git a/src/components/Layout/local_components/index.js b/src/components/Layout/local_components/index.js new file mode 100644 index 00000000..ac8ffda7 --- /dev/null +++ b/src/components/Layout/local_components/index.js @@ -0,0 +1,4 @@ +import CustomMenu from './CustomMenu' + + +export { CustomMenu } diff --git a/src/components/Layout/logo.scss b/src/components/Layout/logo.scss new file mode 100644 index 00000000..7ade2811 --- /dev/null +++ b/src/components/Layout/logo.scss @@ -0,0 +1,13 @@ +@import url('https://fonts.googleapis.com/css?family=Nunito:400&display=swap'); + +.typo1 { + font-family: 'Nunito', sans-serif; + vertical-align: text-top; + color: #333333; + font-size: 25px; + display: inline-block; + font-weight: 400; + white-space: nowrap; + margin-left: 13px; + margin-top: 25px; +} \ No newline at end of file diff --git a/src/components/Loader/Loader.js b/src/components/Loader/Loader.js new file mode 100644 index 00000000..f769598a --- /dev/null +++ b/src/components/Loader/Loader.js @@ -0,0 +1,36 @@ +import React from 'react' +import {CoreLoader} from 'components' +import { DevOptions } from 'ycore' +import PropTypes from 'prop-types' +import classNames from 'classnames' +import styles from './Loader.less' + +const Loader = ({ spinning = true, fullScreen }) => { + if (DevOptions.InfiniteLoading == true) { + return ( + <div className={styles.loader}> + <div className={styles.warpper}> + <CoreLoader type='circle' /> + </div> + </div> + ) + } + return ( + <div + className={classNames(styles.loader, { + [styles.hidden]: !spinning, + [styles.fullScreen]: fullScreen, + })} + > + <div className={styles.warpper}> + <CoreLoader type='circle' /> + </div> + </div> + ) +} +Loader.propTypes = { + spinning: PropTypes.bool, + fullScreen: PropTypes.bool, +} + +export default Loader; diff --git a/src/components/Loader/Loader.less b/src/components/Loader/Loader.less new file mode 100644 index 00000000..eaa7af13 --- /dev/null +++ b/src/components/Loader/Loader.less @@ -0,0 +1,68 @@ +.loader { + background-color: rgba(255, 255, 255, 0.945); + width: 100%; + position: absolute; + top: 0; + bottom: 0; + z-index: 100000; + display: flex; + justify-content: right; + float: right; + opacity: 1; + text-align: center; + + &.fullScreen { + position: fixed; + } + + .warpper { + position: absolute; + right: 0; + width: 100px; + height: 100px; + display: inline-flex; + flex-direction: column; + justify-content: space-around; + } + + .inner { + width: 40px; + height: 40px; + margin: 0 auto; + text-indent: -12345px; + border-top: 1px solid rgba(0, 0, 0, 0.08); + border-right: 1px solid rgba(0, 0, 0, 0.08); + border-bottom: 1px solid rgba(0, 0, 0, 0.08); + border-left: 1px solid rgba(0, 0, 0, 0.7); + border-radius: 50%; + z-index: 100001; + + :local { + animation: spinner 600ms infinite linear; + } + } + + .text { + width: 100px; + height: 20px; + text-align: center; + font-size: 12px; + letter-spacing: 4px; + color: #000; + } + + &.hidden { + z-index: -1; + opacity: 0; + transition: opacity 1s ease 0.5s, z-index 0.1s ease 1.5s; + } +} +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/Page/Page.js b/src/components/Page/Page.js new file mode 100644 index 00000000..7b52d47f --- /dev/null +++ b/src/components/Page/Page.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import Loader from '../Loader/Loader.js' +import styles from './Page.less' + +export default class Page extends Component { + render() { + const { className, children, loading = false, inner = false } = this.props + const loadingStyle = { + height: 'calc(100vh - 184px)', + overflow: 'hidden', + } + return ( + <div + className={classnames(className, { + [styles.contentInner]: inner, + })} + style={loading ? loadingStyle : null} + > + {loading ? <Loader spinning /> : ''} + {children} + </div> + ) + } +} + +Page.propTypes = { + className: PropTypes.string, + children: PropTypes.node, + loading: PropTypes.bool, + inner: PropTypes.bool, +} diff --git a/src/components/Page/Page.less b/src/components/Page/Page.less new file mode 100644 index 00000000..e180131c --- /dev/null +++ b/src/components/Page/Page.less @@ -0,0 +1,16 @@ +@import '~themes/vars.less'; + +.contentInner { + background: #fff; + padding: 24px; + box-shadow: @shadow-1; + min-height: ~'calc(100vh - 230px)'; + position: relative; +} + +@media (max-width: 767px) { + .contentInner { + padding: 12px; + min-height: ~'calc(100vh - 160px)'; + } +} diff --git a/src/components/Page/package.json b/src/components/Page/package.json new file mode 100644 index 00000000..a3811bdb --- /dev/null +++ b/src/components/Page/package.json @@ -0,0 +1,6 @@ +{ + "name": "Page", + "version": "0.0.0", + "private": true, + "main": "./Page.js" +} diff --git a/src/components/ScrollBar/index.js b/src/components/ScrollBar/index.js new file mode 100644 index 00000000..ce752b5d --- /dev/null +++ b/src/components/ScrollBar/index.js @@ -0,0 +1,5 @@ +import ScrollBar from 'react-perfect-scrollbar' +import 'react-perfect-scrollbar/dist/css/styles.css' +import './index.less' + +export default ScrollBar diff --git a/src/components/ScrollBar/index.less b/src/components/ScrollBar/index.less new file mode 100644 index 00000000..31e149bc --- /dev/null +++ b/src/components/ScrollBar/index.less @@ -0,0 +1,31 @@ +:global { + .ps--active-x > .ps__rail-x, + .ps--active-y > .ps__rail-y { + background-color: transparent; + } + + .ps__rail-x:hover > .ps__thumb-x, + .ps__rail-x:focus > .ps__thumb-x { + height: 8px; + } + + .ps__rail-y:hover > .ps__thumb-y, + .ps__rail-y:focus > .ps__thumb-y { + width: 8px; + } + + .ps__rail-y, + .ps__rail-x { + z-index: 9; + } + + .ps__thumb-y { + width: 4px; + right: 4px; + } + + .ps__thumb-x { + height: 4px; + bottom: 4px; + } +} diff --git a/src/components/YulioID/experimental/components/StatusBoxC.js.map b/src/components/YulioID/experimental/components/StatusBoxC.js.map new file mode 100644 index 00000000..f5680ba1 --- /dev/null +++ b/src/components/YulioID/experimental/components/StatusBoxC.js.map @@ -0,0 +1 @@ +{"version":3,"file":"StatusBoxC.js","sourceRoot":"","sources":["StatusBoxC.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,+BAAyC;AACzC,6BAA4B;AAC5B,wCAAiC;AAEjC,yCAAmC;AAEnC;IAAwB,6BAAS;IAE7B,mBAAY,KAAK;QAAjB,YACI,kBAAM,KAAK,CAAC,SAIf;QAHG,KAAI,CAAC,KAAK,GAAG;YACT,QAAQ,EAAE,SAAS;SACtB,CAAA;;IACL,CAAC;IACD,qCAAiB,GAAjB;QACY,IAAA,gCAAS,CAAgB;QACjC,IAAI,CAAC,QAAQ,CAAC,EAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,0BAAM,GAAN;QACY,IAAA,8BAAQ,CAAgB;QAEhC,IAAI,QAAQ,IAAI,SAAS,EAAE;YACvB,OAAO,CACL,0CAAK,SAAS,EAAE,qBAAM,CAAC,gBAAgB,EAAE,EAAE,EAAC,YAAY;gBACtD;oBAAK,iCAAC,WAAI,IAAC,IAAI,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,SAAG,CAAM;gBAChF;oBACE,4CAAM;oBAAA,4CAAM;oBAAA,4CAAM;oBAClB,0CAAK,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;wBAAE,yCAAI,SAAS,EAAE,qBAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,oBAAoB,CAAM,CAClI,CACF,CACP,CAAA;SACJ;QACD,IAAI,QAAQ,IAAI,KAAK,EAAE;YACnB,OAAO,CACL,0CAAK,SAAS,EAAE,qBAAM,CAAC,gBAAgB,EAAE,EAAE,EAAC,YAAY;gBACtD;oBACE,4CAAM;oBAAA,4CAAM;oBAAA,4CAAM;oBAClB,0CAAK,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;wBAAE,yCAAI,SAAS,EAAE,qBAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAM,CACvH,CACF,CACP,CAAA;SACD;QACJ,IAAI,QAAQ,IAAI,KAAK,EAAE;YACrB,OAAO,CACL,0CAAK,SAAS,EAAE,qBAAM,CAAC,gBAAgB,EAAE,EAAE,EAAC,YAAY;gBACtD;oBACE,4CAAM;oBAAA,4CAAM;oBAAA,4CAAM;oBAClB,0CAAK,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;wBAAE,yCAAI,SAAS,EAAE,qBAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAM,CACvH,CACF,CACP,CAAA;SACD;QAEF,OAAO,IAAI,CAAA;IACf,CAAC;IACL,gBAAC;AAAD,CAAC,AAjDD,CAAwB,iBAAS,GAiDhC;AAED,SAAS,CAAC,SAAS,GAAG;IAClB,YAAY,EAAE,uBAAS,CAAC,IAAI;IAC5B,OAAO,EAAE,uBAAS,CAAC,IAAI;IACvB,SAAS,EAAE,uBAAS,CAAC,MAAM;CAC9B,CAAA;AAED,qBAAe,SAAS,CAAC"} \ No newline at end of file diff --git a/src/components/YulioID/experimental/components/StatusBoxC.old.js b/src/components/YulioID/experimental/components/StatusBoxC.old.js new file mode 100644 index 00000000..6aaa2d25 --- /dev/null +++ b/src/components/YulioID/experimental/components/StatusBoxC.old.js @@ -0,0 +1,64 @@ +import React, { Component } from 'react'; +import { Icon } from 'antd'; +import styles from '../yid.scss'; + +import PropTypes from 'prop-types'; + +class StatusBox extends Component { + + constructor(props){ + super(props) + this.state = { + Reactive: 'loading', + } + } + componentDidMount(){ + const { StateCode } = this.props; + this.setState({Reactive: StateCode }); + } + render(){ + const { Reactive } = this.state; + + if (Reactive == 'loading') { + return ( + <div className={styles.spinner__wrapper} id="loadingspn" > + <div><Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin /></div> + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>Wait a sec...</h6></div> + </div> + </div> + ) + } + if (Reactive == '200') { + return ( + <div className={styles.spinner__wrapper} id="loadingspn" > + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>SI</h6></div> + </div> + </div> + ) + } + if (Reactive == '400') { + return ( + <div className={styles.spinner__wrapper} id="loadingspn" > + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>NO</h6></div> + </div> + </div> + ) + } + + return null + } +} + +StatusBox.propTypes = { + handleStatus: PropTypes.func, + Loading: PropTypes.bool, + StateCode: PropTypes.string +} + +export default StatusBox; \ No newline at end of file diff --git a/src/components/YulioID/experimental/components/StatusBoxC.tsx b/src/components/YulioID/experimental/components/StatusBoxC.tsx new file mode 100644 index 00000000..7e53c372 --- /dev/null +++ b/src/components/YulioID/experimental/components/StatusBoxC.tsx @@ -0,0 +1,74 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +import * as PropTypes from 'prop-types'; +var react = require("react"); +var antd = require("antd"); +var yid_scss = require("../yid.scss"); + + +var StatusBox = /** @class */ (function (_super) { + __extends(StatusBox, _super); + function StatusBox(props) { + var _this = _super.call(this, props) || this; + _this.state = { + Reactive: 'loading' + }; + return _this; + } + StatusBox.prototype.componentDidMount = function () { + var StateCode = this.props.StateCode; + this.setState({ Reactive: StateCode }); + }; + StatusBox.prototype.render = function () { + var Reactive = this.state.Reactive; + if (Reactive == 'loading') { + return (react.createElement("div", { className: yid_scss.spinner__wrapper, id: "loadingspn" }, + react.createElement("div", null, + react.createElement(antd.Icon, { type: "loading", style: { fontSize: 24, margin: '13px' }, spin: true })), + react.createElement("div", null, + react.createElement("br", null), + react.createElement("br", null), + react.createElement("br", null), + react.createElement("div", { style: { margin: 'auto' } }, + react.createElement("h6", { className: yid_scss.h6lp, style: { textAlign: 'center', marginTop: '15%' } }, "Wait a sec..."))))); + } + if (Reactive == '200') { + return (react.createElement("div", { className: yid_scss.spinner__wrapper, id: "loadingspn" }, + react.createElement("div", null, + react.createElement("br", null), + react.createElement("br", null), + react.createElement("br", null), + react.createElement("div", { style: { margin: 'auto' } }, + react.createElement("h6", { className: yid_scss.h6lp, style: { textAlign: 'center', marginTop: '15%' } }, "SI"))))); + } + if (Reactive == '400') { + return (react.createElement("div", { className: yid_scss.spinner__wrapper, id: "loadingspn" }, + react.createElement("div", null, + react.createElement("br", null), + react.createElement("br", null), + react.createElement("br", null), + react.createElement("div", { style: { margin: 'auto' } }, + react.createElement("h6", { className: yid_scss.h6lp, style: { textAlign: 'center', marginTop: '15%' } }, "NO"))))); + } + return null; + }; + return StatusBox; +}(react.Component)); +StatusBox.PropTypes = { + handleStatus: PropTypes.func, + Loading: PropTypes.bool, + StateCode: PropTypes.string +}; +exports["default"] = StatusBox; +//# sourceMappingURL=StatusBoxC.js.map \ No newline at end of file diff --git a/src/components/YulioID/experimental/formstyle.less b/src/components/YulioID/experimental/formstyle.less new file mode 100644 index 00000000..923938ae --- /dev/null +++ b/src/components/YulioID/experimental/formstyle.less @@ -0,0 +1,86 @@ + .inputform { + :global{ + input { + height: 50px; + font-size: 16px; + border: 2px solid #d1d3d4; + width: 100%; + padding: 12px; + font-family: "Poppins"; + border-radius: 6px; + color: black + } + input:focus { + outline: none; + border-color: black; + } + } +} + +.check { + animation-delay: 0s; +} +.checkmark { + opacity: 0; +} +.Oval { + opacity: 1; + transform-origin: 30px 30px; + stroke-dasharray: 200px; + transform: rotate(-75deg); + animation: 3s spin infinite ; + stroke-dashoffset: 200; +/* animation-play-state: paused; */ +} + +.animateCheck { + animation: 0.5s check_animation linear forwards; +} + +.animateOvaloop { + animation: 3s spin infinite ; +} + +@keyframes spin{ + 0%{ + opacity: 1; + stroke-dasharray: 360; + stroke-dashoffset: 360; + transform: rotate(-720deg); + + } +50% { + opacity: 1; + stroke-dasharray: 360; + stroke-dashoffset: 260; + transform: rotate(360deg); + } + 100%{ + opacity: 1; + stroke-dasharray: 360; + stroke-dashoffset: 360; + transform: rotate(720deg); + } +} + +@keyframes circle_animation { + 60% { + opacity: 1; + } + 100% { + opacity: 1; + stroke-dasharray: 400px; + transform: rotate(40deg); + } + } +@keyframes check_animation { + 0% { + stroke-dasharray: 126; + stroke-dashoffset: 126; + + } + 100% { + stroke-dasharray: 45; + stroke-dashoffset: 94 + } +} diff --git a/src/components/YulioID/experimental/index.js b/src/components/YulioID/experimental/index.js new file mode 100644 index 00000000..02052f8d --- /dev/null +++ b/src/components/YulioID/experimental/index.js @@ -0,0 +1,216 @@ +import React, { Component } from 'react' +import {GetAuth, InitSDCP, DevOptions, asyncSDCP} from 'ycore'; +import PropTypes from 'prop-types'; +import { connect } from 'dva'; +import { Button, Form, Input, Drawer, Icon, Collapse } from 'antd' +import styles from './yid.scss'; +import formstyle from './formstyle.less' + +const FormItem = Form.Item +const RenderInclude = ({ data }) => { if (!data) { return null; } else { return data; } } + +@connect(({ loading }) => ({ loading })) +@Form.create() +class YulioID extends Component { + + constructor(props) { + super(props) + this.state = { + // Drawers Visibility (Default on False) + MainLoginVisible: true, + ShowLoading: false, + Answered: false, + } + this.handleRetry = this.handleRetry.bind(this); + } + // Handlers & others + handleUsername(text) { + this.setState({ RawUsername: text.target.value }); + } + handlePassword(text) { + this.setState({ RawPassword: text.target.value }); + } + handleRetry() { + this.setState({ShowLoading: false, StateException: false, StateIcon: ''}) + } + handleEnter = (e) => { + this.handleLogin(); + } + + handleLogin = () => { + var prefix = '[YID]: '; + const { RawUsername, RawPassword } = this.state; + var EncPassword = btoa(RawPassword); + var EncUsername = btoa(RawUsername); + + const OriginalPayload = {EncUsername, EncPassword} + + if (!EncUsername || !EncPassword) { + var message = 'Incomplete information!' + console.log(prefix, message) + } + + if (EncUsername && EncPassword){ + this.setState({ ShowLoading: true, StateMessage: 'Wait a sec...' }); + if (DevOptions.InfiniteLogin == true) { + console.log(prefix, 'InfiniteLogin is enabled! Disabled getAuth') + } + else { + console.log(prefix, 'Initialising login process...') + GetAuth(EncUsername, EncPassword, (exception, response) => exception? this.handleResponse(response) : ( this.setState({ AuthResponse: response }), this.handleResponse(response, OriginalPayload) )) + } + + } + } + + handleResponse = (response) => { + var identState = JSON.parse(response)['api_status']; + if (identState == 200) { + const { dispatch } = this.props; + const UserID = JSON.parse(response)['user_id']; + const UserToken = JSON.parse(response)['access_token']; + let FramePayload = { UserID, UserToken } + DevOptions.ShowFunctionsLogs ? console.log(FramePayload) : null + this.setState({ StateIcon: 'login', StateMessage: 'Wait a sec...', StateException: false }) + InitSDCP({UserID, UserToken}, (done) => done? dispatch({type: 'login/login', payload: FramePayload}) : null ) + } + if (identState == 400) { + this.setState({ StateIcon: 'exclamation-circle', StateMessage: 'Invalid credentials', StateException: true }) + } + } + + + render() { + const { getFieldDecorator } = this.props.form; + const { ShowLoading, StateIcon, StateMessage, StateException } = this.state; + const { Panel } = Collapse; + + + return ( + <div> + <Drawer + width={520} + closable={false} + visible={this.state.MainLoginVisible} + > + <main className={styles.mainlp}> + <section className={styles.forms}> + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Welcome Back !</h1> + + {/* <RenderInclude data={include} /> */} + + <form className={styles.formlogin}> + {ShowLoading ? ( + <div style={{ height: '329px' }}> + <div className={styles.spinner__wrapper} id="loadingspn"> + {StateIcon ? (<Icon type={StateIcon} className={StateException? styles.StateIcon_exception : styles.StateIcon} /> ) : (<Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin />)} + <div><br/><br/><br/> + <div style={{ margin: 'auto' }}> + <h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }} > {StateMessage} </h6> + {StateException ? <div className={styles.retryBTN}><Button style={{ width: '270px' }} type='dashed' onClick={this.handleRetry}>Retry</Button></div> : null} + </div> + + </div> + </div> + </div> + ) : ( + <div> + <div className={styles.input__wrapper}> + <label className={styles.labelform}> + <Icon type="user" style={{ fontSize: '15px' }} />{' '} + Username + </label> + <FormItem> + {getFieldDecorator('Username', { + rules: [{ required: true }], + })( + <Input + onPressEnter={this.handleEnter} + className={styles.inputform} + type="text" + placeholder="Username" + onChange={text => { + this.handleUsername(text) + }} + /> + )} + </FormItem> + </div> + + <div className={styles.input__wrapper}> + <label className={styles.labelform}> + <Icon type="unlock" style={{ fontSize: '15px' }} />{' '} + Password + </label> + <FormItem> + {getFieldDecorator('Password', { + rules: [{ required: true }], + })( + <Input.Password + onPressEnter={this.handleEnter} + className={formstyle.inputform} + placeholder="Password" + onChange={text => { + this.handlePassword(text) + }} + /> + )} + </FormItem> + </div> + + <div style={{ margin: 'auto' }}> + <a + className={styles.buttonlp} + id="login" + onClick={this.handleLogin} + > + Login + </a> + </div> + <h2 + style={{ + textAlign: 'center', + margin: '8px', + color: '#666', + }} + > + Or + </h2> + <div style={{ float: 'left' }}> + <Button + type="dashed" + onClick={this.initFPassword} + style={{ top: '8px' }} + > + <Icon type="exclamation-circle" /> Forgotten password + </Button> + </div> + <div style={{ float: 'right' }}> + <Button + type="dashed" + onClick={this.initRegister} + style={{ top: '8px' }} + > + <Icon type="user-add" /> Create an account + </Button> + </div> + </div> + )} + </form> + </section> + </main> + </Drawer> + </div> + ) + } +} + +YulioID.propTypes = { + form: PropTypes.object, + dispatch: PropTypes.func, + loading: PropTypes.object, + include: PropTypes.object, +} + +export default YulioID diff --git a/src/components/YulioID/experimental/model.js b/src/components/YulioID/experimental/model.js new file mode 100644 index 00000000..dbbab857 --- /dev/null +++ b/src/components/YulioID/experimental/model.js @@ -0,0 +1,29 @@ +import { router, pathMatchRegexp } from 'utils' +import api from 'api' + +const { loginUser } = api + +export default { + namespace: 'login', + + state: {}, + + effects: { + *login({ payload }, { put, call, select }) { + const data = yield call(loginUser, payload) + const { locationQuery } = yield select(_ => _.app) + if (data.success) { + const { from } = locationQuery + yield put({ type: 'app/query' }) + if (!pathMatchRegexp('/login', from)) { + if (from === '/') router.push('/dashboard') + else router.push(from) + } else { + router.push('/dashboard') + } + } else { + throw data + } + }, + }, +} diff --git a/src/components/YulioID/experimental/yid.scss b/src/components/YulioID/experimental/yid.scss new file mode 100644 index 00000000..5c6418fe --- /dev/null +++ b/src/components/YulioID/experimental/yid.scss @@ -0,0 +1,769 @@ +@import url('https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css'); +@import url('https://fonts.googleapis.com/css?family=Poppins:300,300i,500,500i,700'); + +.retryBTN{ + margin-top: 150px; + text-align: center; +} +.StateIcon { + font-size: 24px; + margin: 13px; +} + +.StateIcon_exception { + color: red; + font-size: 24px; + margin: 13px; +} + + .mainlp { + --neutralShade0: #f8f8f8; + --neutralShade1: #f2f2f2; + --neutralShade2: #e8e9e9; + --neutralShade3: #d1d3d4; + --neutralShade4: #babdbf; + --neutralShade5: #808488; + --neutralShade6: #666a6d; + --neutralShade7: #4d5052; + --neutralShade8: #212122; + --grayColor: #999; + --lightGrayColor: #ddd; + --borderRadius: 6px; + --boxShadow: 0 2px 5px rgba(#333, 0.2); + } + + /*overall layout*/ + .mainlp { + width: 90%; + max-width: 1050px; + margin: 3em auto 0; + display: grid; + grid: repeat(5, fit-content(300px))/100%; + color: var(--foregroundColor); + text-align: left; + } + + .mainlp .sectionlp { + border: 1px solid var(--accentColor); + position: relative; + padding: 40px 40px 50px; + } + .mainlp .sectionlp > h6 { + color: var(--accentColor); + background: var(--canvasColor); + position: absolute; + top: -10px; + left: 20px; + padding: 0 10px; + } + .mainlp .sectionlp .h6lp.subheader { + color: var(--grayColor); + margin-top: 20px; + margin-bottom: 20px; + width: 100%; + } + + @media (max-width: 992px) { + section:not(:last-child) { + border-width: 0 0 1px; + } + + section:last-child { + border-width: 0; + } + } + @media (min-width: 992px) { + main { + grid: repeat(9, auto)/45% 1fr 45%; + grid-auto-flow: dense; + } + + .media-card-1 { + grid-column: 1 / 2; + border-width: 1px 0; + } + + .media-card-2 { + grid-column: 2 / 4; + border-width: 1px 0 1px 1px; + } + + .media-card-3 { + grid-column: 1 / 4; + border-width: 0; + } + + .filter-section { + grid-column: 3 / 4; + grid-row: 1 / 2; + border-width: 0 0 0 1px; + } + + .well-cta-1 { + grid-row: 3; + grid-column: 1 / 3; + border-width: 1px 1px 0 0; + } + + .well-cta-2 { + grid-row: 2; + grid-column: 2 / 4; + border-width: 1px 0 0; + } + + .tables { + grid-row: 4; + grid-column: 1 / -1; + border-width: 1px 0 0; + } + + .forms { + grid-column: 1 / 3; + border-width: 0; + } + + .comments { + grid-row: 2; + grid-column: 1 / 2; + border-width: 1px 1px 0 0; + padding-top: 60px; + } + + .modals { + grid-row: 3; + grid-column: 3 / 4; + justify-content: center; + border-width: 1px 0 0; + } + } + + + /*checkboxes*/ + input:disabled ~ * { + opacity: 0.3; + user-select: none; + pointer-events: none; + } + + .checkboxtoggle input { + display: none; + } + .checkboxtoggle label { + outline: 0; + display: block; + width: 45px; + height: 16px; + background: var(--grayColor); + position: relative; + cursor: pointer; + border-radius: 2em; + padding: 2px; + transition: all 0.4s ease; + margin: 0; + } + .checkboxtoggle .labellp:after { + position: relative; + display: block; + content: ""; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + transition: all 0.2s ease; + border: 1px solid var(--grayColor); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + left: -4px; + top: -5px; + } + .checkboxtoggle input:checked + .labellp { + background: var(--accent2Color); + } + .checkboxtoggle input:checked + .labellp:after { + left: 52%; + } + + .checkbox { + position: relative; + user-select: none; + margin-bottom: 10px; + } + .checkbox input { + display: none; + } + .checkbox .labellp { + position: relative; + vertical-align: middle; + cursor: pointer; + font-weight: 500; + padding-left: 35px; + } + .checkbox .box { + display: inline-block; + width: 20px; + border-radius: var(--borderRadius); + border: 1px solid var(--grayColor); + width: 24px; + height: 24px; + vertical-align: middle; + margin-right: 3px; + transition: 0.3s ease; + position: absolute; + left: 0; + } + .checkbox .box:before, .checkbox .box:after { + content: ""; + position: absolute; + width: 4px; + height: 16px; + border-radius: 40px; + background: var(--backgroundColor); + transition: all 0.3s ease; + } + .checkbox .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(0); + } + .checkbox .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(0); + } + .checkbox input:checked + .labellp .spanlp.box { + background: var(--accent2Color); + border-color: var(--accent2Color); + } + .checkbox input:checked + .labellp .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(1); + } + .checkbox input:checked + .labellp .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(1); + } + .checkbox input:disabled:checked + .spanlp.box { + background: var(--grayColor); + border: var(--grayColor); + } + .checkbox input:disabled:checked ~ .labellp:before, .checkbox input:disabled:checked ~ .labellp:after { + background: black; + } + + /*buttons & links*/ + .links__sec { + margin: 10px 0 30px; + } + .links a.link { + display: inline; + margin: 10px 30px 5px 0; + border-bottom: 2px dashed; + font-weight: 500; + line-height: 2.5; + cursor: pointer; + color: var(--neutralShade5); + } + .links a.link:hover, .links a.link.hover { + color: var(--neutralShade6); + border-bottom: 2px solid; + } + .links a.link.primary { + color: var(--primaryColor); + } + .links a.link.primary:hover, .links a.link.primary.hover { + color: var(--primaryShade5); + } + .links a.link.secondary { + color: var(--secondaryColor); + } + .links a.link.secondary:hover, .links a.link.secondary.hover { + color: var(--secondaryShade5); + } + + .buttons { + display: flex; + flex-wrap: wrap; + align-items: center; + } + .buttons > * { + flex: 1 1 calc(50% - 20px); + margin-top: 20px; + } + .buttons > *:nth-child(odd) { + margin-right: 20px; + } + + a.buttonlp, + input.buttonlp, + .buttonlp { + outline: none; + width: 100%; + text-align: center; + display: inline-block; + border: none; + font: 500 16px/1 "Poppins", sans-serif; + padding: 20px; + cursor: pointer; + border-radius: var(--borderRadius); + background: var(--primaryColor); + color: var(--backgroundColor); + position: relative; + top: 0; + transition: 0.2s ease; + } + a.buttonlp:hover, a.buttonlp.hover, + input.buttonlp:hover, + input.buttonlp.hover, + .buttonlp:hover, + .buttonlp.hover { + top: -3px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); + } + a.buttonlp:active, a.buttonlp.active, + input.buttonlp:active, + .input.buttonlp.active, + .buttonlp:active, + .buttonlp.active { + background: var(--primaryShade4); + outline: none; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + top: 0; + } + a.buttonlp.disabled, + input.buttonlp.disabled, + .buttonlp.disabled { + opacity: 0.4; + user-select: none; + pointer-events: none; + } + a.buttonlp.medium, + input.buttonlp.medium, + .buttonlp.medium { + padding: 15px 18px; + width: auto; + } + a.buttonlp.small, + input.buttonlp.small, + .buttonlp.small { + padding: 10px 12px; + width: auto; + font-size: 14px; + font-weight: 500; + } + a.buttonlp.secondary, + input.buttonlp.secondary, + .buttonlp.secondary { + background: var(--secondaryColor); + } + a.buttonlp.secondary:active, a.buttonlp.secondary:focus, a.buttonlp.secondary.active, + input.buttonlp.secondary:active, + input.buttonlp.secondary:focus, + input.buttonlp.secondary.active, + .buttonlp.secondary:active, + .buttonlp.secondary:focus, + .buttonlp.secondary.active { + background: var(--secondaryShade4); + outline: none; + } + a.buttonlp.accent, + input.buttonlp.accent, + .buttonlp.accent { + background: var(--accentColor); + } + a.buttonlp.accent:active, a.buttonlp.accent:focus, a.buttonlp.accent.active, + input.buttonlp.accent:active, + input.buttonlp.accent:focus, + input.buttonlp.accent.active, + .buttonlp.accent:active, + .buttonlp.accent:focus, + .buttonlp.accent.active { + background: var(--accentShade4); + } + a.buttonlp.accent2, + input.buttonlp.accent2, + .buttonlp.accent2 { + background: var(--accent2Color); + } + a.buttonlp.accent2:active, a.buttonlp.accent2:focus, a.buttonlp.accent2.active, + input.buttonlp.accent2:active, + input.buttonlp.accent2:focus, + input.buttonlp.accent2.active, + .buttonlp.accent2:active, + .buttonlp.accent2:focus, + .buttonlp.accent2.active { + background: var(--accent2Shade4); + } + a.buttonlp.accent3, + input.buttonlp.accent3, + .buttonlp.accent3 { + background: var(--accent3Color); + } + a.buttonlp.accent3:active, a.buttonlp.accent3:focus, a.buttonlp.accent3.active, + input.buttonlp.accent3:active, + input.buttonlp.accent3:focus, + input.buttonlp.accent3.active, + .buttonlp.accent3:active, + .buttonlp.accent3:focus, + .buttonlp.accent3.active { + background: var(--accent3Shade4); + } + + /*inputs*/ + .input__wrapper { + margin-bottom: 10px; + } + .inputRG__wrapper { + margin-bottom: 0px; + } + + .labelform { + font-weight: 500; + display: block; + margin-bottom: 5px; + } + + .inputform, + select, + textarea { + height: 50px; + font-size: 16px; + border: 2px solid var(--neutralShade3); + width: 100%; + padding: 12px; + font-family: "Poppins"; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + background: var(--backgroundColor); + } + .inputform:focus, .inputform.active, + select:focus, + select.active, + textarea:focus, + textarea.active { + outline: none; + border-color: var(--primaryColor); + } + .inputform:disabled, + select:disabled, + textarea:disabled { + cursor: not-allowed; + background: var(--neutralShade1); + opacity: 0.6; + } + Input .inputPasswordform { + height: 50px; + font-size: 16px; + border: 2px solid var(--neutralShade3); + width: 100%; + padding: 12px; + font-family: "Poppins"; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + background: var(--backgroundColor); + } + + Input .inputPasswordform:focus { + outline: none; + border-color: var(--primaryColor); + } + + .inputform.input { + height: 56px; + font-size: 18px; + padding: 15px; + } + + .TOSAccept { + margin: 7px; + } + .TOSAccept span::first-letter { + color: blue; + } + + /*spinner*/ + .spinner + .labellp { + font-size: 14px; + font-weight: 500; + margin-top: 8px; + display: inline-block; + text-transform: uppercase; + color: var(--primaryShade4); + } + + .spinner1 .spinner { + max-width: 50px; + margin: auto; + height: 20px; + position: relative; + } + .spinner1 .spinner:after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryColor); + animation: spinnerLeftRight 1s infinite; + } + .spinner1 .spinner:before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryShade2); + opacity: 1; + animation: spinnerLeftRight 1s infinite 0.06s; + } + + @keyframes spinnerLeftRight { + 0% { + left: 85%; + } + 50% { + left: -10%; + } + 100% { + left: 85%; + } + } + + + #sunset + .labellp { + background: linear-gradient(to right, #ff9557 50%, #ffcc67 50%); + } + .mainlp { + --canvasColor: #f9f9f9; + --backgroundColor: #fff; + --foregroundColor: #111; + --primaryColor: #373F51; + --primaryShade1: #ffe2d1; + --primaryShade2: #ffceb2; + --primaryShade3: #ffb184; + --primaryShade4: #e88850; + --primaryShade5: #d17a48; + --secondaryColor: #ffcc67; + --secondaryShade1: #fff1d5; + --secondaryShade2: #ffde9e; + --secondaryShade3: #ffd074; + --secondaryShade4: #e8ba5e; + --secondaryShade5: #ba954b; + --accentColor: #4e5166; + --accentShade1: #cecfd5; + --accentShade2: #aeafb9; + --accentShade3: #8e909d; + --accentShade4: #6e7081; + --accentShade5: #404354; + --accent2Color: #588b8b; + --accent2Shade1: #c2d4d4; + --accent2Shade2: #a3bfbf; + --accent2Shade3: #85aaaa; + --accent2Shade4: #507f7f; + --accent2Shade5: #497272; + --accent3Color: #fe5f55; + --accent3Shade1: #fec4c1; + --accent3Shade2: #fea7a2; + --accent3Shade3: #fe7c73; + --accent3Shade4: #e7574e; + --accent3Shade5: #b9463e; + } + + .formlogin { + border-radius: 10px; + padding: 30px; + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + background: var(--backgroundColor); + margin-top: 30px; + position: relative; + overflow: hidden; + vertical-align: middle; + } + .formlogin .checkbox { + margin-bottom: 30px; + } + .formlogin .spinner__wrapper { + place-items: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.85); + + } + + @media (min-width: 768px) { + .formlogin { + grid: auto / 1fr 40%; + } + .formlogin .input__wrapper { + grid-column: span 2; + } + .formlogin .inputRG__wrapper { + grid-column: span 2; + } + .formlogin .checkbox { + align-self: center; + margin-bottom: 0; + } + } + #dark:checked ~ .mainlp .spinner__wrapper, + #pinkaru:checked ~ .mainlp .spinner__wrapper { + background: rgba(20, 20, 20, 0.85); + } + + + + + + + + + /*typography 2*/ + .stonglp { + font-weight: 500; + } + + .emlp { + font-style: italic; + } + + .h1lp { + font: 700 48px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h2lp { + font: 700 32px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h3lp { + font: 700 24px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h4lp { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h5lp { + font: 500 18px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h6lp { + font: 500 16px/1.2 "Poppins", sans-serif; + text-transform: uppercase; + } + + .apierrort { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.apierrort::first-letter { + text-transform: uppercase; +} + +.devServer{ + color: orangered; + text-align: left; + margin: 10px; + float: left; + position: fixed; + z-index: 104; + font-size: 16px; + +} +.devServer span{ + text-shadow: 2px 0 0 #fff, -2px 0 0 #fff, 0 2px 0 #fff, 0 -2px 0 #fff, 1px 1px #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff; +} + + +.bgHero iframe { + width: 100%; + height: 100%; + position: fixed; + top: 0; + z-index: 103; +} + +$circle-length: 340px; +$check-length: 230px; + +@keyframes scaleAnimation { + 0% { + opacity: 0; + transform: scale(1.5); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes drawCircle { + 0% { + stroke-dashoffset: $circle-length; + } + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes drawCheck { + 0% { + stroke-dashoffset: $check-length; + } + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +#successAnimationCircle { + stroke-dasharray: $circle-length $circle-length; + stroke: #FFF; +} + +#successAnimationCheck { + stroke-dasharray: $check-length $check-length; + stroke: #FFF; +} + +#successAnimationResult { + fill: #FFF; + opacity: 0; +} + +#successAnimation .animated { + animation: 1s ease-out 0s 1 both scaleAnimation; + + #successAnimationCircle { + animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both drawCircle, + 0.3s linear 0.9s 1 both fadeOut; + } + + #successAnimationCheck { + animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both drawCheck, + 0.3s linear 0.9s 1 both fadeOut; + } + + #successAnimationResult { + animation: 0.3s linear 0.9s both fadeIn; + } +} diff --git a/src/components/YulioID/legacy/forms.js b/src/components/YulioID/legacy/forms.js new file mode 100644 index 00000000..1ae723e3 --- /dev/null +++ b/src/components/YulioID/legacy/forms.js @@ -0,0 +1,357 @@ +//****************************************| +//**** Yulio ID v1.6 *****| +//****************************************| +// +// @ Licensed by RageStudio(c) 2019 +// @ Build 03102019EU21700 F/WIAPIS +// @ https://api.ragestudio.net/RS-YIBTP +// +//****************************************| + +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'dva' +import { Button, Row, Form, Input, Drawer, Icon, Collapse, Select, Checkbox, Result, Layout, message, notification } from 'antd' +import { Trans, withI18n } from '@lingui/react' +import { setLocale } from 'utils' +import { UIFxPY, UIFxList, DevOptions } from 'ycore'; +import { endpoints } from 'ycore'; +import $ from 'jquery'; +import styles from './yid.scss'; +import {resetToken} from './ycore_sdcp.js' + +import Cookies from 'universal-cookie'; +import Cryptr from 'cryptr'; + +const cookies = new Cookies(); + +const FormItem = Form.Item + +@withI18n() +@connect(({ loading }) => ({ loading })) +@Form.create() +class YulioIDForms extends PureComponent { + constructor() { + super() + this.state = { + // Drawers Visibility (Default on False) + MainLoginVisible: false, + NOTFdrawer: false, + SOTFdrawer: false, + RGSOTFdrawer: false, + registerVisible: false, + ForggotPasswordVisible: false, + // Arrays + ErrorType: '', + FailArray: '', + username: '', + password: '', + server_key: '', + access_token: '', + user_data: [], + ExceptionID: '', + EXCPMS: '', + CompleteFORM: '', + TSDCP: '', + user_id: '', + api_response: {}, + api_response_ud: [], + RGUsername: '', + RGEmail: '', + RGPassword: '', + RGGender: '', + } + this.initRegister = this.initRegister.bind(this); + this.initFPassword = this.initFPassword.bind(this); + this.cancelRegister = this.cancelRegister.bind(this); + this.cancelRecoverPassword = this.cancelRecoverPassword.bind(this); + this.closeNOTF = this.closeNOTF.bind(this); + this.closeSOTF = this.closeSOTF.bind(this); + this.closeRGSOTF = this.closeSOTF.bind(this); + + } + // Handlers & others + handleUsername(text) { + this.setState({ username: text.target.value }) + } + handlePassword(text) { + this.setState({ password: text.target.value }) + } + handleRGUsername(text) { + this.setState({ RGUsername: text.target.value }) + } + handleRGPassword(text) { + this.setState({ RGPassword: text.target.value }) + } + handleRGEmail(text) { + this.setState({ RGEmail: text.target.value }) + } + handleRGGender(Ivalue) { + this.setState({ RGGender: Ivalue }) + } + handleFPEmail(Ivalue) { + this.setState({ FGEmail: Ivalue }) + } + + + triggerNOTF() { + this.setState({ NOTFdrawer: true }); + } + closeNOTF() { + this.setState({ NOTFdrawer: false }); + } + + triggerSOTF() { + this.setState({ SOTFdrawer: true }); + } + closeSOTF() { + this.setState({ SOTFdrawer: false }); + } + + triggerRGSOTF() { + this.setState({ RGSOTFdrawer: true }); + } + closeRGSOTF() { + this.setState({ RGSOTFdrawer: false }); + } + + cancelRegister() { + this.setState({ registerVisible: false }) + } + cancelRecoverPassword(){ + this.setState({ ForggotPasswordVisible: false }) + } + + initRegister() { + var messageListener = message.loading('Initialising YulioID ', 1.5) + { messageListener } + if (DevOptions.DisableRegister == false) { + this.setState({ registerVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Register)', 2.5)) + } + } + + initFPassword() { + var messageListener = message.loading('Initialising YulioID ', 1.5) + { messageListener } + if (DevOptions.DisablePasswordRecover == false) { + this.setState({ ForggotPasswordVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Password Recovery)', 2.5)) + } + } + ValidateSession() { + if (DevOptions.DisableLogin == false) { + this.setState({ MainLoginVisible: true }) + } + else { + message.error('Error trying to connect to YulioID services', 2.5) + $("#ErrorNotification").css({ display: 'block' }) + } + } + + componentDidMount() { + // INIT + this.setState({ server_key: endpoints.server_key }); + this.ValidateSession(); + + const istoken = localStorage.getItem('access_token'); + const isdone = this.state.CompleteFORM; + const getSDCP = localStorage.getItem('SDCP'); + const availableToken = cookies.get('access_token') + if (availableToken) { + resetToken() + } + + if (isdone == 'true') { + setTimeout(() => { location.reload() }, 3000); + } + if (!getSDCP) { + localStorage.setItem('GetNewData', true); + } + } +render() { + const { loading, form, i18n } = this.props + const MensageException = this.state.EXCPMS; + const ExceptionID = this.state.ExceptionID; + const { Panel } = Collapse; + + const { getFieldDecorator } = this.props.form; + + return ( + <div> + {/* LOGIN SECTION */} + <Drawer width={520} closable={false} visible={this.state.MainLoginVisible}> + + <main className={styles.mainlp}> + <section className={styles.forms}> + + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Welcome Back !</h1> + <form className={styles.formlogin}> + + <div className={styles.input__wrapper}> + + <label className={styles.labelform}><Icon type="user" style={{ fontSize: '15px' }} /> Username</label> + <FormItem hasFeedback>{getFieldDecorator('Username', { rules: [{ required: true }] })( + <input className={styles.inputform} type="text" placeholder="Username" onChange={(text) => { this.handleUsername(text) }} /> + )} + </FormItem> + </div> + + <div className={styles.input__wrapper}> + <label className={styles.labelform}><Icon type="unlock" style={{ fontSize: '15px' }} /> Password</label> + <FormItem hasFeedback>{getFieldDecorator('Password', { rules: [{ required: true }] })( + <input className={styles.inputform} type="password" placeholder="Password (At least 8 characters)" onChange={(text) => { this.handlePassword(text) }} /> + )} + </FormItem> + </div> + + <div style={{ margin: 'auto' }}><a className={styles.buttonlp} id="login" onClick={this.getAuth}>Login</a></div> + <h2 style={{ textAlign: 'center', margin: '8px', color: '#666' }}>Or</h2> + <div style={{ float: 'left' }}><Button type="dashed" onClick={this.initFPassword} style={{ top: '8px' }}><Icon type="exclamation-circle" /> Forgotten password</Button></div> + <div style={{ float: 'right' }}><Button type="dashed" onClick={this.initRegister} style={{ top: '8px' }}><Icon type="user-add" /> Create an account</Button></div> + + <div className={styles.spinner__wrapper} id="loadingspn"> + <div><Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin /></div> + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>Wait a sec...</h6></div> + + </div> + + </div> + </form> + + </section> + + + + </main> + + </Drawer> + + {/* REGISTER SECTION */} + <Drawer width={680} closable={true} onClose={this.cancelRegister} visible={this.state.registerVisible}> + <main className={styles.mainlp}> + <section className={styles.forms}> + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Register</h1> + <h3>Wow congratulations, very soon you will begin to discover rStudio, but first you will have to start by filling out this form</h3> + <form className={styles.formlogin}> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Choose your Username</label> + <FormItem hasFeedback>{getFieldDecorator('rgUsername', { rules: [{ required: true }] })( + <Input type="text" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" onChange={(text) => { this.handleRGUsername(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Fill with your email</label> + <FormItem hasFeedback>{getFieldDecorator('rgEmail', { rules: [{ required: true }] })( + <Input type="text" prefix={<Icon type="link" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Email" onChange={(text) => { this.handleRGEmail(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Fill with your password</label> + <FormItem hasFeedback>{getFieldDecorator('rgPassword', { rules: [{ required: true }] })( + <Input type="password" prefix={<Icon type="key" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Password" onChange={(text) => { this.handleRGPassword(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + </div> + <div className={styles.TOSAccept}><span><span style={{ color: 'red', fontSize: '17px' }}>*</span> Clicking the register button you accept our <a href="#">terms and conditions</a></span> </div> + <a className={styles.buttonlp} id="register" onClick={this.getRegister}>Register</a> + <div className={styles.spinner__wrapper} id="loadingRGspn"> + <div style={{ position: 'absolute', marginLeft: '86%', marginTop: '-65%' }}><Icon type="loading" style={{ fontSize: 24 }} spin /></div> + <div> + <div><Icon style={{ fontSize: '160px', margin: '30px', color: '#5B2A86' }} type="smile" /></div> + <h6 className={styles.h6lp} style={{ textAlign: 'center' }}>Ok thanks, wait a minute...</h6> + </div> + </div> + </form> + </section> + </main> + </Drawer> + + {/* FORGOTTEN PASSWORD SECTION */} + <Drawer width={420} closable={true} onClose={this.cancelRecoverPassword} visible={this.state.ForggotPasswordVisible}> + <main className={styles.mainlp}> + <section className={styles.forms}> + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Forgotten Password!</h1> + <h3>To recover your account enter the email used to register</h3> + <form className={styles.formlogin}> + <div className={styles.input__wrapper}> + <label className={styles.labelform}><Icon type="mail" style={{ fontSize: '15px' }} /> Email</label> + <FormItem hasFeedback>{getFieldDecorator('Email', { rules: [{ required: true }] })( + <input className={styles.inputform} type="text" placeholder="myaccount@example.com" onChange={(text) => { this.handleFPEmail(text) }} /> )} + </FormItem> + </div> + {/* <div style={{ margin: 'auto' }}><a className={styles.buttonlp} id="login" onClick={this.RecoverPassword(this.state.FGEmail)}>Recover</a></div> */} + <div className={styles.spinner__wrapper} id="loadingspn"> + <div><Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin /></div> + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>Wait a sec...</h6></div> + </div> + </div> + </form> + </section> + </main> + </Drawer> + + {/* NOTF */} + <Drawer width={320} closable={false} visible={this.state.NOTFdrawer} > + <div style={{ textAlign: 'center', color: 'orange' }} ><Icon type="warning" style={{ fontSize: '230px' }} /> + <h2 className={styles.h2lp}> {this.state.FailArray} </h2> + <h4 className={styles.apierrort}> {MensageException} </h4> <hr /> + <div id="details-collapse" style={{ textAlign: 'center' }}> + <Collapse bordered={false} defaultActiveKey={['0']} expandIcon={({ isActive }) => <Icon type="caret-right" rotate={isActive ? 90 : 0} />}> + <Panel header="Details" key="1" style={{ borderRadius: 4, marginBottom: 24, border: 0, overflow: 'hidden', }}> + <Icon type="exception" /> + <h6>STATUS HANDLER => {this.state.ErrorType} </h6> + <h6>EXCEPTION => {this.state.api_response} </h6> + <h6>EXCEPTION MENSAGE => {MensageException}</h6> + <h6><strong>ID {ExceptionID}</strong></h6> + </Panel> + </Collapse> + <hr /><Button type="danger" onClick={this.closeNOTF}>TRY AGAIN</Button> + </div> + </div> + </Drawer> + + + {/* SOTF */} + <Drawer width={320} closable={false} visible={this.state.SOTFdrawer}> + <div style={{ textAlign: 'center', color: '#4BB543' }} ><Icon type="check" style={{ fontSize: '200px' }} /> + <h2 className={styles.h2lp} style={{ color: '#4BB543' }} > Success </h2> + <h4>Please wait while process your data ...</h4> + </div> + </Drawer> + {/* RGSOTF */} + <Drawer width={320} closable={false} visible={this.state.RGSOTFdrawer}> + <div style={{ textAlign: 'center', color: 'green' }} > + <Icon type="check" style={{ fontSize: '200px' }} /> + <h2 className={styles.h2lp} style={{ color: 'green' }} > Registered </h2> + <h4 className={styles.apierrort}> Welcome to Dashboard, you will start discovering now</h4> + <h4>Please check your new data while we are process you ...</h4> + </div> + </Drawer> + </div> + ) + } +} + +YulioIDForms.propTypes = { + form: PropTypes.object, + dispatch: PropTypes.func, + loading: PropTypes.object, +} + +export default YulioIDForms \ No newline at end of file diff --git a/src/components/YulioID/legacy/index.js b/src/components/YulioID/legacy/index.js new file mode 100644 index 00000000..f4669d1a --- /dev/null +++ b/src/components/YulioID/legacy/index.js @@ -0,0 +1,551 @@ +//****************************************| +//**** Yulio ID v1.6 *****| +//****************************************| +// +// @ Licensed by RageStudio(c) 2019 +// @ Build 03102019EU21700 F/WIAPIS +// @ https://api.ragestudio.net/RS-YIBTP +// +//****************************************| + +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'dva' +import { Button, Row, Form, Input, Drawer, Icon, Collapse, Select, Checkbox, Result, Layout, message, notification } from 'antd' +import { Trans, withI18n } from '@lingui/react' +import { setLocale } from 'utils' +import { UIFxPY, UIFxList, DevOptions } from 'ycore'; +import { endpoints } from 'ycore'; +import $ from 'jquery'; +import styles from './yid.scss'; +import './ycore_sdcp'; +import YIDForms from './forms.js' + +// import {getUserData, getUserRGData, getRegister, getAuth, resetToken, processError, processSuccess, processRGSuccess, processJSON, processRGJSON} from './loginFunctions.js'; + +import Cookies from 'universal-cookie'; +import Cryptr from 'cryptr'; + +const cookies = new Cookies(); + +const FormItem = Form.Item + +@withI18n() +@connect(({ loading }) => ({ loading })) +@Form.create() +class YulioID extends PureComponent { + constructor() { + super() + this.state = { + // Drawers Visibility (Default on False) + MainLoginVisible: false, + NOTFdrawer: false, + SOTFdrawer: false, + RGSOTFdrawer: false, + registerVisible: false, + ForggotPasswordVisible: false, + // Arrays + ErrorType: '', + FailArray: '', + username: '', + password: '', + server_key: '', + access_token: '', + user_data: [], + ExceptionID: '', + EXCPMS: '', + CompleteFORM: '', + TSDCP: '', + user_id: '', + api_response: {}, + api_response_ud: [], + RGUsername: '', + RGEmail: '', + RGPassword: '', + RGGender: '', + } + this.getAuth = this.getAuth.bind(this); + this.getRegister = this.getRegister.bind(this); + this.getUserData = this.getUserData.bind(this); + this.initRegister = this.initRegister.bind(this); + this.initFPassword = this.initFPassword.bind(this); + this.cancelRegister = this.cancelRegister.bind(this); + this.cancelRecoverPassword = this.cancelRecoverPassword.bind(this); + this.closeNOTF = this.closeNOTF.bind(this); + this.closeSOTF = this.closeSOTF.bind(this); + this.closeRGSOTF = this.closeSOTF.bind(this); + this.processSuccess = this.processSuccess.bind(this); + this.processRGSuccess = this.processSuccess.bind(this); + this.processJSON = this.processJSON.bind(this); + this.processRGJSON = this.processJSON.bind(this); + } + // Handlers & others + handleUsername(text) { + this.setState({ username: text.target.value }) + } + handlePassword(text) { + this.setState({ password: text.target.value }) + } + handleRGUsername(text) { + this.setState({ RGUsername: text.target.value }) + } + handleRGPassword(text) { + this.setState({ RGPassword: text.target.value }) + } + handleRGEmail(text) { + this.setState({ RGEmail: text.target.value }) + } + handleRGGender(Ivalue) { + this.setState({ RGGender: Ivalue }) + } + handleFPEmail(Ivalue) { + this.setState({ FGEmail: Ivalue }) + } + + + triggerNOTF() { + this.setState({ NOTFdrawer: true }); + } + closeNOTF() { + this.setState({ NOTFdrawer: false }); + } + + triggerSOTF() { + this.setState({ SOTFdrawer: true }); + } + closeSOTF() { + this.setState({ SOTFdrawer: false }); + } + + triggerRGSOTF() { + this.setState({ RGSOTFdrawer: true }); + } + closeRGSOTF() { + this.setState({ RGSOTFdrawer: false }); + } + + cancelRegister() { + this.setState({ registerVisible: false }) + } + cancelRecoverPassword(){ + this.setState({ ForggotPasswordVisible: false }) + } + + initRegister() { + var messageListener = message.loading('Initialising YulioID ', 1.5) + { messageListener } + if (DevOptions.DisableRegister == false) { + this.setState({ registerVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Register)', 2.5)) + } + } + + initFPassword() { + var messageListener = message.loading('Initialising YulioID ', 1.5) + { messageListener } + if (DevOptions.DisablePasswordRecover == false) { + this.setState({ ForggotPasswordVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Password Recovery)', 2.5)) + } + } + ValidateSession() { + if (DevOptions.DisableLogin == false) { + this.setState({ MainLoginVisible: true }) + } + else { + message.error('Error trying to connect to YulioID services', 2.5) + $("#ErrorNotification").css({ display: 'block' }) + } + } + + componentDidMount() { + // INIT + this.setState({ server_key: endpoints.server_key }); + this.ValidateSession(); + + const istoken = localStorage.getItem('access_token'); + const isdone = this.state.CompleteFORM; + const getSDCP = localStorage.getItem('SDCP'); + const availableToken = cookies.get('access_token') + if (availableToken) { + this.resetToken() + } + + if (isdone == 'true') { + setTimeout(() => { location.reload() }, 3000); + } + if (!getSDCP) { + localStorage.setItem('GetNewData', true); + } + } + + resetToken() { + let _this = this; + const tojb1 = endpoints.removeToken; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'For continue your request, is necessary to login with YulioID™ again', + description: + 'LoginBridge™ report a access token expiration, and is required you for continue login again with security reasons.', + icon: <Icon type="login" style={{ color: '#108ee9' }} />, + }); + cookies.remove('access_token', { path: '/' }) + }); + } + getUserData() { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processSuccess(); + }) + } + getUserRGData() { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processRGSuccess(); + }) + + + } + + getRegister() { + $("#loadingRGspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.RGUsername; + const password = this.state.RGPassword; + const email = this.state.RGEmail; + const confirm_password = this.state.RGPassword; + const server_key = this.state.server_key; + + var form = new FormData(); + + form.append("server_key", server_key); + form.append("username", username); + form.append("email", email); + form.append("password", password); + form.append("confirm_password", confirm_password); + + var settings = { + "url": endpoints.register_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processRGJSON(); + }) + .fail(function (response) { + + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + } + + RecoverPassword(inputIO){ + const cookies = new Cookies(); + let _this = this; + const tojb1 = endpoints.resetPassword_endpoint; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + form.append("email", inputIO); + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'The instructions to recover your account have been sent to the email', + description: + 'If you cant find the email, try looking for it in the spam folder or try again', + icon: <Icon type="mail" style={{ color: '#108ee9' }} />, + }); + console.log(response) + }); + } + + getAuth() { + $("#loadingspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.username; + const password = this.state.password; + const server_key = this.state.server_key; + + var form = new FormData(); + + form.append("server_key", server_key); + form.append("username", username); + form.append("password", password); + var settings = { + "url": endpoints.auth_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processJSON(); + }) + .fail(function (response) { + + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + notification.open({ + placement: 'topLeft', + message: 'Currently our servers are having operating problems', + description: 'Please be patient until the services become available again, try again later. We apologize for the inconveniences', + icon: <Icon type="login" style={{ color: '#ff0f2f' }} /> + }), + $("#loadingspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + + + } + + processError() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer)['api_status']; + const ExceptionMensage = JSON.parse(this.state.api_response)['errors']; + const ExcepID = ExceptionMensage.error_id; + const ExceptionMensagePRC = ExceptionMensage.error_text; + + if (stringParsed == '400') { + this.triggerNOTF(); + this.setState({ FailArray: 'Bad credentials' }); + this.setState({ + ErrorType: stringParsed, + ExceptionID: ExcepID + }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + if (stringParsed == '404') { + this.triggerNOTF(); + this.setState({ ErrorType: stringParsed }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + } + + processSuccess() { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + + const usernameST = this.state.username; + const password = this.state.password; + + this.triggerSOTF(); + + const userID = JSON.parse(proccessForParse)['user_id']; + let avatar = JSON.parse(proccessForParse)['avatar']; + + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.5); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + + } + processRGSuccess() { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + + const usernameST = this.state.RGUsername; + + this.triggerRGSOTF(); + + const userID = JSON.parse(proccessForParse)['user_id']; + const identADMINType = JSON.parse(proccessForParse)['admin']; + const identDEVELOPERType = JSON.parse(proccessForParse)['dev']; + + let avatar = JSON.parse(proccessForParse)['avatar']; + + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.3); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + + } + + processJSON() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (DevOptions.InfiniteLogin == false) { + if (identStatus == '400') { + this.processError(); + } + + if (identStatus == '200') { + this.getUserData(); + } + } + } + + processRGJSON() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (identStatus == '400') { + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + this.processError(); + } + + if (identStatus == '200') { + this.getRGUserData(); + } + + } + + render() { + const ErrorType = this.state.ErrorType; + const MensageException = this.state.EXCPMS; + const ExceptionID = this.state.ExceptionID; + const { Panel } = Collapse; + + return ( + <div> + <div id='ErrorNotification' style={{ display: 'none', marginTop: '15%' }}><Result status="error" title="There are some problems with your operation." /></div> + <YIDForms /> + </div> + ) +} +} + + +export default YulioID diff --git a/src/components/YulioID/legacy/legacy.js b/src/components/YulioID/legacy/legacy.js new file mode 100644 index 00000000..eced2b83 --- /dev/null +++ b/src/components/YulioID/legacy/legacy.js @@ -0,0 +1,738 @@ +//****************************************| +//**** Yulio ID v1.6 *****| +//****************************************| +// +// @ Licensed by RageStudio(c) 2019 +// @ Build 03102019EU21700 F/WIAPIS +// @ https://api.ragestudio.net/RS-YIBTP +// +//****************************************| + +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'dva' +import { Button, Row, Form, Input, Drawer, Icon, Collapse, Select, Checkbox, Result, Layout, message, notification } from 'antd' +import { Trans, withI18n } from '@lingui/react' +import { setLocale } from 'utils' +import { UIFxPY, UIFxList, DevOptions, avilableSDCP } from 'ycore'; +import { endpoints } from 'ycore'; +import router from 'umi/router' +import $ from 'jquery'; +import styles from './yid.scss'; + +// import {getUserData, getUserRGData, getRegister, getAuth, resetToken, processError, processSuccess, processRGSuccess, processJSON, processRGJSON} from './loginFunctions.js'; + +import Cookies from 'universal-cookie'; +import Cryptr from 'cryptr'; + +const cookies = new Cookies(); + +const FormItem = Form.Item + + +const RenderInclude = ({data}) => {if (!data) {return null;} else {return data;}} + + + +@withI18n() +@connect(({ loading }) => ({ loading })) +@Form.create() +class YulioID extends PureComponent { + + constructor(props) { + super() + this.state = { + // Drawers Visibility (Default on False) + MainLoginVisible: false, + NOTFdrawer: false, + SOTFdrawer: false, + RGSOTFdrawer: false, + registerVisible: false, + ForggotPasswordVisible: false, + // Arrays + ErrorType: '', + FailArray: '', + username: '', + password: '', + server_key: '', + access_token: '', + user_data: [], + ExceptionID: '', + EXCPMS: '', + CompleteFORM: '', + TSDCP: '', + user_id: '', + api_response: {}, + api_response_ud: [], + RGUsername: '', + RGEmail: '', + RGPassword: '', + RGGender: '', + } + this.getAuth = this.getAuth.bind(this); + this.getRegister = this.getRegister.bind(this); + this.getUserData = this.getUserData.bind(this); + this.initRegister = this.initRegister.bind(this); + this.initFPassword = this.initFPassword.bind(this); + this.cancelRegister = this.cancelRegister.bind(this); + this.cancelRecoverPassword = this.cancelRecoverPassword.bind(this); + this.closeNOTF = this.closeNOTF.bind(this); + this.closeSOTF = this.closeSOTF.bind(this); + this.closeRGSOTF = this.closeSOTF.bind(this); + this.processSuccess = this.processSuccess.bind(this); + this.processRGSuccess = this.processSuccess.bind(this); + this.processJSON = this.processJSON.bind(this); + this.processRGJSON = this.processJSON.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); + } + // Handlers & others + handleUsername(text) { + this.setState({ username: text.target.value }) + } + handlePassword(text) { + this.setState({ password: text.target.value }) + } + handleRGUsername(text) { + this.setState({ RGUsername: text.target.value }) + } + handleRGPassword(text) { + this.setState({ RGPassword: text.target.value }) + } + handleRGEmail(text) { + this.setState({ RGEmail: text.target.value }) + } + handleRGGender(Ivalue) { + this.setState({ RGGender: Ivalue }) + } + handleFPEmail(Ivalue) { + this.setState({ FGEmail: Ivalue }) + } + + triggerNOTF() { + this.setState({ NOTFdrawer: true }); + } + closeNOTF() { + this.setState({ NOTFdrawer: false }); + } + + triggerSOTF() { + this.setState({ SOTFdrawer: true }); + } + closeSOTF() { + this.setState({ SOTFdrawer: false }); + } + + triggerRGSOTF() { + this.setState({ RGSOTFdrawer: true }); + } + closeRGSOTF() { + this.setState({ RGSOTFdrawer: false }); + } + + cancelRegister() { + this.setState({ registerVisible: false }) + } + cancelRecoverPassword(){ + this.setState({ ForggotPasswordVisible: false }) + } + + initRegister() { + var messageListener = message.loading('Initialising YulioID...', 1.5) + { messageListener } + if (DevOptions.DisableRegister == false) { + this.setState({ registerVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Register)', 2.5)) + } + } + + initFPassword() { + var messageListener = message.loading('Initialising YulioID...', 1.5) + { messageListener } + if (DevOptions.DisablePasswordRecover == false) { + this.setState({ ForggotPasswordVisible: true }) + } + else { + messageListener.then(() => message.error('Cannot connect to YulioID Services (Disabled Password Recovery)', 2.5)) + } + } + ValidateSession() { + if (DevOptions.DisableLogin == false) { + this.setState({ MainLoginVisible: true }) + } + else { + message.error('Error trying to connect to YulioID services', 2.5) + $("#ErrorNotification").css({ display: 'block' }) + } + } + + componentDidMount() { + // INIT + this.setState({ server_key: endpoints.server_key }); + this.ValidateSession(); + + const istoken = localStorage.getItem('access_token'); + const isdone = this.state.CompleteFORM; + const getSDCP = localStorage.getItem('SDCP'); + const availableToken = cookies.get('access_token') + if (availableToken) { + this.resetToken() + + } + + if (isdone == 'true') { + setTimeout(() => { location.reload() }, 3000); + } + if (!getSDCP) { + localStorage.setItem('GetNewData', true); + } + } + + resetToken() { + let _this = this; + const tojb1 = endpoints.removeToken; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'For continue your request, is necessary to login with YulioID™ again', + description: + 'LoginBridge™ report a access token expiration, and is required you for continue login again with security reasons.', + icon: <Icon type="login" style={{ color: '#108ee9' }} />, + }); + cookies.remove('access_token', { path: '/' }) + }); + } + getUserData() { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processSuccess(); + }) + } + getUserRGData() { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processRGSuccess(); + }) + + + } + + getRegister() { + $("#loadingRGspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.RGUsername; + const password = this.state.RGPassword; + const email = this.state.RGEmail; + const confirm_password = this.state.RGPassword; + const server_key = this.state.server_key; + + var form = new FormData(); + + form.append("server_key", server_key); + form.append("username", username); + form.append("email", email); + form.append("password", password); + form.append("confirm_password", confirm_password); + + var settings = { + "url": endpoints.register_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processRGJSON(); + }) + .fail(function (response) { + + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + } + + RecoverPassword(inputIO){ + const cookies = new Cookies(); + let _this = this; + const tojb1 = endpoints.resetPassword_endpoint; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + form.append("email", inputIO); + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'The instructions to recover your account have been sent to the email', + description: + 'If you cant find the email, try looking for it in the spam folder or try again', + icon: <Icon type="mail" style={{ color: '#108ee9' }} />, + }); + console.log(response) + }); + } + + getAuth() { + $("#loadingspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.username; + const password = this.state.password; + const server_key = this.state.server_key; + + var form = new FormData(); + + form.append("server_key", server_key); + form.append("username", username); + form.append("password", password); + var settings = { + "url": endpoints.auth_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processJSON(); + }) + .fail(function (response) { + + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + notification.open({ + placement: 'topLeft', + message: 'Currently our servers are having operating problems', + description: 'Please be patient until the services become available again, try again later. We apologize for the inconveniences', + icon: <Icon type="login" style={{ color: '#ff0f2f' }} /> + }), + $("#loadingspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + + + } + + processError() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer)['api_status']; + const ExceptionMensage = JSON.parse(this.state.api_response)['errors']; + const ExcepID = ExceptionMensage.error_id; + const ExceptionMensagePRC = ExceptionMensage.error_text; + + if (stringParsed == '400') { + this.triggerNOTF(); + this.setState({ FailArray: 'Bad credentials' }); + this.setState({ + ErrorType: stringParsed, + ExceptionID: ExcepID + }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + if (stringParsed == '404') { + this.triggerNOTF(); + this.setState({ ErrorType: stringParsed }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + } + + processSuccess() { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + + const usernameST = this.state.username; + + this.triggerSOTF(); + + const userID = JSON.parse(proccessForParse)['user_id']; + let avatar = JSON.parse(proccessForParse)['avatar']; + + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.5); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + + } + processRGSuccess() { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + + const usernameST = this.state.RGUsername; + + this.triggerRGSOTF(); + + const userID = JSON.parse(proccessForParse)['user_id']; + const identADMINType = JSON.parse(proccessForParse)['admin']; + const identDEVELOPERType = JSON.parse(proccessForParse)['dev']; + + let avatar = JSON.parse(proccessForParse)['avatar']; + + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.3); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + + } + + processJSON() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (DevOptions.InfiniteLogin == false) { + if (identStatus == '400') { + this.processError(); + } + + if (identStatus == '200') { + this.getUserData(); + } + } + } + + processRGJSON() { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (identStatus == '400') { + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + this.processError(); + } + + if (identStatus == '200') { + this.getRGUserData(); + } + + } + + handleKeyDown = (e) => { + const _this = this; + if (e.key === 'Enter') { + this.getAuth + } + } + + + + + render() { + const { loading, form, i18n, include} = this.props + const ErrorType = this.state.ErrorType; + const MensageException = this.state.EXCPMS; + const ExceptionID = this.state.ExceptionID; + const { Panel } = Collapse; + + const { getFieldDecorator } = this.props.form; + + return ( + <div> + <div id='ErrorNotification' style={{ display: 'none', marginTop: '15%' }}><Result status="error" title="There are some problems with your operation." /></div> + + + {/* LOGIN SECTION */} + <Drawer width={520} closable={false} visible={this.state.MainLoginVisible}> + + <main className={styles.mainlp}> + <section className={styles.forms}> + + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Welcome Back !</h1> + + + <form className={styles.formlogin}> + + <div className={styles.input__wrapper}> + + <label className={styles.labelform}><Icon type="user" style={{ fontSize: '15px' }} /> Username</label> + <FormItem hasFeedback>{getFieldDecorator('Username', { rules: [{ required: true }] })( + <input className={styles.inputform} type="text" onKeyDown={this.handleKeyDown} placeholder="Username" onChange={(text) => { this.handleUsername(text) }} /> + )} + </FormItem> + </div> + + <div className={styles.input__wrapper}> + <label className={styles.labelform}><Icon type="unlock" style={{ fontSize: '15px' }} /> Password</label> + <FormItem hasFeedback>{getFieldDecorator('Password', { rules: [{ required: true }] })( + <input className={styles.inputform} type="password" onKeyDown={this.handleKeyDown} dplaceholder="Password (At least 8 characters)" onChange={(text) => { this.handlePassword(text) }} /> + )} + </FormItem> + </div> + + <div style={{ margin: 'auto' }}><a className={styles.buttonlp} id="login" onClick={this.getAuth} >Login</a></div> + <h2 style={{ textAlign: 'center', margin: '8px', color: '#666' }}>Or</h2> + <div style={{ float: 'left' }}><Button type="dashed" onClick={this.initFPassword} style={{ top: '8px' }}><Icon type="exclamation-circle" /> Forgotten password</Button></div> + <div style={{ float: 'right' }}><Button type="dashed" onClick={this.initRegister} style={{ top: '8px' }}><Icon type="user-add" /> Create an account</Button></div><br/><br/> + <div style={{ textAlign: 'center', margin: '20px' }}> <RenderInclude data={include} /></div> + <div className={styles.spinner__wrapper} id="loadingspn"> + <div><Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin /></div> + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>Wait a sec...</h6></div> + + </div> + + </div> + </form> + + </section> + + + + </main> + + </Drawer> + + {/* REGISTER SECTION */} + <Drawer width={680} closable={true} onClose={this.cancelRegister} visible={this.state.registerVisible}> + <main className={styles.mainlp}> + <section className={styles.forms}> + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Register</h1> + <h3>Wow congratulations, very soon you will begin to discover rStudio, but first you will have to start by filling out this form</h3> + <form className={styles.formlogin}> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Choose your Username</label> + <FormItem hasFeedback>{getFieldDecorator('rgUsername', { rules: [{ required: true }] })( + <Input type="text" prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" onChange={(text) => { this.handleRGUsername(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Fill with your email</label> + <FormItem hasFeedback>{getFieldDecorator('rgEmail', { rules: [{ required: true }] })( + <Input type="text" prefix={<Icon type="link" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Email" onChange={(text) => { this.handleRGEmail(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + <label className={styles.labelform}> Fill with your password</label> + <FormItem hasFeedback>{getFieldDecorator('rgPassword', { rules: [{ required: true }] })( + <Input type="password" prefix={<Icon type="key" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Password" onChange={(text) => { this.handleRGPassword(text) }} /> + )} + </FormItem> + </div> + <div className={styles.inputRG__wrapper}> + </div> + <div className={styles.TOSAccept}><span><span style={{ color: 'red', fontSize: '17px' }}>*</span> Clicking the register button you accept our <a href="#">terms and conditions</a></span> </div> + <a className={styles.buttonlp} id="register" onClick={this.getRegister}>Register</a> + <div className={styles.spinner__wrapper} id="loadingRGspn"> + <div style={{ position: 'absolute', marginLeft: '86%', marginTop: '-65%' }}><Icon type="loading" style={{ fontSize: 24 }} spin /></div> + <div> + <div><Icon style={{ fontSize: '160px', margin: '30px', color: '#5B2A86' }} type="smile" /></div> + <h6 className={styles.h6lp} style={{ textAlign: 'center' }}>Ok thanks, wait a minute...</h6> + </div> + </div> + </form> + </section> + </main> + </Drawer> + + {/* FORGOTTEN PASSWORD SECTION */} + <Drawer width={420} closable={true} onClose={this.cancelRecoverPassword} visible={this.state.ForggotPasswordVisible}> + <main className={styles.mainlp}> + <section className={styles.forms}> + <h6 className={styles.h6lp}>YulioID™</h6> + <h1 className={styles.h1lp}>Forgotten Password!</h1> + <h3>To recover your account enter the email used to register</h3> + <form className={styles.formlogin}> + <div className={styles.input__wrapper}> + <label className={styles.labelform}><Icon type="mail" style={{ fontSize: '15px' }} /> Email</label> + <FormItem hasFeedback>{getFieldDecorator('Email', { rules: [{ required: true }] })( + <input className={styles.inputform} type="text" placeholder="myaccount@example.com" onChange={(text) => { this.handleFPEmail(text) }} /> )} + </FormItem> + </div> + {/* <div style={{ margin: 'auto' }}><a className={styles.buttonlp} id="login" onClick={this.RecoverPassword(this.state.FGEmail)}>Recover</a></div> */} + <div className={styles.spinner__wrapper} id="loadingspn"> + <div><Icon type="loading" style={{ fontSize: 24, margin: '13px' }} spin /></div> + <div> + <br /><br /><br /> + <div style={{ margin: 'auto' }}><h6 className={styles.h6lp} style={{ textAlign: 'center', marginTop: '15%' }}>Wait a sec...</h6></div> + </div> + </div> + </form> + </section> + </main> + </Drawer> + + {/* NOTF */} + <Drawer width={320} closable={false} visible={this.state.NOTFdrawer} > + <div style={{ textAlign: 'center', color: 'orange' }} ><Icon type="warning" style={{ fontSize: '230px' }} /> + <h2 className={styles.h2lp}> {this.state.FailArray} </h2> + <h4 className={styles.apierrort}> {MensageException} </h4> <hr /> + <div id="details-collapse" style={{ textAlign: 'center' }}> + <Collapse bordered={false} defaultActiveKey={['0']} expandIcon={({ isActive }) => <Icon type="caret-right" rotate={isActive ? 90 : 0} />}> + <Panel header="Details" key="1" style={{ borderRadius: 4, marginBottom: 24, border: 0, overflow: 'hidden', }}> + <Icon type="exception" /> + <h6>STATUS HANDLER => {this.state.ErrorType} </h6> + <h6>EXCEPTION => {this.state.api_response} </h6> + <h6>EXCEPTION MENSAGE => {MensageException}</h6> + <h6><strong>ID {ExceptionID}</strong></h6> + </Panel> + </Collapse> + <hr /><Button type="danger" onClick={this.closeNOTF}>TRY AGAIN</Button> + </div> + </div> + </Drawer> + + + {/* SOTF */} + <Drawer width={320} closable={false} visible={this.state.SOTFdrawer}> + <div style={{ textAlign: 'center', color: '#4BB543' }} ><Icon type="check" style={{ fontSize: '200px' }} /> + <h2 className={styles.h2lp} style={{ color: '#4BB543' }} > Success </h2> + <h4>Please wait while process your data ...</h4> + </div> + </Drawer> + {/* RGSOTF */} + <Drawer width={320} closable={false} visible={this.state.RGSOTFdrawer}> + <div style={{ textAlign: 'center', color: 'green' }} > + <Icon type="check" style={{ fontSize: '200px' }} /> + <h2 className={styles.h2lp} style={{ color: 'green' }} > Registered </h2> + <h4 className={styles.apierrort}> Welcome to Dashboard, you will start discovering now</h4> + <h4>Please check your new data while we are process you ...</h4> + </div> + </Drawer> + </div> + ) + } +} + +YulioID.propTypes = { + form: PropTypes.object, + dispatch: PropTypes.func, + loading: PropTypes.object, + include: PropTypes.object, +} + +export default YulioID diff --git a/src/components/YulioID/legacy/model.js b/src/components/YulioID/legacy/model.js new file mode 100644 index 00000000..cd0694ae --- /dev/null +++ b/src/components/YulioID/legacy/model.js @@ -0,0 +1,29 @@ +import { router, pathMatchRegexp } from 'utils' +import api from 'api' + +const { legacyloginUser } = api + +export default { + namespace: 'login', + + state: {}, + + effects: { + *login({ payload }, { put, call, select }) { + const data = yield call(legacyloginUser, payload) + const { locationQuery } = yield select(_ => _.app) + if (data.success) { + const { from } = locationQuery + yield put({ type: 'app/query' }) + if (!pathMatchRegexp('/login', from)) { + if (from === '/') router.push('/dashboard') + else router.push(from) + } else { + router.push('/dashboard') + } + } else { + throw data + } + }, + }, +} diff --git a/src/components/YulioID/legacy/ycore_sdcp.js b/src/components/YulioID/legacy/ycore_sdcp.js new file mode 100644 index 00000000..192fad8b --- /dev/null +++ b/src/components/YulioID/legacy/ycore_sdcp.js @@ -0,0 +1,431 @@ +//****************************************| +//**** yCore SDCP v1.6 *****| +//****************************************| +// +// @ Licensed by RageStudio(c) 2019 +// @ Build 03102019EU21700 F/WIAPIS +// @ https://api.ragestudio.net/RS-YIBTP +// +//****************************************| + +import React, { PureComponent } from 'react' +import { Form, Icon, message, notification } from 'antd' +import { UIFxPY, UIFxList, DevOptions } from 'ycoreLegacy'; +import { endpoints } from 'ycoreLegacy'; +import $ from 'jquery'; + +import Cookies from 'universal-cookie'; +import Cryptr from 'cryptr'; + +const cookies = new Cookies(); + +const FormItem = Form.Item + +export class SDCP extends PureComponent { + constructor() { + super() + this.state = { + // Arrays + ErrorType: '', + FailArray: '', + username: '', + password: '', + server_key: '', + access_token: '', + user_data: [], + ExceptionID: '', + EXCPMS: '', + CompleteFORM: '', + TSDCP: '', + user_id: '', + api_response: {}, + api_response_ud: [], + RGUsername: '', + RGEmail: '', + RGPassword: '', + RGGender: '', + } + this.getAuth = this.getAuth.bind(this); + this.getRegister = this.getRegister.bind(this); + this.getUserData = this.getUserData.bind(this); + this.initRegister = this.initRegister.bind(this); + this.initFPassword = this.initFPassword.bind(this); + this.cancelRegister = this.cancelRegister.bind(this); + this.cancelRecoverPassword = this.cancelRecoverPassword.bind(this); + this.closeNOTF = this.closeNOTF.bind(this); + this.closeSOTF = this.closeSOTF.bind(this); + this.closeRGSOTF = this.closeSOTF.bind(this); + this.processSuccess = this.processSuccess.bind(this); + this.processRGSuccess = this.processSuccess.bind(this); + this.processJSON = this.processJSON.bind(this); + this.processRGJSON = this.processJSON.bind(this); + } + + + initRegister(inputIO) { + var messageListener = message.loading('Initialising YulioID Service..', 2.5) + { messageListener } + if (DevOptions.DisableRegister == false) { + this.setState({ registerVisible: true }) + } + else { + messageListener.then(() => message.error('Error trying to connect to YulioID services', 2.5)) + } + } + + initFPassword(inputIO) { + var messageListener = message.loading('Initialising YulioID Service..', 2.5) + { messageListener } + if (DevOptions.DisablePasswordRecover == false) { + this.setState({ ForggotPasswordVisible: true }) + } + else { + messageListener.then(() => message.error('Error trying to connect to YulioID services', 2.5)) + } + } + ValidateSession(inputIO) { + if (DevOptions.DisableLogin == false) { + this.setState({ MainLoginVisible: true }) + } + else { + message.error('Error trying to connect to YulioID services', 2.5) + $("#ErrorNotification").css({ display: 'block' }) + } + } + + componentDidMount(inputIO) { + // INIT + this.setState({ server_key: endpoints.server_key }); + this.ValidateSession(); + + const istoken = localStorage.getItem('access_token'); + const isdone = this.state.CompleteFORM; + const getSDCP = localStorage.getItem('SDCP'); + const availableToken = cookies.get('access_token') + if (availableToken) { + this.resetToken() + } + + if (isdone == 'true') { + setTimeout(() => { location.reload() }, 3000); + } + if (!getSDCP) { + localStorage.setItem('GetNewData', true); + } + } + + resetToken(inputIO) { + let _this = this; + const tojb1 = endpoints.removeToken; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'For continue your request, is necessary to login with YulioID™ again', + description: + 'LoginBridge™ report a access token expiration, and is required you for continue login again with security reasons.', + icon: <Icon type="login" style={{ color: '#108ee9' }} />, + }); + cookies.remove('access_token', { path: '/' }) + }); + } + getUserData(inputIO) { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processSuccess(); + }) + } + getUserRGData(inputIO) { + const nonProccesContainer = this.state.api_response; + const IdFromLRApi = JSON.parse(nonProccesContainer)['user_id']; + const getStoragedToken = JSON.parse(nonProccesContainer)['access_token']; + var form2 = new FormData(); + form2.append("server_key", endpoints.server_key); + form2.append("fetch", "user_data,email,username,avatar"); + form2.append("user_id", IdFromLRApi); + let _this = this; + const yCore_GUDEP = endpoints.get_userData_endpoint; + let urlOBJ = `${yCore_GUDEP}${getStoragedToken}`; + var settings2 = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form2 + }; + $.ajax(settings2) + .done(function (response2) { + _this.setState({ api_response_ud: response2 }), + _this.processRGSuccess(); + }) + } + + getRegister(inputIO) { + $("#loadingRGspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.RGUsername; + const password = this.state.RGPassword; + const email = this.state.RGEmail; + const confirm_password = this.state.RGPassword; + const server_key = this.state.server_key; + var form = new FormData(); + form.append("server_key", server_key); + form.append("username", username); + form.append("email", email); + form.append("password", password); + form.append("confirm_password", confirm_password); + var settings = { + "url": endpoints.register_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processRGJSON(); + }) + .fail(function (response) { + + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + } + + RecoverPassword(inputIO){ + const cookies = new Cookies(); + let _this = this; + const tojb1 = endpoints.resetPassword_endpoint; + const tobj2 = cookies.get('access_token') + let urlOBJ = `${tojb1}${tobj2}`; + UIFxPY(UIFxList.notifyWarning) + var form = new FormData(); + form.append("server_key", endpoints.server_key); + form.append("email", inputIO); + + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + $.ajax(settings).done(function (response) { + notification.open({ + placement: 'topLeft', + message: 'The instructions to recover your account have been sent to the email', + description: + 'If you cant find the email, try looking for it in the spam folder or try again', + icon: <Icon type="mail" style={{ color: '#108ee9' }} />, + }); + console.log(response) + }); + } + + getAuth(inputIO) { + $("#loadingspn").css({ opacity: 1, "z-index": 5 }); + const username = this.state.username; + const password = this.state.password; + const server_key = this.state.server_key; + + var form = new FormData(); + + form.append("server_key", server_key); + form.append("username", username); + form.append("password", password); + var settings = { + "url": endpoints.auth_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form, + }; + let _this = this; + $.ajax(settings) + .done(function (response) { + _this.setState({ api_response: response }), + _this.processJSON(); + }) + .fail(function (response) { + _this.setState({ + FailArray: 'Server Failure', + ErrorType: '1', + api_response: 'Cannot catch response, Error 500', + ExceptionID: '500', + EXCPMS: 'Cannot catch response, Error 500', + + }), + notification.open({ + placement: 'topLeft', + message: 'Currently our servers are having operating problems', + description: 'Please be patient until the services become available again, try again later. We apologize for the inconveniences', + icon: <Icon type="login" style={{ color: '#ff0f2f' }} /> + }), + $("#loadingspn").css({ opacity: 0, "z-index": -1 }), + _this.triggerNOTF(); + }) + } + + processError(inputIO) { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer)['api_status']; + const ExceptionMensage = JSON.parse(this.state.api_response)['errors']; + const ExcepID = ExceptionMensage.error_id; + const ExceptionMensagePRC = ExceptionMensage.error_text; + if (stringParsed == '400') { + this.triggerNOTF(); + this.setState({ FailArray: 'Bad credentials' }); + this.setState({ + ErrorType: stringParsed, + ExceptionID: ExcepID + }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + if (stringParsed == '404') { + this.triggerNOTF(); + this.setState({ ErrorType: stringParsed }); + $("#loadingspn").css({ opacity: 0, "z-index": -1 }); + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }); + this.setState({ EXCPMS: ExceptionMensagePRC }); + } + } + + processSuccess(inputIO) { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + const usernameST = this.state.username; + const password = this.state.password; + this.triggerSOTF(); + const userID = JSON.parse(proccessForParse)['user_id']; + let avatar = JSON.parse(proccessForParse)['avatar']; + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.5); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + + } + processRGSuccess(inputIO) { + // CREATE SDCP PACKAGE + const nonProccesContainer = this.state.api_response; + const accessTokesParsed = JSON.parse(this.state.api_response)['access_token']; + const userDataParsed = JSON.parse(this.state.api_response_ud)['user_data']; + this.setState({ user_data: userDataParsed }); + const proccessForParse = JSON.stringify(this.state.user_data); + const icryptr = new Cryptr(accessTokesParsed); + const encryptedString = icryptr.encrypt(proccessForParse); + this.setState({ access_token: accessTokesParsed, TSDCP: encryptedString }); + cookies.set('access_token', accessTokesParsed, { path: '/' }); + cookies.set('last_api_response', nonProccesContainer, { path: '/' }); + cookies.set('last_api_response_ud', (this.state.TSDCP), { path: '/' }); + localStorage.setItem('UIfx', 0.6); + localStorage.setItem('SDCP', (this.state.TSDCP)); + const usernameST = this.state.RGUsername; + this.triggerRGSOTF(); + const userID = JSON.parse(proccessForParse)['user_id']; + const identADMINType = JSON.parse(proccessForParse)['admin']; + const identDEVELOPERType = JSON.parse(proccessForParse)['dev']; + let avatar = JSON.parse(proccessForParse)['avatar']; + const { dispatch } = this.props; + let dispatchPayloadValue = { userID, usernameST, avatar, accessTokesParsed }; + setTimeout(function () { dispatch({ type: 'login/login', payload: dispatchPayloadValue }) }, 1300) + UIFxPY(UIFxList.notifySuccess, 0.3); + console.log('%c 🎉 Your data has been storaged in SDCP with this values 🎉 =>', 'background: orange; font-size: 16px; color: white; display: block;', dispatchPayloadValue); + } + + processJSON(inputIO) { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (DevOptions.InfiniteLogin == false) { + if (identStatus == '400') { + this.processError(); + } + if (identStatus == '200') { + this.getUserData(); + } + } + } + + processRGJSON(inputIO) { + const nonProccesContainer = this.state.api_response; + const stringParsed = JSON.parse(nonProccesContainer); + const identStatus = JSON.parse(nonProccesContainer)['api_status']; + if (identStatus == '400') { + $("#loadingRGspn").css({ opacity: 0, "z-index": -1 }), + this.processError(); + } + if (identStatus == '200') { + this.getRGUserData(); + } + } +} diff --git a/src/components/YulioID/legacy/yid.scss b/src/components/YulioID/legacy/yid.scss new file mode 100644 index 00000000..6cb1f83d --- /dev/null +++ b/src/components/YulioID/legacy/yid.scss @@ -0,0 +1,1285 @@ +/* (2.0) YulioID V2 */ + +@import url('https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css'); +@import url('https://fonts.googleapis.com/css?family=Poppins:300,300i,500,500i,700'); + + .mainlp { + --neutralShade0: #f8f8f8; + --neutralShade1: #f2f2f2; + --neutralShade2: #e8e9e9; + --neutralShade3: #d1d3d4; + --neutralShade4: #babdbf; + --neutralShade5: #808488; + --neutralShade6: #666a6d; + --neutralShade7: #4d5052; + --neutralShade8: #212122; + --grayColor: #999; + --lightGrayColor: #ddd; + --borderRadius: 6px; + --boxShadow: 0 2px 5px rgba(#333, 0.2); + } + + /*overall layout*/ + .mainlp { + width: 90%; + max-width: 1050px; + margin: 3em auto 0; + display: grid; + grid: repeat(5, fit-content(300px))/100%; + color: var(--foregroundColor); + text-align: left; + } + + .mainlp .sectionlp { + border: 1px solid var(--accentColor); + position: relative; + padding: 40px 40px 50px; + } + .mainlp .sectionlp > h6 { + color: var(--accentColor); + background: var(--canvasColor); + position: absolute; + top: -10px; + left: 20px; + padding: 0 10px; + } + .mainlp .sectionlp .h6lp.subheader { + color: var(--grayColor); + margin-top: 20px; + margin-bottom: 20px; + width: 100%; + } + + @media (max-width: 992px) { + section:not(:last-child) { + border-width: 0 0 1px; + } + + section:last-child { + border-width: 0; + } + } + @media (min-width: 992px) { + main { + grid: repeat(9, auto)/45% 1fr 45%; + grid-auto-flow: dense; + } + + .media-card-1 { + grid-column: 1 / 2; + border-width: 1px 0; + } + + .media-card-2 { + grid-column: 2 / 4; + border-width: 1px 0 1px 1px; + } + + .media-card-3 { + grid-column: 1 / 4; + border-width: 0; + } + + .filter-section { + grid-column: 3 / 4; + grid-row: 1 / 2; + border-width: 0 0 0 1px; + } + + .well-cta-1 { + grid-row: 3; + grid-column: 1 / 3; + border-width: 1px 1px 0 0; + } + + .well-cta-2 { + grid-row: 2; + grid-column: 2 / 4; + border-width: 1px 0 0; + } + + .tables { + grid-row: 4; + grid-column: 1 / -1; + border-width: 1px 0 0; + } + + .forms { + grid-column: 1 / 3; + border-width: 0; + } + + .comments { + grid-row: 2; + grid-column: 1 / 2; + border-width: 1px 1px 0 0; + padding-top: 60px; + } + + .modals { + grid-row: 3; + grid-column: 3 / 4; + justify-content: center; + border-width: 1px 0 0; + } + } + + + /*checkboxes*/ + input:disabled ~ * { + opacity: 0.3; + user-select: none; + pointer-events: none; + } + + .checkboxtoggle input { + display: none; + } + .checkboxtoggle label { + outline: 0; + display: block; + width: 45px; + height: 16px; + background: var(--grayColor); + position: relative; + cursor: pointer; + border-radius: 2em; + padding: 2px; + transition: all 0.4s ease; + margin: 0; + } + .checkboxtoggle .labellp:after { + position: relative; + display: block; + content: ""; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + transition: all 0.2s ease; + border: 1px solid var(--grayColor); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + left: -4px; + top: -5px; + } + .checkboxtoggle input:checked + .labellp { + background: var(--accent2Color); + } + .checkboxtoggle input:checked + .labellp:after { + left: 52%; + } + + .checkbox { + position: relative; + user-select: none; + margin-bottom: 10px; + } + .checkbox input { + display: none; + } + .checkbox .labellp { + position: relative; + vertical-align: middle; + cursor: pointer; + font-weight: 500; + padding-left: 35px; + } + .checkbox .spanlp.box { + display: inline-block; + width: 20px; + border-radius: var(--borderRadius); + border: 1px solid var(--grayColor); + width: 24px; + height: 24px; + vertical-align: middle; + margin-right: 3px; + transition: 0.3s ease; + position: absolute; + left: 0; + } + .checkbox .spanlp.box:before, .checkbox .spanlp.box:after { + content: ""; + position: absolute; + width: 4px; + height: 16px; + border-radius: 40px; + background: var(--backgroundColor); + transition: all 0.3s ease; + } + .checkbox .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(0); + } + .checkbox .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(0); + } + .checkbox input:checked + .labellp .spanlp.box { + background: var(--accent2Color); + border-color: var(--accent2Color); + } + .checkbox input:checked + .labellp .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(1); + } + .checkbox input:checked + .labellp .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(1); + } + .checkbox input:disabled:checked + .spanlp.box { + background: var(--grayColor); + border: var(--grayColor); + } + .checkbox input:disabled:checked ~ .labellp:before, .checkbox input:disabled:checked ~ .labellp:after { + background: black; + } + + /*buttons & links*/ + .links__sec { + margin: 10px 0 30px; + } + .links a.link { + display: inline; + margin: 10px 30px 5px 0; + border-bottom: 2px dashed; + font-weight: 500; + line-height: 2.5; + cursor: pointer; + color: var(--neutralShade5); + } + .links a.link:hover, .links a.link.hover { + color: var(--neutralShade6); + border-bottom: 2px solid; + } + .links a.link.primary { + color: var(--primaryColor); + } + .links a.link.primary:hover, .links a.link.primary.hover { + color: var(--primaryShade5); + } + .links a.link.secondary { + color: var(--secondaryColor); + } + .links a.link.secondary:hover, .links a.link.secondary.hover { + color: var(--secondaryShade5); + } + + .buttons { + display: flex; + flex-wrap: wrap; + align-items: center; + } + .buttons > * { + flex: 1 1 calc(50% - 20px); + margin-top: 20px; + } + .buttons > *:nth-child(odd) { + margin-right: 20px; + } + + a.buttonlp, + input.buttonlp, + .buttonlp { + outline: none; + width: 100%; + text-align: center; + display: inline-block; + border: none; + font: 500 16px/1 "Poppins", sans-serif; + padding: 20px; + cursor: pointer; + border-radius: var(--borderRadius); + background: var(--primaryColor); + color: var(--backgroundColor); + position: relative; + top: 0; + transition: 0.2s ease; + } + a.buttonlp:hover, a.buttonlp.hover, + input.buttonlp:hover, + input.buttonlp.hover, + .buttonlp:hover, + .buttonlp.hover { + top: -3px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); + } + a.buttonlp:active, a.buttonlp.active, + input.buttonlp:active, + .input.buttonlp.active, + .buttonlp:active, + .buttonlp.active { + background: var(--primaryShade4); + outline: none; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + top: 0; + } + a.buttonlp.disabled, + input.buttonlp.disabled, + .buttonlp.disabled { + opacity: 0.4; + user-select: none; + pointer-events: none; + } + a.buttonlp.medium, + input.buttonlp.medium, + .buttonlp.medium { + padding: 15px 18px; + width: auto; + } + a.buttonlp.small, + input.buttonlp.small, + .buttonlp.small { + padding: 10px 12px; + width: auto; + font-size: 14px; + font-weight: 500; + } + a.buttonlp.secondary, + input.buttonlp.secondary, + .buttonlp.secondary { + background: var(--secondaryColor); + } + a.buttonlp.secondary:active, a.buttonlp.secondary:focus, a.buttonlp.secondary.active, + input.buttonlp.secondary:active, + input.buttonlp.secondary:focus, + input.buttonlp.secondary.active, + .buttonlp.secondary:active, + .buttonlp.secondary:focus, + .buttonlp.secondary.active { + background: var(--secondaryShade4); + outline: none; + } + a.buttonlp.accent, + input.buttonlp.accent, + .buttonlp.accent { + background: var(--accentColor); + } + a.buttonlp.accent:active, a.buttonlp.accent:focus, a.buttonlp.accent.active, + input.buttonlp.accent:active, + input.buttonlp.accent:focus, + input.buttonlp.accent.active, + .buttonlp.accent:active, + .buttonlp.accent:focus, + .buttonlp.accent.active { + background: var(--accentShade4); + } + a.buttonlp.accent2, + input.buttonlp.accent2, + .buttonlp.accent2 { + background: var(--accent2Color); + } + a.buttonlp.accent2:active, a.buttonlp.accent2:focus, a.buttonlp.accent2.active, + input.buttonlp.accent2:active, + input.buttonlp.accent2:focus, + input.buttonlp.accent2.active, + .buttonlp.accent2:active, + .buttonlp.accent2:focus, + .buttonlp.accent2.active { + background: var(--accent2Shade4); + } + a.buttonlp.accent3, + input.buttonlp.accent3, + .buttonlp.accent3 { + background: var(--accent3Color); + } + a.buttonlp.accent3:active, a.buttonlp.accent3:focus, a.buttonlp.accent3.active, + input.buttonlp.accent3:active, + input.buttonlp.accent3:focus, + input.buttonlp.accent3.active, + .buttonlp.accent3:active, + .buttonlp.accent3:focus, + .buttonlp.accent3.active { + background: var(--accent3Shade4); + } + + /*inputs*/ + .input__wrapper { + margin-bottom: 10px; + } + .inputRG__wrapper { + margin-bottom: 0px; + } + + .labelform { + font-weight: 500; + display: block; + margin-bottom: 5px; + } + + input.inputform, + select, + textarea { + height: 50px; + font-size: 16px; + border: 2px solid var(--neutralShade3); + width: 100%; + padding: 12px; + font-family: "Poppins"; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + background: var(--backgroundColor); + } + input.inputform:focus, input.inputform.active, + select:focus, + select.active, + textarea:focus, + textarea.active { + outline: none; + border-color: var(--primaryColor); + } + input.inputform:disabled, + select:disabled, + textarea:disabled { + cursor: not-allowed; + background: var(--neutralShade1); + opacity: 0.6; + } + + input.inputform.input { + height: 56px; + font-size: 18px; + padding: 15px; + } + + .TOSAccept { + margin: 7px; + } + .TOSAccept span::first-letter { + color: blue; + } + + /*badges*/ + .badge { + display: inline-block; + padding: 6px 12px; + border-radius: 50px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; + } + + .alert { + margin-bottom: 15px; + display: block; + padding: 10px 15px; + border-radius: var(--borderRadius); + font-weight: 500; + position: relative; + cursor: pointer; + } + .alert.non-collapsible:before, .alert.non-collapsible:after { + content: none; + } + .alert:before, .alert:after { + content: ""; + position: absolute; + width: 4px; + height: 16px; + border-radius: 40px; + right: 30px; + top: 8px; + } + .alert:before { + transform: rotate(45deg) translateY(-5.5px) translateX(13.5px); + } + .alert:after { + transform: rotate(-45deg) translateY(13.5px) translateX(5.5px); + } + + .status-primary { + background: var(--primaryShade1); + color: var(--primaryShade5); + } + .status-primary:before, .status-primary:after { + background: var(--primaryShade5); + } + + .status-secondary { + background: var(--secondaryShade1); + color: var(--secondaryShade5); + } + .status-secondary:before, .status-secondary:after { + background: var(--secondaryShade5); + } + + .status-info { + background: var(--accentShade1); + color: var(--accentShade5); + } + .status-info:before, .status-info:after { + background: var(--accentShade5); + } + + .status-success { + background: var(--accent2Shade1); + color: var(--accent2Shade5); + } + .status-success:before, .status-success:after { + background: var(--accent2Shade5); + } + + .status-error { + background: var(--accent3Shade1); + color: var(--accent3Shade5); + } + .status-error:before, .status-error:after { + background: var(--accent3Shade5); + } + + /*tooltips*/ + .tooltip { + cursor: pointer; + position: relative; + display: block; + width: 100%; + text-align: center; + z-index: 10; + } + .tooltip .spanlp { + border-bottom: 1px dotted; + } + .tooltip:after { + content: attr(data-tooltip); + background: var(--neutralShade2); + max-width: 90%; + width: auto; + position: absolute; + left: 0; + right: 0; + margin: auto; + opacity: 0; + height: auto; + font-size: 14px; + padding: 10px; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + text-align: center; + } + .tooltip.dark:after { + background: var(--neutralShade7); + color: var(--backgroundColor); + } + .tooltip.top:after { + bottom: 80%; + transition: opacity 0.3s ease 0.3s, bottom 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.3s; + } + .tooltip.top:hover:after, .tooltip.top.hovered:after { + bottom: 130%; + opacity: 1; + } + .tooltip.bottom:after { + top: 80%; + transition: opacity 0.3s ease 0.3s, top 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.3s; + } + .tooltip.bottom:hover:after, .tooltip.bottom.hovered:after { + top: 130%; + opacity: 1; + } + + /*spinner*/ + .spinner + .labellp { + font-size: 14px; + font-weight: 500; + margin-top: 8px; + display: inline-block; + text-transform: uppercase; + color: var(--primaryShade4); + } + + .spinner1 .spinner { + max-width: 50px; + margin: auto; + height: 20px; + position: relative; + } + .spinner1 .spinner:after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryColor); + animation: spinnerLeftRight 1s infinite; + } + .spinner1 .spinner:before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryShade2); + opacity: 1; + animation: spinnerLeftRight 1s infinite 0.06s; + } + + @keyframes spinnerLeftRight { + 0% { + left: 85%; + } + 50% { + left: -10%; + } + 100% { + left: 85%; + } + } + + + #sunset + .labellp { + background: linear-gradient(to right, #ff9557 50%, #ffcc67 50%); + } + .mainlp { + --canvasColor: #f9f9f9; + --backgroundColor: #fff; + --foregroundColor: #111; + --primaryColor: #373F51; + --primaryShade1: #ffe2d1; + --primaryShade2: #ffceb2; + --primaryShade3: #ffb184; + --primaryShade4: #e88850; + --primaryShade5: #d17a48; + --secondaryColor: #ffcc67; + --secondaryShade1: #fff1d5; + --secondaryShade2: #ffde9e; + --secondaryShade3: #ffd074; + --secondaryShade4: #e8ba5e; + --secondaryShade5: #ba954b; + --accentColor: #4e5166; + --accentShade1: #cecfd5; + --accentShade2: #aeafb9; + --accentShade3: #8e909d; + --accentShade4: #6e7081; + --accentShade5: #404354; + --accent2Color: #588b8b; + --accent2Shade1: #c2d4d4; + --accent2Shade2: #a3bfbf; + --accent2Shade3: #85aaaa; + --accent2Shade4: #507f7f; + --accent2Shade5: #497272; + --accent3Color: #fe5f55; + --accent3Shade1: #fec4c1; + --accent3Shade2: #fea7a2; + --accent3Shade3: #fe7c73; + --accent3Shade4: #e7574e; + --accent3Shade5: #b9463e; + } + + + + /* PROFILE CARDS */ + .profile { + position: relative; + background: var(--backgroundColor); + color: var(--foregroundColor); + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + border-radius: 10px; + overflow: hidden; + transition: .2s ease; + display: grid; + grid: 200px repeat(5, auto)/100%; + } + .profile__image img { + width: 100%; + height: 100%; + object-fit: cover; + border-bottom: 7px solid var(--secondaryColor); + } + .profile__info { + padding: 20px 25px 0; + } + .profile__stats { + padding: 5px 25px; + } + .profile__stats__title { + color: var(--grayColor); + text-transform: uppercase; + font-size: 16px; + } + .profile__cta { + padding: 0 25px 25px; + } + .profile a:hover { + top: 0; + box-shadow: none; + background: var(--primaryShade4); + } + .profile a:active, .profile a:focus { + top: 0; + box-shadow: none; + background: var(--primaryShade5); + } + + @media (min-width: 500px) { + .profile-default { + min-width: 500px; + max-width: 450px; + margin: auto; + overflow: hidden; + grid: 340px auto auto/repeat(3, minmax(80px, 1fr)); + grid-gap: 10px; + } + .profile-default .profile__image { + grid-column: span 3; + } + .profile-default .profile__info { + grid-column: span 3; + } + .profile-default .profile__stats { + padding: 5px 25px; + } + .profile-default .profile__cta { + grid-column: span 3; + } + } + @media (min-width: 768px) { + .profile-long { + grid-template-columns: 150px repeat(3, 1fr) auto; + grid-template-rows: auto auto; + width: 100%; + padding-right: 20px; + } + .profile-long .profile__image { + grid-column: 1 / 2; + grid-row: 1 / 3; + margin-right: 20px; + } + .profile-long .profile__image img { + border-radius: 10px 0 0 10px; + border: none; + } + .profile-long .profile__info { + grid-column: 2 / 6; + grid-row: 1; + padding: 20px 20px 15px 0; + } + .profile-long .profile__stats { + min-width: 100px; + padding: 15px 0; + border-top: 0.5px solid var(--grayColor); + grid-row: 2 / 3; + } + .profile-long .profile__stats:nth-child(3) { + grid-column: 2 / 3; + } + .profile-long .profile__stats:nth-child(4) { + grid-column: 3 / 4; + } + .profile-long .profile__stats:nth-child(5) { + grid-column: 4 / 5; + } + .profile-long .profile__cta { + grid-row: 2 / 3; + grid-column: 5 / 6; + border-top: 0.5px solid var(--grayColor); + padding: 15px 0 0; + } + } + .profile-imgonly { + border-radius: 10px; + overflow: hidden; + min-width: 250px; + width: 100%; + grid: 480px 0px / 100%; + } + .profile-imgonly:hover { + grid: 434px 56px / 100%; + } + .profile-imgonly .profile__image, .profile-imgonly .profile__info { + grid-row: 1 / 2; + grid-column: 1 / 2; + } + .profile-imgonly .profile__image { + position: relative; + } + .profile-imgonly .profile__image:after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 30%; + background: linear-gradient(to top, rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0)); + } + .profile-imgonly .profile__image img { + border: none; + } + .profile-imgonly .profile__stats { + display: none; + } + .profile-imgonly .profile__info { + z-index: 5; + grid-row: 1 / 2; + align-self: end; + margin: 0 0 15px; + color: #fff; + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); + } + .profile-imgonly .profile__info p { + display: none; + } + .profile-imgonly .profile__cta { + padding: 0; + } + .profile-imgonly .profile__cta a { + border-radius: 0; + } + + #dark:checked ~ .mainlp a.buttonlp, + #pinkaru:checked ~ .mainlp a.buttonlp { + color: var(--foregroundColor); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + } + #dark:checked ~ .mainlp .buttonlp:hover, + #pinkaru:checked ~ .mainlp .buttonlp:hover { + background: var(--primaryShade2); + } + #dark:checked ~ .mainlp .buttonlp:active, + #pinkaru:checked ~ .mainlp .buttonlp:active { + background: var(--primaryShade1); + } + #dark:checked ~ .mainlp .profile-default img, + #pinkaru:checked ~ .mainlp .profile-default img { + border-bottom: 7px solid var(--secondaryShade5); + } + + /*FILTERS*/ + .filters__title { + font-size: 18px; + color: var(--grayColor); + margin: 25px 0; + } + .filters__item { + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + margin-bottom: 10px; + } + .filters__item .checkbox { + position: relative; + margin: 0; + } + .filters__item .checkbox .tooltip { + display: inline-block; + margin-left: 10px; + width: auto; + vertical-align: middle; + } + .filters__item .checkbox .tooltip .spanlp { + border: none; + } + .filters__item .checkbox .tooltip:after { + min-width: 100px; + margin-left: -50px; + } + .filters:not(:first-of-type) { + border-top: 0.5px solid var(--lightGrayColor); + margin-top: 25px; + } + + /* WELL CTA */ + .well-cta { + border-radius: 10px; + background: var(--secondaryColor); + color: var(--foregroundColor); + overflow: hidden; + } + .well-cta__text { + padding: 30px; + } + .well-cta__text p { + font-size: 18px; + line-height: 1.5; + } + .well-cta__text a { + margin: 25px 0 0; + } + .well-cta__image { + padding: 30px 0 0; + } + .well-cta img { + width: 100%; + max-height: 300px; + object-fit: contain; + margin-bottom: -7px; + } + + @media (min-width: 768px) { + .well-cta { + display: grid; + grid: auto / 1fr 250px; + } + .well-cta__image { + align-self: flex-end; + padding: 15px 0 0; + } + } + #bluepurple:checked ~ .mainlp .well-cta__text { + color: var(--backgroundColor); + } + + .well-cta--form { + display: grid; + grid-gap: 10px; + padding: 30px; + background: var(--primaryShade1); + border-radius: 10px; + } + .well-cta--form__text { + margin-bottom: 10px; + } + .well-cta--form h3 { + color: var(--primaryShade5); + } + + @media (min-width: 768px) { + .well-cta--form { + grid-template-columns: 1fr auto; + } + .well-cta--form__text { + grid-column: span 2; + } + } + /*TABLE*/ + .table { + background: var(--backgroundColor); + border-radius: 10px; + } + .table__wrapper { + width: 100%; + overflow-y: hidden; + overflow-x: auto; + border-radius: 10px; + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + } + .table tr { + display: grid; + grid: auto/80px 80px repeat(2, minmax(150px, 2fr)) repeat(2, minmax(120px, 1.5fr)) 50px; + align-items: center; + } + .table td { + padding: 15px; + } + .table__header { + color: var(--neutralShade5); + font-weight: 500; + text-transform: uppercase; + border-bottom: 0.5px solid var(--lightGrayColor); + } + .table__body tr:nth-child(even) { + background: var(--neutralShade0); + } + + #dark:checked ~ .mainlp .table__body tr:nth-child(even), + #pinkaru:checked ~ .mainlp .table__body tr:nth-child(even) { + background: var(--neutralShade8); + } + + /*FORMS*/ + .formlogin { + border-radius: 10px; + padding: 30px; + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + background: var(--backgroundColor); + margin-top: 30px; + position: relative; + overflow: hidden; + } + .formlogin .checkbox { + margin-bottom: 30px; + } + .formlogin .spinner__wrapper { + place-items: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.85); + opacity: 0; + z-index: -1; + } + + @media (min-width: 768px) { + .formlogin { + grid: auto / 1fr 40%; + } + .formlogin .input__wrapper { + grid-column: span 2; + } + .formlogin .inputRG__wrapper { + grid-column: span 2; + } + .formlogin .checkbox { + align-self: center; + margin-bottom: 0; + } + } + #dark:checked ~ .mainlp .spinner__wrapper, + #pinkaru:checked ~ .mainlp .spinner__wrapper { + background: rgba(20, 20, 20, 0.85); + } + + /*COMMENT ITEM*/ + .comment { + display: grid; + grid: auto / 60px 1fr; + grid-gap: 12px; + } + .comment__image { + grid-row: 1 / 4; + } + .comment__image img { + width: 60px; + height: 60px; + object-fit: cover; + border-radius: 50%; + } + .comment__info h5 { + margin-bottom: 0; + } + .comment__info h5 .spanlp { + vertical-align: middle; + } + .comment__info h5 .badge { + margin-left: 8px; + font-size: 80%; + } + .comment__info h5 .badge i { + font-size: 80%; + margin-right: 6px; + } + .comment__info__time { + color: var(--grayColor); + } + .comment__reaction i { + margin-right: 8px; + font-size: 85%; + } + .comment__reaction__heart { + cursor: pointer; + transition: .3s ease; + } + .comment__reaction__heart.toggled { + color: var(--accent3Shade5); + font-weight: 500; + } + + /*PANEL*/ + .panel { + display: grid; + grid: 200px auto min-content / 100%; + border-radius: 10px; + overflow: hidden; + background: var(--backgroundColor); + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + max-width: 480px; + margin: auto; + } + .panel__image img { + width: 100%; + height: 100%; + object-fit: cover; + } + .panel__info { + padding: 30px 30px 20px; + } + .panel__info h1 { + margin-bottom: 25px; + } + .panel__info p { + font-size: 20px; + margin: 15px 0; + } + .panel__info .alert { + font-weight: 300; + margin-top: 30px; + } + .panel__cta { + padding: 0 30px 30px; + text-align: center; + } + + footer { + display: grid; + grid: min-content / 1fr max-content; + text-align: left; + width: 90%; + margin: 1em auto 4em; + max-width: 1050px; + align-items: center; + } + footer a { + text-decoration: none; + color: #333; + padding: 3px 0; + border-bottom: 1px dashed; + } + footer a:hover { + border-bottom: 1px solid; + } + footer .social a { + text-decoration: none; + margin-left: 10px; + } + footer .social a .icons { + display: inline-block; + font-size: 20px; + } + footer.dark, footer.dark a { + color: #f9f9f9; + } + + + + + /*typography 2*/ + .stonglp { + font-weight: 500; + } + + .emlp { + font-style: italic; + } + + .h1lp { + font: 700 48px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h2lp { + font: 700 32px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h3lp { + font: 700 24px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h4lp { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h5lp { + font: 500 18px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + } + + .h6lp { + font: 500 16px/1.2 "Poppins", sans-serif; + text-transform: uppercase; + } + + .apierrort { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.apierrort::first-letter { + text-transform: uppercase; +} + +.devServer{ + color: orangered; + text-align: left; + margin: 10px; + float: left; + position: fixed; + z-index: 104; + font-size: 16px; + +} +.devServer span{ + text-shadow: 2px 0 0 #fff, -2px 0 0 #fff, 0 2px 0 #fff, 0 -2px 0 #fff, 1px 1px #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff; +} + + +.bgHero iframe { + width: 100%; + height: 100%; + position: fixed; + top: 0; + z-index: 103; +} + +$circle-length: 340px; +$check-length: 230px; + +@keyframes scaleAnimation { + 0% { + opacity: 0; + transform: scale(1.5); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes drawCircle { + 0% { + stroke-dashoffset: $circle-length; + } + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes drawCheck { + 0% { + stroke-dashoffset: $check-length; + } + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +#successAnimationCircle { + stroke-dasharray: $circle-length $circle-length; + stroke: #FFF; +} + +#successAnimationCheck { + stroke-dasharray: $check-length $check-length; + stroke: #FFF; +} + +#successAnimationResult { + fill: #FFF; + opacity: 0; +} + +#successAnimation .animated { + animation: 1s ease-out 0s 1 both scaleAnimation; + + #successAnimationCircle { + animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both drawCircle, + 0.3s linear 0.9s 1 both fadeOut; + } + + #successAnimationCheck { + animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both drawCheck, + 0.3s linear 0.9s 1 both fadeOut; + } + + #successAnimationResult { + animation: 0.3s linear 0.9s both fadeIn; + } +} diff --git a/src/components/index.js b/src/components/index.js new file mode 100644 index 00000000..863da32d --- /dev/null +++ b/src/components/index.js @@ -0,0 +1,13 @@ +import Editor from './Editor' +import FilterItem from './FilterItem' +import DropOption from './DropOption' +import Loader from './Loader/Loader.js' +import ScrollBar from './ScrollBar' +import * as MyLayout from './Layout/index.js' +import Page from './Page' +import Debugger from './Debugger' +import YulioID from './YulioID/experimental/index.js' +import YulioAuth from './YulioAuth/index.js' +import CoreLoader from './CoreLoader' + +export { MyLayout, Editor, FilterItem, DropOption, Loader, Page, ScrollBar, YulioID, YulioAuth, Debugger, CoreLoader } diff --git a/src/layouts/BaseLayout.js b/src/layouts/BaseLayout.js new file mode 100644 index 00000000..4f5f5ca7 --- /dev/null +++ b/src/layouts/BaseLayout.js @@ -0,0 +1,59 @@ +import React, { PureComponent, Fragment } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'dva' +import { Helmet } from 'react-helmet' +import { Loader } from 'components' +import { queryLayout } from 'utils' +import NProgress from 'nprogress' +import config from 'config' +import withRouter from 'umi/withRouter' + +import PublicLayout from './PublicLayout' +import PrimaryLayout from './PrimaryLayout' +import SocketLayout from './SocketLayout' +import PublicViewLayout from './PublicViewLayout' +import './BaseLayout.less' + +const LayoutMap = { + socket: SocketLayout, + primary: PrimaryLayout, + public: PublicLayout, + publicview: PublicViewLayout, +} + +@withRouter +@connect(({ loading }) => ({ loading })) +class BaseLayout extends PureComponent { + previousPath = '' + + render() { + const { loading, children, location } = this.props + const Container = LayoutMap[queryLayout(config.layouts, location.pathname)] + + const currentPath = location.pathname + location.search + if (currentPath !== this.previousPath) { + NProgress.start() + } + + if (!loading.global) { + NProgress.done() + this.previousPath = currentPath + } + + return ( + <Fragment> + <Helmet> + <title>{config.siteName}</title> + </Helmet> + <Loader fullScreen spinning={loading.effects['app/query']} /> + <Container>{children}</Container> + </Fragment> + ) + } +} + +BaseLayout.propTypes = { + loading: PropTypes.object, +} + +export default BaseLayout diff --git a/src/layouts/BaseLayout.less b/src/layouts/BaseLayout.less new file mode 100644 index 00000000..31180cf5 --- /dev/null +++ b/src/layouts/BaseLayout.less @@ -0,0 +1,75 @@ +@import '~themes/vars.less'; +@import '~themes/index.less'; + +:global { + + #nprogress { + pointer-events: none; + + .bar { + background: @primary-color; + position: fixed; + z-index: 2048; + top: 0; + left: 0; + right: 0; + width: 100%; + height: 2px; + } + + .peg { + display: block; + position: absolute; + right: 0; + width: 100px; + height: 100%; + box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color; + opacity: 1; + transform: rotate(3deg) translate(0, -4px); + } + + .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; + } + + .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + border: solid 2px transparent; + border-top-color: @primary-color; + border-left-color: @primary-color; + border-radius: 50%; + + :local { + animation: nprogress-spinner 400ms linear infinite; + } + } + } + + .nprogress-custom-parent { + overflow: hidden; + position: relative; + + #nprogress { + .bar, + .spinner { + position: absolute; + } + } + } +} + +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} diff --git a/src/layouts/PrimaryLayout.js b/src/layouts/PrimaryLayout.js new file mode 100644 index 00000000..372fa705 --- /dev/null +++ b/src/layouts/PrimaryLayout.js @@ -0,0 +1,188 @@ +/* global window */ +/* global document */ +import React, { PureComponent, Fragment } from 'react' +import PropTypes from 'prop-types' +import { RefreshONCE, LogoutCall, SDCP } from 'ycore' +import withRouter from 'umi/withRouter' +import { connect } from 'dva' +import { MyLayout } from 'components' +import { Layout, Drawer, Result, Button, Checkbox } from 'antd' +import { enquireScreen, unenquireScreen } from 'enquire-js' +import { config, pathMatchRegexp, langFromPath } from 'utils' +import store from 'store'; +import classNames from 'classnames' +import Error from '../pages/404' +import styles from './PrimaryLayout.less' + +const { Content } = Layout +const { Header, L_Sider, R_Sider, Control } = MyLayout + +@withRouter +@connect(({ app, loading }) => ({ app, loading })) +class PrimaryLayout extends PureComponent { + constructor(props){ + super(props) + this.state = { + isMobile: false, + resbypass: store.get('resbypass') || false, + RemByPass: false, + BarControls: [], + } + this.ResByPassHandler = this.ResByPassHandler.bind(this); + } + setControls(e){ + this.setState({BarControls: e}) + } + + componentDidMount() { + this.enquireHandler = enquireScreen(mobile => { + const { isMobile } = this.state + if (isMobile !== mobile) { + this.setState({ + isMobile: mobile, + }) + } + }) + } + + componentWillUnmount() { + unenquireScreen(this.enquireHandler) + } + + onCollapseChange = collapsed => { + this.props.dispatch({ + type: 'app/handleCollapseChange', + payload: collapsed, + }) + } + + ResByPassHandler() { + const {RemByPass} = this.state; + if (RemByPass == true){ + this.setState({resbypass: true}) + store.set('resbypass', true) + return + } + this.setState({resbypass: true}) + } + + isDarkMode = () => { + const {app} = this.props + const { theme } = app + if (theme == "light") { + return false; + } + return true; + } + + render() { + const { app, location, dispatch, children } = this.props + const { theme, routeList, collapsed, notifications } = app + const { isMobile, resbypass, rememberbypass } = this.state + const { onCollapseChange } = this + // Localized route name. + const lang = langFromPath(location.pathname) + const newRouteList = + lang !== 'en' + ? routeList.map(item => { + const { name, ...other } = item + return { + ...other, + name: (item[lang] || {}).name || name, + } + }) + : routeList + + // Find a route that matches the pathname. + const currentRoute = newRouteList.find( + _ => _.route && pathMatchRegexp(_.route, location.pathname) + ) + + // MenuParentId is equal to -1 is not a available menu. + const menus = newRouteList.filter(_ => _.menuParentId !== '-1') + + const headerProps = { + menus, + theme, + collapsed, + newRouteList, + notifications, + onCollapseChange, + onThemeChange(theme) { + dispatch({ + type: 'app/handleThemeChange', + payload: theme, + }) + }, + fixed: config.fixedHeader, + onAllNotificationsRead() { + dispatch({ type: 'app/allNotificationsRead' }) + }, + + } + + const LeftSiderProps = { + theme, + menus, + isMobile, + collapsed, + onCollapseChange, + } + const RightSiderProps = { + theme, + collapsed, + onCollapseChange, + onThemeChange(theme) { + dispatch({ + type: 'app/handleThemeChange', + payload: theme, + }) + }, + } + + const MobileWarning = () =>{ + if (resbypass == false) { + if (isMobile == true) { + return( + <div className={styles.mobilewarning}> + <Result status="warning" title="Low resolution warning" + extra={ <div style={{ color: "white" }}><h3 style={{ color: "white" }}>This version of the application is not fully compatible with the resolution of this screen, a higher resolution is recommended for an optimal experience</h3><span>Please choose an option to continue</span><br /><br /><br /><Checkbox onChange={this.setState({ RemByPass: true })}>Don't Show this again</Checkbox><br /><br /><br /><Button type="dashed" onClick={this.ResByPassHandler}>Continue</Button></div> }/> + </div> + ) + } + } + return null + } + + return ( + <Fragment> + <MobileWarning /> + <div className={styles.BarControlWrapper}><Control /></div> + <Layout className={this.isDarkMode()? styles.container_dark : styles.container_light}> + <L_Sider {...LeftSiderProps} /> + <div className={styles.container}> + <div style={{ paddingTop: config.fixedHeader ? 72 : 0 }} id="primaryLayout" > + <Header {...headerProps} /> + <Content className={styles.content}> + {children} + </Content> + </div> + </div> + <R_Sider {...RightSiderProps}/> + </Layout> + </Fragment> + ) + + + } +} + +PrimaryLayout.propTypes = { + children: PropTypes.element.isRequired, + location: PropTypes.object, + dispatch: PropTypes.func, + app: PropTypes.object, + loading: PropTypes.object, +} + +export default PrimaryLayout diff --git a/src/layouts/PrimaryLayout.less b/src/layouts/PrimaryLayout.less new file mode 100644 index 00000000..a286c9b7 --- /dev/null +++ b/src/layouts/PrimaryLayout.less @@ -0,0 +1,129 @@ +@import '~themes/vars.less'; + +.mobilewarning{ + background-color: rgba(0, 0, 0, 0.975); + color: white; + width: 100%; + position: absolute; + top: 0; + bottom: 0; + z-index: 100000; + display: flex; + justify-content: center; + text-align: center; + :global { + .ant-result-title { + color: white; + } + } +} + +.content { + padding: 24px; + height: 100vh; + width: 100%; + +} +.container_light { + background-color: #fff; + transition: background-color 200ms linear; +} +// TODO: Complete full dark theme +.container_dark { + background-color: @DarkMode-backgroud_container; + color: @DarkMode-color_container; + transition: background-color 200ms linear; + :global { + h1{ + color: @DarkMode-color_container; + } + h2{ + color: @DarkMode-color_container; + } + h3{ + color: @DarkMode-color_container; + } + h4{ + color: @DarkMode-color_container; + } + h5{ + color: @DarkMode-color_container; + } + h6{ + color: @DarkMode-color_container; + } + p{ + color: @DarkMode-color_container; + } + span{ + color: @DarkMode-color_container; + } + pre{ + color: @DarkMode-color_container; + } + .ant-pro-page-header-wrap-page-header-warp { + color: @DarkMode-color_container; + background-color: @DarkMode-backgroud_container; + transition: background-color 200ms linear; + } + transition: background-color 200ms linear; + } +} + +.sider { + :global { + .ant-layout-sider{ + background: #2d2d2d; + } + .ant-layout-sider-dark { + background-color: #2d2d2d; + color: white; + } + + .ant-menu-dark { + background-color: #2d2d2d; + color: white; + } + + .ant-layout-sider-dark .ant-layout-sider-children { + background-color: #2d2d2d; + display: flex; + flex-direction: column; + justify-content: space-between; + } + .ant-layout-sider-children { + display: flex; + flex-direction: column; + justify-content: space-between; + } + } +} +.container{ + width: 100vh; + flex: 1; + overflow-x: hidden; + height: 100vh; + bottom: 0; +} +.BarControlWrapper{ + width: 100%; + position: absolute; + bottom: 0; + z-index: 30; +} +@media (max-width: 767px) { + .content { + padding: 12px; + } + + .container_light { + height: 100vh; + flex: 1; + + } + .container_dark { + height: 100vh; + flex: 1; + + } +} diff --git a/src/layouts/PublicLayout.js b/src/layouts/PublicLayout.js new file mode 100644 index 00000000..caaaf5cc --- /dev/null +++ b/src/layouts/PublicLayout.js @@ -0,0 +1,3 @@ +export default ({ children }) => { + return children +} diff --git a/src/layouts/index.js b/src/layouts/index.js new file mode 100644 index 00000000..64aa1527 --- /dev/null +++ b/src/layouts/index.js @@ -0,0 +1,72 @@ +import React, { Component } from 'react' +import withRouter from 'umi/withRouter' +import { ConfigProvider } from 'antd' +import { I18nProvider } from '@lingui/react' +import { langFromPath, defaultLanguage } from 'utils' +import en_US from 'antd/lib/locale-provider/en_US' +import BaseLayout from './BaseLayout' + +const languages = { + en: en_US, +} + +@withRouter +class Layout extends Component { + state = { + catalogs: {}, + } + + language = defaultLanguage + + componentDidMount() { + const language = langFromPath(this.props.location.pathname) + this.language = language + this.loadCatalog(language) + } + + shouldComponentUpdate(nextProps, nextState) { + const language = langFromPath(nextProps.location.pathname) + const preLanguage = this.language + const { catalogs } = nextState + + if (preLanguage !== language && !catalogs[language]) { + this.loadCatalog(language) + this.language = language + return false + } + this.language = language + + return true + } + + loadCatalog = async language => { + const catalog = await import(/* webpackMode: "lazy", webpackChunkName: "i18n-[index]" */ + `@lingui/loader!../locales/${language}/messages.json`) + + this.setState(state => ({ + catalogs: { + ...state.catalogs, + [language]: catalog, + }, + })) + } + + render() { + const { location, children } = this.props + const { catalogs } = this.state + + let language = langFromPath(location.pathname) + // If the language pack is not loaded or is loading, use the default language + if (!catalogs[language]) language = defaultLanguage + + return ( + <ConfigProvider locale={languages[language]}> + <I18nProvider language={language} catalogs={catalogs}> + <BaseLayout>{children}</BaseLayout> + </I18nProvider> + </ConfigProvider> + ) + } +} + +export default Layout diff --git a/src/models/app.js b/src/models/app.js new file mode 100644 index 00000000..5b6359f9 --- /dev/null +++ b/src/models/app.js @@ -0,0 +1,132 @@ + +/* global window */ +import { router } from 'utils' +import { stringify } from 'qs' +import store from 'store' +import { queryLayout, pathMatchRegexp } from 'utils' +import { CANCEL_REQUEST_MESSAGE } from 'utils/constant' +import api from 'api' +import config from 'config' +import Cookies from 'js-cookie' +import * as ycore from 'ycore' +import jwt from 'jsonwebtoken' +const { queryRouteList, logoutUser, queryUserInfo } = api + +export default { + namespace: 'app', + state: { + routeList: [ + { + id: '1', + icon: 'home', + name: 'Main', + router: '/Main', + }, + ], + locationPathname: '', + AppSettings: store.get('app_settings') || config.defaultSettings, + locationQuery: {}, + theme: store.get('theme') || 'light', + collapsed: store.get('collapsed') || true, + notifications: [ + { + title: 'Hey! Test notification', + date: new Date(Date.now() - 50000000), + }, + ], + }, + subscriptions: { + setupHistory({ dispatch, history }) { + history.listen(location => { + dispatch({ + type: 'updateState', + payload: { + locationPathname: location.pathname, + locationQuery: location.query, + }, + }) + }) + }, + + setupRequestCancel({ history }) { + history.listen(() => { + const { cancelRequest = new Map() } = window + cancelRequest.forEach((value, key) => { + if (value.pathname !== window.location.pathname) { + value.cancel(CANCEL_REQUEST_MESSAGE) + cancelRequest.delete(key) + } + }) + }) + }, + setup({ dispatch }) { + dispatch({ type: 'query' }) + }, + }, + effects: { + *query({payload}, { call, put, select }) { + const { locationPathname } = yield select(_ => _.app) + const { list } = yield call(queryRouteList) + let routeList = list + yield put({type: 'updateState', payload: { routeList: list }, }) + + const valid = ycore.ValidLoginSession(); + const validBackup = ycore.ValidBackup(); + if ( valid == true) { + if (pathMatchRegexp(['/', '/login'], window.location.pathname)) { + router.push({pathname: '/main',}) + ycore.RefreshONCE() + }else{ + ycore.MakeBackup() + ycore.UpdateSDCP() + } + } else if (queryLayout(config.layouts, locationPathname) !== 'public') { + if (validBackup == true) { + ycore.LogoutCall() + return + }else if (ycore.GetUserToken == false){ + notification.open({ + placement: 'topLeft', + message: 'Unexpectedly failed logout in YulioID™ ', + description: 'It seems that your token has been removed unexpectedly and could not log out from YulioID ', + icon: <Icon type="warning" style={{ color: 'orange' }} /> + }) + return + } + router.push({pathname: '/login',}) + } + }, + + *signOut({ payload }, { call, put }) { + const data = yield call(logoutUser) + if (data.success) { + sessionStorage.clear() + yield put({ type: 'query' }) + } else { + throw data + } + }, + }, + reducers: { + updateState(state, { payload }) { + return { + ...state, + ...payload, + } + }, + + handleThemeChange(state, { payload }) { + store.set('theme', payload) + state.theme = payload + }, + + handleCollapseChange(state, { payload }) { + store.set('collapsed', payload) + state.collapsed = payload + }, + + allNotificationsRead(state) { + state.notifications = [] + }, + }, +} diff --git a/src/pages/404.js b/src/pages/404.js new file mode 100644 index 00000000..77aa752b --- /dev/null +++ b/src/pages/404.js @@ -0,0 +1,16 @@ +import React from 'react' +import { Icon } from 'antd' +import { Page } from 'components' +import styles from './404.less' + +const Error = () => ( + <Page inner> + <div className={styles.error}> + <Icon type="api" /> + <h1>OBA BLYAT</h1> + <p><strong>ERROR 404</strong></p> + </div> + </Page> +) + +export default Error diff --git a/src/pages/404.less b/src/pages/404.less new file mode 100644 index 00000000..38c7e9cb --- /dev/null +++ b/src/pages/404.less @@ -0,0 +1,50 @@ +/* devanagari */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Poppins Regular'), local('Poppins-Regular'), url(https://fonts.gstatic.com/s/poppins/v6/pxiEyp8kv8JHgFVrJJbecmNE.woff2) format('woff2'); + unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB; +} +/* latin-ext */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Poppins Regular'), local('Poppins-Regular'), url(https://fonts.gstatic.com/s/poppins/v6/pxiEyp8kv8JHgFVrJJnecmNE.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Poppins'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: local('Poppins Regular'), local('Poppins-Regular'), url(https://fonts.gstatic.com/s/poppins/v6/pxiEyp8kv8JHgFVrJJfecg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +.error { + color: black; + text-align: center; + position: absolute; + top: 30%; + margin-top: -50px; + left: 50%; + margin-left: -100px; + width: 200px; + + :global .anticon { + font-size: 48px; + margin-bottom: 16px; + } + + h1 { + font-family: 'Poppins', sans-serif; + + } + p { + font-family: 'Poppins', sans-serif; + } +} \ No newline at end of file diff --git a/src/pages/index.js b/src/pages/index.js new file mode 100644 index 00000000..5cbc165a --- /dev/null +++ b/src/pages/index.js @@ -0,0 +1,13 @@ +import React, { PureComponent } from 'react' +import Redirect from 'umi/redirect' +import { withI18n } from '@lingui/react' + +@withI18n() +class Index extends PureComponent { + render() { + const { i18n } = this.props + return <Redirect to={i18n.t`/dashboard`} /> + } +} + +export default Index diff --git a/src/pages/login/index.js b/src/pages/login/index.js new file mode 100644 index 00000000..c7b4b6a0 --- /dev/null +++ b/src/pages/login/index.js @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import { getRandomBG } from 'ycore'; +import { YulioID } from 'components'; +let imgRend; + +class Login extends Component { + constructor(props){ + super(props) + this.state = { + // Setting default method + type: 'stable' + } + this.changeMethod = this.changeMethod.bind(this); + } + + componentDidMount(){ + // INIT + var arrayBg = new Array(); + arrayBg[0] = "bg-1-an"; + arrayBg[1] = "bg-2-an"; + arrayBg[2] = "bg-3-an"; + arrayBg[3] = "bg-4-an"; + arrayBg[4] = "bg-5-an"; + arrayBg[5] = "bg-6-an"; + arrayBg[6] = "bg-1-an"; + imgRend = getRandomBG(arrayBg) + } + + changeMethod() { + this.setState({type: 'stable'}) + } + render() { + const { type } = this.state; + return ( + <YulioID include={<div>Using stable</div>} /> + ) + } +} + +export default Login diff --git a/src/pages/login/model.js b/src/pages/login/model.js new file mode 100644 index 00000000..bcff3b4c --- /dev/null +++ b/src/pages/login/model.js @@ -0,0 +1,27 @@ +import { router, pathMatchRegexp } from 'utils' +import api from 'api' + +const { loginUser } = api + +export default { + namespace: 'login', + state: {}, + effects: { + *login({ payload }, { put, call, select }) { + const data = yield call(loginUser, payload) + const { locationQuery } = yield select(_ => _.app) + if (data.success == true) { + const { from } = locationQuery + yield put({ type: 'app/query' }) + if (!pathMatchRegexp('/login', from)) { + if (from === '/') router.push('/dashboard') + else router.push(from) + } else { + router.push('/dashboard') + } + } else { + throw data + } + }, + }, +} diff --git a/src/pages/main/index.tsx b/src/pages/main/index.tsx new file mode 100644 index 00000000..ababced9 --- /dev/null +++ b/src/pages/main/index.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import * as ycore from 'ycore' +import * as antd from 'antd' + + + +class Main extends React.Component{ + render(){ + return ( + <div> + <h1> + Sigueme pe + </h1> + </div> + ) + } +} +export default Main; \ No newline at end of file diff --git a/src/services/api.js b/src/services/api.js new file mode 100644 index 00000000..72149962 --- /dev/null +++ b/src/services/api.js @@ -0,0 +1,6 @@ +export default { + queryRouteList: '/routes', + + loginUser: 'POST /user/login', + logoutUser: '/user/logout', +} diff --git a/src/services/index.js b/src/services/index.js new file mode 100644 index 00000000..98317353 --- /dev/null +++ b/src/services/index.js @@ -0,0 +1,38 @@ +import request from 'utils/request'; +import { apiPrefix } from 'config'; + +import api from './api'; + +const gen = params => { + let url = apiPrefix + params + let method = 'GET' + + const paramsArray = params.split(' ') + if (paramsArray.length === 2) { + method = paramsArray[0]; + url = apiPrefix + paramsArray[1]; + } + + return function(data) { + return request({ + url, + data, + method, + }) + } +} + +const APIFunction = {} +for (const key in api) { + APIFunction[key] = gen(api[key]); +} + +APIFunction.queryWeather = params => { + params.key = 'i7sau1babuzwhycn' + return request({ + url: `${apiPrefix}/weather/now.json`, + data: params, + }) +} + +export default APIFunction; diff --git a/src/themes/default.less b/src/themes/default.less new file mode 100644 index 00000000..43cf08e8 --- /dev/null +++ b/src/themes/default.less @@ -0,0 +1,848 @@ +// 本文件是对 ant-design: +// https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less +// 相应变量值的覆盖 +// 注意:只需写出要覆盖的变量即可(不需要覆盖的变量不要写) + + +/* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */ +@import '../../node_modules/antd/lib/style/themes/default.less'; + + +// -------- Colors ----------- +@primary-color: @blue-6; +@info-color: @blue-6; +@success-color: @green-6; +@processing-color: @blue-6; +@error-color: @red-6; +@highlight-color: @red-6; +@warning-color: @gold-6; +@normal-color: #d9d9d9; +@white: #fff; +@black: #000; + +// Color used by default to control hover and active backgrounds and for +// alert info backgrounds. +@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) +@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) +@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused +@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-5: color( + ~`colorPalette('@{primary-color}', 5) ` +); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) +@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color +@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) +@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused +@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused +@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused + +// Base Scaffolding Variables +// --- + +// Background color for `<body>` +@body-background: #fff; +// Base background color for most components +@component-background: #fff; +@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', + 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol'; +@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; +@text-color: fade(@black, 65%); +@text-color-secondary: fade(@black, 45%); +@text-color-inverse: @white; +@icon-color: inherit; +@icon-color-hover: fade(@black, 75%); +@heading-color: fade(#000, 85%); +@heading-color-dark: fade(@white, 100%); +@text-color-dark: fade(@white, 85%); +@text-color-secondary-dark: fade(@white, 65%); +@text-selection-bg: @primary-color; +@font-variant-base: tabular-nums; +@font-feature-settings-base: 'tnum'; +@font-size-base: 14px; +@font-size-lg: @font-size-base + 2px; +@font-size-sm: 12px; +@heading-1-size: ceil(@font-size-base * 2.71); +@heading-2-size: ceil(@font-size-base * 2.14); +@heading-3-size: ceil(@font-size-base * 1.71); +@heading-4-size: ceil(@font-size-base * 1.42); +@line-height-base: 1.5; +@border-radius-base: 4px; +@border-radius-sm: 2px; + +// vertical paddings +@padding-lg: 24px; // containers +@padding-md: 16px; // small containers and buttons +@padding-sm: 12px; // Form controls and items +@padding-xs: 8px; // small items + +// vertical padding for all form controls +@control-padding-horizontal: @padding-sm; +@control-padding-horizontal-sm: @padding-xs; + +// The background colors for active and hover states for things like +// list items or table cells. +@item-active-bg: @primary-1; +@item-hover-bg: @primary-1; + +// ICONFONT +@iconfont-css-prefix: anticon; + +// LINK +@link-color: @primary-color; +@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); +@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-decoration: none; +@link-hover-decoration: none; + +// Animation +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); + +// Border color +@border-color-base: hsv(0, 0, 85%); // base border outline a component +@border-color-split: hsv(0, 0, 91%); // split border inside a component +@border-color-inverse: @white; +@border-width-base: 1px; // width of the border for a component +@border-style-base: solid; // style of a components border + +// Outline +@outline-blur-size: 0; +@outline-width: 2px; +@outline-color: @primary-color; + +@background-color-light: hsv(0, 0, 98%); // background of header and selected item +@background-color-base: hsv(0, 0, 96%); // Default grey background color + +// Disabled states +@disabled-color: fade(#000, 25%); +@disabled-bg: @background-color-base; +@disabled-color-dark: fade(#fff, 35%); + +// Shadow +@shadow-color: rgba(0, 0, 0, 0.15); +@shadow-color-inverse: @component-background; +@box-shadow-base: @shadow-1-down; +@shadow-1-up: 0 -2px 8px @shadow-color; +@shadow-1-down: 0 2px 8px @shadow-color; +@shadow-1-left: -2px 0 8px @shadow-color; +@shadow-1-right: 2px 0 8px @shadow-color; +@shadow-2: 0 4px 12px @shadow-color; + +// Buttons +@btn-font-weight: 400; +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-sm: @border-radius-base; +@btn-border-width: @border-width-base; +@btn-border-style: @border-style-base; +@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); +@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); +@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + +@btn-primary-color: #fff; +@btn-primary-bg: @primary-color; + +@btn-default-color: @text-color; +@btn-default-bg: @component-background; +@btn-default-border: @border-color-base; + +@btn-danger-color: #fff; +@btn-danger-bg: color(~`colorPalette('@{error-color}', 5) `); +@btn-danger-border: color(~`colorPalette('@{error-color}', 5) `); + +@btn-disable-color: @disabled-color; +@btn-disable-bg: @disabled-bg; +@btn-disable-border: @border-color-base; + +@btn-padding-base: 0 @padding-md - 1px; +@btn-font-size-lg: @font-size-lg; +@btn-font-size-sm: @font-size-base; +@btn-padding-lg: @btn-padding-base; +@btn-padding-sm: 0 @padding-xs - 1px; + +@btn-height-base: 32px; +@btn-height-lg: 40px; +@btn-height-sm: 24px; + +@btn-circle-size: @btn-height-base; +@btn-circle-size-lg: @btn-height-lg; +@btn-circle-size-sm: @btn-height-sm; + +@btn-square-size: @btn-height-base; +@btn-square-size-lg: @btn-height-lg; +@btn-square-size-sm: @btn-height-sm; + +@btn-group-border: @primary-5; + +// Checkbox +@checkbox-size: 16px; +@checkbox-color: @primary-color; +@checkbox-check-color: #fff; +@checkbox-border-width: @border-width-base; + +// Descriptions +@descriptions-bg: #fafafa; + +// Dropdown +@dropdown-selected-color: @primary-color; + +// Empty +@empty-font-size: @font-size-base; + +// Radio +@radio-size: 16px; +@radio-dot-color: @primary-color; + +// Radio buttons +@radio-button-bg: @btn-default-bg; +@radio-button-checked-bg: @btn-default-bg; +@radio-button-color: @btn-default-color; +@radio-button-hover-color: @primary-5; +@radio-button-active-color: @primary-7; + +// Media queries breakpoints +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-xxl: 1600px; +@screen-xxl-min: @screen-xxl; + +// provide a maximum +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-xxl-min - 1px); + +// Grid system +@grid-columns: 24; +@grid-gutter-width: 0; + +// Layout +@layout-body-background: #f0f2f5; +@layout-header-background: #424242; +@layout-footer-background: @layout-body-background; +@layout-header-height: 64px; +@layout-header-padding: 0 50px; +@layout-footer-padding: 24px 50px; +@layout-sider-background: @layout-header-background; +@layout-trigger-height: 48px; +@layout-trigger-background: #2d2d2d; +@layout-trigger-color: #fff; +@layout-zero-trigger-width: 36px; +@layout-zero-trigger-height: 42px; +// Layout light theme +@layout-sider-background-light: #fff; +@layout-trigger-background-light: #fff; +@layout-trigger-color-light: @text-color; + +// z-index list, order by `z-index` +@zindex-table-fixed: auto; +@zindex-affix: 10; +@zindex-back-top: 10; +@zindex-badge: 10; +@zindex-picker-panel: 10; +@zindex-popup-close: 10; +@zindex-modal: 1000; +@zindex-modal-mask: 1000; +@zindex-message: 1010; +@zindex-notification: 1010; +@zindex-popover: 1030; +@zindex-dropdown: 1050; +@zindex-picker: 1050; +@zindex-tooltip: 1060; + +// Animation +@animation-duration-slow: 0.3s; // Modal +@animation-duration-base: 0.2s; +@animation-duration-fast: 0.1s; // Tooltip + +//CollapsePanel +@collapse-panel-border-radius: @border-radius-base; + +//Dropdown +@dropdown-vertical-padding: 5px; +@dropdown-font-size: @font-size-base; +@dropdown-line-height: 22px; + +// Form +// --- +@label-required-color: @highlight-color; +@label-color: @heading-color; +@form-warning-input-bg: @input-bg; +@form-item-margin-bottom: 24px; +@form-item-trailing-colon: true; +@form-vertical-label-padding: 0 0 8px; +@form-vertical-label-margin: 0; +@form-item-label-colon-margin-right: 8px; +@form-item-label-colon-margin-left: 2px; +@form-error-input-bg: @input-bg; + +// Input +// --- +@input-height-base: 32px; +@input-height-lg: 40px; +@input-height-sm: 24px; +@input-padding-horizontal: @control-padding-horizontal - 1px; +@input-padding-horizontal-base: @input-padding-horizontal; +@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; +@input-padding-horizontal-lg: @input-padding-horizontal; +@input-padding-vertical-base: 4px; +@input-padding-vertical-sm: 1px; +@input-padding-vertical-lg: 6px; +@input-placeholder-color: hsv(0, 0, 75%); +@input-color: @text-color; +@input-border-color: @border-color-base; +@input-bg: @component-background; +@input-number-handler-active-bg: #f4f4f4; +@input-number-handler-hover-bg: @primary-5; +@input-number-handler-bg: @component-background; +@input-number-handler-border-color: @border-color-base; +@input-addon-bg: @background-color-light; +@input-hover-border-color: @primary-5; +@input-disabled-bg: @disabled-bg; +@input-outline-offset: 0 0; + +// Select +// --- +@select-border-color: @border-color-base; +@select-item-selected-font-weight: 600; +@select-dropdown-bg: @component-background; +@select-item-selected-bg: @background-color-light; +@select-item-active-bg: @item-active-bg; + +// Anchor +// --- +@anchor-border-color: @border-color-split; + +// Tooltip +// --- +// Tooltip max width +@tooltip-max-width: 250px; +// Tooltip text color +@tooltip-color: #fff; +// Tooltip background color +@tooltip-bg: rgba(0, 0, 0, 0.75); +// Tooltip arrow width +@tooltip-arrow-width: 5px; +// Tooltip distance with trigger +@tooltip-distance: @tooltip-arrow-width - 1px + 4px; +// Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + +// Popover +// --- +// Popover body background color +@popover-bg: @component-background; +// Popover text color +@popover-color: @text-color; +// Popover maximum width +@popover-min-width: 177px; +// Popover arrow width +@popover-arrow-width: 6px; +// Popover arrow color +@popover-arrow-color: @popover-bg; +// Popover outer arrow width +// Popover outer arrow color +@popover-arrow-outer-color: @popover-bg; +// Popover distance with trigger +@popover-distance: @popover-arrow-width + 4px; + +// Modal +// -- +@modal-body-padding: 24px; +@modal-header-bg: @component-background; +@modal-footer-bg: transparent; +@modal-footer-border-color-split: @border-color-split; +@modal-mask-bg: fade(@black, 45%); + +// Progress +// -- +@progress-default-color: @processing-color; +@progress-remaining-color: @background-color-base; +@progress-text-color: @text-color; +@progress-radius: 100px; + +// Menu +// --- +@menu-inline-toplevel-item-height: 40px; +@menu-item-height: 40px; +@menu-collapsed-width: 80px; +@menu-bg: @component-background; +@menu-popup-bg: @component-background; +@menu-item-color: @text-color; +@menu-highlight-color: @primary-color; +@menu-item-active-bg: @item-active-bg; +@menu-item-active-border-width: 3px; +@menu-item-group-title-color: @text-color-secondary; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; + +@menu-item-vertical-margin: 4px; +@menu-item-font-size: @font-size-base; +@menu-item-boundary-margin: 8px; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@dark-menu-item-hover-bg: transparent; + +// dark theme +@menu-dark-color: @text-color-secondary-dark; +@menu-dark-bg: #2d2d2d; +@menu-dark-arrow-color: #fff; +@menu-dark-submenu-bg: #2d2d2d; +@menu-dark-highlight-color: #fff; +@menu-dark-item-active-bg: @primary-color; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@menu-dark-item-hover-bg: transparent; +// Spin +// --- +@spin-dot-size-sm: 14px; +@spin-dot-size: 20px; +@spin-dot-size-lg: 32px; + +// Table +// -- +@table-header-bg: @background-color-light; +@table-header-color: @heading-color; +@table-header-sort-bg: @background-color-base; +@table-body-sort-bg: rgba(0, 0, 0, 0.01); +@table-row-hover-bg: @primary-1; +@table-selected-row-color: inherit; +@table-selected-row-bg: #fafafa; +@table-body-selected-sort-bg: @table-selected-row-bg; +@table-selected-row-hover-bg: @table-selected-row-bg; +@table-expanded-row-bg: #fbfbfb; +@table-padding-vertical: 16px; +@table-padding-horizontal: 16px; +@table-border-radius-base: @border-radius-base; +@table-footer-bg: @background-color-light; +@table-footer-color: @heading-color; + +// Tag +// -- +@tag-default-bg: @background-color-light; +@tag-default-color: @text-color; +@tag-font-size: @font-size-sm; + +// TimePicker +// --- +@time-picker-panel-column-width: 56px; +@time-picker-panel-width: @time-picker-panel-column-width * 3; +@time-picker-selected-bg: @background-color-base; + +// Carousel +// --- +@carousel-dot-width: 16px; +@carousel-dot-height: 3px; +@carousel-dot-active-width: 24px; + +// Badge +// --- +@badge-height: 20px; +@badge-dot-size: 6px; +@badge-font-size: @font-size-sm; +@badge-font-weight: normal; +@badge-status-size: 6px; +@badge-text-color: @component-background; + +// Rate +// --- +@rate-star-color: @yellow-6; +@rate-star-bg: @border-color-split; + +// Card +// --- +@card-head-color: @heading-color; +@card-head-background: transparent; +@card-head-padding: 16px; +@card-inner-head-padding: 12px; +@card-padding-base: 24px; +@card-actions-background: @background-color-light; +@card-skeleton-bg: #cfd8dc; +@card-background: @component-background; +@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); +@card-radius: @border-radius-sm; + +// Comment +// --- +@comment-padding-base: 16px 0; +@comment-nest-indent: 44px; +@comment-font-size-base: @font-size-base; +@comment-font-size-sm: @font-size-sm; +@comment-author-name-color: @text-color-secondary; +@comment-author-time-color: #ccc; +@comment-action-color: @text-color-secondary; +@comment-action-hover-color: #595959; + +// Tabs +// --- +@tabs-card-head-background: @background-color-light; +@tabs-card-height: 40px; +@tabs-card-active-color: @primary-color; +@tabs-title-font-size: @font-size-base; +@tabs-title-font-size-lg: @font-size-lg; +@tabs-title-font-size-sm: @font-size-base; +@tabs-ink-bar-color: @primary-color; +@tabs-bar-margin: 0 0 16px 0; +@tabs-horizontal-margin: 0 32px 0 0; +@tabs-horizontal-padding: 12px 16px; +@tabs-horizontal-padding-lg: 16px; +@tabs-horizontal-padding-sm: 8px 16px; +@tabs-vertical-padding: 8px 24px; +@tabs-vertical-margin: 0 0 16px 0; +@tabs-scrolling-size: 32px; +@tabs-highlight-color: @primary-color; +@tabs-hover-color: @primary-5; +@tabs-active-color: @primary-7; +@tabs-card-gutter: 2px; +@tabs-card-tab-active-border-top: 2px solid transparent; + +// BackTop +// --- +@back-top-color: #fff; +@back-top-bg: @text-color-secondary; +@back-top-hover-bg: @text-color; + +// Avatar +// --- +@avatar-size-base: 32px; +@avatar-size-lg: 40px; +@avatar-size-sm: 24px; +@avatar-font-size-base: 18px; +@avatar-font-size-lg: 24px; +@avatar-font-size-sm: 14px; +@avatar-bg: #ccc; +@avatar-color: #fff; +@avatar-border-radius: @border-radius-base; + +// Switch +// --- +@switch-height: 22px; +@switch-sm-height: 16px; +@switch-sm-checked-margin-left: -(@switch-sm-height - 3px); +@switch-disabled-opacity: 0.4; +@switch-color: @primary-color; +@switch-shadow-color: fade(#00230b, 20%); + +// Pagination +// --- +@pagination-item-size: 32px; +@pagination-item-size-sm: 24px; +@pagination-font-family: Arial; +@pagination-font-weight-active: 500; +@pagination-item-bg-active: @component-background; + +// PageHeader +// --- +@page-header-padding: 24px; +@page-header-padding-vertical: 16px; +@page-header-padding-breadcrumb: 12px; +@page-header-back-color: #000; + +// Breadcrumb +// --- +@breadcrumb-base-color: @text-color-secondary; +@breadcrumb-last-item-color: @text-color; +@breadcrumb-font-size: @font-size-base; +@breadcrumb-icon-font-size: @font-size-base; +@breadcrumb-link-color: @text-color-secondary; +@breadcrumb-link-color-hover: @primary-5; +@breadcrumb-separator-color: @text-color-secondary; +@breadcrumb-separator-margin: 0 @padding-xs; + +// Slider +// --- +@slider-margin: 14px 6px 10px; +@slider-rail-background-color: @background-color-base; +@slider-rail-background-color-hover: #e1e1e1; +@slider-track-background-color: @primary-3; +@slider-track-background-color-hover: @primary-4; +@slider-handle-border-width: 2px; +@slider-handle-background-color: @component-background; +@slider-handle-color: @primary-3; +@slider-handle-color-hover: @primary-4; +@slider-handle-color-focus: tint(@primary-color, 20%); +@slider-handle-color-focus-shadow: fade(@primary-color, 20%); +@slider-handle-color-tooltip-open: @primary-color; +@slider-handle-shadow: 0; +@slider-dot-border-color: @border-color-split; +@slider-dot-border-color-active: tint(@primary-color, 50%); +@slider-disabled-color: @disabled-color; +@slider-disabled-background-color: @component-background; + +// Tree +// --- +@tree-title-height: 24px; +@tree-child-padding: 18px; +@tree-directory-selected-color: #fff; +@tree-directory-selected-bg: @primary-color; +@tree-node-hover-bg: @item-hover-bg; +@tree-node-selected-bg: @primary-2; + +// Collapse +// --- +@collapse-header-padding: 12px 16px; +@collapse-header-padding-extra: 40px; +@collapse-header-bg: @background-color-light; +@collapse-content-padding: @padding-md; +@collapse-content-bg: @component-background; + +// Skeleton +// --- +@skeleton-color: #f2f2f2; + +// Transfer +// --- +@transfer-header-height: 40px; +@transfer-disabled-bg: @disabled-bg; +@transfer-list-height: 200px; + +// Message +// --- +@message-notice-content-padding: 10px 16px; + +// Motion +// --- +@wave-animation-width: 6px; + +// Alert +// --- +@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; +@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-icon-color: @success-color; +@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; +@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-icon-color: @info-color; +@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; +@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-icon-color: @warning-color; +@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; +@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-icon-color: @error-color; + +// List +// --- +@list-header-background: transparent; +@list-footer-background: transparent; +@list-empty-text-padding: @padding-md; +@list-item-padding: @padding-sm 0; +@list-item-meta-margin-bottom: @padding-md; +@list-item-meta-avatar-margin-right: @padding-md; +@list-item-meta-title-margin-bottom: @padding-sm; + +// Statistic +// --- +@statistic-title-font-size: @font-size-base; +@statistic-content-font-size: 24px; +@statistic-unit-font-size: 16px; +@statistic-font-family: @font-family; + +// Drawer +// --- +@drawer-header-padding: 16px 24px; +@drawer-body-padding: 24px; + +// Timeline +// --- +@timeline-width: 2px; +@timeline-color: @border-color-split; +@timeline-dot-border-width: 2px; +@timeline-dot-color: @primary-color; +@timeline-dot-bg: @component-background; + +// Typography +// --- +@typography-title-font-weight: 600; +@typography-title-margin-top: 1.2em; +@typography-title-margin-bottom: 0.5em; + +// color palettes +@blue-1: color(~`colorPalette('@{blue-6}', 1) `); +@blue-2: color(~`colorPalette('@{blue-6}', 2) `); +@blue-3: color(~`colorPalette('@{blue-6}', 3) `); +@blue-4: color(~`colorPalette('@{blue-6}', 4) `); +@blue-5: color(~`colorPalette('@{blue-6}', 5) `); +@blue-6: #1890ff; +@blue-7: color(~`colorPalette('@{blue-6}', 7) `); +@blue-8: color(~`colorPalette('@{blue-6}', 8) `); +@blue-9: color(~`colorPalette('@{blue-6}', 9) `); +@blue-10: color(~`colorPalette('@{blue-6}', 10) `); + +@purple-1: color(~`colorPalette('@{purple-6}', 1) `); +@purple-2: color(~`colorPalette('@{purple-6}', 2) `); +@purple-3: color(~`colorPalette('@{purple-6}', 3) `); +@purple-4: color(~`colorPalette('@{purple-6}', 4) `); +@purple-5: color(~`colorPalette('@{purple-6}', 5) `); +@purple-6: #722ed1; +@purple-7: color(~`colorPalette('@{purple-6}', 7) `); +@purple-8: color(~`colorPalette('@{purple-6}', 8) `); +@purple-9: color(~`colorPalette('@{purple-6}', 9) `); +@purple-10: color(~`colorPalette('@{purple-6}', 10) `); + +@cyan-1: color(~`colorPalette('@{cyan-6}', 1) `); +@cyan-2: color(~`colorPalette('@{cyan-6}', 2) `); +@cyan-3: color(~`colorPalette('@{cyan-6}', 3) `); +@cyan-4: color(~`colorPalette('@{cyan-6}', 4) `); +@cyan-5: color(~`colorPalette('@{cyan-6}', 5) `); +@cyan-6: #13c2c2; +@cyan-7: color(~`colorPalette('@{cyan-6}', 7) `); +@cyan-8: color(~`colorPalette('@{cyan-6}', 8) `); +@cyan-9: color(~`colorPalette('@{cyan-6}', 9) `); +@cyan-10: color(~`colorPalette('@{cyan-6}', 10) `); + +@green-1: color(~`colorPalette('@{green-6}', 1) `); +@green-2: color(~`colorPalette('@{green-6}', 2) `); +@green-3: color(~`colorPalette('@{green-6}', 3) `); +@green-4: color(~`colorPalette('@{green-6}', 4) `); +@green-5: color(~`colorPalette('@{green-6}', 5) `); +@green-6: #52c41a; +@green-7: color(~`colorPalette('@{green-6}', 7) `); +@green-8: color(~`colorPalette('@{green-6}', 8) `); +@green-9: color(~`colorPalette('@{green-6}', 9) `); +@green-10: color(~`colorPalette('@{green-6}', 10) `); + +@magenta-1: color(~`colorPalette('@{magenta-6}', 1) `); +@magenta-2: color(~`colorPalette('@{magenta-6}', 2) `); +@magenta-3: color(~`colorPalette('@{magenta-6}', 3) `); +@magenta-4: color(~`colorPalette('@{magenta-6}', 4) `); +@magenta-5: color(~`colorPalette('@{magenta-6}', 5) `); +@magenta-6: #eb2f96; +@magenta-7: color(~`colorPalette('@{magenta-6}', 7) `); +@magenta-8: color(~`colorPalette('@{magenta-6}', 8) `); +@magenta-9: color(~`colorPalette('@{magenta-6}', 9) `); +@magenta-10: color(~`colorPalette('@{magenta-6}', 10) `); + +// alias of magenta +@pink-1: color(~`colorPalette('@{pink-6}', 1) `); +@pink-2: color(~`colorPalette('@{pink-6}', 2) `); +@pink-3: color(~`colorPalette('@{pink-6}', 3) `); +@pink-4: color(~`colorPalette('@{pink-6}', 4) `); +@pink-5: color(~`colorPalette('@{pink-6}', 5) `); +@pink-6: #eb2f96; +@pink-7: color(~`colorPalette('@{pink-6}', 7) `); +@pink-8: color(~`colorPalette('@{pink-6}', 8) `); +@pink-9: color(~`colorPalette('@{pink-6}', 9) `); +@pink-10: color(~`colorPalette('@{pink-6}', 10) `); + +@red-1: color(~`colorPalette('@{red-6}', 1) `); +@red-2: color(~`colorPalette('@{red-6}', 2) `); +@red-3: color(~`colorPalette('@{red-6}', 3) `); +@red-4: color(~`colorPalette('@{red-6}', 4) `); +@red-5: color(~`colorPalette('@{red-6}', 5) `); +@red-6: #f5222d; +@red-7: color(~`colorPalette('@{red-6}', 7) `); +@red-8: color(~`colorPalette('@{red-6}', 8) `); +@red-9: color(~`colorPalette('@{red-6}', 9) `); +@red-10: color(~`colorPalette('@{red-6}', 10) `); + +@orange-1: color(~`colorPalette('@{orange-6}', 1) `); +@orange-2: color(~`colorPalette('@{orange-6}', 2) `); +@orange-3: color(~`colorPalette('@{orange-6}', 3) `); +@orange-4: color(~`colorPalette('@{orange-6}', 4) `); +@orange-5: color(~`colorPalette('@{orange-6}', 5) `); +@orange-6: #fa8c16; +@orange-7: color(~`colorPalette('@{orange-6}', 7) `); +@orange-8: color(~`colorPalette('@{orange-6}', 8) `); +@orange-9: color(~`colorPalette('@{orange-6}', 9) `); +@orange-10: color(~`colorPalette('@{orange-6}', 10) `); + +@yellow-1: color(~`colorPalette('@{yellow-6}', 1) `); +@yellow-2: color(~`colorPalette('@{yellow-6}', 2) `); +@yellow-3: color(~`colorPalette('@{yellow-6}', 3) `); +@yellow-4: color(~`colorPalette('@{yellow-6}', 4) `); +@yellow-5: color(~`colorPalette('@{yellow-6}', 5) `); +@yellow-6: #fadb14; +@yellow-7: color(~`colorPalette('@{yellow-6}', 7) `); +@yellow-8: color(~`colorPalette('@{yellow-6}', 8) `); +@yellow-9: color(~`colorPalette('@{yellow-6}', 9) `); +@yellow-10: color(~`colorPalette('@{yellow-6}', 10) `); + +@volcano-1: color(~`colorPalette('@{volcano-6}', 1) `); +@volcano-2: color(~`colorPalette('@{volcano-6}', 2) `); +@volcano-3: color(~`colorPalette('@{volcano-6}', 3) `); +@volcano-4: color(~`colorPalette('@{volcano-6}', 4) `); +@volcano-5: color(~`colorPalette('@{volcano-6}', 5) `); +@volcano-6: #fa541c; +@volcano-7: color(~`colorPalette('@{volcano-6}', 7) `); +@volcano-8: color(~`colorPalette('@{volcano-6}', 8) `); +@volcano-9: color(~`colorPalette('@{volcano-6}', 9) `); +@volcano-10: color(~`colorPalette('@{volcano-6}', 10) `); + +@geekblue-1: color(~`colorPalette('@{geekblue-6}', 1) `); +@geekblue-2: color(~`colorPalette('@{geekblue-6}', 2) `); +@geekblue-3: color(~`colorPalette('@{geekblue-6}', 3) `); +@geekblue-4: color(~`colorPalette('@{geekblue-6}', 4) `); +@geekblue-5: color(~`colorPalette('@{geekblue-6}', 5) `); +@geekblue-6: #2f54eb; +@geekblue-7: color(~`colorPalette('@{geekblue-6}', 7) `); +@geekblue-8: color(~`colorPalette('@{geekblue-6}', 8) `); +@geekblue-9: color(~`colorPalette('@{geekblue-6}', 9) `); +@geekblue-10: color(~`colorPalette('@{geekblue-6}', 10) `); + +@lime-1: color(~`colorPalette('@{lime-6}', 1) `); +@lime-2: color(~`colorPalette('@{lime-6}', 2) `); +@lime-3: color(~`colorPalette('@{lime-6}', 3) `); +@lime-4: color(~`colorPalette('@{lime-6}', 4) `); +@lime-5: color(~`colorPalette('@{lime-6}', 5) `); +@lime-6: #a0d911; +@lime-7: color(~`colorPalette('@{lime-6}', 7) `); +@lime-8: color(~`colorPalette('@{lime-6}', 8) `); +@lime-9: color(~`colorPalette('@{lime-6}', 9) `); +@lime-10: color(~`colorPalette('@{lime-6}', 10) `); + +@gold-1: color(~`colorPalette('@{gold-6}', 1) `); +@gold-2: color(~`colorPalette('@{gold-6}', 2) `); +@gold-3: color(~`colorPalette('@{gold-6}', 3) `); +@gold-4: color(~`colorPalette('@{gold-6}', 4) `); +@gold-5: color(~`colorPalette('@{gold-6}', 5) `); +@gold-6: #faad14; +@gold-7: color(~`colorPalette('@{gold-6}', 7) `); +@gold-8: color(~`colorPalette('@{gold-6}', 8) `); +@gold-9: color(~`colorPalette('@{gold-6}', 9) `); +@gold-10: color(~`colorPalette('@{gold-6}', 10) `); + +@preset-colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue, + purple; + + +@border-radius-base: 3px; +@border-radius-sm: 2px; +@shadow-color: rgba(0, 0, 0, 0.05); +@shadow-1-down: 4px 4px 40px @shadow-color; +@border-color-split: #f4f4f4; +@border-color-base: #e5e5e5; +@font-size-base: 13px; +@text-color: #666; +@hover-color: #f9f9fc; diff --git a/src/themes/index.less b/src/themes/index.less new file mode 100644 index 00000000..a4218382 --- /dev/null +++ b/src/themes/index.less @@ -0,0 +1,127 @@ +@import '~themes/vars.less'; + +body { + height: 100%; + overflow-y: hidden; + background-color: #fff; +} + +::-webkit-scrollbar-thumb { + background-color: #fff; +} + + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +:global { + + .ant-breadcrumb { + & > span { + &:last-child { + color: #999; + font-weight: normal; + } + } + } + + .ant-breadcrumb-link { + .anticon + span { + margin-left: 4px; + } + } + + .ant-table { + .ant-table-thead > tr > th { + text-align: center; + } + + .ant-table-tbody > tr > td { + text-align: center; + } + + &.ant-table-small { + .ant-table-thead > tr > th { + background: #f7f7f7; + } + + .ant-table-body > table { + padding: 0; + } + } + } + + + .ant-table-pagination { + float: none !important; + display: table; + margin: 16px auto !important; + } + + .ant-popover-inner { + border: none; + border-radius: 0; + box-shadow: 0 0 20px rgba(100, 100, 100, 0.2); + } + + .ant-form-item-control { + vertical-align: middle; + } + + .ant-modal-mask { + background-color: rgba(55, 55, 55, 0.2); + } + + .ant-modal-content { + box-shadow: none; + } + + .ant-select-dropdown-menu-item { + padding: 12px 16px !important; + } + + .margin-right { + margin-right: 16px; + } + + a:focus { + text-decoration: none; + } + + .ant-table-layout-fixed table { + table-layout: auto; + } +} +@media (min-width: 1600px) { + :global { + .ant-col-xl-48 { + width: 20%; + } + + .ant-col-xl-96 { + width: 40%; + } + } +} +@media (max-width: 767px) { + :global { + .ant-pagination-item, + .ant-pagination-next, + .ant-pagination-options, + .ant-pagination-prev { + margin-bottom: 8px; + } + + .ant-card { + .ant-card-head { + padding: 0 12px; + } + + .ant-card-body { + padding: 12px; + } + } + } +} \ No newline at end of file diff --git a/src/themes/mixin.less b/src/themes/mixin.less new file mode 100644 index 00000000..d8a4d070 --- /dev/null +++ b/src/themes/mixin.less @@ -0,0 +1,35 @@ +@import '~themes/default'; + +@dark-half: #494949; +@purple: #d897eb; +@shadow-1: 4px 4px 20px 0 rgba(0, 0, 0, 0.01); +@shadow-2: 4px 4px 40px 0 rgba(0, 0, 0, 0.05); +@transition-ease-in: all 0.3s ease-out; +@transition-ease-out: all 0.3s ease-out; +@ease-in: ease-in; + +.text-overflow { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.text-gradient { + background-image: -webkit-gradient( + linear, + 37.219838% 34.532506%, + 36.425669% 93.178216%, + from(#29cdff), + to(#0a60ff), + color-stop(0.37, #148eff) + ); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.background-hover { + transition: @transition-ease-in; + &:hover { + background-color: @hover-color; + } +} diff --git a/src/themes/vars.less b/src/themes/vars.less new file mode 100644 index 00000000..b1c52c52 --- /dev/null +++ b/src/themes/vars.less @@ -0,0 +1,14 @@ +@import '~themes/default.less'; +@import '~themes/mixin.less'; + +@DarkMode-backgroud_container: rgb(24, 26, 27); +@DarkMode-backgroud: #2F2E30; +@LightMode-backgroud: #fff; + +@DarkMode-color_container: rgb(195, 191, 182); +@DarkMode-color: #fff; +@LightMode-color: #2F2E30; + + + + diff --git a/src/utils/constant.js b/src/utils/constant.js new file mode 100644 index 00000000..36834282 --- /dev/null +++ b/src/utils/constant.js @@ -0,0 +1,8 @@ +// ** Deprecated Roles ** // +// export const ROLE_TYPE = { +// ADMIN: 'admin', +// DEFAULT: 'guest', +// DEVELOPER: 'developer', +// } + +export const CANCEL_REQUEST_MESSAGE = 'cancel request'; diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 00000000..b254fc58 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,253 @@ +import { cloneDeep, isString, flow, curry } from 'lodash'; +import umiRouter from 'umi/router'; +import pathToRegexp from 'path-to-regexp'; +import { i18n } from 'config'; + +export classnames from 'classnames'; +export config from 'config'; +export request from './request'; +export { Color } from './theme'; + +export const { defaultLanguage } = i18n +export const languages = i18n.languages.map(item => item.key) + +/** + * Query objects that specify keys and values in an array where all values are objects. + * @param {array} array An array where all values are objects, like [{key:1},{key:2}]. + * @param {string} key The key of the object that needs to be queried. + * @param {string} value The value of the object that needs to be queried. + * @return {object|undefined} Return frist object when query success. + */ +export function queryArray(array, key, value) { + if (!Array.isArray(array)) { + return; + } + return array.find(_ => _[key] === value); +} + +/** + * Convert an array to a tree-structured array. + * @param {array} array The Array need to Converted. + * @param {string} id The alias of the unique ID of the object in the array. + * @param {string} parentId The alias of the parent ID of the object in the array. + * @param {string} children The alias of children of the object in the array. + * @return {array} Return a tree-structured array. + */ +export function arrayToTree( + array, + id = 'id', + parentId = 'pid', + children = 'children' +) { + const result = []; + const hash = {}; + const data = cloneDeep(array); + + data.forEach((item, index) => { + hash[data[index][id]] = data[index] + }) + + data.forEach(item => { + const hashParent = hash[item[parentId]] + if (hashParent) { + !hashParent[children] && (hashParent[children] = []) + hashParent[children].push(item) + } else { + result.push(item); + } + }) + return result; +} + +export const langFromPath = curry( + /** + * Query language from pathname. + * @param {array} languages Specify which languages are currently available. + * @param {string} defaultLanguage Specify the default language. + * @param {string} pathname Pathname to be queried. + * @return {string} Return the queryed language. + */ + (languages, defaultLanguage, pathname) => { + for (const item of languages) { + if (pathname.startsWith(`/${item}/`)) { + return item; + } + } + return defaultLanguage; + } +)(languages)(defaultLanguage) + +export const deLangPrefix = curry( + /** + * Remove the language prefix in pathname. + * @param {array} languages Specify which languages are currently available. + * @param {string} pathname Remove the language prefix in the pathname. + * @return {string} Return the pathname after removing the language prefix. + */ + (languages, pathname) => { + if (!pathname) { + return; + } + for (const item of languages) { + if (pathname.startsWith(`/${item}/`)) { + return pathname.replace(`/${item}/`, '/') + } + } + + return pathname; + } +)(languages) + +/** + * Add the language prefix in pathname. + * @param {string} pathname Add the language prefix in the pathname. + * @return {string} Return the pathname after adding the language prefix. + */ +export function addLangPrefix(pathname) { + const prefix = langFromPath(window.location.pathname) + return `/${prefix}${deLangPrefix(pathname)}`; +} + +const routerAddLangPrefix = params => { + if (isString(params)) { + params = addLangPrefix(params) + } else { + params.pathname = addLangPrefix(params.pathname) + } + return params; +} + +/** + * Adjust the router to automatically add the current language prefix before the pathname in push and replace. + */ +const myRouter = { ...umiRouter } + +myRouter.push = flow( + routerAddLangPrefix, + umiRouter.push +) + +myRouter.replace = flow( + routerAddLangPrefix, + myRouter.replace +) + +export const router = myRouter + +/** + * Whether the path matches the regexp if the language prefix is ignored, https://github.com/pillarjs/path-to-regexp. + * @param {string|regexp|array} regexp Specify a string, array of strings, or a regular expression. + * @param {string} pathname Specify the pathname to match. + * @return {array|null} Return the result of the match or null. + */ +export function pathMatchRegexp(regexp, pathname) { + return pathToRegexp(regexp).exec(deLangPrefix(pathname)) +} + +/** + * In an array object, traverse all parent IDs based on the value of an object. + * @param {array} array The Array need to Converted. + * @param {string} current Specify the value of the object that needs to be queried. + * @param {string} parentId The alias of the parent ID of the object in the array. + * @param {string} id The alias of the unique ID of the object in the array. + * @return {array} Return a key array. + */ +export function queryPathKeys(array, current, parentId, id = 'id') { + const result = [current] + const hashMap = new Map() + array.forEach(item => hashMap.set(item[id], item)) + + const getPath = current => { + const currentParentId = hashMap.get(current)[parentId] + if (currentParentId) { + result.push(currentParentId) + getPath(currentParentId) + } + } + + getPath(current) + return result; +} + +/** + * In an array of objects, specify an object that traverses the objects whose parent ID matches. + * @param {array} array The Array need to Converted. + * @param {string} current Specify the object that needs to be queried. + * @param {string} parentId The alias of the parent ID of the object in the array. + * @param {string} id The alias of the unique ID of the object in the array. + * @return {array} Return a key array. + */ +export function queryAncestors(array, current, parentId, id = 'id') { + const result = [current] + const hashMap = new Map() + array.forEach(item => hashMap.set(item[id], item)) + + const getPath = current => { + const currentParentId = hashMap.get(current[id])[parentId] + if (currentParentId) { + result.push(hashMap.get(currentParentId)) + getPath(hashMap.get(currentParentId)) + } + } + + getPath(current) + return result; +} + +/** + * Query which layout should be used for the current path based on the configuration. + * @param {layouts} layouts Layout configuration. + * @param {pathname} pathname Path name to be queried. + * @return {string} Return frist object when query success. + */ +export function queryLayout(layouts, pathname) { + let result = 'public'; + + const isMatch = regepx => { + return regepx instanceof RegExp + ? regepx.test(pathname) + : pathMatchRegexp(regepx, pathname) + } + + for (const item of layouts) { + let include = false + let exclude = false + if (item.include) { + for (const regepx of item.include) { + if (isMatch(regepx)) { + include = true; + break; + } + } + } + + if (include && item.exclude) { + for (const regepx of item.exclude) { + if (isMatch(regepx)) { + exclude = true; + break; + } + } + } + + if (include && !exclude) { + result = item.name; + break; + } + } + + return result; +} + +export function getLocale() { + return langFromPath(window.location.pathname); +} + +export function setLocale(language) { + if (getLocale() !== language) { + umiRouter.push({ + pathname: `/${language}${deLangPrefix(window.location.pathname)}`, + search: window.location.search, + }); + } +} diff --git a/src/utils/index.test.js b/src/utils/index.test.js new file mode 100644 index 00000000..e72a0bbe --- /dev/null +++ b/src/utils/index.test.js @@ -0,0 +1,20 @@ +import { pathMatchRegexp } from './index' +import pathToRegexp from 'path-to-regexp' + +describe('test pathMatchRegexp', () => { + it('get right', () => { + expect(pathMatchRegexp('/user', '/zh/user')).toEqual( + pathToRegexp('/user').exec('/user') + ) + expect(pathMatchRegexp('/user', '/user')).toEqual( + pathToRegexp('/user').exec('/user') + ) + + expect(pathMatchRegexp('/user/:id', '/zh/user/1')).toEqual( + pathToRegexp('/user/:id').exec('/user/1') + ) + expect(pathMatchRegexp('/user/:id', '/user/1')).toEqual( + pathToRegexp('/user/:id').exec('/user/1') + ) + }) +}) diff --git a/src/utils/model.js b/src/utils/model.js new file mode 100644 index 00000000..6bc8b9ba --- /dev/null +++ b/src/utils/model.js @@ -0,0 +1,39 @@ +import modelExtend from 'dva-model-extend' + +export const model = { + reducers: { + updateState(state, { payload }) { + return { + ...state, + ...payload, + } + }, + }, +} + +export const pageModel = modelExtend(model, { + state: { + list: [], + pagination: { + showSizeChanger: true, + showQuickJumper: true, + current: 1, + total: 0, + pageSize: 10, + }, + }, + + reducers: { + querySuccess(state, { payload }) { + const { list, pagination } = payload + return { + ...state, + list, + pagination: { + ...state.pagination, + ...pagination, + }, + } + }, + }, +}) diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 00000000..8de3efa1 --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,97 @@ +import axios from 'axios' +import { cloneDeep, isEmpty } from 'lodash' +import pathToRegexp from 'path-to-regexp' +import { message } from 'antd' +import { CANCEL_REQUEST_MESSAGE } from 'utils/constant' +import qs from 'qs' + +const { CancelToken } = axios +window.cancelRequest = new Map() + +export default function request(options) { + let { data, url, method = 'get' } = options; + const cloneData = cloneDeep(data); + + try { + let domain = '' + const urlMatch = url.match(/[a-zA-z]+:\/\/[^/]*/) + if (urlMatch) { + ;[domain] = urlMatch + url = url.slice(domain.length); + } + + const match = pathToRegexp.parse(url); + url = pathToRegexp.compile(url)(data); + + for (const item of match) { + if (item instanceof Object && item.name in cloneData) { + delete cloneData[item.name]; + } + } + url = domain + url; + } catch (e) { + message.error(e.message); + } + + options.url = + method.toLocaleLowerCase() === 'get' + ? `${url}${isEmpty(cloneData) ? '' : '?'}${qs.stringify(cloneData)}` + : url + + options.cancelToken = new CancelToken(cancel => { + window.cancelRequest.set(Symbol(Date.now()), { + pathname: window.location.pathname, + cancel, + }) + }) + + return axios(options) + .then(response => { + const { statusText, status, data } = response + + let result = {} + if (typeof data === 'object') { + result = data; + if (Array.isArray(data)) { + result.list = data; + } + } else { + result.data = data; + } + + return Promise.resolve({ + success: true, + message: statusText, + statusCode: status, + ...result, + }) + }) + .catch(error => { + const { response, message } = error + + if (String(message) === CANCEL_REQUEST_MESSAGE) { + return { + success: false, + } + } + + let msg; + let statusCode; + + if (response && response instanceof Object) { + const { data, statusText } = response + statusCode = response.status + msg = data.message || statusText + } else { + statusCode = 600 + msg = error.message || 'Network Error' + } + + /* eslint-disable */ + return Promise.reject({ + success: false, + statusCode, + message: msg, + }); + }) +} diff --git a/src/utils/theme.js b/src/utils/theme.js new file mode 100644 index 00000000..0a610df4 --- /dev/null +++ b/src/utils/theme.js @@ -0,0 +1,14 @@ +module.exports = { + Color: { + green: '#64ea91', + blue: '#8fc9fb', + purple: '#d897eb', + red: '#f69899', + yellow: '#f8c82e', + peach: '#f797d6', + borderBase: '#e5e5e5', + borderSplit: '#f4f4f4', + grass: '#d6fbb5', + sky: '#c1e0fc', + }, +} diff --git a/src/ycore_style.scss b/src/ycore_style.scss new file mode 100644 index 00000000..5759afe8 --- /dev/null +++ b/src/ycore_style.scss @@ -0,0 +1,1488 @@ +/* (2.0) YulioID V2 */ + +@import url('https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.min.css'); +@import url('https://fonts.googleapis.com/css?family=Poppins:300,300i,500,500i,700'); + + + +.mainlp { + --neutralShade0: #f8f8f8; + --neutralShade1: #f2f2f2; + --neutralShade2: #e8e9e9; + --neutralShade3: #d1d3d4; + --neutralShade4: #babdbf; + --neutralShade5: #808488; + --neutralShade6: #666a6d; + --neutralShade7: #4d5052; + --neutralShade8: #212122; + --grayColor: #999; + --lightGrayColor: #ddd; + --borderRadius: 6px; + --boxShadow: 0 2px 5px rgba(#333, 0.2); +} + +/*overall layout*/ +.mainlp { + width: 90%; + max-width: 1050px; + margin: 3em auto 0; + display: grid; + grid: repeat(5, fit-content(300px))/100%; + color: var(--foregroundColor); + text-align: left; +} + +.mainlp .sectionlp { + border: 1px solid var(--accentColor); + position: relative; + padding: 40px 40px 50px; +} + +.mainlp .sectionlp>h6 { + color: var(--accentColor); + background: var(--canvasColor); + position: absolute; + top: -10px; + left: 20px; + padding: 0 10px; +} + +.mainlp .sectionlp .h6lp.subheader { + color: var(--grayColor); + margin-top: 20px; + margin-bottom: 20px; + width: 100%; +} + +@media (max-width: 992px) { + section:not(:last-child) { + border-width: 0 0 1px; + } + + section:last-child { + border-width: 0; + } +} + +@media (min-width: 992px) { + main { + grid: repeat(9, auto)/45% 1fr 45%; + grid-auto-flow: dense; + } + + .media-card-1 { + grid-column: 1 / 2; + border-width: 1px 0; + } + + .media-card-2 { + grid-column: 2 / 4; + border-width: 1px 0 1px 1px; + } + + .media-card-3 { + grid-column: 1 / 4; + border-width: 0; + } + + .filter-section { + grid-column: 3 / 4; + grid-row: 1 / 2; + border-width: 0 0 0 1px; + } + + .well-cta-1 { + grid-row: 3; + grid-column: 1 / 3; + border-width: 1px 1px 0 0; + } + + .well-cta-2 { + grid-row: 2; + grid-column: 2 / 4; + border-width: 1px 0 0; + } + + .tables { + grid-row: 4; + grid-column: 1 / -1; + border-width: 1px 0 0; + } + + .forms { + grid-column: 1 / 3; + border-width: 0; + } + + .comments { + grid-row: 2; + grid-column: 1 / 2; + border-width: 1px 1px 0 0; + padding-top: 60px; + } + + .modals { + grid-row: 3; + grid-column: 3 / 4; + justify-content: center; + border-width: 1px 0 0; + } +} + + +/*checkboxes*/ +input:disabled~* { + opacity: 0.3; + user-select: none; + pointer-events: none; +} + +.checkboxtoggle input { + display: none; +} + +.checkboxtoggle label { + outline: 0; + display: block; + width: 45px; + height: 16px; + background: var(--grayColor); + position: relative; + cursor: pointer; + border-radius: 2em; + padding: 2px; + transition: all 0.4s ease; + margin: 0; +} + +.checkboxtoggle .labellp:after { + position: relative; + display: block; + content: ""; + width: 20px; + height: 20px; + border-radius: 50%; + background: #fff; + transition: all 0.2s ease; + border: 1px solid var(--grayColor); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + left: -4px; + top: -5px; +} + +.checkboxtoggle input:checked+.labellp { + background: var(--accent2Color); +} + +.checkboxtoggle input:checked+.labellp:after { + left: 52%; +} + +.checkbox { + position: relative; + user-select: none; + margin-bottom: 10px; +} + +.checkbox input { + display: none; +} + +.checkbox .labellp { + position: relative; + vertical-align: middle; + cursor: pointer; + font-weight: 500; + padding-left: 35px; +} + +.checkbox .spanlp.box { + display: inline-block; + width: 20px; + border-radius: var(--borderRadius); + border: 1px solid var(--grayColor); + width: 24px; + height: 24px; + vertical-align: middle; + margin-right: 3px; + transition: 0.3s ease; + position: absolute; + left: 0; +} + +.checkbox .spanlp.box:before, +.checkbox .spanlp.box:after { + content: ""; + position: absolute; + width: 4px; + height: 16px; + border-radius: 40px; + background: var(--backgroundColor); + transition: all 0.3s ease; +} + +.checkbox .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(0); +} + +.checkbox .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(0); +} + +.checkbox input:checked+.labellp .spanlp.box { + background: var(--accent2Color); + border-color: var(--accent2Color); +} + +.checkbox input:checked+.labellp .spanlp.box:before { + transform: rotate(45deg) translateY(-5px) translateX(10px) scale(1); +} + +.checkbox input:checked+.labellp .spanlp.box:after { + height: 8px; + transform: rotate(-45deg) translateY(10px) translateX(-4px) scale(1); +} + +.checkbox input:disabled:checked+.spanlp.box { + background: var(--grayColor); + border: var(--grayColor); +} + +.checkbox input:disabled:checked~.labellp:before, +.checkbox input:disabled:checked~.labellp:after { + background: black; +} + +/*buttons & links*/ +.links__sec { + margin: 10px 0 30px; +} + +.links a.link { + display: inline; + margin: 10px 30px 5px 0; + border-bottom: 2px dashed; + font-weight: 500; + line-height: 2.5; + cursor: pointer; + color: var(--neutralShade5); +} + +.links a.link:hover, +.links a.link.hover { + color: var(--neutralShade6); + border-bottom: 2px solid; +} + +.links a.link.primary { + color: var(--primaryColor); +} + +.links a.link.primary:hover, +.links a.link.primary.hover { + color: var(--primaryShade5); +} + +.links a.link.secondary { + color: var(--secondaryColor); +} + +.links a.link.secondary:hover, +.links a.link.secondary.hover { + color: var(--secondaryShade5); +} + +.buttons { + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.buttons>* { + flex: 1 1 calc(50% - 20px); + margin-top: 20px; +} + +.buttons>*:nth-child(odd) { + margin-right: 20px; +} + +a.buttonlp, +input.buttonlp, +.buttonlp { + outline: none; + width: 100%; + text-align: center; + display: inline-block; + border: none; + font: 500 16px/1 "Poppins", sans-serif; + padding: 20px; + cursor: pointer; + border-radius: var(--borderRadius); + background: var(--primaryColor); + color: var(--backgroundColor); + position: relative; + top: 0; + transition: 0.2s ease; +} + +a.buttonlp:hover, +a.buttonlp.hover, +input.buttonlp:hover, +input.buttonlp.hover, +.buttonlp:hover, +.buttonlp.hover { + top: -3px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); +} + +a.buttonlp:active, +a.buttonlp.active, +input.buttonlp:active, +.input.buttonlp.active, +.buttonlp:active, +.buttonlp.active { + background: var(--primaryShade4); + outline: none; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + top: 0; +} + +a.buttonlp.disabled, +input.buttonlp.disabled, +.buttonlp.disabled { + opacity: 0.4; + user-select: none; + pointer-events: none; +} + +a.buttonlp.medium, +input.buttonlp.medium, +.buttonlp.medium { + padding: 15px 18px; + width: auto; +} + +a.buttonlp.small, +input.buttonlp.small, +.buttonlp.small { + padding: 10px 12px; + width: auto; + font-size: 14px; + font-weight: 500; +} + +a.buttonlp.secondary, +input.buttonlp.secondary, +.buttonlp.secondary { + background: var(--secondaryColor); +} + +a.buttonlp.secondary:active, +a.buttonlp.secondary:focus, +a.buttonlp.secondary.active, +input.buttonlp.secondary:active, +input.buttonlp.secondary:focus, +input.buttonlp.secondary.active, +.buttonlp.secondary:active, +.buttonlp.secondary:focus, +.buttonlp.secondary.active { + background: var(--secondaryShade4); + outline: none; +} + +a.buttonlp.accent, +input.buttonlp.accent, +.buttonlp.accent { + background: var(--accentColor); +} + +a.buttonlp.accent:active, +a.buttonlp.accent:focus, +a.buttonlp.accent.active, +input.buttonlp.accent:active, +input.buttonlp.accent:focus, +input.buttonlp.accent.active, +.buttonlp.accent:active, +.buttonlp.accent:focus, +.buttonlp.accent.active { + background: var(--accentShade4); +} + +a.buttonlp.accent2, +input.buttonlp.accent2, +.buttonlp.accent2 { + background: var(--accent2Color); +} + +a.buttonlp.accent2:active, +a.buttonlp.accent2:focus, +a.buttonlp.accent2.active, +input.buttonlp.accent2:active, +input.buttonlp.accent2:focus, +input.buttonlp.accent2.active, +.buttonlp.accent2:active, +.buttonlp.accent2:focus, +.buttonlp.accent2.active { + background: var(--accent2Shade4); +} + +a.buttonlp.accent3, +input.buttonlp.accent3, +.buttonlp.accent3 { + background: var(--accent3Color); +} + +a.buttonlp.accent3:active, +a.buttonlp.accent3:focus, +a.buttonlp.accent3.active, +input.buttonlp.accent3:active, +input.buttonlp.accent3:focus, +input.buttonlp.accent3.active, +.buttonlp.accent3:active, +.buttonlp.accent3:focus, +.buttonlp.accent3.active { + background: var(--accent3Shade4); +} + +/*inputs*/ +.input__wrapper { + margin-bottom: 10px; +} + + +.labelform { + font-weight: 500; + display: block; + margin-bottom: 5px; +} + +input.inputform, +select, +textarea { + height: 50px; + font-size: 16px; + border: 2px solid var(--neutralShade3); + width: 100%; + padding: 12px; + font-family: "Poppins"; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + background: var(--backgroundColor); +} + +input.inputform:focus, +input.inputform.active, +select:focus, +select.active, +textarea:focus, +textarea.active { + outline: none; + border-color: var(--primaryColor); +} + +input.inputform:disabled, +select:disabled, +textarea:disabled { + cursor: not-allowed; + background: var(--neutralShade1); + opacity: 0.6; +} + +input.inputform.input { + height: 56px; + font-size: 18px; + padding: 15px; +} + +/*badges*/ +.badge { + display: inline-block; + padding: 6px 12px; + border-radius: 50px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; +} + +.alert { + margin-bottom: 15px; + display: block; + padding: 10px 15px; + border-radius: var(--borderRadius); + font-weight: 500; + position: relative; + cursor: pointer; +} + +.alert.non-collapsible:before, +.alert.non-collapsible:after { + content: none; +} + +.alert:before, +.alert:after { + content: ""; + position: absolute; + width: 4px; + height: 16px; + border-radius: 40px; + right: 30px; + top: 8px; +} + +.alert:before { + transform: rotate(45deg) translateY(-5.5px) translateX(13.5px); +} + +.alert:after { + transform: rotate(-45deg) translateY(13.5px) translateX(5.5px); +} + +.status-primary { + background: var(--primaryShade1); + color: var(--primaryShade5); +} + +.status-primary:before, +.status-primary:after { + background: var(--primaryShade5); +} + +.status-secondary { + background: var(--secondaryShade1); + color: var(--secondaryShade5); +} + +.status-secondary:before, +.status-secondary:after { + background: var(--secondaryShade5); +} + +.status-info { + background: var(--accentShade1); + color: var(--accentShade5); +} + +.status-info:before, +.status-info:after { + background: var(--accentShade5); +} + +.status-success { + background: var(--accent2Shade1); + color: var(--accent2Shade5); +} + +.status-success:before, +.status-success:after { + background: var(--accent2Shade5); +} + +.status-error { + background: var(--accent3Shade1); + color: var(--accent3Shade5); +} + +.status-error:before, +.status-error:after { + background: var(--accent3Shade5); +} + +/*tooltips*/ +.tooltip { + cursor: pointer; + position: relative; + display: block; + width: 100%; + text-align: center; + z-index: 10; +} + +.tooltip .spanlp { + border-bottom: 1px dotted; +} + +.tooltip:after { + content: attr(data-tooltip); + background: var(--neutralShade2); + max-width: 90%; + width: auto; + position: absolute; + left: 0; + right: 0; + margin: auto; + opacity: 0; + height: auto; + font-size: 14px; + padding: 10px; + border-radius: var(--borderRadius); + color: var(--foregroundColor); + text-align: center; +} + +.tooltip.dark:after { + background: var(--neutralShade7); + color: var(--backgroundColor); +} + +.tooltip.top:after { + bottom: 80%; + transition: opacity 0.3s ease 0.3s, bottom 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.3s; +} + +.tooltip.top:hover:after, +.tooltip.top.hovered:after { + bottom: 130%; + opacity: 1; +} + +.tooltip.bottom:after { + top: 80%; + transition: opacity 0.3s ease 0.3s, top 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.3s; +} + +.tooltip.bottom:hover:after, +.tooltip.bottom.hovered:after { + top: 130%; + opacity: 1; +} + +/*spinner*/ +.spinner+.labellp { + font-size: 14px; + font-weight: 500; + margin-top: 8px; + display: inline-block; + text-transform: uppercase; + color: var(--primaryShade4); +} + +.spinner1 .spinner { + max-width: 50px; + margin: auto; + height: 20px; + position: relative; +} + +.spinner1 .spinner:after { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryColor); + animation: spinnerLeftRight 1s infinite; +} + +.spinner1 .spinner:before { + content: ""; + position: absolute; + width: 20px; + height: 20px; + left: -10%; + background: var(--primaryShade2); + opacity: 1; + animation: spinnerLeftRight 1s infinite 0.06s; +} + +@keyframes spinnerLeftRight { + 0% { + left: 85%; + } + + 50% { + left: -10%; + } + + 100% { + left: 85%; + } +} + + +#sunset+.labellp { + background: linear-gradient(to right, #ff9557 50%, #ffcc67 50%); +} + +.mainlp { + --canvasColor: #f9f9f9; + --backgroundColor: #fff; + --foregroundColor: #111; + --primaryColor: #ff9557; + --primaryShade1: #ffe2d1; + --primaryShade2: #ffceb2; + --primaryShade3: #ffb184; + --primaryShade4: #e88850; + --primaryShade5: #d17a48; + --secondaryColor: #ffcc67; + --secondaryShade1: #fff1d5; + --secondaryShade2: #ffde9e; + --secondaryShade3: #ffd074; + --secondaryShade4: #e8ba5e; + --secondaryShade5: #ba954b; + --accentColor: #4e5166; + --accentShade1: #cecfd5; + --accentShade2: #aeafb9; + --accentShade3: #8e909d; + --accentShade4: #6e7081; + --accentShade5: #404354; + --accent2Color: #588b8b; + --accent2Shade1: #c2d4d4; + --accent2Shade2: #a3bfbf; + --accent2Shade3: #85aaaa; + --accent2Shade4: #507f7f; + --accent2Shade5: #497272; + --accent3Color: #fe5f55; + --accent3Shade1: #fec4c1; + --accent3Shade2: #fea7a2; + --accent3Shade3: #fe7c73; + --accent3Shade4: #e7574e; + --accent3Shade5: #b9463e; +} + + + +/* PROFILE CARDS */ +.profile { + position: relative; + background: var(--backgroundColor); + color: var(--foregroundColor); + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + border-radius: 10px; + overflow: hidden; + transition: .2s ease; + display: grid; + grid: 200px repeat(5, auto)/100%; +} + +.profile__image img { + width: 100%; + height: 100%; + object-fit: cover; + border-bottom: 7px solid var(--secondaryColor); +} + +.profile__info { + padding: 20px 25px 0; +} + +.profile__stats { + padding: 5px 25px; +} + +.profile__stats__title { + color: var(--grayColor); + text-transform: uppercase; + font-size: 16px; +} + +.profile__cta { + padding: 0 25px 25px; +} + +.profile a:hover { + top: 0; + box-shadow: none; + background: var(--primaryShade4); +} + +.profile a:active, +.profile a:focus { + top: 0; + box-shadow: none; + background: var(--primaryShade5); +} + +@media (min-width: 500px) { + .profile-default { + min-width: 500px; + max-width: 450px; + margin: auto; + overflow: hidden; + grid: 340px auto auto/repeat(3, minmax(80px, 1fr)); + grid-gap: 10px; + } + + .profile-default .profile__image { + grid-column: span 3; + } + + .profile-default .profile__info { + grid-column: span 3; + } + + .profile-default .profile__stats { + padding: 5px 25px; + } + + .profile-default .profile__cta { + grid-column: span 3; + } +} + +@media (min-width: 768px) { + .profile-long { + grid-template-columns: 150px repeat(3, 1fr) auto; + grid-template-rows: auto auto; + width: 100%; + padding-right: 20px; + } + + .profile-long .profile__image { + grid-column: 1 / 2; + grid-row: 1 / 3; + margin-right: 20px; + } + + .profile-long .profile__image img { + border-radius: 10px 0 0 10px; + border: none; + } + + .profile-long .profile__info { + grid-column: 2 / 6; + grid-row: 1; + padding: 20px 20px 15px 0; + } + + .profile-long .profile__stats { + min-width: 100px; + padding: 15px 0; + border-top: 0.5px solid var(--grayColor); + grid-row: 2 / 3; + } + + .profile-long .profile__stats:nth-child(3) { + grid-column: 2 / 3; + } + + .profile-long .profile__stats:nth-child(4) { + grid-column: 3 / 4; + } + + .profile-long .profile__stats:nth-child(5) { + grid-column: 4 / 5; + } + + .profile-long .profile__cta { + grid-row: 2 / 3; + grid-column: 5 / 6; + border-top: 0.5px solid var(--grayColor); + padding: 15px 0 0; + } +} + +.profile-imgonly { + border-radius: 10px; + overflow: hidden; + min-width: 250px; + width: 100%; + grid: 480px 0px / 100%; +} + +.profile-imgonly:hover { + grid: 434px 56px / 100%; +} + +.profile-imgonly .profile__image, +.profile-imgonly .profile__info { + grid-row: 1 / 2; + grid-column: 1 / 2; +} + +.profile-imgonly .profile__image { + position: relative; +} + +.profile-imgonly .profile__image:after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 30%; + background: linear-gradient(to top, rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0)); +} + +.profile-imgonly .profile__image img { + border: none; +} + +.profile-imgonly .profile__stats { + display: none; +} + +.profile-imgonly .profile__info { + z-index: 5; + grid-row: 1 / 2; + align-self: end; + margin: 0 0 15px; + color: #fff; + text-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); +} + +.profile-imgonly .profile__info p { + display: none; +} + +.profile-imgonly .profile__cta { + padding: 0; +} + +.profile-imgonly .profile__cta a { + border-radius: 0; +} + +#dark:checked~.mainlp a.buttonlp, +#pinkaru:checked~.mainlp a.buttonlp { + color: var(--foregroundColor); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); +} + +#dark:checked~.mainlp .buttonlp:hover, +#pinkaru:checked~.mainlp .buttonlp:hover { + background: var(--primaryShade2); +} + +#dark:checked~.mainlp .buttonlp:active, +#pinkaru:checked~.mainlp .buttonlp:active { + background: var(--primaryShade1); +} + +#dark:checked~.mainlp .profile-default img, +#pinkaru:checked~.mainlp .profile-default img { + border-bottom: 7px solid var(--secondaryShade5); +} + +/*FILTERS*/ +.filters__title { + font-size: 18px; + color: var(--grayColor); + margin: 25px 0; +} + +.filters__item { + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + margin-bottom: 10px; +} + +.filters__item .checkbox { + position: relative; + margin: 0; +} + +.filters__item .checkbox .tooltip { + display: inline-block; + margin-left: 10px; + width: auto; + vertical-align: middle; +} + +.filters__item .checkbox .tooltip .spanlp { + border: none; +} + +.filters__item .checkbox .tooltip:after { + min-width: 100px; + margin-left: -50px; +} + +.filters:not(:first-of-type) { + border-top: 0.5px solid var(--lightGrayColor); + margin-top: 25px; +} + +/* WELL CTA */ +.well-cta { + border-radius: 10px; + background: var(--secondaryColor); + color: var(--foregroundColor); + overflow: hidden; +} + +.well-cta__text { + padding: 30px; +} + +.well-cta__text p { + font-size: 18px; + line-height: 1.5; +} + +.well-cta__text a { + margin: 25px 0 0; +} + +.well-cta__image { + padding: 30px 0 0; +} + +.well-cta img { + width: 100%; + max-height: 300px; + object-fit: contain; + margin-bottom: -7px; +} + +@media (min-width: 768px) { + .well-cta { + display: grid; + grid: auto / 1fr 250px; + } + + .well-cta__image { + align-self: flex-end; + padding: 15px 0 0; + } +} + +#bluepurple:checked~.mainlp .well-cta__text { + color: var(--backgroundColor); +} + +.well-cta--form { + display: grid; + grid-gap: 10px; + padding: 30px; + background: var(--primaryShade1); + border-radius: 10px; +} + +.well-cta--form__text { + margin-bottom: 10px; +} + +.well-cta--form h3 { + color: var(--primaryShade5); +} + +@media (min-width: 768px) { + .well-cta--form { + grid-template-columns: 1fr auto; + } + + .well-cta--form__text { + grid-column: span 2; + } +} + +/*TABLE*/ +.table { + background: var(--backgroundColor); + border-radius: 10px; +} + +.table__wrapper { + width: 100%; + overflow-y: hidden; + overflow-x: auto; + border-radius: 10px; + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); +} + +.table tr { + display: grid; + grid: auto/80px 80px repeat(2, minmax(150px, 2fr)) repeat(2, minmax(120px, 1.5fr)) 50px; + align-items: center; +} + +.table td { + padding: 15px; +} + +.table__header { + color: var(--neutralShade5); + font-weight: 500; + text-transform: uppercase; + border-bottom: 0.5px solid var(--lightGrayColor); +} + +.table__body tr:nth-child(even) { + background: var(--neutralShade0); +} + +#dark:checked~.mainlp .table__body tr:nth-child(even), +#pinkaru:checked~.mainlp .table__body tr:nth-child(even) { + background: var(--neutralShade8); +} + +/*FORMS*/ +.formlogin { + border-radius: 10px; + padding: 30px; + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + background: var(--backgroundColor); + margin-top: 30px; + position: relative; + overflow: hidden; +} + +.formlogin .checkbox { + margin-bottom: 30px; +} + +.formlogin .spinner__wrapper { + display: grid; + place-items: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background: rgba(255, 255, 255, 0.85); + opacity: 0; + z-index: -1; +} + +@media (min-width: 768px) { + .formlogin { + display: grid; + grid: auto / 1fr 40%; + } + + .formlogin .input__wrapper { + grid-column: span 2; + } + + .formlogin .checkbox { + align-self: center; + margin-bottom: 0; + } +} + +#dark:checked~.mainlp .spinner__wrapper, +#pinkaru:checked~.mainlp .spinner__wrapper { + background: rgba(20, 20, 20, 0.85); +} + +/*COMMENT ITEM*/ +.comment { + display: grid; + grid: auto / 60px 1fr; + grid-gap: 12px; +} + +.comment__image { + grid-row: 1 / 4; +} + +.comment__image img { + width: 60px; + height: 60px; + object-fit: cover; + border-radius: 50%; +} + +.comment__info h5 { + margin-bottom: 0; +} + +.comment__info h5 .spanlp { + vertical-align: middle; +} + +.comment__info h5 .badge { + margin-left: 8px; + font-size: 80%; +} + +.comment__info h5 .badge i { + font-size: 80%; + margin-right: 6px; +} + +.comment__info__time { + color: var(--grayColor); +} + +.comment__reaction i { + margin-right: 8px; + font-size: 85%; +} + +.comment__reaction__heart { + cursor: pointer; + transition: .3s ease; +} + +.comment__reaction__heart.toggled { + color: var(--accent3Shade5); + font-weight: 500; +} + +/*PANEL*/ +.panel { + display: grid; + grid: 200px auto min-content / 100%; + border-radius: 10px; + overflow: hidden; + background: var(--backgroundColor); + box-shadow: 0 3px 15px rgba(51, 51, 51, 0.2); + max-width: 480px; + margin: auto; +} + +.panel__image img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.panel__info { + padding: 30px 30px 20px; +} + +.panel__info h1 { + margin-bottom: 25px; +} + +.panel__info p { + font-size: 20px; + margin: 15px 0; +} + +.panel__info .alert { + font-weight: 300; + margin-top: 30px; +} + +.panel__cta { + padding: 0 30px 30px; + text-align: center; +} + +footer { + display: grid; + grid: min-content / 1fr max-content; + text-align: left; + width: 90%; + margin: 1em auto 4em; + max-width: 1050px; + align-items: center; +} + +footer a { + text-decoration: none; + color: #333; + padding: 3px 0; + border-bottom: 1px dashed; +} + +footer a:hover { + border-bottom: 1px solid; +} + +footer .social a { + text-decoration: none; + margin-left: 10px; +} + +footer .social a .icons { + display: inline-block; + font-size: 20px; +} + +footer.dark, +footer.dark a { + color: #f9f9f9; +} + + + + +/*typography 2*/ +.logoHR { + color: #000; +} + +.logoh1wp { + color: #242331; + +} + +.logoh1wp h1 { + font: 700 48px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.logoh1wp h2 { + font: 700 32px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.logoh1wp h3 { + font: 700 24px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.logoh1wp h4 { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.logoh1wp h5 { + font: 500 18px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.logoh1wp h6 { + font: 500 16px/1.2 "Poppins", sans-serif; + text-transform: uppercase; +} + + +.stonglp { + font-weight: 500; +} + +.emlp { + font-style: italic; +} + +.h1lp { + font: 700 48px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.h2lp { + font: 700 32px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.h3lp { + font: 700 24px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.h4lp { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.h5lp { + font: 500 18px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.h6lp { + font: 500 16px/1.2 "Poppins", sans-serif; + text-transform: uppercase; +} + +.apierrort { + font: 700 20px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; +} + +.apierrort::first-letter { + text-transform: uppercase; +} + + +.coverprc img { + position: absolute; + left: 0px; + top: 0px; + z-index: 1; +} + +.befcoverprc { + z-index: 2; +} + +.flex { + /*Flexbox for containers*/ + display: flex; + justify-content: center; + align-items: center; + text-align: center; +} + +.wavesNav { + + bottom: 0; + +} + +.postNavWaves { + background-color: #F0F2F5; + height: 100%; +} + +.waves { + position: relative; + z-index: 0; + width: 100%; + height: 80vh; + margin-bottom: -7px; + /*Fix for safari gap*/ + min-height: 100px; + max-height: 150px; +} + + +/* Animation */ + +.parallax>use { + animation: move-forever 25s cubic-bezier(.55, .5, .45, .5) infinite; +} + +.parallax>use:nth-child(1) { + animation-delay: -2s; + animation-duration: 7s; +} + +.parallax>use:nth-child(2) { + animation-delay: -3s; + animation-duration: 10s; +} + +.parallax>use:nth-child(3) { + animation-delay: -4s; + animation-duration: 13s; +} + +.parallax>use:nth-child(4) { + animation-delay: -5s; + animation-duration: 20s; +} + +@keyframes move-forever { + 0% { + transform: translate3d(-90px, 0, 0); + } + + 100% { + transform: translate3d(85px, 0, 0); + } +} + +/*Shrinking for mobile*/ +@media (max-width: 768px) { + .waves { + height: 40px; + min-height: 40px; + } + + .content { + height: 30vh; + } + + h1 { + font-size: 24px; + } +} + + + +.ClockDashboard { + float: right; + font: 700 26px/1.2 "Poppins", sans-serif; + margin-bottom: 10px; + margin: 12px; + z-index: 9999; +} \ No newline at end of file diff --git a/src/ycore_worker.tsx b/src/ycore_worker.tsx new file mode 100644 index 00000000..0e552b43 --- /dev/null +++ b/src/ycore_worker.tsx @@ -0,0 +1,580 @@ +import Cookies from "ts-cookies"; +import axios from "axios"; +import {SetControls, CloseControls} from "./components/Layout/Control" +import {secretOrKey} from "../config/keys.js" + +var react = require("react"); +var antd = require("antd"); +var package_json = require("../package.json"); +var jquery = require("jquery"); +var uifx = require("uifx"); +var config = require("config"); +var utils = require("utils"); +var { router } = require("utils") +var jwt = require("jsonwebtoken") + +var endpoints = config.Endpoints; +var DevOptions = config.DevOptions; +var yConfig = config.yConfig; + +// Export global objects +exports.router = router; +exports.endpoints = endpoints; +exports.DevOptions = DevOptions; +exports.ycore_worker = { + ServerVersion: package_json.version, + ServerType: package_json.VersionPhase, + FXapiProvider: 'https://api.ragestudio.net/RS-YIBTP/lib/uiFXProvider/' +}; + +exports.about_this = { + Service_name: package_json.name, + Version: package_json.version, + Description: package_json.description, + Branding: package_json.copyright, + Licensing: package_json.license, + // Temporaly added from yConfig + logotype_uri: 'https://api.ragestudio.net/branding/lib/RDSeries-Branding/rDashboard/BLACK/SVG/T3/rDashboard-FullTextBlack-TM-T3.svg', + Phase: package_json.VersionPhase +}; +// UIFX LIBRARY 0.2v +exports.UIFxList = { + notifyDefault: (exports.ycore_worker.FXapiProvider + 'NotifyDefault.wav'), + notifyWarning: (exports.ycore_worker.FXapiProvider + 'NotifyWarning.wav'), + notifySuccess: (exports.ycore_worker.FXapiProvider + 'notifySuccess.wav') +}; +exports.infoServer = (exports.ycore_worker.ServerType + ' Server | v' + exports.ycore_worker.ServerVersion); + + +function InitSocket(id, params){ + console.log('Starting socket with _id: ', id) + const defaultParams = {fullscreen: true, collapse: true} + let globalParm; + + if (!params) { + globalParm = defaultParams; + }else{ + globalParm = params; + } + + if (id) { + console.log(globalParm) + globalParm.fullscreen? requestFullscreen() : null; + globalParm.collapse? null : null; + Cookies.set('inApp', true) + router.push({pathname: `/socket/${id}`,}) + } + else{ + console.error('Failure starting the app... Invalid or Missing ID') + } +} +exports.InitSocket = InitSocket; + +function requestFullscreen(){ + var elem = document.documentElement; + if (elem.requestFullscreen) { + elem.requestFullscreen(); + } else if (elem.mozRequestFullScreen) { /* Firefox */ + elem.mozRequestFullScreen(); + } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */ + elem.webkitRequestFullscreen(); + } else if (elem.msRequestFullscreen) { /* IE/Edge */ + elem.msRequestFullscreen(); + } +} +exports.requestFullscreen = requestFullscreen; + + +export const asyncLocalStorage = { + setItem: function (key, value) { + return Promise.resolve().then(function () { + localStorage.setItem(key, value); + }); + }, + getItem: function (key) { + return Promise.resolve().then(function () { + return localStorage.getItem(key); + }); + } +}; +export const asyncSessionStorage = { + setItem: function (key, value) { + return Promise.resolve().then(function () { + sessionStorage.setItem(key, value); + }); + }, + getItem: function (key) { + return Promise.resolve().then(function () { + return sessionStorage.getItem(key); + }); + } +}; +export const asyncSDCP = { + setSDCP: function (value) { + return Promise.resolve().then(function () { + sessionStorage.setItem('SDCP', value); + }); + }, + getSDCP: function () { + return sessionStorage.getItem('SDCP'); + } +}; + +export const ControlBar = { + set: (e) => { + SetControls(e) + }, + close: () => { + CloseControls() + } +} +function SyncSocketAccount(title:any, socket:any, logo:any) { + DevOptions.ShowFunctionsLogs? console.log('Initialising auth for ', title) : null + const signkey = secretOrKey; + const ExpireTime = '300'; + + const key:object = {title, socket, logo} + const ckey = jwt.sign( + key, + signkey, + { expiresIn: ExpireTime }, + ) + + DevOptions.ShowFunctionsLogs? console.log(key, jwt.decode(ckey)) : null + asyncLocalStorage.setItem('AUTHRES', ckey).then( + window.open('/ec/authorize', title, "height=589,width=511") + ) +} +exports.SyncSocketAccount = SyncSocketAccount; +function GetAuthSocket(sc, values) { + const prefix = '[YID Sync]' + if (!sc) { + DevOptions.ShowFunctionsLogs? console.warn(prefix, 'Socket API missing!') : null + return + } + const PayloadData = new FormData(); + PayloadData.append("server_key", yConfig.server_key); + + +} +exports.GetAuthSockets = GetAuthSocket; + + +function ValidLoginSession(){ + const prefix = '[YID Session]'; + let final = false; + let ValidCookiesToken = false; + let ValidSDCP = false; + let TokenContainer = Cookies.get('token'); + let SDCPContainer = asyncSDCP.getSDCP(); + if (TokenContainer) { + let TokenContainerDC = jwt.decode(TokenContainer) + if (TokenContainerDC){ + ValidCookiesToken = true + } + } + if (SDCPContainer) { + try { + let SDCPContainerDC = atob(SDCPContainer) + ValidSDCP = true + } catch (error) { + return + } + } + if (ValidCookiesToken == true && ValidSDCP == true) {final = true} + DevOptions.ShowFunctionsLogs? ( + console.group(`%c ${prefix} `, 'background: #339edf; color: #fff'), + console.log(`Valid SDCP => ${ValidSDCP}`), + console.log(`Valid Token => ${ValidCookiesToken}`), + console.log(`Session is valid => ${final}`), + console.groupEnd() + ) : null + return final + +} +exports.ValidLoginSession = ValidLoginSession; + +function ValidBackup(){ + const prefix = '[YID SessionState]'; + let ValidBackupToken = false; + let LastestToken = localStorage.getItem('last_backup'); + if (LastestToken) { + let LastestTokenDC = jwt.decode(LastestToken) + if (LastestTokenDC){ + ValidBackupToken = true + } + } + return ValidBackupToken; +} +exports.ValidBackup = ValidBackup; + +function MakeBackup(){ + if (ValidBackup() == false) { + asyncLocalStorage.setItem('last_backup', Cookies.get('token')) + return + } +} +exports.MakeBackup = MakeBackup; + +function LogoutCall(){ + const prefix = ('[YID Session] ') + console.log('Logout Called !') + let DecodedToken = GetUserToken.decrypted() + if (DecodedToken == false) { + antd.notification.open({ + placement: 'topLeft', + message: 'Unexpectedly failed logout in YulioID™ ', + description: 'It seems that your token has been removed unexpectedly and could not log out from YulioID ', + icon: <antd.Icon type="warning" style={{ color: 'orange' }} /> + }) + router.push({pathname: '/login',}) + return + } + const urlOBJ = "" + endpoints.removeToken + DecodedToken.UserToken; + DevOptions.ShowFunctionsLogs? console.log(prefix, ' Login out with token => ', DecodedToken.UserToken, urlOBJ) : null + const form = new FormData(); + form.append("server_key", yConfig.server_key); + const settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + jquery.ajax(settings) + .done( (response) => { + const url = '/api/v1/user/logout' + const method = 'GET' + utils.request({method, url}) + sessionStorage.clear() + console.log("Successful logout in YulioID™", response, urlOBJ) + router.push({pathname: '/login',}) + }) + + } +exports.LogoutCall = LogoutCall; + +export function GetAuth(EncUsername, EncPassword, callback) { + const prefix = '[Auth Server]:'; + if (!EncUsername || !EncPassword) { + const message = 'Missing Data! Process Aborted...'; + console.log(prefix, message); + } + const server_key = yConfig.server_key; + let username = atob(EncUsername); + let password = atob(EncPassword); + const form = new FormData(); + form.append("server_key", server_key); + form.append("username", username); + form.append("password", password); + const settings = { + "url": endpoints.auth_endpoint, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + jquery.ajax(settings) + .done(function (response) { + console.log(prefix, 'Server response... Dispathing data to login API...'); + return callback(null, response); + }) + .fail(function (response) { + const exception = new Error("Server failed response . . . :( "); + return callback(exception, response); + }); +} +exports.GetAuth = GetAuth; + +export const GetUserToken = { + decrypted: function () { + let final = jwt.decode(Cookies.get('token')) || jwt.decode(localStorage.getItem('last_backup')); + const FC = jwt.decode(Cookies.get('token')) + const FB = jwt.decode(localStorage.getItem('last_backup')) + if (!FC && !FB) { + final = false + return final + } + if (!FC) { + final = FB + } + if (!FB) { + final = FC + } + console.log(final) + return final + }, + raw: function () { + return Cookies.get('token') || localStorage.getItem('last_backup'); + } +}; + +function GetUserData (values, customPayload, callback) { + const prefix = '[YID SDCP]'; + const request = 'user_data' || customPayload; + const globalValue = values || GetUserToken.decrypted(); + const usertoken = globalValue.UserToken + const userid = globalValue.UserID + if (!globalValue) { + const message = 'Missing payload! Exception while request data... Maybe the user is not login'; + DevOptions.ShowFunctionsLogs? console.log(prefix, message) : null + return; + } + const ApiPayload = new FormData(); + ApiPayload.append("server_key", yConfig.server_key); + ApiPayload.append("fetch", request); + ApiPayload.append("user_id", userid); + const uri = endpoints.get_userData_endpoint; + const urlOBJ = "" + uri + usertoken; + const settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": ApiPayload + }; + jquery.ajax(settings) + .done( + function (response) { + let resString = JSON.stringify(response); + let resParsed = JSON.parse(resString); + DevOptions.ShowFunctionsLogs ? console.log(prefix, 'Fechted user data...' ) : null + callback( resParsed ) + return resParsed + } + ) + .fail( + function (response) { + DevOptions.ShowFunctionsLogs ? console.log(prefix, 'Server failure!', response) : null + callback( null ) + return + } + ); +} + +exports.GetUserData = GetUserData; + +function InitSDCP(values, done) { + const prefix = '[InitSDCP]'; + let payload = {}; + if (!values) { + const message = 'Missing payload! Exception while request data...'; + DevOptions.ShowFunctionsLogs? console.log(prefix, message) : null + return; + } + payload.UserToken = values.UserToken; + payload.UserID = values.UserID; + if (payload) { + GetUserData(payload, {}, (callback) => + { + let cooked = JSON.parse(callback)['user_data'] + let Ensamblator = btoa(JSON.stringify(cooked)) + asyncSDCP.setSDCP(Ensamblator).then(() => { + DevOptions.ShowFunctionsLogs? console.log(prefix, ' SDCP Setup done') : null + return done(true) + }); + } + ) + } +} +exports.InitSDCP = InitSDCP; + +function UpdateSDCP() { + const prefix = '[UpdateSDCP]'; + GetUserData(null, null, (callback) => { + let cooked = JSON.parse(callback)['user_data'] + let Lsdcp:any = [atob(sessionStorage.getItem('SDCP'))]; + let Nsdcp:any = [JSON.stringify(cooked)] + const e1 = btoa(Lsdcp) + const e2 = btoa(Nsdcp) + const n = e1.localeCompare(e2) + if (e1 == e2) { + console.log(prefix, 'SDCP Equality') + }else{ + DevOptions.ShowFunctionsLogs? console.log(prefix, 'SDCP Update detected ! => ', n) : null + asyncSDCP.setSDCP(e2) + GlobalRefreshONCE() + } + }) +} +exports.UpdateSDCP = UpdateSDCP; + +function SDCPCooker() { + const prefix = '[SDCPCooker]'; + let SDCPContainer = sessionStorage.getItem('SDCP') + if (SDCPContainer) { + try { + let decodedSDCP = atob(SDCPContainer); + } catch (err) { + console.error(prefix, err) + router.push({pathname: '/login',}) + return null + } + try { + let parsedSDCP = JSON.parse(decodedSDCP); + } catch (err) { + console.error(prefix, err) + router.push({pathname: '/login',}) + return null + } + return parsedSDCP; + } +} +exports.SDCP = SDCPCooker; + +function PushUserData(inputIO1, inputIO2) { + var getStoragedToken = Cookies.get('access_token'); + var _this = this; + var yCore_GUDEP = endpoints.update_userData_endpoint; + var urlOBJ = "" + yCore_GUDEP + getStoragedToken; + DevOptions.ShowFunctionsLogs? console.log('Recived', global, 'sending to ', urlOBJ) : null + var form = new FormData(); + form.append("server_key", yConfig.server_key); + form.append(inputIO1, inputIO2); + var settings = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": false, + "mimeType": "multipart/form-data", + "contentType": false, + "data": form + }; + jquery.ajax(settings).done(function (response) { + DevOptions.ShowFunctionsLogs? console.log(response) : null + }); +} +exports.PushUserData = PushUserData; + +function GetGlobalMarketplaceSource() { + let global; + let TokenContainer = Cookies.get('token') || localStorage.getItem('last_backup'); + let DecodedToken = jwt.decode(TokenContainer) + let usertoken = DecodedToken.UserToken; + + const uri = endpoints.get_marketplace_global; + const urlOBJ = "" + uri + usertoken; + + (async () => { + const response = await axios({ + url: urlOBJ, + method: 'get' + }) + global = response.data + console.log(response.data, global) + return {global}; + + })() + +} +exports.GetGlobalMarketplaceSource = GetGlobalMarketplaceSource; + +function StorageWidgets(id, socketMemoryAdress) { + // Dinamic Widgets Storage Container (DWSC) + var values = ([id + socketMemoryAdress]); +} +exports.StorageWidgets = StorageWidgets; + + +//* *// +//* Helpers *// +//* *// +function DetectNoNStableBuild(e1) { + switch (e1) { + case 'TagComponent': + if (package_json.DevBuild == true) { + return react.createElement(antd.Tag, { color: 'orange' }, " No Stable"); + } + if (package_json.DevBuild == false) { + return react.createElement(antd.Tag, { color: 'blue' }, " Stable"); + } + else { + return ('No Stable'); + } + break; + default: + if (package_json.DevBuild == true) { + return ('No Stable'); + } + if (package_json.DevBuild == false) { + return ('Stable'); + } + else { + return ('No Stable'); + } + break; + } +} +exports.DetectNoNStableBuild = DetectNoNStableBuild; + +function getRandomBG(imgAr) { + var path = 'https://api.ragestudio.net/RS-YIBTP/lib/statics/heros/'; + var num = Math.floor(Math.random() * imgAr.length); + var img = imgAr[num]; + var out = (path + img); + return (out); +} +exports.getRandomBG = getRandomBG; + + +function UIFxPY(value, customVLM) { + // UIFX Player v1.4A + var dispatcher = value; + var userVLM = localStorage.getItem('UIfx'); + var VLM; + var conv = parseFloat(userVLM); + if (conv < 1.1) { + if (conv == 1) { + VLM = 1.0; + } + if (conv == 0) { + VLM = 0.0; + } + else { + VLM = conv; + } + } + else { + VLM = 1.0; + } + var beep = new uifx({ asset: dispatcher }); + DevOptions.ShowFunctionsLogs? console.log('The Volume of UIFX is on ', VLM || customVLM, '/ User set on', conv) : null + beep.setVolume(VLM || customVLM).play(); +} +exports.UIFxPY = UIFxPY; + +function WeatherAPI() { + let city = 'pamplona'; + let country = 'spain'; + var Api_Key = yConfig.openwheater_apiKey; + var _this = this; + var urlOBJ = ("http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + country + "&appid=2acf34be0b8f033b89ba4de1e674d42a"); + var returnData; + var AjaxRequest = { + "url": urlOBJ, + "method": "POST", + "timeout": 0, + "processData": true, + "contentType": false + }; + jquery.ajax(AjaxRequest) + .done(function (response) { + returnData = response; + }); + return (returnData); +} +exports.WeatherAPI = WeatherAPI; + +function GlobalRefreshONCE(){ + window.location.reload(); +} +exports.RefreshONCE = GlobalRefreshONCE; + + + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..f0aeeee3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "module": "commonjs", + "sourceMap": true, + "jsx": "react" + }, + "include": [ + "./src/components/YulioID/**/*" +], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file