@ -0,0 +1,27 @@ |
|||||||
|
{ |
||||||
|
"extends": "airbnb", |
||||||
|
"parser": "babel-eslint", |
||||||
|
|
||||||
|
"plugins": [ |
||||||
|
"react" |
||||||
|
], |
||||||
|
|
||||||
|
"env": { |
||||||
|
"browser": true, |
||||||
|
"node": true, |
||||||
|
"mocha": true, |
||||||
|
"es6": true |
||||||
|
}, |
||||||
|
|
||||||
|
"rules": { |
||||||
|
"jsx-a11y/anchor-is-valid": [ "error", { |
||||||
|
"components": [ "Link" ], |
||||||
|
"specialLink": [ "to", "hrefLeft", "hrefRight" ], |
||||||
|
"aspects": [ "noHref", "invalidHref", "preferButton" ] |
||||||
|
}], |
||||||
|
"max-len": ["error", {"code": 120, "ignoreRegExpLiterals": true, "tabWidth": 2}], |
||||||
|
"no-console": [1], |
||||||
|
"linebreak-style": "off", |
||||||
|
"react/jsx-one-expression-per-line": [0, { "allow": "literal" }] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |
||||||
|
|
||||||
|
# dependencies |
||||||
|
/node_modules |
||||||
|
|
||||||
|
# testing |
||||||
|
/coverage |
||||||
|
|
||||||
|
# production |
||||||
|
/build |
||||||
|
|
||||||
|
# misc |
||||||
|
.DS_Store |
||||||
|
.env.local |
||||||
|
.env.development.local |
||||||
|
.env.test.local |
||||||
|
.env.production.local |
||||||
|
|
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
@ -0,0 +1,93 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const fs = require('fs'); |
||||||
|
const path = require('path'); |
||||||
|
const paths = require('./paths'); |
||||||
|
|
||||||
|
// Make sure that including paths.js after env.js will read .env variables.
|
||||||
|
delete require.cache[require.resolve('./paths')]; |
||||||
|
|
||||||
|
const NODE_ENV = process.env.NODE_ENV; |
||||||
|
if (!NODE_ENV) { |
||||||
|
throw new Error( |
||||||
|
'The NODE_ENV environment variable is required but was not specified.' |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
|
||||||
|
var dotenvFiles = [ |
||||||
|
`${paths.dotenv}.${NODE_ENV}.local`, |
||||||
|
`${paths.dotenv}.${NODE_ENV}`, |
||||||
|
// Don't include `.env.local` for `test` environment
|
||||||
|
// since normally you expect tests to produce the same
|
||||||
|
// results for everyone
|
||||||
|
NODE_ENV !== 'test' && `${paths.dotenv}.local`, |
||||||
|
paths.dotenv, |
||||||
|
].filter(Boolean); |
||||||
|
|
||||||
|
// Load environment variables from .env* files. Suppress warnings using silent
|
||||||
|
// if this file is missing. dotenv will never modify any environment variables
|
||||||
|
// that have already been set. Variable expansion is supported in .env files.
|
||||||
|
// https://github.com/motdotla/dotenv
|
||||||
|
// https://github.com/motdotla/dotenv-expand
|
||||||
|
dotenvFiles.forEach(dotenvFile => { |
||||||
|
if (fs.existsSync(dotenvFile)) { |
||||||
|
require('dotenv-expand')( |
||||||
|
require('dotenv').config({ |
||||||
|
path: dotenvFile, |
||||||
|
}) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// We support resolving modules according to `NODE_PATH`.
|
||||||
|
// This lets you use absolute paths in imports inside large monorepos:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253.
|
||||||
|
// It works similar to `NODE_PATH` in Node itself:
|
||||||
|
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
|
||||||
|
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
|
||||||
|
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
|
||||||
|
// We also resolve them to make sure all tools using them work consistently.
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd()); |
||||||
|
process.env.NODE_PATH = (process.env.NODE_PATH || '') |
||||||
|
.split(path.delimiter) |
||||||
|
.filter(folder => folder && !path.isAbsolute(folder)) |
||||||
|
.map(folder => path.resolve(appDirectory, folder)) |
||||||
|
.join(path.delimiter); |
||||||
|
|
||||||
|
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
|
||||||
|
// injected into the application via DefinePlugin in Webpack configuration.
|
||||||
|
const REACT_APP = /^REACT_APP_/i; |
||||||
|
|
||||||
|
function getClientEnvironment(publicUrl) { |
||||||
|
const raw = Object.keys(process.env) |
||||||
|
.filter(key => REACT_APP.test(key)) |
||||||
|
.reduce( |
||||||
|
(env, key) => { |
||||||
|
env[key] = process.env[key]; |
||||||
|
return env; |
||||||
|
}, |
||||||
|
{ |
||||||
|
// Useful for determining whether we’re running in production mode.
|
||||||
|
// Most importantly, it switches React into the correct mode.
|
||||||
|
NODE_ENV: process.env.NODE_ENV || 'development', |
||||||
|
// Useful for resolving the correct path to static assets in `public`.
|
||||||
|
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
|
||||||
|
// This should only be used as an escape hatch. Normally you would put
|
||||||
|
// images into the `src` and `import` them in code to get their paths.
|
||||||
|
PUBLIC_URL: publicUrl, |
||||||
|
} |
||||||
|
); |
||||||
|
// Stringify all values so we can feed into Webpack DefinePlugin
|
||||||
|
const stringified = { |
||||||
|
'process.env': Object.keys(raw).reduce((env, key) => { |
||||||
|
env[key] = JSON.stringify(raw[key]); |
||||||
|
return env; |
||||||
|
}, {}), |
||||||
|
}; |
||||||
|
|
||||||
|
return { raw, stringified }; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = getClientEnvironment; |
@ -0,0 +1,14 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
// This is a custom Jest transformer turning style imports into empty objects.
|
||||||
|
// http://facebook.github.io/jest/docs/en/webpack.html
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
process() { |
||||||
|
return 'module.exports = {};'; |
||||||
|
}, |
||||||
|
getCacheKey() { |
||||||
|
// The output is always the same.
|
||||||
|
return 'cssTransform'; |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,30 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
|
||||||
|
// This is a custom Jest transformer turning file imports into filenames.
|
||||||
|
// http://facebook.github.io/jest/docs/en/webpack.html
|
||||||
|
|
||||||
|
module.exports = { |
||||||
|
process(src, filename) { |
||||||
|
const assetFilename = JSON.stringify(path.basename(filename)); |
||||||
|
|
||||||
|
if (filename.match(/\.svg$/)) { |
||||||
|
return `module.exports = {
|
||||||
|
__esModule: true, |
||||||
|
default: ${assetFilename}, |
||||||
|
ReactComponent: (props) => ({ |
||||||
|
$$typeof: Symbol.for('react.element'), |
||||||
|
type: 'svg', |
||||||
|
ref: null, |
||||||
|
key: null, |
||||||
|
props: Object.assign({}, props, { |
||||||
|
children: ${assetFilename} |
||||||
|
}) |
||||||
|
}), |
||||||
|
};`;
|
||||||
|
} |
||||||
|
|
||||||
|
return `module.exports = ${assetFilename};`; |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,57 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
const fs = require('fs'); |
||||||
|
const url = require('url'); |
||||||
|
|
||||||
|
// Make sure any symlinks in the project folder are resolved:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/637
|
||||||
|
const appDirectory = fs.realpathSync(process.cwd()); |
||||||
|
const resolveApp = relativePath => path.resolve(appDirectory, relativePath); |
||||||
|
|
||||||
|
const envPublicUrl = process.env.PUBLIC_URL; |
||||||
|
|
||||||
|
function ensureSlash(inputPath, needsSlash) { |
||||||
|
const hasSlash = inputPath.endsWith('/'); |
||||||
|
if (hasSlash && !needsSlash) { |
||||||
|
return inputPath.substr(0, inputPath.length - 1); |
||||||
|
} else if (!hasSlash && needsSlash) { |
||||||
|
return `${inputPath}/`; |
||||||
|
} else { |
||||||
|
return inputPath; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getPublicUrl = appPackageJson => |
||||||
|
envPublicUrl || require(appPackageJson).homepage; |
||||||
|
|
||||||
|
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||||
|
// "public path" at which the app is served.
|
||||||
|
// Webpack needs to know it to put the right <script> hrefs into HTML even in
|
||||||
|
// single-page apps that may serve index.html for nested URLs like /todos/42.
|
||||||
|
// We can't use a relative path in HTML because we don't want to load something
|
||||||
|
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||||
|
function getServedPath(appPackageJson) { |
||||||
|
const publicUrl = getPublicUrl(appPackageJson); |
||||||
|
const servedUrl = |
||||||
|
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/'); |
||||||
|
return ensureSlash(servedUrl, true); |
||||||
|
} |
||||||
|
|
||||||
|
// config after eject: we're in ./config/
|
||||||
|
module.exports = { |
||||||
|
dotenv: resolveApp('.env'), |
||||||
|
appPath: resolveApp('.'), |
||||||
|
appBuild: resolveApp('build'), |
||||||
|
appPublic: resolveApp('public'), |
||||||
|
appHtml: resolveApp('public/index.html'), |
||||||
|
appIndexJs: resolveApp('src/index.jsx'), |
||||||
|
appPackageJson: resolveApp('package.json'), |
||||||
|
appSrc: resolveApp('src'), |
||||||
|
yarnLockFile: resolveApp('yarn.lock'), |
||||||
|
testsSetup: resolveApp('src/setupTests.js'), |
||||||
|
proxySetup: resolveApp('src/setupProxy.js'), |
||||||
|
appNodeModules: resolveApp('node_modules'), |
||||||
|
publicUrl: getPublicUrl(resolveApp('package.json')), |
||||||
|
servedPath: getServedPath(resolveApp('package.json')), |
||||||
|
}; |
@ -0,0 +1,394 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
const webpack = require('webpack'); |
||||||
|
const PnpWebpackPlugin = require('pnp-webpack-plugin'); |
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin'); |
||||||
|
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); |
||||||
|
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); |
||||||
|
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); |
||||||
|
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); |
||||||
|
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); |
||||||
|
const getClientEnvironment = require('./env'); |
||||||
|
const paths = require('./paths'); |
||||||
|
const ManifestPlugin = require('webpack-manifest-plugin'); |
||||||
|
const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); |
||||||
|
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); |
||||||
|
|
||||||
|
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||||
|
// In development, we always serve from the root. This makes config easier.
|
||||||
|
const publicPath = '/'; |
||||||
|
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||||
|
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||||
|
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
|
||||||
|
const publicUrl = ''; |
||||||
|
// Get environment variables to inject into our app.
|
||||||
|
const env = getClientEnvironment(publicUrl); |
||||||
|
|
||||||
|
// style files regexes
|
||||||
|
const cssRegex = /\.css$/; |
||||||
|
const cssModuleRegex = /\.module\.css$/; |
||||||
|
const sassRegex = /\.(scss|sass)$/; |
||||||
|
const sassModuleRegex = /\.module\.(scss|sass)$/; |
||||||
|
|
||||||
|
// common function to get style loaders
|
||||||
|
const getStyleLoaders = (cssOptions, preProcessor) => { |
||||||
|
const loaders = [ |
||||||
|
require.resolve('style-loader'), |
||||||
|
{ |
||||||
|
loader: require.resolve('css-loader'), |
||||||
|
options: cssOptions, |
||||||
|
}, |
||||||
|
{ |
||||||
|
// Options for PostCSS as we reference these options twice
|
||||||
|
// Adds vendor prefixing based on your specified browser support in
|
||||||
|
// package.json
|
||||||
|
loader: require.resolve('postcss-loader'), |
||||||
|
options: { |
||||||
|
// Necessary for external CSS imports to work
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2677
|
||||||
|
ident: 'postcss', |
||||||
|
plugins: () => [ |
||||||
|
require('postcss-flexbugs-fixes'), |
||||||
|
require('postcss-preset-env')({ |
||||||
|
autoprefixer: { |
||||||
|
flexbox: 'no-2009', |
||||||
|
}, |
||||||
|
stage: 3, |
||||||
|
}), |
||||||
|
], |
||||||
|
}, |
||||||
|
}, |
||||||
|
]; |
||||||
|
if (preProcessor) { |
||||||
|
loaders.push(require.resolve(preProcessor)); |
||||||
|
} |
||||||
|
return loaders; |
||||||
|
}; |
||||||
|
|
||||||
|
// This is the development configuration.
|
||||||
|
// It is focused on developer experience and fast rebuilds.
|
||||||
|
// The production configuration is different and lives in a separate file.
|
||||||
|
module.exports = { |
||||||
|
mode: 'development', |
||||||
|
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
|
||||||
|
// See the discussion in https://github.com/facebook/create-react-app/issues/343
|
||||||
|
devtool: 'cheap-module-source-map', |
||||||
|
// These are the "entry points" to our application.
|
||||||
|
// This means they will be the "root" imports that are included in JS bundle.
|
||||||
|
entry: [ |
||||||
|
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||||
|
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||||
|
// When you save a file, the client will either apply hot updates (in case
|
||||||
|
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||||
|
// make a syntax error, this client will display a syntax error overlay.
|
||||||
|
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||||
|
// to bring better experience for Create React App users. You can replace
|
||||||
|
// the line below with these two lines if you prefer the stock client:
|
||||||
|
// require.resolve('webpack-dev-server/client') + '?/',
|
||||||
|
// require.resolve('webpack/hot/dev-server'),
|
||||||
|
require.resolve('react-dev-utils/webpackHotDevClient'), |
||||||
|
// Finally, this is your app's code:
|
||||||
|
paths.appIndexJs, |
||||||
|
// We include the app code last so that if there is a runtime error during
|
||||||
|
// initialization, it doesn't blow up the WebpackDevServer client, and
|
||||||
|
// changing JS code would still trigger a refresh.
|
||||||
|
], |
||||||
|
output: { |
||||||
|
// Add /* filename */ comments to generated require()s in the output.
|
||||||
|
pathinfo: true, |
||||||
|
// This does not produce a real file. It's just the virtual path that is
|
||||||
|
// served by WebpackDevServer in development. This is the JS bundle
|
||||||
|
// containing code from all our entry points, and the Webpack runtime.
|
||||||
|
filename: 'static/js/bundle.js', |
||||||
|
// There are also additional JS chunk files if you use code splitting.
|
||||||
|
chunkFilename: 'static/js/[name].chunk.js', |
||||||
|
// This is the URL that app is served from. We use "/" in development.
|
||||||
|
publicPath: publicPath, |
||||||
|
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||||
|
devtoolModuleFilenameTemplate: info => |
||||||
|
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), |
||||||
|
}, |
||||||
|
optimization: { |
||||||
|
// Automatically split vendor and commons
|
||||||
|
// https://twitter.com/wSokra/status/969633336732905474
|
||||||
|
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||||
|
splitChunks: { |
||||||
|
chunks: 'all', |
||||||
|
name: false, |
||||||
|
}, |
||||||
|
// Keep the runtime chunk seperated to enable long term caching
|
||||||
|
// https://twitter.com/wSokra/status/969679223278505985
|
||||||
|
runtimeChunk: true, |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
// This allows you to set a fallback for where Webpack should look for modules.
|
||||||
|
// We placed these paths second because we want `node_modules` to "win"
|
||||||
|
// if there are any conflicts. This matches Node resolution mechanism.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253
|
||||||
|
modules: ['node_modules'].concat( |
||||||
|
// It is guaranteed to exist because we tweak it in `env.js`
|
||||||
|
process.env.NODE_PATH.split(path.delimiter).filter(Boolean) |
||||||
|
), |
||||||
|
// These are the reasonable defaults supported by the Node ecosystem.
|
||||||
|
// We also include JSX as a common component filename extension to support
|
||||||
|
// some tools, although we do not recommend using it, see:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/290
|
||||||
|
// `web` extension prefixes have been added for better support
|
||||||
|
// for React Native Web.
|
||||||
|
extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'], |
||||||
|
alias: { |
||||||
|
// Support React Native Web
|
||||||
|
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||||
|
'react-native': 'react-native-web', |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||||
|
// guards against forgotten dependencies and such.
|
||||||
|
PnpWebpackPlugin, |
||||||
|
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||||
|
// This often causes confusion because we only process files within src/ with babel.
|
||||||
|
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||||
|
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||||
|
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||||
|
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), |
||||||
|
], |
||||||
|
}, |
||||||
|
resolveLoader: { |
||||||
|
plugins: [ |
||||||
|
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||||
|
// from the current package.
|
||||||
|
PnpWebpackPlugin.moduleLoader(module), |
||||||
|
], |
||||||
|
}, |
||||||
|
module: { |
||||||
|
strictExportPresence: true, |
||||||
|
rules: [ |
||||||
|
// Disable require.ensure as it's not a standard language feature.
|
||||||
|
{ parser: { requireEnsure: false } }, |
||||||
|
|
||||||
|
// First, run the linter.
|
||||||
|
// It's important to do this before Babel processes the JS.
|
||||||
|
{ |
||||||
|
test: /\.(js|jsx)$/, |
||||||
|
enforce: 'pre', |
||||||
|
use: [ |
||||||
|
{ |
||||||
|
options: { |
||||||
|
formatter: require.resolve('react-dev-utils/eslintFormatter'), |
||||||
|
eslintPath: require.resolve('eslint'), |
||||||
|
|
||||||
|
}, |
||||||
|
loader: require.resolve('eslint-loader'), |
||||||
|
}, |
||||||
|
], |
||||||
|
include: paths.appSrc, |
||||||
|
}, |
||||||
|
{ |
||||||
|
// `mjs` support is still in its infancy in the ecosystem, so we don't
|
||||||
|
// support it.
|
||||||
|
// Modules who define their `browser` or `module` key as `mjs` force
|
||||||
|
// the use of this extension, so we need to tell webpack to fall back
|
||||||
|
// to auto mode (ES Module interop, allows ESM to import CommonJS).
|
||||||
|
test: /\.mjs$/, |
||||||
|
include: /node_modules/, |
||||||
|
type: 'javascript/auto', |
||||||
|
}, |
||||||
|
{ |
||||||
|
// "oneOf" will traverse all following loaders until one will
|
||||||
|
// match the requirements. When no loader matches it will fall
|
||||||
|
// back to the "file" loader at the end of the loader list.
|
||||||
|
oneOf: [ |
||||||
|
// "url" loader works like "file" loader except that it embeds assets
|
||||||
|
// smaller than specified limit in bytes as data URLs to avoid requests.
|
||||||
|
// A missing `test` is equivalent to a match.
|
||||||
|
{ |
||||||
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
||||||
|
loader: require.resolve('url-loader'), |
||||||
|
options: { |
||||||
|
limit: 10000, |
||||||
|
name: 'static/media/[name].[hash:8].[ext]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
// Process application JS with Babel.
|
||||||
|
// The preset includes JSX, Flow, and some ESnext features.
|
||||||
|
{ |
||||||
|
test: /\.(js|jsx)$/, |
||||||
|
include: paths.appSrc, |
||||||
|
loader: require.resolve('babel-loader'), |
||||||
|
options: { |
||||||
|
customize: require.resolve( |
||||||
|
'babel-preset-react-app/webpack-overrides' |
||||||
|
), |
||||||
|
|
||||||
|
plugins: [ |
||||||
|
[ |
||||||
|
require.resolve('babel-plugin-named-asset-import'), |
||||||
|
{ |
||||||
|
loaderMap: { |
||||||
|
svg: { |
||||||
|
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
], |
||||||
|
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
||||||
|
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||||
|
// directory for faster rebuilds.
|
||||||
|
cacheDirectory: true, |
||||||
|
// Don't waste time on Gzipping the cache
|
||||||
|
cacheCompression: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
// Process any JS outside of the app with Babel.
|
||||||
|
// Unlike the application JS, we only compile the standard ES features.
|
||||||
|
{ |
||||||
|
test: /\.js$/, |
||||||
|
exclude: /@babel(?:\/|\\{1,2})runtime/, |
||||||
|
loader: require.resolve('babel-loader'), |
||||||
|
options: { |
||||||
|
babelrc: false, |
||||||
|
configFile: false, |
||||||
|
compact: false, |
||||||
|
presets: [ |
||||||
|
[ |
||||||
|
require.resolve('babel-preset-react-app/dependencies'), |
||||||
|
{ helpers: true }, |
||||||
|
], |
||||||
|
], |
||||||
|
cacheDirectory: true, |
||||||
|
// Don't waste time on Gzipping the cache
|
||||||
|
cacheCompression: false, |
||||||
|
|
||||||
|
// If an error happens in a package, it's possible to be
|
||||||
|
// because it was compiled. Thus, we don't want the browser
|
||||||
|
// debugger to show the original code. Instead, the code
|
||||||
|
// being evaluated would be much more helpful.
|
||||||
|
sourceMaps: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
// "postcss" loader applies autoprefixer to our CSS.
|
||||||
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||||
|
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||||
|
// In production, we use a plugin to extract that CSS to a file, but
|
||||||
|
// in development "style" loader enables hot editing of CSS.
|
||||||
|
// By default we support CSS Modules with the extension .module.css
|
||||||
|
{ |
||||||
|
test: cssRegex, |
||||||
|
exclude: cssModuleRegex, |
||||||
|
use: getStyleLoaders({ |
||||||
|
importLoaders: 1, |
||||||
|
}), |
||||||
|
}, |
||||||
|
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||||
|
// using the extension .module.css
|
||||||
|
{ |
||||||
|
test: cssModuleRegex, |
||||||
|
use: getStyleLoaders({ |
||||||
|
importLoaders: 1, |
||||||
|
modules: true, |
||||||
|
getLocalIdent: getCSSModuleLocalIdent, |
||||||
|
}), |
||||||
|
}, |
||||||
|
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||||
|
// Chains the sass-loader with the css-loader and the style-loader
|
||||||
|
// to immediately apply all styles to the DOM.
|
||||||
|
// By default we support SASS Modules with the
|
||||||
|
// extensions .module.scss or .module.sass
|
||||||
|
{ |
||||||
|
test: sassRegex, |
||||||
|
exclude: sassModuleRegex, |
||||||
|
use: getStyleLoaders({ importLoaders: 2 }, 'sass-loader'), |
||||||
|
}, |
||||||
|
// Adds support for CSS Modules, but using SASS
|
||||||
|
// using the extension .module.scss or .module.sass
|
||||||
|
{ |
||||||
|
test: sassModuleRegex, |
||||||
|
use: getStyleLoaders( |
||||||
|
{ |
||||||
|
importLoaders: 2, |
||||||
|
modules: true, |
||||||
|
getLocalIdent: getCSSModuleLocalIdent, |
||||||
|
}, |
||||||
|
'sass-loader' |
||||||
|
), |
||||||
|
}, |
||||||
|
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||||
|
// When you `import` an asset, you get its (virtual) filename.
|
||||||
|
// In production, they would get copied to the `build` folder.
|
||||||
|
// This loader doesn't use a "test" so it will catch all modules
|
||||||
|
// that fall through the other loaders.
|
||||||
|
{ |
||||||
|
// Exclude `js` files to keep "css" loader working as it injects
|
||||||
|
// its runtime that would otherwise be processed through "file" loader.
|
||||||
|
// Also exclude `html` and `json` extensions so they get processed
|
||||||
|
// by webpacks internal loaders.
|
||||||
|
exclude: [/\.(js|jsx)$/, /\.html$/, /\.json$/], |
||||||
|
loader: require.resolve('file-loader'), |
||||||
|
options: { |
||||||
|
name: 'static/media/[name].[hash:8].[ext]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
// ** STOP ** Are you adding a new loader?
|
||||||
|
// Make sure to add the new loader(s) before the "file" loader.
|
||||||
|
], |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
// Generates an `index.html` file with the <script> injected.
|
||||||
|
new HtmlWebpackPlugin({ |
||||||
|
inject: true, |
||||||
|
template: paths.appHtml, |
||||||
|
}), |
||||||
|
// Makes some environment variables available in index.html.
|
||||||
|
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||||
|
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// In development, this will be an empty string.
|
||||||
|
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), |
||||||
|
// This gives some necessary context to module not found errors, such as
|
||||||
|
// the requesting resource.
|
||||||
|
new ModuleNotFoundPlugin(paths.appPath), |
||||||
|
// Makes some environment variables available to the JS code, for example:
|
||||||
|
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
|
||||||
|
new webpack.DefinePlugin(env.stringified), |
||||||
|
// This is necessary to emit hot updates (currently CSS only):
|
||||||
|
new webpack.HotModuleReplacementPlugin(), |
||||||
|
// Watcher doesn't work well if you mistype casing in a path so we use
|
||||||
|
// a plugin that prints an error when you attempt to do this.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/240
|
||||||
|
new CaseSensitivePathsPlugin(), |
||||||
|
// If you require a missing module and then `npm install` it, you still have
|
||||||
|
// to restart the development server for Webpack to discover it. This plugin
|
||||||
|
// makes the discovery automatic so you don't have to restart.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/186
|
||||||
|
new WatchMissingNodeModulesPlugin(paths.appNodeModules), |
||||||
|
// Moment.js is an extremely popular library that bundles large locale files
|
||||||
|
// by default due to how Webpack interprets its code. This is a practical
|
||||||
|
// solution that requires the user to opt into importing specific locales.
|
||||||
|
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||||
|
// You can remove this if you don't use Moment.js:
|
||||||
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
||||||
|
// Generate a manifest file which contains a mapping of all asset filenames
|
||||||
|
// to their corresponding output file so that tools can pick it up without
|
||||||
|
// having to parse `index.html`.
|
||||||
|
new ManifestPlugin({ |
||||||
|
fileName: 'asset-manifest.json', |
||||||
|
publicPath: publicPath, |
||||||
|
}), |
||||||
|
], |
||||||
|
|
||||||
|
// Some libraries import Node modules but don't use them in the browser.
|
||||||
|
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||||
|
node: { |
||||||
|
dgram: 'empty', |
||||||
|
fs: 'empty', |
||||||
|
net: 'empty', |
||||||
|
tls: 'empty', |
||||||
|
child_process: 'empty', |
||||||
|
}, |
||||||
|
// Turn off performance processing because we utilize
|
||||||
|
// our own hints via the FileSizeReporter
|
||||||
|
performance: false, |
||||||
|
}; |
@ -0,0 +1,500 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
const webpack = require('webpack'); |
||||||
|
const PnpWebpackPlugin = require('pnp-webpack-plugin'); |
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin'); |
||||||
|
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin'); |
||||||
|
const TerserPlugin = require('terser-webpack-plugin'); |
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); |
||||||
|
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); |
||||||
|
const safePostCssParser = require('postcss-safe-parser'); |
||||||
|
const ManifestPlugin = require('webpack-manifest-plugin'); |
||||||
|
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); |
||||||
|
const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); |
||||||
|
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); |
||||||
|
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); |
||||||
|
const paths = require('./paths'); |
||||||
|
const getClientEnvironment = require('./env'); |
||||||
|
const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); |
||||||
|
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); |
||||||
|
|
||||||
|
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||||
|
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||||
|
const publicPath = paths.servedPath; |
||||||
|
// Some apps do not use client-side routing with pushState.
|
||||||
|
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||||
|
const shouldUseRelativeAssetPaths = publicPath === './'; |
||||||
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||||
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; |
||||||
|
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||||
|
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||||
|
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||||
|
const publicUrl = publicPath.slice(0, -1); |
||||||
|
// Get environment variables to inject into our app.
|
||||||
|
const env = getClientEnvironment(publicUrl); |
||||||
|
|
||||||
|
// Assert this just to be safe.
|
||||||
|
// Development builds of React are slow and not intended for production.
|
||||||
|
if (env.stringified['process.env'].NODE_ENV !== '"production"') { |
||||||
|
throw new Error('Production builds must have NODE_ENV=production.'); |
||||||
|
} |
||||||
|
|
||||||
|
// style files regexes
|
||||||
|
const cssRegex = /\.css$/; |
||||||
|
const cssModuleRegex = /\.module\.css$/; |
||||||
|
const sassRegex = /\.(scss|sass)$/; |
||||||
|
const sassModuleRegex = /\.module\.(scss|sass)$/; |
||||||
|
|
||||||
|
// common function to get style loaders
|
||||||
|
const getStyleLoaders = (cssOptions, preProcessor) => { |
||||||
|
const loaders = [ |
||||||
|
{ |
||||||
|
loader: MiniCssExtractPlugin.loader, |
||||||
|
options: Object.assign( |
||||||
|
{}, |
||||||
|
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined |
||||||
|
), |
||||||
|
}, |
||||||
|
{ |
||||||
|
loader: require.resolve('css-loader'), |
||||||
|
options: cssOptions, |
||||||
|
}, |
||||||
|
{ |
||||||
|
// Options for PostCSS as we reference these options twice
|
||||||
|
// Adds vendor prefixing based on your specified browser support in
|
||||||
|
// package.json
|
||||||
|
loader: require.resolve('postcss-loader'), |
||||||
|
options: { |
||||||
|
// Necessary for external CSS imports to work
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2677
|
||||||
|
ident: 'postcss', |
||||||
|
plugins: () => [ |
||||||
|
require('postcss-flexbugs-fixes'), |
||||||
|
require('postcss-preset-env')({ |
||||||
|
autoprefixer: { |
||||||
|
flexbox: 'no-2009', |
||||||
|
}, |
||||||
|
stage: 3, |
||||||
|
}), |
||||||
|
], |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
}, |
||||||
|
}, |
||||||
|
]; |
||||||
|
if (preProcessor) { |
||||||
|
loaders.push({ |
||||||
|
loader: require.resolve(preProcessor), |
||||||
|
options: { |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
}, |
||||||
|
}); |
||||||
|
} |
||||||
|
return loaders; |
||||||
|
}; |
||||||
|
|
||||||
|
// This is the production configuration.
|
||||||
|
// It compiles slowly and is focused on producing a fast and minimal bundle.
|
||||||
|
// The development configuration is different and lives in a separate file.
|
||||||
|
module.exports = { |
||||||
|
mode: 'production', |
||||||
|
// Don't attempt to continue if there are any errors.
|
||||||
|
bail: true, |
||||||
|
// We generate sourcemaps in production. This is slow but gives good results.
|
||||||
|
// You can exclude the *.map files from the build during deployment.
|
||||||
|
devtool: shouldUseSourceMap ? 'source-map' : false, |
||||||
|
// In production, we only want to load the app code.
|
||||||
|
entry: [paths.appIndexJs], |
||||||
|
output: { |
||||||
|
// The build folder.
|
||||||
|
path: paths.appBuild, |
||||||
|
// Generated JS file names (with nested folders).
|
||||||
|
// There will be one main bundle, and one file per asynchronous chunk.
|
||||||
|
// We don't currently advertise code splitting but Webpack supports it.
|
||||||
|
filename: 'static/js/[name].[chunkhash:8].js', |
||||||
|
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js', |
||||||
|
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||||
|
publicPath: publicPath, |
||||||
|
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||||
|
devtoolModuleFilenameTemplate: info => |
||||||
|
path |
||||||
|
.relative(paths.appSrc, info.absoluteResourcePath) |
||||||
|
.replace(/\\/g, '/'), |
||||||
|
}, |
||||||
|
optimization: { |
||||||
|
minimizer: [ |
||||||
|
new TerserPlugin({ |
||||||
|
terserOptions: { |
||||||
|
parse: { |
||||||
|
// we want terser to parse ecma 8 code. However, we don't want it
|
||||||
|
// to apply any minfication steps that turns valid ecma 5 code
|
||||||
|
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||||
|
// sections only apply transformations that are ecma 5 safe
|
||||||
|
// https://github.com/facebook/create-react-app/pull/4234
|
||||||
|
ecma: 8, |
||||||
|
}, |
||||||
|
compress: { |
||||||
|
ecma: 5, |
||||||
|
warnings: false, |
||||||
|
// Disabled because of an issue with Uglify breaking seemingly valid code:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2376
|
||||||
|
// Pending further investigation:
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/2011
|
||||||
|
comparisons: false, |
||||||
|
}, |
||||||
|
mangle: { |
||||||
|
safari10: true, |
||||||
|
}, |
||||||
|
output: { |
||||||
|
ecma: 5, |
||||||
|
comments: false, |
||||||
|
// Turned on because emoji and regex is not minified properly using default
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2488
|
||||||
|
ascii_only: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
// Use multi-process parallel running to improve the build speed
|
||||||
|
// Default number of concurrent runs: os.cpus().length - 1
|
||||||
|
parallel: true, |
||||||
|
// Enable file caching
|
||||||
|
cache: true, |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
}), |
||||||
|
new OptimizeCSSAssetsPlugin({ |
||||||
|
cssProcessorOptions: { |
||||||
|
parser: safePostCssParser, |
||||||
|
map: { |
||||||
|
// `inline: false` forces the sourcemap to be output into a
|
||||||
|
// separate file
|
||||||
|
inline: false, |
||||||
|
// `annotation: true` appends the sourceMappingURL to the end of
|
||||||
|
// the css file, helping the browser find the sourcemap
|
||||||
|
annotation: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}), |
||||||
|
], |
||||||
|
// Automatically split vendor and commons
|
||||||
|
// https://twitter.com/wSokra/status/969633336732905474
|
||||||
|
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||||
|
splitChunks: { |
||||||
|
chunks: 'all', |
||||||
|
name: false, |
||||||
|
}, |
||||||
|
// Keep the runtime chunk seperated to enable long term caching
|
||||||
|
// https://twitter.com/wSokra/status/969679223278505985
|
||||||
|
runtimeChunk: true, |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
// This allows you to set a fallback for where Webpack should look for modules.
|
||||||
|
// We placed these paths second because we want `node_modules` to "win"
|
||||||
|
// if there are any conflicts. This matches Node resolution mechanism.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/253
|
||||||
|
modules: ['node_modules'].concat( |
||||||
|
// It is guaranteed to exist because we tweak it in `env.js`
|
||||||
|
process.env.NODE_PATH.split(path.delimiter).filter(Boolean) |
||||||
|
), |
||||||
|
// These are the reasonable defaults supported by the Node ecosystem.
|
||||||
|
// We also include JSX as a common component filename extension to support
|
||||||
|
// some tools, although we do not recommend using it, see:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/290
|
||||||
|
// `web` extension prefixes have been added for better support
|
||||||
|
// for React Native Web.
|
||||||
|
extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'], |
||||||
|
alias: { |
||||||
|
// Support React Native Web
|
||||||
|
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||||
|
'react-native': 'react-native-web', |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||||
|
// guards against forgotten dependencies and such.
|
||||||
|
PnpWebpackPlugin, |
||||||
|
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||||
|
// This often causes confusion because we only process files within src/ with babel.
|
||||||
|
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||||
|
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||||
|
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||||
|
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), |
||||||
|
], |
||||||
|
}, |
||||||
|
resolveLoader: { |
||||||
|
plugins: [ |
||||||
|
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||||
|
// from the current package.
|
||||||
|
PnpWebpackPlugin.moduleLoader(module), |
||||||
|
], |
||||||
|
}, |
||||||
|
module: { |
||||||
|
strictExportPresence: true, |
||||||
|
rules: [ |
||||||
|
// Disable require.ensure as it's not a standard language feature.
|
||||||
|
{ parser: { requireEnsure: false } }, |
||||||
|
|
||||||
|
// First, run the linter.
|
||||||
|
// It's important to do this before Babel processes the JS.
|
||||||
|
{ |
||||||
|
test: /\.(js|jsx)$/, |
||||||
|
enforce: 'pre', |
||||||
|
use: [ |
||||||
|
{ |
||||||
|
options: { |
||||||
|
formatter: require.resolve('react-dev-utils/eslintFormatter'), |
||||||
|
eslintPath: require.resolve('eslint'), |
||||||
|
|
||||||
|
}, |
||||||
|
loader: require.resolve('eslint-loader'), |
||||||
|
}, |
||||||
|
], |
||||||
|
include: paths.appSrc, |
||||||
|
}, |
||||||
|
{ |
||||||
|
// `mjs` support is still in its infancy in the ecosystem, so we don't
|
||||||
|
// support it.
|
||||||
|
// Modules who define their `browser` or `module` key as `mjs` force
|
||||||
|
// the use of this extension, so we need to tell webpack to fall back
|
||||||
|
// to auto mode (ES Module interop, allows ESM to import CommonJS).
|
||||||
|
test: /\.mjs$/, |
||||||
|
include: /node_modules/, |
||||||
|
type: 'javascript/auto', |
||||||
|
}, |
||||||
|
{ |
||||||
|
// "oneOf" will traverse all following loaders until one will
|
||||||
|
// match the requirements. When no loader matches it will fall
|
||||||
|
// back to the "file" loader at the end of the loader list.
|
||||||
|
oneOf: [ |
||||||
|
// "url" loader works just like "file" loader but it also embeds
|
||||||
|
// assets smaller than specified size as data URLs to avoid requests.
|
||||||
|
{ |
||||||
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
||||||
|
loader: require.resolve('url-loader'), |
||||||
|
options: { |
||||||
|
limit: 10000, |
||||||
|
name: 'static/media/[name].[hash:8].[ext]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
// Process application JS with Babel.
|
||||||
|
// The preset includes JSX, Flow, and some ESnext features.
|
||||||
|
{ |
||||||
|
test: /\.(js|jsx)$/, |
||||||
|
include: paths.appSrc, |
||||||
|
|
||||||
|
loader: require.resolve('babel-loader'), |
||||||
|
options: { |
||||||
|
customize: require.resolve( |
||||||
|
'babel-preset-react-app/webpack-overrides' |
||||||
|
), |
||||||
|
|
||||||
|
plugins: [ |
||||||
|
[ |
||||||
|
require.resolve('babel-plugin-named-asset-import'), |
||||||
|
{ |
||||||
|
loaderMap: { |
||||||
|
svg: { |
||||||
|
ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
], |
||||||
|
cacheDirectory: true, |
||||||
|
// Save disk space when time isn't as important
|
||||||
|
cacheCompression: true, |
||||||
|
compact: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
// Process any JS outside of the app with Babel.
|
||||||
|
// Unlike the application JS, we only compile the standard ES features.
|
||||||
|
{ |
||||||
|
test: /\.js$/, |
||||||
|
exclude: /@babel(?:\/|\\{1,2})runtime/, |
||||||
|
loader: require.resolve('babel-loader'), |
||||||
|
options: { |
||||||
|
babelrc: false, |
||||||
|
configFile: false, |
||||||
|
compact: false, |
||||||
|
presets: [ |
||||||
|
[ |
||||||
|
require.resolve('babel-preset-react-app/dependencies'), |
||||||
|
{ helpers: true }, |
||||||
|
], |
||||||
|
], |
||||||
|
cacheDirectory: true, |
||||||
|
// Save disk space when time isn't as important
|
||||||
|
cacheCompression: true, |
||||||
|
|
||||||
|
// If an error happens in a package, it's possible to be
|
||||||
|
// because it was compiled. Thus, we don't want the browser
|
||||||
|
// debugger to show the original code. Instead, the code
|
||||||
|
// being evaluated would be much more helpful.
|
||||||
|
sourceMaps: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
// "postcss" loader applies autoprefixer to our CSS.
|
||||||
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||||
|
// `MiniCSSExtractPlugin` extracts styles into CSS
|
||||||
|
// files. If you use code splitting, async bundles will have their own separate CSS chunk file.
|
||||||
|
// By default we support CSS Modules with the extension .module.css
|
||||||
|
{ |
||||||
|
test: cssRegex, |
||||||
|
exclude: cssModuleRegex, |
||||||
|
loader: getStyleLoaders({ |
||||||
|
importLoaders: 1, |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
}), |
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true, |
||||||
|
}, |
||||||
|
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||||
|
// using the extension .module.css
|
||||||
|
{ |
||||||
|
test: cssModuleRegex, |
||||||
|
loader: getStyleLoaders({ |
||||||
|
importLoaders: 1, |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
modules: true, |
||||||
|
getLocalIdent: getCSSModuleLocalIdent, |
||||||
|
}), |
||||||
|
}, |
||||||
|
// Opt-in support for SASS. The logic here is somewhat similar
|
||||||
|
// as in the CSS routine, except that "sass-loader" runs first
|
||||||
|
// to compile SASS files into CSS.
|
||||||
|
// By default we support SASS Modules with the
|
||||||
|
// extensions .module.scss or .module.sass
|
||||||
|
{ |
||||||
|
test: sassRegex, |
||||||
|
exclude: sassModuleRegex, |
||||||
|
loader: getStyleLoaders( |
||||||
|
{ |
||||||
|
importLoaders: 2, |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
}, |
||||||
|
'sass-loader' |
||||||
|
), |
||||||
|
// Don't consider CSS imports dead code even if the
|
||||||
|
// containing package claims to have no side effects.
|
||||||
|
// Remove this when webpack adds a warning or an error for this.
|
||||||
|
// See https://github.com/webpack/webpack/issues/6571
|
||||||
|
sideEffects: true, |
||||||
|
}, |
||||||
|
// Adds support for CSS Modules, but using SASS
|
||||||
|
// using the extension .module.scss or .module.sass
|
||||||
|
{ |
||||||
|
test: sassModuleRegex, |
||||||
|
loader: getStyleLoaders( |
||||||
|
{ |
||||||
|
importLoaders: 2, |
||||||
|
sourceMap: shouldUseSourceMap, |
||||||
|
modules: true, |
||||||
|
getLocalIdent: getCSSModuleLocalIdent, |
||||||
|
}, |
||||||
|
'sass-loader' |
||||||
|
), |
||||||
|
}, |
||||||
|
// "file" loader makes sure assets end up in the `build` folder.
|
||||||
|
// When you `import` an asset, you get its filename.
|
||||||
|
// This loader doesn't use a "test" so it will catch all modules
|
||||||
|
// that fall through the other loaders.
|
||||||
|
{ |
||||||
|
loader: require.resolve('file-loader'), |
||||||
|
// Exclude `js` files to keep "css" loader working as it injects
|
||||||
|
// it's runtime that would otherwise be processed through "file" loader.
|
||||||
|
// Also exclude `html` and `json` extensions so they get processed
|
||||||
|
// by webpacks internal loaders.
|
||||||
|
exclude: [/\.(js|jsx)$/, /\.html$/, /\.json$/], |
||||||
|
options: { |
||||||
|
name: 'static/media/[name].[hash:8].[ext]', |
||||||
|
}, |
||||||
|
}, |
||||||
|
// ** STOP ** Are you adding a new loader?
|
||||||
|
// Make sure to add the new loader(s) before the "file" loader.
|
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
// Generates an `index.html` file with the <script> injected.
|
||||||
|
new HtmlWebpackPlugin({ |
||||||
|
inject: true, |
||||||
|
template: paths.appHtml, |
||||||
|
minify: { |
||||||
|
removeComments: true, |
||||||
|
collapseWhitespace: true, |
||||||
|
removeRedundantAttributes: true, |
||||||
|
useShortDoctype: true, |
||||||
|
removeEmptyAttributes: true, |
||||||
|
removeStyleLinkTypeAttributes: true, |
||||||
|
keepClosingSlash: true, |
||||||
|
minifyJS: true, |
||||||
|
minifyCSS: true, |
||||||
|
minifyURLs: true, |
||||||
|
}, |
||||||
|
}), |
||||||
|
// Inlines the webpack runtime script. This script is too small to warrant
|
||||||
|
// a network request.
|
||||||
|
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]), |
||||||
|
// Makes some environment variables available in index.html.
|
||||||
|
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||||
|
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// In production, it will be an empty string unless you specify "homepage"
|
||||||
|
// in `package.json`, in which case it will be the pathname of that URL.
|
||||||
|
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw), |
||||||
|
// This gives some necessary context to module not found errors, such as
|
||||||
|
// the requesting resource.
|
||||||
|
new ModuleNotFoundPlugin(paths.appPath), |
||||||
|
// Makes some environment variables available to the JS code, for example:
|
||||||
|
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
||||||
|
// It is absolutely essential that NODE_ENV was set to production here.
|
||||||
|
// Otherwise React will be compiled in the very slow development mode.
|
||||||
|
new webpack.DefinePlugin(env.stringified), |
||||||
|
new MiniCssExtractPlugin({ |
||||||
|
// Options similar to the same options in webpackOptions.output
|
||||||
|
// both options are optional
|
||||||
|
filename: 'static/css/[name].[contenthash:8].css', |
||||||
|
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css', |
||||||
|
}), |
||||||
|
// Generate a manifest file which contains a mapping of all asset filenames
|
||||||
|
// to their corresponding output file so that tools can pick it up without
|
||||||
|
// having to parse `index.html`.
|
||||||
|
new ManifestPlugin({ |
||||||
|
fileName: 'asset-manifest.json', |
||||||
|
publicPath: publicPath, |
||||||
|
}), |
||||||
|
// Moment.js is an extremely popular library that bundles large locale files
|
||||||
|
// by default due to how Webpack interprets its code. This is a practical
|
||||||
|
// solution that requires the user to opt into importing specific locales.
|
||||||
|
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||||
|
// You can remove this if you don't use Moment.js:
|
||||||
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
||||||
|
// Generate a service worker script that will precache, and keep up to date,
|
||||||
|
// the HTML & assets that are part of the Webpack build.
|
||||||
|
new WorkboxWebpackPlugin.GenerateSW({ |
||||||
|
clientsClaim: true, |
||||||
|
exclude: [/\.map$/, /asset-manifest\.json$/], |
||||||
|
importWorkboxFrom: 'cdn', |
||||||
|
navigateFallback: publicUrl + '/index.html', |
||||||
|
navigateFallbackBlacklist: [ |
||||||
|
// Exclude URLs starting with /_, as they're likely an API call
|
||||||
|
new RegExp('^/_'), |
||||||
|
// Exclude URLs containing a dot, as they're likely a resource in
|
||||||
|
// public/ and not a SPA route
|
||||||
|
new RegExp('/[^/]+\\.[^/]+$'), |
||||||
|
], |
||||||
|
}), |
||||||
|
], |
||||||
|
// Some libraries import Node modules but don't use them in the browser.
|
||||||
|
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||||
|
node: { |
||||||
|
dgram: 'empty', |
||||||
|
fs: 'empty', |
||||||
|
net: 'empty', |
||||||
|
tls: 'empty', |
||||||
|
child_process: 'empty', |
||||||
|
}, |
||||||
|
// Turn off performance processing because we utilize
|
||||||
|
// our own hints via the FileSizeReporter
|
||||||
|
performance: false, |
||||||
|
}; |
@ -0,0 +1,105 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware'); |
||||||
|
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware'); |
||||||
|
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware'); |
||||||
|
const ignoredFiles = require('react-dev-utils/ignoredFiles'); |
||||||
|
const config = require('./webpack.config.dev'); |
||||||
|
const paths = require('./paths'); |
||||||
|
const fs = require('fs'); |
||||||
|
|
||||||
|
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; |
||||||
|
const host = process.env.HOST || '0.0.0.0'; |
||||||
|
|
||||||
|
module.exports = function(proxy, allowedHost) { |
||||||
|
return { |
||||||
|
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
|
||||||
|
// websites from potentially accessing local content through DNS rebinding:
|
||||||
|
// https://github.com/webpack/webpack-dev-server/issues/887
|
||||||
|
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
|
||||||
|
// However, it made several existing use cases such as development in cloud
|
||||||
|
// environment or subdomains in development significantly more complicated:
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2271
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2233
|
||||||
|
// While we're investigating better solutions, for now we will take a
|
||||||
|
// compromise. Since our WDS configuration only serves files in the `public`
|
||||||
|
// folder we won't consider accessing them a vulnerability. However, if you
|
||||||
|
// use the `proxy` feature, it gets more dangerous because it can expose
|
||||||
|
// remote code execution vulnerabilities in backends like Django and Rails.
|
||||||
|
// So we will disable the host check normally, but enable it if you have
|
||||||
|
// specified the `proxy` setting. Finally, we let you override it if you
|
||||||
|
// really know what you're doing with a special environment variable.
|
||||||
|
disableHostCheck: |
||||||
|
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true', |
||||||
|
// Enable gzip compression of generated files.
|
||||||
|
compress: true, |
||||||
|
// Silence WebpackDevServer's own logs since they're generally not useful.
|
||||||
|
// It will still show compile warnings and errors with this setting.
|
||||||
|
clientLogLevel: 'none', |
||||||
|
// By default WebpackDevServer serves physical files from current directory
|
||||||
|
// in addition to all the virtual build products that it serves from memory.
|
||||||
|
// This is confusing because those files won’t automatically be available in
|
||||||
|
// production build folder unless we copy them. However, copying the whole
|
||||||
|
// project directory is dangerous because we may expose sensitive files.
|
||||||
|
// Instead, we establish a convention that only files in `public` directory
|
||||||
|
// get served. Our build script will copy `public` into the `build` folder.
|
||||||
|
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
|
||||||
|
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||||
|
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
|
||||||
|
// Note that we only recommend to use `public` folder as an escape hatch
|
||||||
|
// for files like `favicon.ico`, `manifest.json`, and libraries that are
|
||||||
|
// for some reason broken when imported through Webpack. If you just want to
|
||||||
|
// use an image, put it in `src` and `import` it from JavaScript instead.
|
||||||
|
contentBase: paths.appPublic, |
||||||
|
// By default files from `contentBase` will not trigger a page reload.
|
||||||
|
watchContentBase: true, |
||||||
|
// Enable hot reloading server. It will provide /sockjs-node/ endpoint
|
||||||
|
// for the WebpackDevServer client so it can learn when the files were
|
||||||
|
// updated. The WebpackDevServer client is included as an entry point
|
||||||
|
// in the Webpack development configuration. Note that only changes
|
||||||
|
// to CSS are currently hot reloaded. JS changes will refresh the browser.
|
||||||
|
hot: true, |
||||||
|
// It is important to tell WebpackDevServer to use the same "root" path
|
||||||
|
// as we specified in the config. In development, we always serve from /.
|
||||||
|
publicPath: config.output.publicPath, |
||||||
|
// WebpackDevServer is noisy by default so we emit custom message instead
|
||||||
|
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
||||||
|
quiet: true, |
||||||
|
// Reportedly, this avoids CPU overload on some systems.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/293
|
||||||
|
// src/node_modules is not ignored to support absolute imports
|
||||||
|
// https://github.com/facebook/create-react-app/issues/1065
|
||||||
|
watchOptions: { |
||||||
|
ignored: ignoredFiles(paths.appSrc), |
||||||
|
}, |
||||||
|
// Enable HTTPS if the HTTPS environment variable is set to 'true'
|
||||||
|
https: protocol === 'https', |
||||||
|
host, |
||||||
|
overlay: false, |
||||||
|
historyApiFallback: { |
||||||
|
// Paths with dots should still use the history fallback.
|
||||||
|
// See https://github.com/facebook/create-react-app/issues/387.
|
||||||
|
disableDotRule: true, |
||||||
|
}, |
||||||
|
public: allowedHost, |
||||||
|
proxy, |
||||||
|
before(app, server) { |
||||||
|
if (fs.existsSync(paths.proxySetup)) { |
||||||
|
// This registers user provided middleware for proxy reasons
|
||||||
|
require(paths.proxySetup)(app); |
||||||
|
} |
||||||
|
|
||||||
|
// This lets us fetch source contents from webpack for the error overlay
|
||||||
|
app.use(evalSourceMapMiddleware(server)); |
||||||
|
// This lets us open files from the runtime error overlay.
|
||||||
|
app.use(errorOverlayMiddleware()); |
||||||
|
|
||||||
|
// This service worker file is effectively a 'no-op' that will reset any
|
||||||
|
// previous service worker registered for the same host:port combination.
|
||||||
|
// We do this in development to avoid hitting the production cache if
|
||||||
|
// it used the same host and port.
|
||||||
|
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||||
|
app.use(noopServiceWorkerMiddleware()); |
||||||
|
}, |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,130 @@ |
|||||||
|
{ |
||||||
|
"name": "easydev-seed", |
||||||
|
"version": "2.0.0", |
||||||
|
"private": true, |
||||||
|
"homepage": "http://previews.aspirity.com/easydev", |
||||||
|
"dependencies": { |
||||||
|
"bfj": "^6.1.1", |
||||||
|
"bootstrap": "^4.3.1", |
||||||
|
"case-sensitive-paths-webpack-plugin": "^2.2.0", |
||||||
|
"chalk": "^2.4.2", |
||||||
|
"classnames": "^2.2.6", |
||||||
|
"dotenv": "^6.2.0", |
||||||
|
"dotenv-expand": "^4.2.0", |
||||||
|
"file-loader": "^3.0.1", |
||||||
|
"fs-extra": "^7.0.1", |
||||||
|
"html-webpack-plugin": "4.0.0-alpha.2", |
||||||
|
"identity-obj-proxy": "^3.0.0", |
||||||
|
"jest": "^24.3.1", |
||||||
|
"jest-pnp-resolver": "^1.2.1", |
||||||
|
"jest-resolve": "^24.3.1", |
||||||
|
"mdi-react": "^5.3.0", |
||||||
|
"mini-css-extract-plugin": "^0.5.0", |
||||||
|
"optimize-css-assets-webpack-plugin": "^5.0.1", |
||||||
|
"pnp-webpack-plugin": "^1.4.1", |
||||||
|
"postcss-flexbugs-fixes": "^4.1.0", |
||||||
|
"postcss-loader": "^3.0.0", |
||||||
|
"postcss-preset-env": "^6.6.0", |
||||||
|
"postcss-safe-parser": "^4.0.1", |
||||||
|
"prop-types": "^15.7.2", |
||||||
|
"react": "^16.8.4", |
||||||
|
"react-app-polyfill": "^0.2.2", |
||||||
|
"react-dev-utils": "6.0.3", |
||||||
|
"react-dom": "^16.8.4", |
||||||
|
"react-redux": "^6.0.1", |
||||||
|
"react-router": "^4.3.1", |
||||||
|
"react-router-dom": "^4.3.1", |
||||||
|
"react-smooth-scrollbar": "^8.0.6", |
||||||
|
"reactstrap": "^7.1.0", |
||||||
|
"redux": "^4.0.1", |
||||||
|
"redux-form": "^8.1.0", |
||||||
|
"redux-thunk": "^2.3.0", |
||||||
|
"resolve": "1.10.0", |
||||||
|
"smooth-scrollbar": "^8.3.1", |
||||||
|
"style-loader": "0.23.1", |
||||||
|
"terser-webpack-plugin": "1.2.3", |
||||||
|
"url-loader": "1.1.2" |
||||||
|
}, |
||||||
|
"scripts": { |
||||||
|
"start": "node scripts/start.js", |
||||||
|
"build": "node scripts/build.js", |
||||||
|
"test": "node scripts/test.js" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@babel/core": "7.3.4", |
||||||
|
"@svgr/webpack": "4.1.0", |
||||||
|
"babel-core": "7.0.0-bridge.0", |
||||||
|
"babel-eslint": "10.0.1", |
||||||
|
"babel-jest": "24.3.1", |
||||||
|
"babel-loader": "8.0.5", |
||||||
|
"babel-plugin-named-asset-import": "^0.3.1", |
||||||
|
"babel-preset-react-app": "^7.0.2", |
||||||
|
"babel-runtime": "6.26.0", |
||||||
|
"css-loader": "2.1.1", |
||||||
|
"eslint": "5.15.1", |
||||||
|
"eslint-config-airbnb": "^17.1.0", |
||||||
|
"eslint-config-react-app": "^3.0.8", |
||||||
|
"eslint-loader": "2.1.2", |
||||||
|
"eslint-plugin-flowtype": "3.4.2", |
||||||
|
"eslint-plugin-import": "2.16.0", |
||||||
|
"eslint-plugin-jsx-a11y": "6.2.1", |
||||||
|
"eslint-plugin-react": "7.12.4", |
||||||
|
"node-sass": "^4.11.0", |
||||||
|
"react-hot-loader": "^4.8.0", |
||||||
|
"sass-loader": "7.1.0", |
||||||
|
"webpack": "4.29.6", |
||||||
|
"webpack-dev-server": "3.2.1", |
||||||
|
"webpack-manifest-plugin": "2.0.4", |
||||||
|
"workbox-webpack-plugin": "4.1.0" |
||||||
|
}, |
||||||
|
"eslintConfig": { |
||||||
|
"extends": "react-app" |
||||||
|
}, |
||||||
|
"browserslist": [ |
||||||
|
">0.2%", |
||||||
|
"not dead", |
||||||
|
"not ie <= 11", |
||||||
|
"not op_mini all" |
||||||
|
], |
||||||
|
"jest": { |
||||||
|
"collectCoverageFrom": [ |
||||||
|
"src/**/*.{js,jsx}" |
||||||
|
], |
||||||
|
"resolver": "jest-pnp-resolver", |
||||||
|
"setupFiles": [ |
||||||
|
"react-app-polyfill/jsdom" |
||||||
|
], |
||||||
|
"testMatch": [ |
||||||
|
"<rootDir>/src/**/__tests__/**/*.{js,jsx}", |
||||||
|
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx}" |
||||||
|
], |
||||||
|
"testEnvironment": "jsdom", |
||||||
|
"testURL": "http://localhost", |
||||||
|
"transform": { |
||||||
|
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest", |
||||||
|
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js", |
||||||
|
"^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js" |
||||||
|
}, |
||||||
|
"transformIgnorePatterns": [ |
||||||
|
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$", |
||||||
|
"^.+\\.module\\.(css|sass|scss)$" |
||||||
|
], |
||||||
|
"moduleNameMapper": { |
||||||
|
"^react-native$": "react-native-web", |
||||||
|
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy" |
||||||
|
}, |
||||||
|
"moduleFileExtensions": [ |
||||||
|
"web.js", |
||||||
|
"js", |
||||||
|
"json", |
||||||
|
"web.jsx", |
||||||
|
"jsx", |
||||||
|
"node" |
||||||
|
] |
||||||
|
}, |
||||||
|
"babel": { |
||||||
|
"presets": [ |
||||||
|
"react-app" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 172 B |
@ -0,0 +1,53 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||||
|
<meta name="theme-color" content="#000000"> |
||||||
|
<!-- |
||||||
|
manifest.json provides metadata used when your web app is added to the |
||||||
|
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ |
||||||
|
--> |
||||||
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> |
||||||
|
<link rel="shortcut icon" href="%PUBLIC_URL%/fav.ico"> |
||||||
|
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> |
||||||
|
<link rel="stylesheet" href="https://cdn.linearicons.com/free/1.0.0/icon-font.min.css"> |
||||||
|
<link rel="stylesheet" href="%PUBLIC_URL%/load.css"> |
||||||
|
<!-- |
||||||
|
Notice the use of %PUBLIC_URL% in the tags above. |
||||||
|
It will be replaced with the URL of the `public` folder during the build. |
||||||
|
Only files inside the `public` folder can be referenced from the HTML. |
||||||
|
|
||||||
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will |
||||||
|
work correctly both with client-side routing and a non-root public URL. |
||||||
|
Learn how to configure a non-root public URL by running `npm run build`. |
||||||
|
--> |
||||||
|
<title>EasyDEV</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<noscript> |
||||||
|
You need to enable JavaScript to run this app. |
||||||
|
</noscript> |
||||||
|
<div id="root"> |
||||||
|
<!--Loader--> |
||||||
|
<div class="load"> |
||||||
|
<div class="load__icon-wrap"> |
||||||
|
<svg class="load__icon"> |
||||||
|
<path fill="#4ce1b6" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z"/> |
||||||
|
</svg> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<!--Loader--> |
||||||
|
</div> |
||||||
|
<!-- |
||||||
|
This HTML file is a template. |
||||||
|
If you open it directly in the browser, you will see an empty page. |
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file. |
||||||
|
The build step will place the bundled scripts into the <body> tag. |
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`. |
||||||
|
To create a production bundle, use `npm run build` or `yarn build`. |
||||||
|
--> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,25 @@ |
|||||||
|
.load__icon { |
||||||
|
animation: linear load 2s infinite; |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
} |
||||||
|
|
||||||
|
.load__icon-wrap { |
||||||
|
margin: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.load { |
||||||
|
height: calc(100vh - 16px); |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes load { |
||||||
|
from { |
||||||
|
transform: rotate(0deg) scale(2); |
||||||
|
} |
||||||
|
to { |
||||||
|
transform: rotate(360deg) scale(2); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
{ |
||||||
|
"short_name": "EasyDEV", |
||||||
|
"name": "EasyDEV", |
||||||
|
"icons": [ |
||||||
|
{ |
||||||
|
"src": "fav.ico", |
||||||
|
"sizes": "64x64 32x32 24x24 16x16", |
||||||
|
"type": "image/x-icon" |
||||||
|
} |
||||||
|
], |
||||||
|
"start_url": ".", |
||||||
|
"display": "standalone", |
||||||
|
"theme_color": "#4ce1b6", |
||||||
|
"background_color": "#ffffff" |
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'production'; |
||||||
|
process.env.NODE_ENV = 'production'; |
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => { |
||||||
|
throw err; |
||||||
|
}); |
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env'); |
||||||
|
|
||||||
|
|
||||||
|
const path = require('path'); |
||||||
|
const chalk = require('chalk'); |
||||||
|
const fs = require('fs-extra'); |
||||||
|
const webpack = require('webpack'); |
||||||
|
const bfj = require('bfj'); |
||||||
|
const config = require('../config/webpack.config.prod'); |
||||||
|
const paths = require('../config/paths'); |
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); |
||||||
|
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); |
||||||
|
const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); |
||||||
|
const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); |
||||||
|
const printBuildError = require('react-dev-utils/printBuildError'); |
||||||
|
|
||||||
|
const measureFileSizesBeforeBuild = |
||||||
|
FileSizeReporter.measureFileSizesBeforeBuild; |
||||||
|
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; |
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile); |
||||||
|
|
||||||
|
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
||||||
|
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; |
||||||
|
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; |
||||||
|
|
||||||
|
const isInteractive = process.stdout.isTTY; |
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
// Process CLI arguments
|
||||||
|
const argv = process.argv.slice(2); |
||||||
|
const writeStatsJson = argv.indexOf('--stats') !== -1; |
||||||
|
|
||||||
|
// We require that you explictly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper'); |
||||||
|
checkBrowsers(paths.appPath, isInteractive) |
||||||
|
.then(() => { |
||||||
|
// First, read the current file sizes in build directory.
|
||||||
|
// This lets us display how much they changed later.
|
||||||
|
return measureFileSizesBeforeBuild(paths.appBuild); |
||||||
|
}) |
||||||
|
.then(previousFileSizes => { |
||||||
|
// Remove all content but keep the directory so that
|
||||||
|
// if you're in it, you don't end up in Trash
|
||||||
|
fs.emptyDirSync(paths.appBuild); |
||||||
|
// Merge with the public folder
|
||||||
|
copyPublicFolder(); |
||||||
|
// Start the webpack build
|
||||||
|
return build(previousFileSizes); |
||||||
|
}) |
||||||
|
.then( |
||||||
|
({ stats, previousFileSizes, warnings }) => { |
||||||
|
if (warnings.length) { |
||||||
|
console.log(chalk.yellow('Compiled with warnings.\n')); |
||||||
|
console.log(warnings.join('\n\n')); |
||||||
|
console.log( |
||||||
|
'\nSearch for the ' + |
||||||
|
chalk.underline(chalk.yellow('keywords')) + |
||||||
|
' to learn more about each warning.' |
||||||
|
); |
||||||
|
console.log( |
||||||
|
'To ignore, add ' + |
||||||
|
chalk.cyan('// eslint-disable-next-line') + |
||||||
|
' to the line before.\n' |
||||||
|
); |
||||||
|
} else { |
||||||
|
console.log(chalk.green('Compiled successfully.\n')); |
||||||
|
} |
||||||
|
|
||||||
|
console.log('File sizes after gzip:\n'); |
||||||
|
printFileSizesAfterBuild( |
||||||
|
stats, |
||||||
|
previousFileSizes, |
||||||
|
paths.appBuild, |
||||||
|
WARN_AFTER_BUNDLE_GZIP_SIZE, |
||||||
|
WARN_AFTER_CHUNK_GZIP_SIZE |
||||||
|
); |
||||||
|
console.log(); |
||||||
|
|
||||||
|
const appPackage = require(paths.appPackageJson); |
||||||
|
const publicUrl = paths.publicUrl; |
||||||
|
const publicPath = config.output.publicPath; |
||||||
|
const buildFolder = path.relative(process.cwd(), paths.appBuild); |
||||||
|
printHostingInstructions( |
||||||
|
appPackage, |
||||||
|
publicUrl, |
||||||
|
publicPath, |
||||||
|
buildFolder, |
||||||
|
useYarn |
||||||
|
); |
||||||
|
}, |
||||||
|
err => { |
||||||
|
console.log(chalk.red('Failed to compile.\n')); |
||||||
|
printBuildError(err); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
) |
||||||
|
.catch(err => { |
||||||
|
if (err && err.message) { |
||||||
|
console.log(err.message); |
||||||
|
} |
||||||
|
process.exit(1); |
||||||
|
}); |
||||||
|
|
||||||
|
// Create the production build and print the deployment instructions.
|
||||||
|
function build(previousFileSizes) { |
||||||
|
console.log('Creating an optimized production build...'); |
||||||
|
|
||||||
|
let compiler = webpack(config); |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
compiler.run((err, stats) => { |
||||||
|
let messages; |
||||||
|
if (err) { |
||||||
|
if (!err.message) { |
||||||
|
return reject(err); |
||||||
|
} |
||||||
|
messages = formatWebpackMessages({ |
||||||
|
errors: [err.message], |
||||||
|
warnings: [], |
||||||
|
}); |
||||||
|
} else { |
||||||
|
messages = formatWebpackMessages( |
||||||
|
stats.toJson({ all: false, warnings: true, errors: true }) |
||||||
|
); |
||||||
|
} |
||||||
|
if (messages.errors.length) { |
||||||
|
// Only keep the first error. Others are often indicative
|
||||||
|
// of the same problem, but confuse the reader with noise.
|
||||||
|
if (messages.errors.length > 1) { |
||||||
|
messages.errors.length = 1; |
||||||
|
} |
||||||
|
return reject(new Error(messages.errors.join('\n\n'))); |
||||||
|
} |
||||||
|
if ( |
||||||
|
process.env.CI && |
||||||
|
(typeof process.env.CI !== 'string' || |
||||||
|
process.env.CI.toLowerCase() !== 'false') && |
||||||
|
messages.warnings.length |
||||||
|
) { |
||||||
|
console.log( |
||||||
|
chalk.yellow( |
||||||
|
'\nTreating warnings as errors because process.env.CI = true.\n' + |
||||||
|
'Most CI servers set it automatically.\n' |
||||||
|
) |
||||||
|
); |
||||||
|
return reject(new Error(messages.warnings.join('\n\n'))); |
||||||
|
} |
||||||
|
|
||||||
|
const resolveArgs = { |
||||||
|
stats, |
||||||
|
previousFileSizes, |
||||||
|
warnings: messages.warnings, |
||||||
|
}; |
||||||
|
if (writeStatsJson) { |
||||||
|
return bfj |
||||||
|
.write(paths.appBuild + '/bundle-stats.json', stats.toJson()) |
||||||
|
.then(() => resolve(resolveArgs)) |
||||||
|
.catch(error => reject(new Error(error))); |
||||||
|
} |
||||||
|
|
||||||
|
return resolve(resolveArgs); |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function copyPublicFolder() { |
||||||
|
fs.copySync(paths.appPublic, paths.appBuild, { |
||||||
|
dereference: true, |
||||||
|
filter: file => file !== paths.appHtml, |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'development'; |
||||||
|
process.env.NODE_ENV = 'development'; |
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => { |
||||||
|
throw err; |
||||||
|
}); |
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env'); |
||||||
|
|
||||||
|
|
||||||
|
const fs = require('fs'); |
||||||
|
const chalk = require('chalk'); |
||||||
|
const webpack = require('webpack'); |
||||||
|
const WebpackDevServer = require('webpack-dev-server'); |
||||||
|
const clearConsole = require('react-dev-utils/clearConsole'); |
||||||
|
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); |
||||||
|
const { |
||||||
|
choosePort, |
||||||
|
createCompiler, |
||||||
|
prepareProxy, |
||||||
|
prepareUrls, |
||||||
|
} = require('react-dev-utils/WebpackDevServerUtils'); |
||||||
|
const openBrowser = require('react-dev-utils/openBrowser'); |
||||||
|
const paths = require('../config/paths'); |
||||||
|
const config = require('../config/webpack.config.dev'); |
||||||
|
const createDevServerConfig = require('../config/webpackDevServer.config'); |
||||||
|
|
||||||
|
const useYarn = fs.existsSync(paths.yarnLockFile); |
||||||
|
const isInteractive = process.stdout.isTTY; |
||||||
|
|
||||||
|
// Warn and crash if required files are missing
|
||||||
|
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
// Tools like Cloud9 rely on this.
|
||||||
|
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; |
||||||
|
const HOST = process.env.HOST || '0.0.0.0'; |
||||||
|
|
||||||
|
if (process.env.HOST) { |
||||||
|
console.log( |
||||||
|
chalk.cyan( |
||||||
|
`Attempting to bind to HOST environment variable: ${chalk.yellow( |
||||||
|
chalk.bold(process.env.HOST) |
||||||
|
)}` |
||||||
|
) |
||||||
|
); |
||||||
|
console.log( |
||||||
|
`If this was unintentional, check that you haven't mistakenly set it in your shell.` |
||||||
|
); |
||||||
|
console.log( |
||||||
|
`Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}` |
||||||
|
); |
||||||
|
console.log(); |
||||||
|
} |
||||||
|
|
||||||
|
// We require that you explictly set browsers and do not fall back to
|
||||||
|
// browserslist defaults.
|
||||||
|
const { checkBrowsers } = require('react-dev-utils/browsersHelper'); |
||||||
|
checkBrowsers(paths.appPath, isInteractive) |
||||||
|
.then(() => { |
||||||
|
// We attempt to use the default port but if it is busy, we offer the user to
|
||||||
|
// run on a different port. `choosePort()` Promise resolves to the next free port.
|
||||||
|
return choosePort(HOST, DEFAULT_PORT); |
||||||
|
}) |
||||||
|
.then(port => { |
||||||
|
if (port == null) { |
||||||
|
// We have not found a port.
|
||||||
|
return; |
||||||
|
} |
||||||
|
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; |
||||||
|
const appName = require(paths.appPackageJson).name; |
||||||
|
const urls = prepareUrls(protocol, HOST, port); |
||||||
|
// Create a webpack compiler that is configured with custom messages.
|
||||||
|
const compiler = createCompiler(webpack, config, appName, urls, useYarn); |
||||||
|
// Load proxy config
|
||||||
|
const proxySetting = require(paths.appPackageJson).proxy; |
||||||
|
const proxyConfig = prepareProxy(proxySetting, paths.appPublic); |
||||||
|
// Serve webpack assets generated by the compiler over a web server.
|
||||||
|
const serverConfig = createDevServerConfig( |
||||||
|
proxyConfig, |
||||||
|
urls.lanUrlForConfig |
||||||
|
); |
||||||
|
const devServer = new WebpackDevServer(compiler, serverConfig); |
||||||
|
// Launch WebpackDevServer.
|
||||||
|
devServer.listen(port, HOST, err => { |
||||||
|
if (err) { |
||||||
|
return console.log(err); |
||||||
|
} |
||||||
|
if (isInteractive) { |
||||||
|
clearConsole(); |
||||||
|
} |
||||||
|
console.log(chalk.cyan('Starting the development server...\n')); |
||||||
|
openBrowser(urls.localUrlForBrowser); |
||||||
|
}); |
||||||
|
|
||||||
|
['SIGINT', 'SIGTERM'].forEach(function(sig) { |
||||||
|
process.on(sig, function() { |
||||||
|
devServer.close(); |
||||||
|
process.exit(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}) |
||||||
|
.catch(err => { |
||||||
|
if (err && err.message) { |
||||||
|
console.log(err.message); |
||||||
|
} |
||||||
|
process.exit(1); |
||||||
|
}); |
@ -0,0 +1,53 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
// Do this as the first thing so that any code reading it knows the right env.
|
||||||
|
process.env.BABEL_ENV = 'test'; |
||||||
|
process.env.NODE_ENV = 'test'; |
||||||
|
process.env.PUBLIC_URL = ''; |
||||||
|
|
||||||
|
// Makes the script crash on unhandled rejections instead of silently
|
||||||
|
// ignoring them. In the future, promise rejections that are not handled will
|
||||||
|
// terminate the Node.js process with a non-zero exit code.
|
||||||
|
process.on('unhandledRejection', err => { |
||||||
|
throw err; |
||||||
|
}); |
||||||
|
|
||||||
|
// Ensure environment variables are read.
|
||||||
|
require('../config/env'); |
||||||
|
|
||||||
|
|
||||||
|
const jest = require('jest'); |
||||||
|
const execSync = require('child_process').execSync; |
||||||
|
let argv = process.argv.slice(2); |
||||||
|
|
||||||
|
function isInGitRepository() { |
||||||
|
try { |
||||||
|
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); |
||||||
|
return true; |
||||||
|
} catch (e) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function isInMercurialRepository() { |
||||||
|
try { |
||||||
|
execSync('hg --cwd . root', { stdio: 'ignore' }); |
||||||
|
return true; |
||||||
|
} catch (e) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Watch unless on CI, in coverage mode, or explicitly running all tests
|
||||||
|
if ( |
||||||
|
!process.env.CI && |
||||||
|
argv.indexOf('--coverage') === -1 && |
||||||
|
argv.indexOf('--watchAll') === -1 |
||||||
|
) { |
||||||
|
// https://github.com/facebook/create-react-app/issues/5210
|
||||||
|
const hasSourceControl = isInGitRepository() || isInMercurialRepository(); |
||||||
|
argv.push(hasSourceControl ? '--watch' : '--watchAll'); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
jest.run(argv); |
@ -0,0 +1,57 @@ |
|||||||
|
import React, { Component, Fragment } from 'react'; |
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies |
||||||
|
import { hot } from 'react-hot-loader'; |
||||||
|
import { Provider } from 'react-redux'; |
||||||
|
import { BrowserRouter } from 'react-router-dom'; |
||||||
|
import 'bootstrap/dist/css/bootstrap.css'; |
||||||
|
import '../../scss/app.scss'; |
||||||
|
import Router from './Router'; |
||||||
|
import store from './store'; |
||||||
|
import ScrollToTop from './ScrollToTop'; |
||||||
|
|
||||||
|
class App extends Component { |
||||||
|
constructor() { |
||||||
|
super(); |
||||||
|
this.state = { |
||||||
|
loading: true, |
||||||
|
loaded: false, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
componentDidMount() { |
||||||
|
window.addEventListener('load', () => { |
||||||
|
this.setState({ loading: false }); |
||||||
|
setTimeout(() => this.setState({ loaded: true }), 500); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
render() { |
||||||
|
const { loaded, loading } = this.state; |
||||||
|
return ( |
||||||
|
<Provider store={store}> |
||||||
|
<BrowserRouter> |
||||||
|
<ScrollToTop> |
||||||
|
<Fragment> |
||||||
|
{!loaded |
||||||
|
&& ( |
||||||
|
<div className={`load${loading ? '' : ' loaded'}`}> |
||||||
|
<div className="load__icon-wrap"> |
||||||
|
<svg className="load__icon"> |
||||||
|
<path fill="#4ce1b6" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" /> |
||||||
|
</svg> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
||||||
|
<div> |
||||||
|
<Router /> |
||||||
|
</div> |
||||||
|
</Fragment> |
||||||
|
</ScrollToTop> |
||||||
|
</BrowserRouter> |
||||||
|
</Provider> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default hot(module)(App); |
@ -0,0 +1,9 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import ReactDOM from 'react-dom'; |
||||||
|
import App from './App'; |
||||||
|
|
||||||
|
it('renders without crashing', () => { |
||||||
|
const div = document.createElement('div'); |
||||||
|
ReactDOM.render(<App />, div); |
||||||
|
ReactDOM.unmountComponentAtNode(div); |
||||||
|
}); |
@ -0,0 +1,27 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import { connect } from 'react-redux'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import { ThemeProps } from '../../shared/prop-types/ReducerProps'; |
||||||
|
|
||||||
|
class MainWrapper extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
theme: ThemeProps.isRequired, |
||||||
|
children: PropTypes.element.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { theme, children } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={theme.className}> |
||||||
|
<div className="wrapper"> |
||||||
|
{children} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default connect(state => ({ |
||||||
|
theme: state.theme, |
||||||
|
}))(MainWrapper); |
@ -0,0 +1,38 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Route, Switch } from 'react-router-dom'; |
||||||
|
import Layout from '../Layout/index'; |
||||||
|
import MainWrapper from './MainWrapper'; |
||||||
|
|
||||||
|
import LogIn from '../LogIn/index'; |
||||||
|
import ExamplePageOne from '../Example/index'; |
||||||
|
import ExamplePageTwo from '../ExampleTwo/index'; |
||||||
|
|
||||||
|
const Pages = () => ( |
||||||
|
<Switch> |
||||||
|
<Route path="/pages/one" component={ExamplePageOne} /> |
||||||
|
<Route path="/pages/two" component={ExamplePageTwo} /> |
||||||
|
</Switch> |
||||||
|
); |
||||||
|
|
||||||
|
const wrappedRoutes = () => ( |
||||||
|
<div> |
||||||
|
<Layout /> |
||||||
|
<div className="container__wrap"> |
||||||
|
<Route path="/pages" component={Pages} /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
|
||||||
|
const Router = () => ( |
||||||
|
<MainWrapper> |
||||||
|
<main> |
||||||
|
<Switch> |
||||||
|
<Route exact path="/" component={LogIn} /> |
||||||
|
<Route exact path="/log_in" component={LogIn} /> |
||||||
|
<Route path="/" component={wrappedRoutes} /> |
||||||
|
</Switch> |
||||||
|
</main> |
||||||
|
</MainWrapper> |
||||||
|
); |
||||||
|
|
||||||
|
export default Router; |
@ -0,0 +1,26 @@ |
|||||||
|
import { PureComponent } from 'react'; |
||||||
|
import { withRouter } from 'react-router-dom'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
|
||||||
|
class ScrollToTop extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
location: PropTypes.shape({ |
||||||
|
pathname: PropTypes.string, |
||||||
|
}).isRequired, |
||||||
|
children: PropTypes.element.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
componentDidUpdate(prevProps) { |
||||||
|
const { location } = this.props; |
||||||
|
if (location.pathname !== prevProps.location.pathname) { |
||||||
|
window.scrollTo(0, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
render() { |
||||||
|
const { children } = this.props; |
||||||
|
return children; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default withRouter(ScrollToTop); |
@ -0,0 +1,11 @@ |
|||||||
|
import { combineReducers } from 'redux'; |
||||||
|
import { reducer as formReducer } from 'redux-form'; |
||||||
|
import { sidebarReducer, themeReducer } from '../../redux/reducers/index'; |
||||||
|
|
||||||
|
const objReducers = { |
||||||
|
form: formReducer, // mounted under "form",
|
||||||
|
theme: themeReducer, |
||||||
|
sidebar: sidebarReducer, |
||||||
|
}; |
||||||
|
|
||||||
|
export default combineReducers(objReducers); |
@ -0,0 +1,13 @@ |
|||||||
|
import { createStore, compose, applyMiddleware } from 'redux'; |
||||||
|
import thunk from 'redux-thunk'; |
||||||
|
import reducers from './reducers'; |
||||||
|
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; |
||||||
|
const store = createStore( |
||||||
|
reducers, |
||||||
|
{}, |
||||||
|
composeEnhancers(applyMiddleware(thunk)), |
||||||
|
); |
||||||
|
|
||||||
|
export default store; |
@ -0,0 +1,18 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Card, CardBody, Col } from 'reactstrap'; |
||||||
|
|
||||||
|
const ExampleCard = () => ( |
||||||
|
<Col md={12}> |
||||||
|
<Card> |
||||||
|
<CardBody> |
||||||
|
<div className="card__title"> |
||||||
|
<h5 className="bold-text">Example title</h5> |
||||||
|
<h5 className="subhead">Example subhead</h5> |
||||||
|
</div> |
||||||
|
<p>Your content here</p> |
||||||
|
</CardBody> |
||||||
|
</Card> |
||||||
|
</Col> |
||||||
|
); |
||||||
|
|
||||||
|
export default ExampleCard; |
@ -0,0 +1,18 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Col, Container, Row } from 'reactstrap'; |
||||||
|
import ExampleCard from './components/ExampleCard'; |
||||||
|
|
||||||
|
const ExamplePage = () => ( |
||||||
|
<Container className="dashboard"> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<h3 className="page-title">Example Page One</h3> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<ExampleCard /> |
||||||
|
</Row> |
||||||
|
</Container> |
||||||
|
); |
||||||
|
|
||||||
|
export default ExamplePage; |
@ -0,0 +1,18 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Card, CardBody, Col } from 'reactstrap'; |
||||||
|
|
||||||
|
const ExampleCard = () => ( |
||||||
|
<Col md={12}> |
||||||
|
<Card> |
||||||
|
<CardBody> |
||||||
|
<div className="card__title"> |
||||||
|
<h5 className="bold-text">Example title</h5> |
||||||
|
<h5 className="subhead">Example subhead</h5> |
||||||
|
</div> |
||||||
|
<p>Your content here</p> |
||||||
|
</CardBody> |
||||||
|
</Card> |
||||||
|
</Col> |
||||||
|
); |
||||||
|
|
||||||
|
export default ExampleCard; |
@ -0,0 +1,18 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Col, Container, Row } from 'reactstrap'; |
||||||
|
import ExampleCard from './components/ExampleCard'; |
||||||
|
|
||||||
|
const ExamplePage = () => ( |
||||||
|
<Container className="dashboard"> |
||||||
|
<Row> |
||||||
|
<Col md={12}> |
||||||
|
<h3 className="page-title">Example Page Two</h3> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
<Row> |
||||||
|
<ExampleCard /> |
||||||
|
</Row> |
||||||
|
</Container> |
||||||
|
); |
||||||
|
|
||||||
|
export default ExamplePage; |
@ -0,0 +1,66 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import { withRouter } from 'react-router-dom'; |
||||||
|
import { connect } from 'react-redux'; |
||||||
|
import classNames from 'classnames'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import Topbar from './topbar/Topbar'; |
||||||
|
import Sidebar from './sidebar/Sidebar'; |
||||||
|
|
||||||
|
import { changeThemeToDark, changeThemeToLight } from '../../redux/actions/themeActions'; |
||||||
|
import { changeMobileSidebarVisibility, changeSidebarVisibility } from '../../redux/actions/sidebarActions'; |
||||||
|
import { SidebarProps } from '../../shared/prop-types/ReducerProps'; |
||||||
|
|
||||||
|
class Layout extends Component { |
||||||
|
static propTypes = { |
||||||
|
dispatch: PropTypes.func.isRequired, |
||||||
|
sidebar: SidebarProps.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
changeSidebarVisibility = () => { |
||||||
|
const { dispatch } = this.props; |
||||||
|
dispatch(changeSidebarVisibility()); |
||||||
|
}; |
||||||
|
|
||||||
|
changeMobileSidebarVisibility = () => { |
||||||
|
const { dispatch } = this.props; |
||||||
|
dispatch(changeMobileSidebarVisibility()); |
||||||
|
}; |
||||||
|
|
||||||
|
changeToDark = () => { |
||||||
|
const { dispatch } = this.props; |
||||||
|
dispatch(changeThemeToDark()); |
||||||
|
}; |
||||||
|
|
||||||
|
changeToLight = () => { |
||||||
|
const { dispatch } = this.props; |
||||||
|
dispatch(changeThemeToLight()); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { sidebar } = this.props; |
||||||
|
|
||||||
|
const layoutClass = classNames({ |
||||||
|
layout: true, |
||||||
|
'layout--collapse': sidebar.collapse, |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={layoutClass}> |
||||||
|
<Topbar |
||||||
|
changeMobileSidebarVisibility={this.changeMobileSidebarVisibility} |
||||||
|
changeSidebarVisibility={this.changeSidebarVisibility} |
||||||
|
/> |
||||||
|
<Sidebar |
||||||
|
sidebar={sidebar} |
||||||
|
changeToDark={this.changeToDark} |
||||||
|
changeToLight={this.changeToLight} |
||||||
|
changeMobileSidebarVisibility={this.changeMobileSidebarVisibility} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default withRouter(connect(state => ({ |
||||||
|
sidebar: state.sidebar, |
||||||
|
}))(Layout)); |
@ -0,0 +1,47 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import Scrollbar from 'react-smooth-scrollbar'; |
||||||
|
import classNames from 'classnames'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import SidebarContent from './SidebarContent'; |
||||||
|
import { SidebarProps } from '../../../shared/prop-types/ReducerProps'; |
||||||
|
|
||||||
|
const Sidebar = ({ |
||||||
|
changeToDark, changeToLight, changeMobileSidebarVisibility, sidebar, |
||||||
|
}) => { |
||||||
|
const sidebarClass = classNames({ |
||||||
|
sidebar: true, |
||||||
|
'sidebar--show': sidebar.show, |
||||||
|
'sidebar--collapse': sidebar.collapse, |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={sidebarClass}> |
||||||
|
<button type="button" className="sidebar__back" onClick={changeMobileSidebarVisibility} /> |
||||||
|
<Scrollbar className="sidebar__scroll scroll"> |
||||||
|
<div className="sidebar__wrapper sidebar__wrapper--desktop"> |
||||||
|
<SidebarContent |
||||||
|
onClick={() => {}} |
||||||
|
changeToDark={changeToDark} |
||||||
|
changeToLight={changeToLight} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
<div className="sidebar__wrapper sidebar__wrapper--mobile"> |
||||||
|
<SidebarContent |
||||||
|
onClick={changeMobileSidebarVisibility} |
||||||
|
changeToDark={changeToDark} |
||||||
|
changeToLight={changeToLight} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</Scrollbar> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
Sidebar.propTypes = { |
||||||
|
sidebar: SidebarProps.isRequired, |
||||||
|
changeToDark: PropTypes.func.isRequired, |
||||||
|
changeToLight: PropTypes.func.isRequired, |
||||||
|
changeMobileSidebarVisibility: PropTypes.func.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
export default Sidebar; |
@ -0,0 +1,59 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import { Collapse } from 'reactstrap'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import classNames from 'classnames'; |
||||||
|
|
||||||
|
export default class SidebarCategory extends Component { |
||||||
|
static propTypes = { |
||||||
|
title: PropTypes.string.isRequired, |
||||||
|
icon: PropTypes.string, |
||||||
|
isNew: PropTypes.bool, |
||||||
|
children: PropTypes.arrayOf(PropTypes.element).isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
static defaultProps = { |
||||||
|
icon: '', |
||||||
|
isNew: false, |
||||||
|
}; |
||||||
|
|
||||||
|
constructor() { |
||||||
|
super(); |
||||||
|
this.state = { |
||||||
|
collapse: false, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
toggle = () => { |
||||||
|
this.setState(prevState => ({ collapse: !prevState.collapse })); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { |
||||||
|
title, icon, isNew, children, |
||||||
|
} = this.props; |
||||||
|
const { collapse } = this.state; |
||||||
|
const categoryClass = classNames({ |
||||||
|
'sidebar__category-wrap': true, |
||||||
|
'sidebar__category-wrap--open': collapse, |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={categoryClass}> |
||||||
|
<button type="button" className="sidebar__link sidebar__category" onClick={this.toggle}> |
||||||
|
{icon ? <span className={`sidebar__link-icon lnr lnr-${icon}`} /> : ''} |
||||||
|
<p className="sidebar__link-title">{title} |
||||||
|
{isNew && <span className="sidebar__category-new" />} |
||||||
|
</p> |
||||||
|
<span className="sidebar__category-icon lnr lnr-chevron-right" /> |
||||||
|
</button> |
||||||
|
<Collapse isOpen={collapse} className="sidebar__submenu-wrap"> |
||||||
|
<ul className="sidebar__submenu"> |
||||||
|
<div> |
||||||
|
{children} |
||||||
|
</div> |
||||||
|
</ul> |
||||||
|
</Collapse> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
import React, { Component } from 'react'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import SidebarLink from './SidebarLink'; |
||||||
|
import SidebarCategory from './SidebarCategory'; |
||||||
|
|
||||||
|
class SidebarContent extends Component { |
||||||
|
static propTypes = { |
||||||
|
changeToDark: PropTypes.func.isRequired, |
||||||
|
changeToLight: PropTypes.func.isRequired, |
||||||
|
onClick: PropTypes.func.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
hideSidebar = () => { |
||||||
|
const { onClick } = this.props; |
||||||
|
onClick(); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { changeToDark, changeToLight } = this.props; |
||||||
|
return ( |
||||||
|
<div className="sidebar__content"> |
||||||
|
<ul className="sidebar__block"> |
||||||
|
<SidebarLink title="Log In" icon="exit" route="/log_in" onClick={this.hideSidebar} /> |
||||||
|
<SidebarCategory title="Layout" icon="layers"> |
||||||
|
<button type="button" className="sidebar__link" onClick={changeToLight}> |
||||||
|
<p className="sidebar__link-title">Light Theme</p> |
||||||
|
</button> |
||||||
|
<button type="button" className="sidebar__link" onClick={changeToDark}> |
||||||
|
<p className="sidebar__link-title">Dark Theme</p> |
||||||
|
</button> |
||||||
|
</SidebarCategory> |
||||||
|
</ul> |
||||||
|
<ul className="sidebar__block"> |
||||||
|
<SidebarCategory title="Example Pages" icon="diamond"> |
||||||
|
<SidebarLink title="Page one" route="/pages/one" onClick={this.hideSidebar} /> |
||||||
|
<SidebarLink title="Page two" route="/pages/two" onClick={this.hideSidebar} /> |
||||||
|
</SidebarCategory> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default SidebarContent; |
@ -0,0 +1,39 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import { Badge } from 'reactstrap'; |
||||||
|
import { NavLink } from 'react-router-dom'; |
||||||
|
|
||||||
|
const SidebarLink = ({ |
||||||
|
title, icon, newLink, route, onClick, |
||||||
|
}) => ( |
||||||
|
<NavLink |
||||||
|
to={route} |
||||||
|
onClick={onClick} |
||||||
|
activeClassName="sidebar__link-active" |
||||||
|
> |
||||||
|
<li className="sidebar__link"> |
||||||
|
{icon ? <span className={`sidebar__link-icon lnr lnr-${icon}`} /> : ''} |
||||||
|
<p className="sidebar__link-title"> |
||||||
|
{title} |
||||||
|
{newLink ? <Badge className="sidebar__link-badge"><span>New</span></Badge> : ''} |
||||||
|
</p> |
||||||
|
</li> |
||||||
|
</NavLink> |
||||||
|
); |
||||||
|
|
||||||
|
SidebarLink.propTypes = { |
||||||
|
title: PropTypes.string.isRequired, |
||||||
|
icon: PropTypes.string, |
||||||
|
newLink: PropTypes.bool, |
||||||
|
route: PropTypes.string, |
||||||
|
onClick: PropTypes.func, |
||||||
|
}; |
||||||
|
|
||||||
|
SidebarLink.defaultProps = { |
||||||
|
icon: '', |
||||||
|
newLink: false, |
||||||
|
route: '/', |
||||||
|
onClick: () => {}, |
||||||
|
}; |
||||||
|
|
||||||
|
export default SidebarLink; |
@ -0,0 +1,35 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import TopbarSidebarButton from './TopbarSidebarButton'; |
||||||
|
import TopbarProfile from './TopbarProfile'; |
||||||
|
|
||||||
|
class Topbar extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
changeMobileSidebarVisibility: PropTypes.func.isRequired, |
||||||
|
changeSidebarVisibility: PropTypes.func.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { changeMobileSidebarVisibility, changeSidebarVisibility } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="topbar"> |
||||||
|
<div className="topbar__wrapper"> |
||||||
|
<div className="topbar__left"> |
||||||
|
<TopbarSidebarButton |
||||||
|
changeMobileSidebarVisibility={changeMobileSidebarVisibility} |
||||||
|
changeSidebarVisibility={changeSidebarVisibility} |
||||||
|
/> |
||||||
|
<Link className="topbar__logo" to="/dashboard_default" /> |
||||||
|
</div> |
||||||
|
<div className="topbar__right"> |
||||||
|
<TopbarProfile /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default Topbar; |
@ -0,0 +1,22 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
|
||||||
|
export default class TopbarMenuLinks extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
title: PropTypes.string.isRequired, |
||||||
|
icon: PropTypes.string.isRequired, |
||||||
|
path: PropTypes.string.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { title, icon, path } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<Link className="topbar__link" to={path}> |
||||||
|
<span className={`topbar__link-icon lnr lnr-${icon}`} /> |
||||||
|
<p className="topbar__link-title">{title}</p> |
||||||
|
</Link> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import DownIcon from 'mdi-react/ChevronDownIcon'; |
||||||
|
import { Collapse } from 'reactstrap'; |
||||||
|
import TopbarMenuLink from './TopbarMenuLink'; |
||||||
|
|
||||||
|
const Ava = `${process.env.PUBLIC_URL}/img/ava.png`; |
||||||
|
|
||||||
|
export default class TopbarProfile extends PureComponent { |
||||||
|
constructor() { |
||||||
|
super(); |
||||||
|
this.state = { |
||||||
|
collapse: false, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
toggle = () => { |
||||||
|
this.setState(prevState => ({ collapse: !prevState.collapse })); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { collapse } = this.state; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="topbar__profile"> |
||||||
|
<button type="button" className="topbar__avatar" onClick={this.toggle}> |
||||||
|
<img className="topbar__avatar-img" src={Ava} alt="avatar" /> |
||||||
|
<p className="topbar__avatar-name">Roman Johanson</p> |
||||||
|
<DownIcon className="topbar__icon" /> |
||||||
|
</button> |
||||||
|
{collapse && <button type="button" className="topbar__back" onClick={this.toggle} />} |
||||||
|
<Collapse isOpen={collapse} className="topbar__menu-wrap"> |
||||||
|
<div className="topbar__menu"> |
||||||
|
<TopbarMenuLink title="Page one" icon="list" path="/pages/one" /> |
||||||
|
<TopbarMenuLink title="Page two" icon="inbox" path="/pages/two" /> |
||||||
|
<div className="topbar__menu-divider" /> |
||||||
|
<TopbarMenuLink title="Log Out" icon="exit" path="/" /> |
||||||
|
</div> |
||||||
|
</Collapse> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
|
||||||
|
const icon = `${process.env.PUBLIC_URL}/img/burger.svg`; |
||||||
|
|
||||||
|
class TopbarSidebarButton extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
changeMobileSidebarVisibility: PropTypes.func.isRequired, |
||||||
|
changeSidebarVisibility: PropTypes.func.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { changeMobileSidebarVisibility, changeSidebarVisibility } = this.props; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<button type="button" className="topbar__button topbar__button--desktop" onClick={changeSidebarVisibility}> |
||||||
|
<img src={icon} alt="" className="topbar__button-icon" /> |
||||||
|
</button> |
||||||
|
<button type="button" className="topbar__button topbar__button--mobile" onClick={changeMobileSidebarVisibility}> |
||||||
|
<img src={icon} alt="" className="topbar__button-icon" /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default TopbarSidebarButton; |
@ -0,0 +1,88 @@ |
|||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import { Field, reduxForm } from 'redux-form'; |
||||||
|
import EyeIcon from 'mdi-react/EyeIcon'; |
||||||
|
import KeyVariantIcon from 'mdi-react/KeyVariantIcon'; |
||||||
|
import AccountOutlineIcon from 'mdi-react/AccountOutlineIcon'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import renderCheckBoxField from '../../../shared/components/form/CheckBox'; |
||||||
|
|
||||||
|
class LogInForm extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
handleSubmit: PropTypes.func.isRequired, |
||||||
|
}; |
||||||
|
|
||||||
|
constructor() { |
||||||
|
super(); |
||||||
|
this.state = { |
||||||
|
showPassword: false, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
showPassword = (e) => { |
||||||
|
e.preventDefault(); |
||||||
|
this.setState(prevState => ({ showPassword: !prevState.showPassword })); |
||||||
|
}; |
||||||
|
|
||||||
|
render() { |
||||||
|
const { handleSubmit } = this.props; |
||||||
|
const { showPassword } = this.state; |
||||||
|
|
||||||
|
return ( |
||||||
|
<form className="form" onSubmit={handleSubmit}> |
||||||
|
<div className="form__form-group"> |
||||||
|
<span className="form__form-group-label">Username</span> |
||||||
|
<div className="form__form-group-field"> |
||||||
|
<div className="form__form-group-icon"> |
||||||
|
<AccountOutlineIcon /> |
||||||
|
</div> |
||||||
|
<Field |
||||||
|
name="name" |
||||||
|
component="input" |
||||||
|
type="text" |
||||||
|
placeholder="Name" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className="form__form-group"> |
||||||
|
<span className="form__form-group-label">Password</span> |
||||||
|
<div className="form__form-group-field"> |
||||||
|
<div className="form__form-group-icon"> |
||||||
|
<KeyVariantIcon /> |
||||||
|
</div> |
||||||
|
<Field |
||||||
|
name="password" |
||||||
|
component="input" |
||||||
|
type={showPassword ? 'text' : 'password'} |
||||||
|
placeholder="Password" |
||||||
|
/> |
||||||
|
<button |
||||||
|
className={`form__form-group-button${showPassword ? ' active' : ''}`} |
||||||
|
onClick={e => this.showPassword(e)} |
||||||
|
type="button" |
||||||
|
><EyeIcon /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div className="account__forgot-password"> |
||||||
|
<a href="/">Forgot a password?</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className="form__form-group"> |
||||||
|
<div className="form__form-group-field"> |
||||||
|
<Field |
||||||
|
name="remember_me" |
||||||
|
component={renderCheckBoxField} |
||||||
|
label="Remember me" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<Link className="btn btn-primary account__btn account__btn--small" to="/pages/one">Sign In</Link> |
||||||
|
<Link className="btn btn-outline-primary account__btn account__btn--small" to="/log_in">Create Account</Link> |
||||||
|
</form> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export default reduxForm({ |
||||||
|
form: 'log_in_form', |
||||||
|
})(LogInForm); |
@ -0,0 +1,43 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { Link } from 'react-router-dom'; |
||||||
|
import FacebookIcon from 'mdi-react/FacebookIcon'; |
||||||
|
import GooglePlusIcon from 'mdi-react/GooglePlusIcon'; |
||||||
|
import LogInForm from './components/LogInForm'; |
||||||
|
|
||||||
|
const LogIn = () => ( |
||||||
|
<div className="account"> |
||||||
|
<div className="account__wrapper"> |
||||||
|
<div className="account__card"> |
||||||
|
<div className="account__head"> |
||||||
|
<h3 className="account__title">Welcome to |
||||||
|
<span className="account__logo"> Easy |
||||||
|
<span className="account__logo-accent">DEV</span> |
||||||
|
</span> |
||||||
|
</h3> |
||||||
|
<h4 className="account__subhead subhead">Start your business easily</h4> |
||||||
|
</div> |
||||||
|
<LogInForm onSubmit /> |
||||||
|
<div className="account__or"> |
||||||
|
<p>Or Easily Using</p> |
||||||
|
</div> |
||||||
|
<div className="account__social"> |
||||||
|
<Link |
||||||
|
className="account__social-btn account__social-btn--facebook" |
||||||
|
to="/pages/one" |
||||||
|
><FacebookIcon /> |
||||||
|
</Link> |
||||||
|
<Link |
||||||
|
className="account__social-btn account__social-btn--google" |
||||||
|
to="/pages/one" |
||||||
|
><GooglePlusIcon /> |
||||||
|
</Link> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
|
||||||
|
export default LogIn; |
||||||
|
|
||||||
|
// if you want to add select, date-picker and time-picker in your app you need to uncomment the first |
||||||
|
// four lines in /scss/components/form.scss to add styles |
@ -0,0 +1,8 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { render } from 'react-dom'; |
||||||
|
import App from './containers/App/App'; |
||||||
|
|
||||||
|
render( |
||||||
|
<App />, |
||||||
|
document.getElementById('root'), |
||||||
|
); |
@ -0,0 +1,14 @@ |
|||||||
|
export const CHANGE_SIDEBAR_VISIBILITY = 'CHANGE_SIDEBAR_VISIBILITY'; |
||||||
|
export const CHANGE_MOBILE_SIDEBAR_VISIBILITY = 'CHANGE_MOBILE_SIDEBAR_VISIBILITY'; |
||||||
|
|
||||||
|
export function changeSidebarVisibility() { |
||||||
|
return { |
||||||
|
type: CHANGE_SIDEBAR_VISIBILITY, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export function changeMobileSidebarVisibility() { |
||||||
|
return { |
||||||
|
type: CHANGE_MOBILE_SIDEBAR_VISIBILITY, |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
export const CHANGE_THEME_TO_DARK = 'CHANGE_THEME_TO_DARK'; |
||||||
|
export const CHANGE_THEME_TO_LIGHT = 'CHANGE_THEME_TO_LIGHT'; |
||||||
|
|
||||||
|
export function changeThemeToDark() { |
||||||
|
return { |
||||||
|
type: CHANGE_THEME_TO_DARK, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
export function changeThemeToLight() { |
||||||
|
return { |
||||||
|
type: CHANGE_THEME_TO_LIGHT, |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
import themeReducer from './themeReducer'; |
||||||
|
import sidebarReducer from './sidebarReducer'; |
||||||
|
|
||||||
|
export { |
||||||
|
themeReducer, |
||||||
|
sidebarReducer, |
||||||
|
}; |
@ -0,0 +1,20 @@ |
|||||||
|
import { |
||||||
|
CHANGE_SIDEBAR_VISIBILITY, |
||||||
|
CHANGE_MOBILE_SIDEBAR_VISIBILITY, |
||||||
|
} from '../actions/sidebarActions'; |
||||||
|
|
||||||
|
const initialState = { |
||||||
|
show: false, |
||||||
|
collapse: false, |
||||||
|
}; |
||||||
|
|
||||||
|
export default function (state = initialState, action) { |
||||||
|
switch (action.type) { |
||||||
|
case CHANGE_SIDEBAR_VISIBILITY: |
||||||
|
return { ...state, collapse: !state.collapse }; |
||||||
|
case CHANGE_MOBILE_SIDEBAR_VISIBILITY: |
||||||
|
return { ...state, show: !state.show }; |
||||||
|
default: |
||||||
|
return state; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
import { |
||||||
|
CHANGE_THEME_TO_DARK, |
||||||
|
CHANGE_THEME_TO_LIGHT, |
||||||
|
} from '../actions/themeActions'; |
||||||
|
|
||||||
|
const initialState = { |
||||||
|
className: 'theme-light', |
||||||
|
}; |
||||||
|
|
||||||
|
export default function (state = initialState, action) { |
||||||
|
switch (action.type) { |
||||||
|
case CHANGE_THEME_TO_DARK: |
||||||
|
return { className: 'theme-dark' }; |
||||||
|
case CHANGE_THEME_TO_LIGHT: |
||||||
|
return { className: 'theme-light' }; |
||||||
|
default: |
||||||
|
return state; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
@import 'settings/variable'; //themes' colors |
||||||
|
|
||||||
|
//base... |
||||||
|
@import 'generic/normalize.scss'; |
||||||
|
@import 'generic/box-sizing.scss'; |
||||||
|
@import './base/scaffolding'; // styles of base elements |
||||||
|
@import './base/typography'; // base styles of h1-h6, p, span |
||||||
|
|
||||||
|
//components... |
||||||
|
@import 'component/btn'; |
||||||
|
@import './component/card'; |
||||||
|
@import './component/check-box'; |
||||||
|
@import './component/sidebar'; |
||||||
|
@import './component/topbar'; |
||||||
|
@import './component/load'; |
||||||
|
@import './component/form'; |
||||||
|
|
||||||
|
//pages... |
||||||
|
@import 'containers/account'; |
||||||
|
|
||||||
|
//objects... |
||||||
|
@import 'objects/layout.scss'; |
||||||
|
|
@ -0,0 +1,39 @@ |
|||||||
|
main { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
body { |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
box-sizing: border-box; |
||||||
|
font-family: 'Roboto', sans-serif; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 1.6; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
* { |
||||||
|
box-sizing: inherit; |
||||||
|
} |
||||||
|
|
||||||
|
ul, ol { |
||||||
|
padding-left: 15px; |
||||||
|
margin-bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
color: $color-blue; |
||||||
|
transition: all 0.3s; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
text-decoration: none; |
||||||
|
color: $color-blue-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
img { |
||||||
|
width: 100%; |
||||||
|
} |
@ -0,0 +1,150 @@ |
|||||||
|
p, h1, h2, h3, h4, h5, h6 { |
||||||
|
margin-top: 0; |
||||||
|
font-weight: 400; |
||||||
|
margin-bottom: 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
margin: 10px 0 0 0; |
||||||
|
|
||||||
|
&:first-child { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
font-size: 36px; |
||||||
|
line-height: 48px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 30px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 36px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h2 { |
||||||
|
font-size: 30px; |
||||||
|
line-height: 36px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 24px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 32px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h3 { |
||||||
|
font-size: 24px; |
||||||
|
line-height: 32px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 18px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 24px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h4 { |
||||||
|
font-size: 18px; |
||||||
|
line-height: 24px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 12px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 16px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h5 { |
||||||
|
font-size: 14px; |
||||||
|
line-height: 18px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 10px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 12px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
h6 { |
||||||
|
font-size: 12px; |
||||||
|
line-height: 16px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 8px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.bold-text { |
||||||
|
font-weight: 700; |
||||||
|
} |
||||||
|
|
||||||
|
.typography--inline { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
* { |
||||||
|
margin-top: auto; |
||||||
|
margin-right: 15px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.typography-card { |
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 { |
||||||
|
margin-bottom: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
blockquote { |
||||||
|
font-size: 13px; |
||||||
|
font-style: italic; |
||||||
|
border-left: 3px solid $color-accent; |
||||||
|
margin-bottom: 0; |
||||||
|
padding-left: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.highlight { |
||||||
|
background-color: $color-accent; |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
.red-text { |
||||||
|
color: #ad4444; |
||||||
|
} |
||||||
|
|
||||||
|
.page-title { |
||||||
|
font-weight: 500; |
||||||
|
text-transform: capitalize; |
||||||
|
font-size: 20px; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-bottom: 30px; |
||||||
|
} |
||||||
|
|
||||||
|
&.page-title--not-last { |
||||||
|
margin-top: 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.page-subhead { |
||||||
|
margin-bottom: 20px; |
||||||
|
|
||||||
|
&.subhead { |
||||||
|
font-size: 14px; |
||||||
|
opacity: 0.7; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
::selection { |
||||||
|
color: #ffffff; |
||||||
|
background: $color-accent; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,433 @@ |
|||||||
|
.btn { |
||||||
|
border-radius: 5px; |
||||||
|
padding: 10px 25px; |
||||||
|
margin-bottom: 20px; |
||||||
|
margin-right: 15px; |
||||||
|
transition: all 0.4s; |
||||||
|
font-size: 14px; |
||||||
|
position: relative; |
||||||
|
overflow: hidden; |
||||||
|
z-index: 0; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
position: absolute; |
||||||
|
height: 0; |
||||||
|
width: 0; |
||||||
|
border-radius: 50%; |
||||||
|
background-color: $color-accent; |
||||||
|
transition: width 0.3s ease-in-out, height 0.3s ease-in-out; |
||||||
|
transform: translate(-50%, -50%); |
||||||
|
z-index: -1; |
||||||
|
content: ""; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
display: flex; |
||||||
|
transition: all 0.3s; |
||||||
|
font-weight: 500; |
||||||
|
color: #444444; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
height: 14px; |
||||||
|
width: 14px; |
||||||
|
margin: 2px 5px 0 0; |
||||||
|
transition: all 0.3s; |
||||||
|
fill: #444444; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
outline: none; |
||||||
|
box-shadow: none !important; |
||||||
|
|
||||||
|
&:before { |
||||||
|
height: 500%; |
||||||
|
width: 225%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:focus, &:active, &:active:focus { |
||||||
|
|
||||||
|
&:before { |
||||||
|
transition: all 0s; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.square { |
||||||
|
border-radius: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&.rounded { |
||||||
|
border-radius: 30px !important; |
||||||
|
} |
||||||
|
|
||||||
|
&.icon { |
||||||
|
padding: 10px 15px; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
p { |
||||||
|
color: #646777; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #646777; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.icon--right { |
||||||
|
|
||||||
|
svg { |
||||||
|
margin: 2px 0 0 5px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-sm { |
||||||
|
padding: 5px 25px; |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-lg { |
||||||
|
padding: 12px 25px; |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-secondary { |
||||||
|
background-color: #e7e2e2; |
||||||
|
border-color: #e7e2e2; |
||||||
|
color: #646777; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: darken(#e7e2e2, 10%); |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
border-color: darken(#e7e2e2, 10%); |
||||||
|
color: #646777; |
||||||
|
} |
||||||
|
|
||||||
|
&:not([disabled]):not(.disabled):active, &:not([disabled]):not(.disabled).active { |
||||||
|
background-color: #dddddd; |
||||||
|
border-color: #dddddd; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-secondary { |
||||||
|
border-color: #e7e2e2; |
||||||
|
|
||||||
|
&, p { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
fill: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: #e7e2e2; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
background: transparent; |
||||||
|
border-color: #e7e2e2; |
||||||
|
color: #444444; |
||||||
|
|
||||||
|
p { |
||||||
|
color: #444444; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #444444; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-primary { |
||||||
|
background-color: $color-blue; |
||||||
|
border-color: $color-blue; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-blue-hover; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
border-color: $color-blue-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-primary { |
||||||
|
color: $color-blue; |
||||||
|
border-color: $color-blue; |
||||||
|
|
||||||
|
p { |
||||||
|
color: $color-blue; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-blue; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-blue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-success { |
||||||
|
background-color: $color-accent; |
||||||
|
border-color: $color-accent; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-accent-hover; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
border-color: $color-accent-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-success { |
||||||
|
color: $color-accent; |
||||||
|
border-color: $color-accent; |
||||||
|
|
||||||
|
p { |
||||||
|
color: $color-accent; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-accent; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-warning { |
||||||
|
background-color: $color-yellow; |
||||||
|
border-color: $color-yellow; |
||||||
|
color: #ffffff; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-yellow-hover; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
border-color: $color-yellow-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-warning { |
||||||
|
color: $color-yellow; |
||||||
|
border-color: $color-yellow; |
||||||
|
|
||||||
|
p { |
||||||
|
color: $color-yellow; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-yellow; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-yellow; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-danger { |
||||||
|
background-color: $color-red; |
||||||
|
border-color: $color-red; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-red-hover; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
border-color: $color-red-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-danger { |
||||||
|
color: $color-red; |
||||||
|
border-color: $color-red; |
||||||
|
|
||||||
|
p { |
||||||
|
color: $color-red; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-red; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: $color-red; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&, &.btn-primary, &.btn-danger, &.btn-warning, &.btn-success, &.btn-outline-secondary, &.btn-secondary, |
||||||
|
&.btn-outline-primary, &.btn-outline-danger, &.btn-outline-warning, &.btn-outline-success, |
||||||
|
&.icon, &.icon.btn-secondary { |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
background-color: #f2f4f7; |
||||||
|
border-color: #f2f4f7; |
||||||
|
color: #dddddd; |
||||||
|
pointer-events: none; |
||||||
|
|
||||||
|
p { |
||||||
|
color: #dddddd; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #dddddd; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-primary, &.btn-danger, &.btn-warning, &.btn-success { |
||||||
|
p { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-outline-primary, &.btn-outline-danger, &.btn-outline-warning, &.btn-outline-success { |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:active:focus { |
||||||
|
color: #ffffff; |
||||||
|
background: transparent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-primary, &.btn-danger, &.btn-warning, &.btn-success, |
||||||
|
&.btn-outline-primary, &.btn-outline-danger, &.btn-outline-warning, &.btn-outline-success { |
||||||
|
|
||||||
|
&:hover, &:focus, |
||||||
|
&:active, &:active:focus { |
||||||
|
|
||||||
|
p { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
&.expand { |
||||||
|
|
||||||
|
svg { |
||||||
|
width: 0; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
&.expand--load { |
||||||
|
|
||||||
|
@keyframes rotating { |
||||||
|
from { |
||||||
|
transform: rotate(0deg); |
||||||
|
} |
||||||
|
to { |
||||||
|
transform: rotate(360deg); |
||||||
|
} |
||||||
|
} |
||||||
|
svg { |
||||||
|
width: 14px; |
||||||
|
animation: rotating 2s linear infinite; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.btn-toolbar { |
||||||
|
margin-top: 15px; |
||||||
|
margin-bottom: 10px; |
||||||
|
|
||||||
|
& > * { |
||||||
|
margin-right: 15px; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:first-child { |
||||||
|
margin-top: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-bottom: -10px; |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-toolbar--center { |
||||||
|
|
||||||
|
& > * { |
||||||
|
margin-right: auto; |
||||||
|
margin-left: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.btn-group { |
||||||
|
border-radius: 5px; |
||||||
|
margin-bottom: -10px; |
||||||
|
|
||||||
|
.btn { |
||||||
|
margin-right: 0; |
||||||
|
padding: 10px 15px; |
||||||
|
font-weight: 500; |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-group--justified { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
width: 100%; |
||||||
|
|
||||||
|
.btn { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.btn-group--icons { |
||||||
|
|
||||||
|
.btn { |
||||||
|
padding: 7px 8px; |
||||||
|
line-height: 14px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.open .dropdown-toggle { |
||||||
|
box-shadow: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
button:focus, button:active { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
|
||||||
|
.open > .dropdown-toggle.btn-default, |
||||||
|
.btn-default:active:focus, .btn-default:active:focus, |
||||||
|
.btn-default.focus, .btn-default:focus { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
.card { |
||||||
|
width: 100%; |
||||||
|
padding-bottom: 30px; |
||||||
|
height: 100%; |
||||||
|
border: none; |
||||||
|
background-color: transparent; |
||||||
|
|
||||||
|
&.card--not-full-height { |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.card-body { |
||||||
|
padding: 30px; |
||||||
|
height: 100%; |
||||||
|
border-radius: 5px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.card__title { |
||||||
|
margin-bottom: 30px; |
||||||
|
text-transform: uppercase; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&:not(:first-child) { |
||||||
|
margin-top: 40px; |
||||||
|
} |
||||||
|
|
||||||
|
.subhead { |
||||||
|
text-transform: none; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 18px; |
||||||
|
opacity: 0.7; |
||||||
|
margin-top: 3px; |
||||||
|
} |
||||||
|
|
||||||
|
* { |
||||||
|
margin-bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
h5 { |
||||||
|
font-size: 13px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.squared-corner-theme { |
||||||
|
|
||||||
|
.card-body { |
||||||
|
border-radius: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.blocks-with-shadow-theme { |
||||||
|
|
||||||
|
.card-body { |
||||||
|
box-shadow: 0 10px 30px 1px rgba(0, 0, 0, 0.06); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,200 @@ |
|||||||
|
.checkbox-btn { |
||||||
|
display: flex; |
||||||
|
cursor: pointer; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
border-color: $color-accent; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
pointer-events: none; |
||||||
|
cursor: default; |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
transition: 0s; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
border-color: themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #dddddd; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
color: #dddddd; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.checkbox-btn--colored { |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
border-color: $color-accent; |
||||||
|
background-color: $color-accent; |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
opacity: 0.4; |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
border-color: $color-accent; |
||||||
|
background-color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.checkbox-btn--colored-click { |
||||||
|
|
||||||
|
.checkbox-btn__checkbox:checked + .checkbox-btn__checkbox-custom { |
||||||
|
border-color: $color-accent; |
||||||
|
background-color: $color-accent; |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
|
||||||
|
.checkbox-btn__checkbox:checked + .checkbox-btn__checkbox-custom { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
border-color: themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #dddddd; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.checkbox-btn--button { |
||||||
|
background: $color-accent; |
||||||
|
min-width: 150px; |
||||||
|
color: #ffffff; |
||||||
|
height: 24px; |
||||||
|
border-radius: 4px; |
||||||
|
transition: all 0.3s; |
||||||
|
padding: 0 6px; |
||||||
|
width: 100%; |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label-svg { |
||||||
|
margin: auto 4px auto auto; |
||||||
|
height: 16px; |
||||||
|
line-height: 1; |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
width: 14px; |
||||||
|
height: 14px; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label-check { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox:checked ~ .checkbox-btn__label-svg { |
||||||
|
|
||||||
|
.checkbox-btn__label-check { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label-uncheck { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
margin: auto auto auto 0; |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
background: $color-accent-hover; |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.disabled { |
||||||
|
opacity: 0.4; |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom { |
||||||
|
position: absolute; |
||||||
|
width: 18px; |
||||||
|
height: 18px; |
||||||
|
border-radius: 3px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border: 1px solid themed('colorIcon'); |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
transition: all 0.3s; |
||||||
|
opacity: 0; |
||||||
|
height: 16px; |
||||||
|
width: 16px; |
||||||
|
fill: $color-accent; |
||||||
|
margin-top: -6px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__label { |
||||||
|
line-height: 18px; |
||||||
|
padding-left: 28px; |
||||||
|
padding-top: 2px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox-custom, |
||||||
|
.checkbox-btn__label { |
||||||
|
display: inline-block; |
||||||
|
vertical-align: middle; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
.checkbox-btn__checkbox:checked + .checkbox-btn__checkbox-custom { |
||||||
|
|
||||||
|
svg { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,508 @@ |
|||||||
|
.form { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
input, textarea { |
||||||
|
width: 100%; |
||||||
|
padding: 5px 10px; |
||||||
|
font-size: 12px; |
||||||
|
height: 32px; |
||||||
|
transition: border 0.3s; |
||||||
|
background: transparent; |
||||||
|
|
||||||
|
&::-webkit-input-placeholder { |
||||||
|
color: $color-additional; |
||||||
|
} |
||||||
|
&::-moz-placeholder { |
||||||
|
color: $color-additional; |
||||||
|
} |
||||||
|
/* Firefox 19+ */ |
||||||
|
&:-moz-placeholder { |
||||||
|
color: $color-additional; |
||||||
|
} |
||||||
|
/* Firefox 18- */ |
||||||
|
&:-ms-input-placeholder { |
||||||
|
color: $color-additional; |
||||||
|
} |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border: 1px solid themed('colorFieldsBorder'); |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&[disabled] { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackgroundBody'); |
||||||
|
} |
||||||
|
|
||||||
|
&:focus, &:active { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border-color: themed('colorBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:focus, &:active { |
||||||
|
outline: none; |
||||||
|
border-color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
textarea { |
||||||
|
min-height: 85px; |
||||||
|
} |
||||||
|
|
||||||
|
&.form--horizontal { |
||||||
|
|
||||||
|
.form__form-group { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-field { |
||||||
|
width: calc(100% - 80px); |
||||||
|
padding-left: 10px; |
||||||
|
margin-left: 80px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-label { |
||||||
|
width: 80px; |
||||||
|
max-height: 32px; |
||||||
|
line-height: 18px; |
||||||
|
margin: auto 0; |
||||||
|
|
||||||
|
& + .form__form-group-field { |
||||||
|
margin-left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-description { |
||||||
|
margin-left: 90px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__button-toolbar { |
||||||
|
margin-left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-input-wrap--error-above { |
||||||
|
margin-bottom: 15px; |
||||||
|
|
||||||
|
.form__form-group-error { |
||||||
|
top: -28px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 480px) { |
||||||
|
|
||||||
|
.form__form-group-label { |
||||||
|
width: 120px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-field { |
||||||
|
width: calc(100% - 120px); |
||||||
|
margin-left: 120px; |
||||||
|
padding-left: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-description, .form__button-toolbar { |
||||||
|
margin-left: 140px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.form--preview { |
||||||
|
display: flex; |
||||||
|
|
||||||
|
& > div:nth-child(2) { |
||||||
|
margin-right: 50px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group { |
||||||
|
margin-bottom: 10px; |
||||||
|
width: auto; |
||||||
|
min-height: 18px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__select-color { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
max-width: 84px; |
||||||
|
margin-right: 40px; |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
margin-bottom: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.form--justify { |
||||||
|
display: flex; |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
.form__form-group { |
||||||
|
width: 33.3333%; |
||||||
|
} |
||||||
|
|
||||||
|
.form__button-toolbar { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-select { |
||||||
|
width: 100%; |
||||||
|
height: 32px; |
||||||
|
font-size: 12px; |
||||||
|
|
||||||
|
.Select-control { |
||||||
|
height: 32px; |
||||||
|
border-radius: 0; |
||||||
|
transition: all 0.3s; |
||||||
|
background: transparent; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border: 1px solid themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.Select-placeholder, .Select-input { |
||||||
|
height: 30px; |
||||||
|
} |
||||||
|
|
||||||
|
.Select-input { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
width: 100% !important; |
||||||
|
border: none; |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.Select-multi-value-wrapper { |
||||||
|
|
||||||
|
.Select-input { |
||||||
|
width: inherit; |
||||||
|
} |
||||||
|
|
||||||
|
.Select-value { |
||||||
|
background: transparent; |
||||||
|
border-color: $color-blue; |
||||||
|
} |
||||||
|
|
||||||
|
.Select-value-label { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText') !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.Select-value-icon { |
||||||
|
border-color: $color-blue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.Select-menu-outer { |
||||||
|
top: calc(100% + 1px); |
||||||
|
border-radius: 0; |
||||||
|
box-shadow: none; |
||||||
|
font-size: 12px; |
||||||
|
animation: open 0.3s ease-in-out; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border: 1px solid themed('colorBorder'); |
||||||
|
background: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes open { |
||||||
|
0% { |
||||||
|
max-height: 0 |
||||||
|
} |
||||||
|
100% { |
||||||
|
max-height: 200px |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.Select-option { |
||||||
|
transition: all 0.3s; |
||||||
|
border-radius: 0; |
||||||
|
display: flex; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackground'); |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&.is-focused { |
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.is-focused, &.is-focused:not(.is-open) { |
||||||
|
|
||||||
|
.Select-control { |
||||||
|
border-color: $color-accent; |
||||||
|
box-shadow: none; |
||||||
|
background: transparent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-select-color { |
||||||
|
display: block; |
||||||
|
border-radius: 50%; |
||||||
|
height: 10px; |
||||||
|
width: 10px; |
||||||
|
margin: auto 0 auto 5px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__half { |
||||||
|
width: calc(50% - 15px); |
||||||
|
height: 100%; |
||||||
|
|
||||||
|
&:first-child { |
||||||
|
margin-right: 30px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__button-toolbar { |
||||||
|
float: right; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 1200px) { |
||||||
|
width: 100%; |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group { |
||||||
|
margin-bottom: 20px; |
||||||
|
width: 100%; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group--address { |
||||||
|
|
||||||
|
input:last-child { |
||||||
|
margin-left: 15px; |
||||||
|
width: 70%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-field { |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
margin: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-label { |
||||||
|
margin-bottom: 4px; |
||||||
|
display: inline-block; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
span { |
||||||
|
color: #dddddd; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-button { |
||||||
|
padding: 6px; |
||||||
|
height: 32px; |
||||||
|
cursor: pointer; |
||||||
|
transition: all 0.3s; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorFieldsBorder'); |
||||||
|
border: 1px solid themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-additional; |
||||||
|
width: 18px; |
||||||
|
height: 18px; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
&.active { |
||||||
|
background: $color-accent; |
||||||
|
border: 1px solid $color-accent; |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-file { |
||||||
|
|
||||||
|
label { |
||||||
|
border-radius: 2px; |
||||||
|
line-height: 18px; |
||||||
|
font-size: 12px; |
||||||
|
padding: 4px 20px; |
||||||
|
cursor: pointer; |
||||||
|
transition: all 0.3s; |
||||||
|
text-align: center; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border: 1px solid themed('colorFieldsBorder'); |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
span { |
||||||
|
padding-left: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-icon { |
||||||
|
padding: 6px; |
||||||
|
height: 32px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorFieldsBorder'); |
||||||
|
border: 1px solid themed('colorFieldsBorder'); |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-additional; |
||||||
|
width: 18px; |
||||||
|
height: 18px; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-description { |
||||||
|
font-size: 10px; |
||||||
|
color: $color-additional; |
||||||
|
line-height: 13px; |
||||||
|
margin-top: 2px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__button-toolbar { |
||||||
|
margin-top: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-input-wrap { |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-error { |
||||||
|
font-size: 10px; |
||||||
|
line-height: 13px; |
||||||
|
color: #ad4444; |
||||||
|
margin-bottom: -5px; |
||||||
|
display: block; |
||||||
|
margin-top: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-input-wrap--error-above { |
||||||
|
|
||||||
|
.form__form-group-error { |
||||||
|
position: absolute; |
||||||
|
margin: 0; |
||||||
|
right: 0; |
||||||
|
top: 0; |
||||||
|
padding: 5px 10px; |
||||||
|
background: #ffbcbc; |
||||||
|
border-radius: 3px; |
||||||
|
|
||||||
|
&:after { |
||||||
|
content: ''; |
||||||
|
position: absolute; |
||||||
|
right: 10px; |
||||||
|
bottom: -8px; |
||||||
|
border: 4px solid transparent; |
||||||
|
border-top: 4px solid #ffbcbc; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-date-cvc { |
||||||
|
display: flex; |
||||||
|
width: 100%; |
||||||
|
|
||||||
|
.form__form-group-date { |
||||||
|
width: 100%; |
||||||
|
margin-right: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-cvc { |
||||||
|
max-width: 280px; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 767px) { |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
.form__form-group-date { |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-cvc { |
||||||
|
max-width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-id-category { |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
|
||||||
|
.form__form-group-id { |
||||||
|
min-width: 100px; |
||||||
|
width: 40%; |
||||||
|
margin-right: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 767px) { |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
.form__form-group-id { |
||||||
|
margin-right: 0; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-price-discount { |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
margin-bottom: 20px; |
||||||
|
|
||||||
|
& > div { |
||||||
|
margin-bottom: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-price { |
||||||
|
margin-right: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 767px) { |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
.form__form-group-price { |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,47 @@ |
|||||||
|
.load { |
||||||
|
height: 100vh; |
||||||
|
width: 100vw; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
position: fixed; |
||||||
|
background: #ffffff; |
||||||
|
z-index: 1000; |
||||||
|
|
||||||
|
& + div { |
||||||
|
height: 100vh; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
&.loaded { |
||||||
|
animation: ease loaded 0.5s; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.load__icon { |
||||||
|
animation: linear load 2s infinite; |
||||||
|
margin: auto; |
||||||
|
width: 32px; |
||||||
|
height: 32px; |
||||||
|
} |
||||||
|
|
||||||
|
.load__icon-wrap { |
||||||
|
margin: auto; |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes load { |
||||||
|
from { |
||||||
|
transform: rotate(0deg) scale(2); |
||||||
|
} |
||||||
|
to { |
||||||
|
transform: rotate(360deg) scale(2); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes loaded { |
||||||
|
from { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
to { |
||||||
|
opacity: 0; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,390 @@ |
|||||||
|
.sidebar { |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
z-index: 99; |
||||||
|
height: 100vh; |
||||||
|
width: 240px; |
||||||
|
box-shadow: 0 1px 30px 1px rgba(0, 0, 0, 0.11); |
||||||
|
padding-top: 60px; |
||||||
|
transition: transform 0.3s, width 0.3s; |
||||||
|
transform: translateX(calc(-100% - 20px)); |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackground'); |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
&.sidebar--show { |
||||||
|
transform: translateX(0); |
||||||
|
|
||||||
|
.sidebar__back { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__back { |
||||||
|
height: 100%; |
||||||
|
width: 100vw; |
||||||
|
position: absolute; |
||||||
|
display: none; |
||||||
|
background: transparent; |
||||||
|
border: none; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link-active { |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
|
||||||
|
&:before { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__scroll { |
||||||
|
width: 240px; |
||||||
|
|
||||||
|
& > div { |
||||||
|
height: calc(100vh - 60px); |
||||||
|
} |
||||||
|
|
||||||
|
.scrollbar-track { |
||||||
|
|
||||||
|
&.scrollbar-track-y { |
||||||
|
width: 2px; |
||||||
|
margin-right: 3px; |
||||||
|
} |
||||||
|
|
||||||
|
&.scrollbar-track-x { |
||||||
|
display: none !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.scrollbar-thumb { |
||||||
|
opacity: 0.3; |
||||||
|
width: 5px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__content { |
||||||
|
padding-top: 15px; |
||||||
|
height: 100%; |
||||||
|
overflow: auto; |
||||||
|
|
||||||
|
& > div:last-child { |
||||||
|
width: 4px !important; |
||||||
|
|
||||||
|
div { |
||||||
|
transition: height 0.3s; |
||||||
|
opacity: 0.52; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__block { |
||||||
|
padding: 15px 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border-bottom: 1px solid themed('colorBorder'); |
||||||
|
} |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
border: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
height: 36px; |
||||||
|
width: 240px; |
||||||
|
transition: all 0.3s; |
||||||
|
position: relative; |
||||||
|
cursor: pointer; |
||||||
|
display: flex; |
||||||
|
padding: 11px 20px; |
||||||
|
overflow: hidden; |
||||||
|
background: transparent; |
||||||
|
border: none; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
content: ""; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 0; |
||||||
|
height: 100%; |
||||||
|
width: 2px; |
||||||
|
background: $color-accent; |
||||||
|
opacity: 0; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
position: absolute; |
||||||
|
left: 43px; |
||||||
|
width: 160px; |
||||||
|
transition: left 0.3s; |
||||||
|
top: 50%; |
||||||
|
transform: translateY(-50%); |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
text-decoration: none; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link-title { |
||||||
|
margin: 0; |
||||||
|
font-size: 14px; |
||||||
|
line-height: 16px; |
||||||
|
position: relative; |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link-icon { |
||||||
|
margin-right: 10px; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 13px; |
||||||
|
color: #b1c3c8; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__submenu { |
||||||
|
transition: height 0.5s 0s, padding 0.5s 0s, opacity 0.4s 0.1s; |
||||||
|
padding: 15px 0; |
||||||
|
|
||||||
|
& .sidebar__submenu { |
||||||
|
margin-bottom: 0; |
||||||
|
padding-bottom: 0; |
||||||
|
padding-top: 0; |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
padding-left: 53px; |
||||||
|
|
||||||
|
p { |
||||||
|
left: 53px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
padding-left: 43px; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__category-icon { |
||||||
|
position: absolute; |
||||||
|
right: 15px; |
||||||
|
font-size: 10px; |
||||||
|
line-height: 14px; |
||||||
|
opacity: 1; |
||||||
|
transition: opacity 0.5s 0.2s, transform 0.3s; |
||||||
|
color: $color-gray; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link-badge { |
||||||
|
width: 26px; |
||||||
|
height: 14px; |
||||||
|
background-color: $color-red; |
||||||
|
font-size: 8px; |
||||||
|
font-weight: 400; |
||||||
|
padding: 2px; |
||||||
|
margin-left: 5px; |
||||||
|
line-height: 9px; |
||||||
|
position: relative; |
||||||
|
text-transform: uppercase; |
||||||
|
border-radius: 7px; |
||||||
|
|
||||||
|
span { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 3px; |
||||||
|
width: 26px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__wrapper--desktop { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__category-wrap { |
||||||
|
|
||||||
|
&.sidebar__category-wrap--open { |
||||||
|
|
||||||
|
.sidebar__category-icon { |
||||||
|
transform: rotate(90deg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__category-new { |
||||||
|
height: 6px; |
||||||
|
width: 6px; |
||||||
|
border-radius: 50%; |
||||||
|
top: -3px; |
||||||
|
display: block; |
||||||
|
margin-left: 5px; |
||||||
|
background: $color-red; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 576px) { |
||||||
|
|
||||||
|
.sidebar { |
||||||
|
transform: translateX(0); |
||||||
|
|
||||||
|
&.sidebar--no-desktop { |
||||||
|
transform: translateX(calc(-100% - 20px)); |
||||||
|
|
||||||
|
&.sidebar--show { |
||||||
|
transform: translateX(0); |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__wrapper--mobile { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.sidebar--collapse { |
||||||
|
width: 55px; |
||||||
|
overflow: visible; |
||||||
|
|
||||||
|
.sidebar__scroll, .sidebar__content { |
||||||
|
width: 55px; |
||||||
|
overflow: visible !important; |
||||||
|
transition: width 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__submenu { |
||||||
|
padding: 0 0 15px 0; |
||||||
|
transition: 0s; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__category-wrap { |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
.sidebar__category { |
||||||
|
width: 240px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorHover'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__submenu-wrap { |
||||||
|
width: 185px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__submenu-wrap { |
||||||
|
position: absolute; |
||||||
|
left: 55px; |
||||||
|
width: 0; |
||||||
|
transition: 0.3s; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
width: 185px; |
||||||
|
padding-left: 15px; |
||||||
|
|
||||||
|
p { |
||||||
|
position: relative; |
||||||
|
left: 0; |
||||||
|
animation: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__submenu-wrap { |
||||||
|
position: relative; |
||||||
|
left: 0; |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
padding-left: 30px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__link { |
||||||
|
overflow: hidden; |
||||||
|
width: 55px; |
||||||
|
background-color: transparent; |
||||||
|
|
||||||
|
p { |
||||||
|
position: absolute; |
||||||
|
left: 70px; |
||||||
|
width: 160px; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
width: 240px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__category-icon { |
||||||
|
opacity: 0; |
||||||
|
transition: opacity 0s; |
||||||
|
} |
||||||
|
|
||||||
|
.scrollbar-track.scrollbar-track-y { |
||||||
|
margin-right: 188px; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__wrapper--desktop { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.sidebar__wrapper--mobile { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 992px) { |
||||||
|
|
||||||
|
.sidebar.sidebar--no-desktop { |
||||||
|
transform: translateX(0); |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,803 @@ |
|||||||
|
.topbar { |
||||||
|
width: 100%; |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
height: 60px; |
||||||
|
z-index: 101; |
||||||
|
box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.05); |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__wrapper { |
||||||
|
position: relative; |
||||||
|
display: flex; |
||||||
|
height: 60px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__button { |
||||||
|
width: 60px; |
||||||
|
height: 60px; |
||||||
|
display: flex; |
||||||
|
background: transparent; |
||||||
|
border: none; |
||||||
|
cursor: pointer; |
||||||
|
transition: 0.3s; |
||||||
|
|
||||||
|
&:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.topbar__button--desktop { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__button-icon { |
||||||
|
margin: auto; |
||||||
|
transition: all 0.3s; |
||||||
|
width: 16px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__logo { |
||||||
|
width: 150px; |
||||||
|
height: 32px; |
||||||
|
margin: auto 0; |
||||||
|
background-repeat: no-repeat; |
||||||
|
background-position-y: center; |
||||||
|
background-position-x: left; |
||||||
|
background-size: contain; |
||||||
|
display: none; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-image: themed('logoImg'); |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 768px) { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__right { |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
display: flex; |
||||||
|
height: 100%; |
||||||
|
margin-right: 15px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__left { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
display: flex; |
||||||
|
height: 100%; |
||||||
|
width: 50%; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__avatar { |
||||||
|
height: 100%; |
||||||
|
display: flex; |
||||||
|
cursor: pointer; |
||||||
|
position: relative; |
||||||
|
border-radius: 0; |
||||||
|
border: none; |
||||||
|
transition: all 0.3s; |
||||||
|
box-shadow: none; |
||||||
|
padding: 0 15px; |
||||||
|
background-color: transparent; |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:focus:active { |
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__avatar-img, .topbar__avatar-name, .topbar__icon { |
||||||
|
margin: auto 0; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__avatar-img { |
||||||
|
border-radius: 50%; |
||||||
|
height: 36px; |
||||||
|
width: 36px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__avatar-name { |
||||||
|
font-size: 13px; |
||||||
|
line-height: 18px; |
||||||
|
font-weight: 400; |
||||||
|
display: none; |
||||||
|
margin-left: 10px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__icon { |
||||||
|
margin-left: 8px; |
||||||
|
height: 18px; |
||||||
|
margin-top: auto; |
||||||
|
fill: #b1c3c8; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__menu { |
||||||
|
width: 200px; |
||||||
|
border-radius: 0; |
||||||
|
border: none; |
||||||
|
padding: 15px 0; |
||||||
|
box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.05); |
||||||
|
margin-top: 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackground'); |
||||||
|
} |
||||||
|
|
||||||
|
button { |
||||||
|
padding: 0; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
*:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__menu-wrap { |
||||||
|
z-index: 101; |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
padding: 0 10px; |
||||||
|
min-width: 220px; |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__link { |
||||||
|
display: flex; |
||||||
|
padding: 9px 20px; |
||||||
|
transition: all 0.3s; |
||||||
|
height: 32px; |
||||||
|
width: 100%; |
||||||
|
position: relative; |
||||||
|
cursor: pointer; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
content: ""; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 0; |
||||||
|
height: 100%; |
||||||
|
width: 2px; |
||||||
|
background: $color-accent; |
||||||
|
opacity: 0; |
||||||
|
transition: all 0.3s; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
opacity: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__link-title { |
||||||
|
margin: 0; |
||||||
|
font-size: 14px; |
||||||
|
line-height: 16px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__link-icon { |
||||||
|
margin-right: 10px; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 13px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorIcon'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__menu-divider { |
||||||
|
margin: 15px 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border-top: 1px solid themed('colorBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__profile { |
||||||
|
margin-bottom: 0; |
||||||
|
margin-left: 20px; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse { |
||||||
|
position: relative; |
||||||
|
display: none; |
||||||
|
|
||||||
|
&.topbar__collapse--language { |
||||||
|
min-width: 70px; |
||||||
|
display: block; |
||||||
|
|
||||||
|
& > button { |
||||||
|
padding: 0 4px; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 568px) { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-content { |
||||||
|
width: 270px; |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
bottom: 20px; |
||||||
|
transform: translateY(100%); |
||||||
|
box-shadow: 0 10px 25px 0 rgba(33, 36, 50, 0.13); |
||||||
|
z-index: 101; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackground'); |
||||||
|
} |
||||||
|
|
||||||
|
&.topbar__collapse-content--language { |
||||||
|
max-width: 70px; |
||||||
|
padding: 10px 0; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 768px) { |
||||||
|
left: 50%; |
||||||
|
transform: translate(-50%, 100%); |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 520px) { |
||||||
|
width: 330px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__language-btn { |
||||||
|
padding: 4px 15px; |
||||||
|
width: 100%; |
||||||
|
border: none; |
||||||
|
background: transparent; |
||||||
|
cursor: pointer; |
||||||
|
text-align: left; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 16px; |
||||||
|
transition: 0.3s; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__language-btn-title { |
||||||
|
display: flex; |
||||||
|
font-size: 11px; |
||||||
|
align-items: center; |
||||||
|
margin: auto 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:not(:last-child) { |
||||||
|
margin-right: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
img { |
||||||
|
height: 11px; |
||||||
|
width: 16px; |
||||||
|
margin-right: 4px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__back { |
||||||
|
position: fixed; |
||||||
|
width: 100vw; |
||||||
|
height: 100vh; |
||||||
|
top: 0; |
||||||
|
bottom: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
z-index: 100; |
||||||
|
background: transparent; |
||||||
|
border: none; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-title-wrap { |
||||||
|
padding: 20px 15px 15px 15px; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border-bottom: 1px solid themed('colorBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-item { |
||||||
|
padding: 12px 55px 12px 70px; |
||||||
|
display: flex; |
||||||
|
position: relative; |
||||||
|
height: 62px; |
||||||
|
align-items: center; |
||||||
|
flex-wrap: wrap; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
border-bottom: 1px solid themed('colorBorder'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-img-wrap { |
||||||
|
height: 40px; |
||||||
|
width: 40px; |
||||||
|
border-radius: 50%; |
||||||
|
overflow: hidden; |
||||||
|
position: absolute; |
||||||
|
left: 15px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-message { |
||||||
|
margin: 0; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 16px; |
||||||
|
color: $color-gray; |
||||||
|
|
||||||
|
&.topbar__collapse-message--mail { |
||||||
|
text-overflow: ellipsis; |
||||||
|
overflow: hidden; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-name { |
||||||
|
margin: 0; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 16px; |
||||||
|
color: $color-accent; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-date { |
||||||
|
position: absolute; |
||||||
|
top: 12px; |
||||||
|
right: 15px; |
||||||
|
font-size: 10px; |
||||||
|
color: $color-gray; |
||||||
|
margin-top: 2px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-link { |
||||||
|
display: block; |
||||||
|
padding: 10px; |
||||||
|
text-transform: uppercase; |
||||||
|
color: $color-accent; |
||||||
|
transition: 0.3s; |
||||||
|
text-align: center; |
||||||
|
font-weight: 500; |
||||||
|
font-size: 10px; |
||||||
|
line-height: 16px; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
color: $color-accent-hover; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-title { |
||||||
|
font-size: 14px; |
||||||
|
line-height: 16px; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__collapse-button { |
||||||
|
color: #c5d2d6; |
||||||
|
border: none; |
||||||
|
padding: 0; |
||||||
|
text-align: right; |
||||||
|
font-size: 12px; |
||||||
|
line-height: 16px; |
||||||
|
transition: 0.3s; |
||||||
|
background: transparent; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
color: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__btn { |
||||||
|
font-size: 18px; |
||||||
|
height: 100%; |
||||||
|
padding: 0 10px; |
||||||
|
cursor: pointer; |
||||||
|
position: relative; |
||||||
|
display: flex; |
||||||
|
border: none; |
||||||
|
background: transparent; |
||||||
|
transition: all 0.3s; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
margin: auto; |
||||||
|
height: 18px; |
||||||
|
width: 18px; |
||||||
|
fill: #b1c3c8; |
||||||
|
} |
||||||
|
|
||||||
|
&.topbar__btn--new { |
||||||
|
|
||||||
|
.topbar__btn-new-label { |
||||||
|
position: absolute; |
||||||
|
right: 9px; |
||||||
|
top: 20px; |
||||||
|
|
||||||
|
& > div { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&:before { |
||||||
|
background-color: rgba(224, 83, 111, 0.2); |
||||||
|
content: ""; |
||||||
|
position: absolute; |
||||||
|
top: 50%; |
||||||
|
left: 50%; |
||||||
|
border-radius: 50%; |
||||||
|
transform: translate(-50%, -50%); |
||||||
|
animation: beforePulse 1.5s infinite; |
||||||
|
} |
||||||
|
|
||||||
|
&:after { |
||||||
|
height: 7px; |
||||||
|
width: 7px; |
||||||
|
background-color: #e0536f; |
||||||
|
content: ""; |
||||||
|
position: absolute; |
||||||
|
top: 50%; |
||||||
|
left: 50%; |
||||||
|
border-radius: 50%; |
||||||
|
transform: translate(-50%, -50%); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@keyframes beforePulse { |
||||||
|
from { |
||||||
|
width: 7px; |
||||||
|
height: 7px; |
||||||
|
} |
||||||
|
25% { |
||||||
|
width: 13px; |
||||||
|
height: 13px; |
||||||
|
} |
||||||
|
to { |
||||||
|
width: 7px; |
||||||
|
height: 7px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__nav { |
||||||
|
width: 100%; |
||||||
|
display: none; |
||||||
|
height: 100%; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar .topbar__nav-dropdown-toggle { |
||||||
|
height: 60px; |
||||||
|
background: transparent; |
||||||
|
border-radius: 0; |
||||||
|
border: none; |
||||||
|
font-size: 14px; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
margin: 0; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
&:hover, &:focus, &:active, &:focus:active { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-additional; |
||||||
|
margin-left: 3px; |
||||||
|
height: 16px; |
||||||
|
width: 16px; |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__nav-dropdown-menu { |
||||||
|
width: 240px; |
||||||
|
border-top: 2px solid $color-accent; |
||||||
|
|
||||||
|
button { |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__link-badge { |
||||||
|
width: 26px; |
||||||
|
height: 14px; |
||||||
|
background-color: $color-red; |
||||||
|
font-size: 8px; |
||||||
|
font-weight: 400; |
||||||
|
padding: 2px; |
||||||
|
margin-left: 5px; |
||||||
|
line-height: 9px; |
||||||
|
position: relative; |
||||||
|
text-transform: uppercase; |
||||||
|
border-radius: 7px; |
||||||
|
|
||||||
|
span { |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
top: 3px; |
||||||
|
width: 26px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__nav-link { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
height: 60px; |
||||||
|
padding: 10px 25px; |
||||||
|
transition: 0.3s; |
||||||
|
font-size: 14px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorText'); |
||||||
|
} |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__category-wrap { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
.topbar__submenu { |
||||||
|
opacity: 1; |
||||||
|
width: auto; |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__category-icon { |
||||||
|
position: absolute; |
||||||
|
right: 20px; |
||||||
|
font-size: 10px; |
||||||
|
line-height: 14px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
color: themed('colorIcon'); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__submenu { |
||||||
|
position: absolute; |
||||||
|
right: 1px; |
||||||
|
top: 0; |
||||||
|
transform: translateX(100%); |
||||||
|
transition: 0.3s; |
||||||
|
opacity: 0; |
||||||
|
width: 0; |
||||||
|
height: 0; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorHover'); |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__link { |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackground'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__search { |
||||||
|
display: none; |
||||||
|
margin: auto 0; |
||||||
|
padding: 0; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__search-field { |
||||||
|
width: 0; |
||||||
|
transition: all 0.3s; |
||||||
|
opacity: 0; |
||||||
|
margin: auto auto auto 0; |
||||||
|
border: none; |
||||||
|
border-radius: 13px; |
||||||
|
height: 26px; |
||||||
|
padding-left: 10px; |
||||||
|
padding-right: 46px; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackgroundBody'); |
||||||
|
} |
||||||
|
|
||||||
|
&.topbar__search-field--open { |
||||||
|
width: 200px; |
||||||
|
opacity: 1; |
||||||
|
margin-left: 10px; |
||||||
|
|
||||||
|
& + button { |
||||||
|
right: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__search-btn { |
||||||
|
height: 26px; |
||||||
|
width: 26px; |
||||||
|
border-radius: 13px; |
||||||
|
border: none; |
||||||
|
padding: 0; |
||||||
|
background: transparent; |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackgroundBody'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 480px) { |
||||||
|
|
||||||
|
.topbar__avatar-name { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__menu { |
||||||
|
width: 100%; |
||||||
|
left: 0 !important; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 576px) { |
||||||
|
|
||||||
|
.topbar__button { |
||||||
|
|
||||||
|
&.topbar__button--desktop { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
&.topbar__button--mobile { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.topbar.topbar--navigation { |
||||||
|
|
||||||
|
.topbar__button.topbar__button--mobile { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 768px) { |
||||||
|
|
||||||
|
.topbar__search { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 992px) { |
||||||
|
|
||||||
|
.topbar__nav { |
||||||
|
display: flex; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar.topbar--navigation { |
||||||
|
|
||||||
|
.topbar__logo { |
||||||
|
margin-left: 15px; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__button.topbar__button--mobile { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__avatar-name { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
.topbar__profile { |
||||||
|
margin-left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 1200px) { |
||||||
|
|
||||||
|
.topbar.topbar--navigation { |
||||||
|
|
||||||
|
.topbar__avatar-name { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 1580px) { |
||||||
|
|
||||||
|
.topbar__nav-dropdown-toggle, .topbar__nav-link { |
||||||
|
width: 240px; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,246 @@ |
|||||||
|
.account { |
||||||
|
height: 100vh; |
||||||
|
width: 100%; |
||||||
|
min-height: 100vh; |
||||||
|
display: flex; |
||||||
|
overflow-y: auto; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackgroundBody'); |
||||||
|
} |
||||||
|
|
||||||
|
&.account--photo { |
||||||
|
background: url(../shared/img/404/bg_404.png) no-repeat center; |
||||||
|
background-size: cover; |
||||||
|
|
||||||
|
.account__card { |
||||||
|
background-color: rgba(0, 10, 16, 0.8); |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-icon, .form__form-group-button { |
||||||
|
background: transparent; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-icon, input:not(:last-child) { |
||||||
|
border-right: none; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-button, input { |
||||||
|
border-left: none; |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group-button.active { |
||||||
|
border-color: #eff1f5; |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: $color-accent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
input { |
||||||
|
color: #ffffff; |
||||||
|
|
||||||
|
&:focus { |
||||||
|
border-color: #eff1f5; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
p { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
|
||||||
|
.account__title { |
||||||
|
color: #ffffff; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.account__wrapper { |
||||||
|
margin: auto; |
||||||
|
padding: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.account__card { |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background-color: themed('colorBackground'); |
||||||
|
} |
||||||
|
|
||||||
|
background-color: #ffffff; |
||||||
|
padding: 50px 60px; |
||||||
|
max-width: 520px; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.account__profile { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.account__btns { |
||||||
|
display: flex; |
||||||
|
width: calc(100% + 10px); |
||||||
|
margin: -10px 0 -20px -10px; |
||||||
|
|
||||||
|
a { |
||||||
|
margin: 10px 0 20px 10px; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.account__btn { |
||||||
|
width: 100%; |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.account__avatar { |
||||||
|
height: 64px; |
||||||
|
width: 64px; |
||||||
|
border-radius: 50%; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
.account__name { |
||||||
|
font-size: 11px; |
||||||
|
text-transform: uppercase; |
||||||
|
font-weight: 700; |
||||||
|
line-height: 15px; |
||||||
|
margin-top: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
.account__sub { |
||||||
|
margin-top: 0; |
||||||
|
margin-bottom: 10px; |
||||||
|
color: $color-additional; |
||||||
|
font-size: 11px; |
||||||
|
line-height: 15px; |
||||||
|
} |
||||||
|
|
||||||
|
.account__forgot-password { |
||||||
|
position: absolute; |
||||||
|
font-size: 11px; |
||||||
|
line-height: 15px; |
||||||
|
bottom: -18px; |
||||||
|
right: 0; |
||||||
|
|
||||||
|
a { |
||||||
|
color: $color-blue; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
color: $color-blue-hover; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.form__form-group--forgot { |
||||||
|
margin-bottom: 40px; |
||||||
|
} |
||||||
|
|
||||||
|
.account__or { |
||||||
|
text-align: center; |
||||||
|
margin-top: 35px; |
||||||
|
margin-bottom: 20px; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
&:before, &:after { |
||||||
|
content: ""; |
||||||
|
height: 1px; |
||||||
|
width: calc(50% - 90px); |
||||||
|
background: #dddddd; |
||||||
|
position: absolute; |
||||||
|
top: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
&:before { |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
&:after { |
||||||
|
right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.account__social { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.account__social-btn { |
||||||
|
display: inline-block; |
||||||
|
height: 38px; |
||||||
|
width: 38px; |
||||||
|
border-radius: 5px; |
||||||
|
padding: 9px; |
||||||
|
margin-right: 10px; |
||||||
|
transition: all 0.3s; |
||||||
|
border: none; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
margin-right: 0; |
||||||
|
} |
||||||
|
|
||||||
|
svg { |
||||||
|
fill: #ffffff; |
||||||
|
height: 20px; |
||||||
|
width: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
&.account__social-btn--facebook { |
||||||
|
background: #4766a4; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
background: darken(#4766a4, 10%); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.account__social-btn--google { |
||||||
|
background: #c74d4d; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
background: darken(#c74d4d, 10%); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.account__head { |
||||||
|
margin-bottom: 30px; |
||||||
|
padding-left: 10px; |
||||||
|
border-left: 4px solid $color-blue; |
||||||
|
} |
||||||
|
|
||||||
|
.account__logo { |
||||||
|
font-weight: 700; |
||||||
|
} |
||||||
|
|
||||||
|
.account__logo-accent { |
||||||
|
color: $color-blue; |
||||||
|
} |
||||||
|
|
||||||
|
.account__have-account { |
||||||
|
text-align: center; |
||||||
|
margin-top: 20px; |
||||||
|
|
||||||
|
a { |
||||||
|
color: $color-blue; |
||||||
|
transition: all 0.3s; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
color: $color-blue-hover; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 520px) { |
||||||
|
|
||||||
|
.account__card { |
||||||
|
padding: 35px 30px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (max-width: 425px) { |
||||||
|
|
||||||
|
.account__btns { |
||||||
|
flex-wrap: wrap; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
html { |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
|
||||||
|
*, *:before, *:after { |
||||||
|
box-sizing: inherit; |
||||||
|
} |
@ -0,0 +1,447 @@ |
|||||||
|
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ |
||||||
|
|
||||||
|
/* Document |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the line height in all browsers. |
||||||
|
* 2. Prevent adjustments of font size after orientation changes in |
||||||
|
* IE on Windows Phone and in iOS. |
||||||
|
*/ |
||||||
|
|
||||||
|
html { |
||||||
|
line-height: 1.15; /* 1 */ |
||||||
|
-ms-text-size-adjust: 100%; /* 2 */ |
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/* Sections |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the margin in all browsers (opinionated). |
||||||
|
*/ |
||||||
|
|
||||||
|
body { |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE 9-. |
||||||
|
*/ |
||||||
|
|
||||||
|
article, |
||||||
|
aside, |
||||||
|
footer, |
||||||
|
header, |
||||||
|
nav, |
||||||
|
section { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Correct the font size and margin on `h1` elements within `section` and |
||||||
|
* `article` contexts in Chrome, Firefox, and Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
h1 { |
||||||
|
font-size: 2em; |
||||||
|
margin: 0.67em 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Grouping content |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE 9-. |
||||||
|
* 1. Add the correct display in IE. |
||||||
|
*/ |
||||||
|
|
||||||
|
figcaption, |
||||||
|
figure, |
||||||
|
main { /* 1 */ |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct margin in IE 8. |
||||||
|
*/ |
||||||
|
|
||||||
|
figure { |
||||||
|
margin: 1em 40px; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Add the correct box sizing in Firefox. |
||||||
|
* 2. Show the overflow in Edge and IE. |
||||||
|
*/ |
||||||
|
|
||||||
|
hr { |
||||||
|
box-sizing: content-box; /* 1 */ |
||||||
|
height: 0; /* 1 */ |
||||||
|
overflow: visible; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers. |
||||||
|
* 2. Correct the odd `em` font sizing in all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
pre { |
||||||
|
font-family: monospace, monospace; /* 1 */ |
||||||
|
font-size: 1em; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/* Text-level semantics |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Remove the gray background on active links in IE 10. |
||||||
|
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+. |
||||||
|
*/ |
||||||
|
|
||||||
|
a { |
||||||
|
background-color: transparent; /* 1 */ |
||||||
|
-webkit-text-decoration-skip: objects; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Remove the bottom border in Chrome 57- and Firefox 39-. |
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
abbr[title] { |
||||||
|
border-bottom: none; /* 1 */ |
||||||
|
text-decoration: underline; /* 2 */ |
||||||
|
text-decoration: underline dotted; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prevent the duplicate application of `bolder` by the next rule in Safari 6. |
||||||
|
*/ |
||||||
|
|
||||||
|
b, |
||||||
|
strong { |
||||||
|
font-weight: inherit; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
b, |
||||||
|
strong { |
||||||
|
font-weight: bolder; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers. |
||||||
|
* 2. Correct the odd `em` font sizing in all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
code, |
||||||
|
kbd, |
||||||
|
samp { |
||||||
|
font-family: monospace, monospace; /* 1 */ |
||||||
|
font-size: 1em; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct font style in Android 4.3-. |
||||||
|
*/ |
||||||
|
|
||||||
|
dfn { |
||||||
|
font-style: italic; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct background and color in IE 9-. |
||||||
|
*/ |
||||||
|
|
||||||
|
mark { |
||||||
|
background-color: #ff0; |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct font size in all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
small { |
||||||
|
font-size: 80%; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in |
||||||
|
* all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
sub, |
||||||
|
sup { |
||||||
|
font-size: 75%; |
||||||
|
line-height: 0; |
||||||
|
position: relative; |
||||||
|
vertical-align: baseline; |
||||||
|
} |
||||||
|
|
||||||
|
sub { |
||||||
|
bottom: -0.25em; |
||||||
|
} |
||||||
|
|
||||||
|
sup { |
||||||
|
top: -0.5em; |
||||||
|
} |
||||||
|
|
||||||
|
/* Embedded content |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE 9-. |
||||||
|
*/ |
||||||
|
|
||||||
|
audio, |
||||||
|
video { |
||||||
|
display: inline-block; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in iOS 4-7. |
||||||
|
*/ |
||||||
|
|
||||||
|
audio:not([controls]) { |
||||||
|
display: none; |
||||||
|
height: 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the border on images inside links in IE 10-. |
||||||
|
*/ |
||||||
|
|
||||||
|
img { |
||||||
|
border-style: none; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Hide the overflow in IE. |
||||||
|
*/ |
||||||
|
|
||||||
|
svg:not(:root) { |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
|
||||||
|
/* Forms |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Change the font styles in all browsers (opinionated). |
||||||
|
* 2. Remove the margin in Firefox and Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
button, |
||||||
|
input, |
||||||
|
optgroup, |
||||||
|
select, |
||||||
|
textarea { |
||||||
|
font-family: sans-serif; /* 1 */ |
||||||
|
font-size: 100%; /* 1 */ |
||||||
|
line-height: 1.15; /* 1 */ |
||||||
|
margin: 0; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Show the overflow in IE. |
||||||
|
* 1. Show the overflow in Edge. |
||||||
|
*/ |
||||||
|
|
||||||
|
button, |
||||||
|
input { /* 1 */ |
||||||
|
overflow: visible; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE. |
||||||
|
* 1. Remove the inheritance of text transform in Firefox. |
||||||
|
*/ |
||||||
|
|
||||||
|
button, |
||||||
|
select { /* 1 */ |
||||||
|
text-transform: none; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` |
||||||
|
* controls in Android 4. |
||||||
|
* 2. Correct the inability to style clickable types in iOS and Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
button, |
||||||
|
html [type="button"], /* 1 */ |
||||||
|
[type="reset"], |
||||||
|
[type="submit"] { |
||||||
|
-webkit-appearance: button; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the inner border and padding in Firefox. |
||||||
|
*/ |
||||||
|
|
||||||
|
button::-moz-focus-inner, |
||||||
|
[type="button"]::-moz-focus-inner, |
||||||
|
[type="reset"]::-moz-focus-inner, |
||||||
|
[type="submit"]::-moz-focus-inner { |
||||||
|
border-style: none; |
||||||
|
padding: 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Restore the focus styles unset by the previous rule. |
||||||
|
*/ |
||||||
|
|
||||||
|
button:-moz-focusring, |
||||||
|
[type="button"]:-moz-focusring, |
||||||
|
[type="reset"]:-moz-focusring, |
||||||
|
[type="submit"]:-moz-focusring { |
||||||
|
outline: 1px dotted ButtonText; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Correct the padding in Firefox. |
||||||
|
*/ |
||||||
|
|
||||||
|
fieldset { |
||||||
|
padding: 0.35em 0.75em 0.625em; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the text wrapping in Edge and IE. |
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE. |
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out |
||||||
|
* `fieldset` elements in all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
legend { |
||||||
|
box-sizing: border-box; /* 1 */ |
||||||
|
color: inherit; /* 2 */ |
||||||
|
display: table; /* 1 */ |
||||||
|
max-width: 100%; /* 1 */ |
||||||
|
padding: 0; /* 3 */ |
||||||
|
white-space: normal; /* 1 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Add the correct display in IE 9-. |
||||||
|
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. |
||||||
|
*/ |
||||||
|
|
||||||
|
progress { |
||||||
|
display: inline-block; /* 1 */ |
||||||
|
vertical-align: baseline; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the default vertical scrollbar in IE. |
||||||
|
*/ |
||||||
|
|
||||||
|
textarea { |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Add the correct box sizing in IE 10-. |
||||||
|
* 2. Remove the padding in IE 10-. |
||||||
|
*/ |
||||||
|
|
||||||
|
[type="checkbox"], |
||||||
|
[type="radio"] { |
||||||
|
box-sizing: border-box; /* 1 */ |
||||||
|
padding: 0; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome. |
||||||
|
*/ |
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button, |
||||||
|
[type="number"]::-webkit-outer-spin-button { |
||||||
|
height: auto; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the odd appearance in Chrome and Safari. |
||||||
|
* 2. Correct the outline style in Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
[type="search"] { |
||||||
|
-webkit-appearance: textfield; /* 1 */ |
||||||
|
outline-offset: -2px; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS. |
||||||
|
*/ |
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button, |
||||||
|
[type="search"]::-webkit-search-decoration { |
||||||
|
-webkit-appearance: none; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari. |
||||||
|
* 2. Change font properties to `inherit` in Safari. |
||||||
|
*/ |
||||||
|
|
||||||
|
::-webkit-file-upload-button { |
||||||
|
-webkit-appearance: button; /* 1 */ |
||||||
|
font: inherit; /* 2 */ |
||||||
|
} |
||||||
|
|
||||||
|
/* Interactive |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/* |
||||||
|
* Add the correct display in IE 9-. |
||||||
|
* 1. Add the correct display in Edge, IE, and Firefox. |
||||||
|
*/ |
||||||
|
|
||||||
|
details, /* 1 */ |
||||||
|
menu { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Add the correct display in all browsers. |
||||||
|
*/ |
||||||
|
|
||||||
|
summary { |
||||||
|
display: list-item; |
||||||
|
} |
||||||
|
|
||||||
|
/* Scripting |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE 9-. |
||||||
|
*/ |
||||||
|
|
||||||
|
canvas { |
||||||
|
display: inline-block; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE. |
||||||
|
*/ |
||||||
|
|
||||||
|
template { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
/* Hidden |
||||||
|
========================================================================== */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Add the correct display in IE 10-. |
||||||
|
*/ |
||||||
|
|
||||||
|
[hidden] { |
||||||
|
display: none; |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
.container { |
||||||
|
|
||||||
|
@media screen and (min-width: 768px) { |
||||||
|
width: 100%; |
||||||
|
max-width: 1630px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.container__wrap { |
||||||
|
padding-left: 0; |
||||||
|
padding-top: 90px; |
||||||
|
min-height: 100vh; |
||||||
|
transition: padding-left 0.3s; |
||||||
|
|
||||||
|
@include themify($themes) { |
||||||
|
background: themed('colorBackgroundBody'); |
||||||
|
} |
||||||
|
|
||||||
|
@media screen and (min-width: 576px) { |
||||||
|
padding-left: 250px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.layout { |
||||||
|
|
||||||
|
&.layout--collapse { |
||||||
|
|
||||||
|
& + .container__wrap { |
||||||
|
padding-left: 0; |
||||||
|
|
||||||
|
@media screen and (min-width: 576px) { |
||||||
|
padding-left: 60px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
&.layout--top-navigation{ |
||||||
|
|
||||||
|
& + .container__wrap{ |
||||||
|
|
||||||
|
@media screen and (min-width: 576px) { |
||||||
|
padding-left: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
$themes: ( |
||||||
|
light: ( |
||||||
|
colorBackground: white, |
||||||
|
colorBackgroundBody: #f2f4f7, |
||||||
|
colorText: #646777, |
||||||
|
colorTextAdditional: #646777, |
||||||
|
logoImg: url(../shared/img/logo/logo_light.svg), |
||||||
|
colorHover: #fafbfe, |
||||||
|
colorBorder: #eff1f5, |
||||||
|
colorIcon: #dddddd, |
||||||
|
imgInvert: invert(0%), |
||||||
|
colorFieldsBorder: #f2f4f7, |
||||||
|
colorBubble: rgba(242, 244, 247, 0.65), |
||||||
|
colorBubbleActive: rgba(234, 238, 255, 0.6), |
||||||
|
colorScrollbar: #B4BFD0, |
||||||
|
colorFitness: #646777, |
||||||
|
), |
||||||
|
dark: ( |
||||||
|
colorBackground: #232329, |
||||||
|
colorBackgroundBody: #2a2a31, |
||||||
|
colorText: #dddddd, |
||||||
|
colorTextAdditional: #999999, |
||||||
|
logoImg: url(../shared/img/logo/logo_dark.svg), |
||||||
|
colorHover: #38373f, |
||||||
|
colorBorder: #333246, |
||||||
|
colorIcon: #605f7b, |
||||||
|
imgInvert: invert(100%), |
||||||
|
colorFieldsBorder: #33333a, |
||||||
|
colorBubble: rgba(68, 79, 97, 0.65), |
||||||
|
colorBubbleActive: rgba(92, 104, 156, 0.6), |
||||||
|
colorScrollbar: #606071, |
||||||
|
colorFitness: #ffffff |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
@mixin themify($themes) { |
||||||
|
@each $theme, $map in $themes { |
||||||
|
.theme-#{$theme} & { |
||||||
|
$theme-map: () !global; |
||||||
|
@each $key, $submap in $map { |
||||||
|
$value: map-get(map-get($themes, $theme), '#{$key}'); |
||||||
|
$theme-map: map-merge($theme-map, ($key: $value)) !global; |
||||||
|
} |
||||||
|
@content; |
||||||
|
$theme-map: null !global; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@function themed($key) { |
||||||
|
@return map-get($theme-map, $key); |
||||||
|
} |
||||||
|
|
||||||
|
$color-accent: #4ce1b6; |
||||||
|
$color-accent-hover: darken($color-accent, 10%); |
||||||
|
$color-additional: #999999; |
||||||
|
$color-additional-hover: darken($color-additional, 10%); |
||||||
|
|
||||||
|
$color-yellow: #f6da6e; |
||||||
|
$color-yellow-hover: darken($color-yellow, 10%); |
||||||
|
|
||||||
|
$color-violet: #c88ffa; |
||||||
|
|
||||||
|
$color-red: #ff4861; |
||||||
|
$color-red-hover: darken($color-red, 10%); |
||||||
|
|
||||||
|
$color-blue: #70bbfd; |
||||||
|
$color-blue-hover: darken($color-blue, 10%); |
||||||
|
|
||||||
|
$color-gray: #787985; |
@ -0,0 +1,127 @@ |
|||||||
|
// In production, we register a service worker to serve assets from local cache.
|
||||||
|
|
||||||
|
// 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 the "N+1" visit to a page, since previously
|
||||||
|
// cached resources are updated in the background.
|
||||||
|
|
||||||
|
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
|
||||||
|
// This link also includes instructions on opting out of this behavior.
|
||||||
|
|
||||||
|
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); |
||||||
|
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 https://goo.gl/SC7cgQ' |
||||||
|
); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
// Is not local host. Just register service worker
|
||||||
|
registerValidSW(swUrl, config); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function registerValidSW(swUrl, config) { |
||||||
|
navigator.serviceWorker |
||||||
|
.register(swUrl) |
||||||
|
.then(registration => { |
||||||
|
registration.onupdatefound = () => { |
||||||
|
const installingWorker = registration.installing; |
||||||
|
installingWorker.onstatechange = () => { |
||||||
|
if (installingWorker.state === 'installed') { |
||||||
|
if (navigator.serviceWorker.controller) { |
||||||
|
// At this point, the old content will have been purged and
|
||||||
|
// the fresh content will have been added to the cache.
|
||||||
|
// It's the perfect time to display a "New content is
|
||||||
|
// available; please refresh." message in your web app.
|
||||||
|
console.log('New content is available; please refresh.'); |
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (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.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.
|
||||||
|
if ( |
||||||
|
response.status === 404 || |
||||||
|
response.headers.get('content-type').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(); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* eslint-disable jsx-a11y/label-has-for */ |
||||||
|
import React, { PureComponent } from 'react'; |
||||||
|
import CheckIcon from 'mdi-react/CheckIcon'; |
||||||
|
import CloseIcon from 'mdi-react/CloseIcon'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import classNames from 'classnames'; |
||||||
|
|
||||||
|
|
||||||
|
class CheckBoxField extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
onChange: PropTypes.func.isRequired, |
||||||
|
name: PropTypes.string.isRequired, |
||||||
|
value: PropTypes.oneOfType([ |
||||||
|
PropTypes.string, |
||||||
|
PropTypes.bool, |
||||||
|
]).isRequired, |
||||||
|
label: PropTypes.string, |
||||||
|
defaultChecked: PropTypes.bool, |
||||||
|
disabled: PropTypes.bool, |
||||||
|
className: PropTypes.string, |
||||||
|
color: PropTypes.string, |
||||||
|
}; |
||||||
|
|
||||||
|
static defaultProps = { |
||||||
|
label: '', |
||||||
|
defaultChecked: false, |
||||||
|
disabled: false, |
||||||
|
className: '', |
||||||
|
color: '', |
||||||
|
}; |
||||||
|
|
||||||
|
componentDidMount() { |
||||||
|
const { onChange, defaultChecked } = this.props; |
||||||
|
onChange(defaultChecked); |
||||||
|
} |
||||||
|
|
||||||
|
render() { |
||||||
|
const { |
||||||
|
disabled, className, name, value, onChange, label, color, |
||||||
|
} = this.props; |
||||||
|
const CheckboxClass = classNames({ |
||||||
|
'checkbox-btn': true, |
||||||
|
disabled, |
||||||
|
}); |
||||||
|
|
||||||
|
return ( |
||||||
|
<label |
||||||
|
className={`${CheckboxClass} ${className ? ` checkbox-btn--${className}` : ''}`} |
||||||
|
htmlFor={name} |
||||||
|
> |
||||||
|
<input |
||||||
|
className="checkbox-btn__checkbox" |
||||||
|
type="checkbox" |
||||||
|
id={name} |
||||||
|
name={name} |
||||||
|
onChange={onChange} |
||||||
|
checked={value} |
||||||
|
disabled={disabled} |
||||||
|
/> |
||||||
|
<span |
||||||
|
className="checkbox-btn__checkbox-custom" |
||||||
|
style={color ? { background: color, borderColor: color } : {}} |
||||||
|
> |
||||||
|
<CheckIcon /> |
||||||
|
</span> |
||||||
|
{className === 'button' |
||||||
|
? ( |
||||||
|
<span className="checkbox-btn__label-svg"> |
||||||
|
<CheckIcon className="checkbox-btn__label-check" /> |
||||||
|
<CloseIcon className="checkbox-btn__label-uncheck" /> |
||||||
|
</span> |
||||||
|
) : ''} |
||||||
|
<span className="checkbox-btn__label"> |
||||||
|
{label} |
||||||
|
</span> |
||||||
|
</label> |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const renderCheckBoxField = (props) => { |
||||||
|
const { |
||||||
|
input, label, defaultChecked, disabled, className, color, |
||||||
|
} = props; |
||||||
|
return ( |
||||||
|
<CheckBoxField |
||||||
|
{...input} |
||||||
|
label={label} |
||||||
|
defaultChecked={defaultChecked} |
||||||
|
disabled={disabled} |
||||||
|
className={className} |
||||||
|
color={color} |
||||||
|
/> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
renderCheckBoxField.propTypes = { |
||||||
|
input: PropTypes.shape({ |
||||||
|
onChange: PropTypes.func, |
||||||
|
name: PropTypes.string, |
||||||
|
value: PropTypes.oneOfType([ |
||||||
|
PropTypes.string, |
||||||
|
PropTypes.bool, |
||||||
|
]), |
||||||
|
}).isRequired, |
||||||
|
label: PropTypes.string, |
||||||
|
defaultChecked: PropTypes.bool, |
||||||
|
disabled: PropTypes.bool, |
||||||
|
className: PropTypes.string, |
||||||
|
color: PropTypes.string, |
||||||
|
}; |
||||||
|
|
||||||
|
renderCheckBoxField.defaultProps = { |
||||||
|
label: '', |
||||||
|
defaultChecked: false, |
||||||
|
disabled: false, |
||||||
|
className: '', |
||||||
|
color: '', |
||||||
|
}; |
||||||
|
|
||||||
|
export default renderCheckBoxField; |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
import PropTypes from 'prop-types'; |
||||||
|
|
||||||
|
const { |
||||||
|
string, shape, |
||||||
|
} = PropTypes; |
||||||
|
|
||||||
|
export const SidebarProps = shape({ |
||||||
|
show: PropTypes.bool, |
||||||
|
collapse: PropTypes.bool, |
||||||
|
}); |
||||||
|
|
||||||
|
export const ThemeProps = shape({ |
||||||
|
className: string, |
||||||
|
}); |