박선진

remade from create-react-app for completely deleting unnecessary codes from template code

Showing 180 changed files with 209 additions and 4685 deletions
This diff could not be displayed because it is too large.
module.exports = {
"presets": [
"react-app"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-optional-chaining"
]
};
\ No newline at end of file
'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;
'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';
},
};
'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};`;
},
};
'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.js'),
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')),
};
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
'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());
},
};
};
This diff could not be displayed because it is too large.
{
"name": "sing-app-react",
"version": "5.0.0",
"name": "oss-front-end",
"version": "0.1.0",
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"animate.css": "^4.1.0",
"awesome-bootstrap-checkbox": "^1.0.1",
"bootstrap": "^4.5.0",
"classnames": "^2.2.6",
"debug": "^4.1.1",
"font-awesome": "^4.7.0",
"glyphicons-halflings": "^1.9.1",
"jquery": "^3.5.1",
"line-awesome": "^1.3.0",
"mixins": "0.0.1",
"node-sass": "^4.14.1",
"prop-types": "^15.7.2",
"rc-hammerjs": "^0.6.10",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"react-table": "^7.2.0",
"react-transition-group": "^4.4.1",
"reactstrap": "^8.4.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"scss": "^0.2.4"
},
"scripts": {
"build": "node scripts/build.js",
"start": "node scripts/start.js",
"test": "node scripts/test.js"
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"eslintConfig": {
"extends": "react-app"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"moduleFileExtensions": [
"web.js",
"js",
"json",
"web.jsx",
"jsx",
"node"
],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"resolver": "jest-pnp-resolver",
"setupFiles": [
"react-app-polyfill/jsdom"
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"testEnvironment": "jsdom",
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx}"
],
"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)$"
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"animate.css": "3.7.0",
"awesome-bootstrap-checkbox": "1.0.1",
"axios": "^0.18.0",
"bootstrap": "4.0.0",
"bootstrap-slider": "^10.2.1",
"bootstrap_calendar": "https://github.com/xero/bootstrap_calendar.git#1.0.1",
"classnames": "^2.2.6",
"draft-js": "^0.10.5",
"flot": "^0.8.0-alpha",
"flot.dashes": "https://github.com/cquartier/flot.dashes.git",
"font-awesome": "4.7.0",
"formsy-react": "0.19.5",
"fullcalendar": "^3.9.0",
"glyphicons-halflings": "^1.9.1",
"jasny-bootstrap": "^3.1.3",
"jquery": "^3.3.1",
"jquery-mapael": "^2.2.0",
"jquery-sparkline": "^2.4.0",
"jquery-ui": "1.12.1",
"jquery.animate-number": "0.0.14",
"jquery.flot-orderBars": "https://github.com/emmerich/flot-orderBars.git",
"jquery.flot.animator": "https://github.com/Codicode/flotanimator.git#3c256c0183d713fd3bf41d04417873928eb1a751",
"jsonwebtoken": "^8.5.1",
"jvectormap": "2.0.4",
"line-awesome": "github:icons8/line-awesome",
"messenger": "git+https://github.com/HubSpot/messenger.git#v1.4.2",
"metrojs": "0.9.77",
"moment": "^2.22.2",
"moment-timezone": "^0.5.26",
"nvd3": "1.8.6",
"pretty": "^2.0.0",
"prettysize": "^2.0.0",
"rc-color-picker": "^1.2.6",
"rc-hammerjs": "0.6.9",
"react": "^16.5.2",
"react-animated-number": "^0.4.4",
"react-app-polyfill": "^0.1.3",
"react-autosize-textarea": "^5.0.0",
"react-bootstrap-slider": "^2.1.5",
"react-bootstrap-table": "4.1.5",
"react-datetime": "^2.16.1",
"react-dev-utils": "^6.0.5",
"react-dom": "^16.5.2",
"react-draft-wysiwyg": "1.10.12",
"react-dropzone": "^6.2.4",
"react-flot": "^1.3.0",
"react-google-maps": "^9.4.5",
"react-images": "^0.5.19",
"react-maskedinput": "^4.0.1",
"react-mde": "2.3.4",
"react-redux": "^5.0.7",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router-hash-link": "^1.2.1",
"react-scrollspy": "^3.3.5",
"react-select": "^3.0.4",
"react-select2-wrapper": "^1.0.4-beta6",
"react-shuffle": "2.1.0",
"react-slick": "^0.23.1",
"react-sortable-hoc": "^0.8.3",
"react-sortable-tree": "^2.2.0",
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^10.1.2",
"react-table": "6.7.6",
"react-tagsinput": "^3.19.0",
"react-toastify": "^5.1.1",
"react-transition-group": "^2.5.2",
"reactstrap": "7.1.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"rickshaw": "1.6.6",
"semantic-ui-react": "^0.87.3",
"showdown": "1.8.6",
"skycons": "^1.0.0",
"widgster": "^1.0.0",
"xlsx": "^0.14.4"
},
"devDependencies": {
"@babel/core": "7.4.4",
"@babel/plugin-proposal-class-properties": "7.4.4",
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
"@svgr/webpack": "4.2.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "24.8.0",
"babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "1.0.0-next.103",
"babel-preset-react-app": "9.0.0",
"bfj": "6.1.1",
"bundle-loader": "0.5.6",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"chalk": "^2.4.2",
"css-loader": "2.1.1",
"dotenv": "^8.2.0",
"dotenv-expand": "^5.1.0",
"eslint": "5.16.0",
"eslint-config-react-app": "4.0.1",
"eslint-loader": "2.1.1",
"eslint-plugin-flowtype": "3.8.1",
"eslint-plugin-import": "2.17.2",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.13.0",
"eslint-plugin-react-hooks": "1.6.0",
"expose-loader": "0.7.5",
"file-loader": "3.0.1",
"fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-alpha.2",
"identity-obj-proxy": "3.0.0",
"imports-loader": "0.8.0",
"jest": "24.8.0",
"jest-pnp-resolver": "1.2.1",
"jest-resolve": "24.8.0",
"lodash": "4.17.11",
"mini-css-extract-plugin": "0.6.0",
"node-sass": "4.12.0",
"optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.4.3",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.6.0",
"postcss-safe-parser": "4.0.1",
"resolve": "1.10.1",
"sass-loader": "7.1.0",
"style-loader": "0.23.0",
"terser-webpack-plugin": "1.2.3",
"url-loader": "1.1.2",
"webpack": "^4.31.0",
"webpack-dev-server": "3.3.1",
"webpack-manifest-plugin": "2.0.4",
"webpack-raphael": "2.1.4",
"workbox-webpack-plugin": "4.3.1"
},
"resolutions": {
"jquery": "3.3.1"
}
}
......

12 KB | W: | H:

37 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
......@@ -19,27 +25,10 @@
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>Video Emergency Detection</title>
<meta name="description" content="React Admin Dashboard Template built with Bootstrap, Redux and React Router by Flatlogic. Over 40 unique pages, hundreds of components and theme support.">
<meta name="keywords" content="react admin, react dashboard, react admin template, react theme, react dashboard template, react dashboard template">
<meta name="author" content="Flatlogic LLC.">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-36759672-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-36759672-9');
</script>
<!-- Yandex.Metrika counter --> <script type="text/javascript" > (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://cdn.jsdelivr.net/npm/yandex-metrica-watch/tag.js", "ym"); ym(48020168, "init", { id:48020168, clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer" }); </script> <!-- /Yandex.Metrika counter -->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
......
{
"short_name": "Sing App 5.0.0 - Isomorphic React Dashboard",
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "/favicon.png",
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
......
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
'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,
});
}
'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);
});
'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);
import React from 'react';
import { connect } from 'react-redux';
import { Switch, Route, Redirect } from 'react-router';
import { HashRouter } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
/* eslint-disable */
import ErrorPage from '../pages/error';
/* eslint-enable */
import '../styles/theme.scss';
import LayoutComponent from '../components/Layout';
const CloseButton = ({closeToast}) => <i onClick={closeToast} className="la la-close notifications-close"/>
import LayoutComponent from '../components/Layout/Layout';
class App extends React.PureComponent {
render() {
return (
<div>
<ToastContainer
autoClose={5000}
hideProgressBar
closeButton={<CloseButton/>}
/>
<HashRouter>
<Switch>
<Route path="/" exact render={() => <Redirect to="/app/main"/>}/>
<Route path="/app" exact render={() => <Redirect to="/app/main"/>}/>
<Route path="/app" component={LayoutComponent}/>
<Route path="/error" exact component={ErrorPage}/>
<Redirect from="*" to="/app/main/"/>
</Switch>
</HashRouter>
</div>
);
}
}
const mapStateToProps = state => ({
});
export default connect(mapStateToProps)(App);
export default App;
......
......@@ -13,103 +13,103 @@ import s from './Layout.module.scss';
import { DashboardThemes } from '../../reducers/layout';
class Layout extends React.Component {
static propTypes = {
sidebarStatic: PropTypes.bool,
sidebarOpened: PropTypes.bool,
dashboardTheme: PropTypes.string,
dispatch: PropTypes.func.isRequired,
};
static defaultProps = {
sidebarStatic: false,
sidebarOpened: false,
dashboardTheme: DashboardThemes.DARK
};
constructor(props) {
super(props);
this.handleSwipe = this.handleSwipe.bind(this);
}
async componentDidMount() {
const staticSidebar = JSON.parse(localStorage.getItem('staticSidebar'));
if (staticSidebar && window.innerWidth > 768) {
this.props.dispatch(toggleSidebar());
} else if (this.props.sidebarOpened) {
setTimeout(() => {
this.props.dispatch(closeSidebar());
this.props.dispatch(changeActiveSidebarItem(null));
}, 2500);
}
this.handleResize();
window.addEventListener('resize', this.handleResize.bind(this));
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize.bind(this));
}
handleResize() {
if (window.innerWidth <= 768 && this.props.sidebarStatic) {
this.props.dispatch(toggleSidebar());
static propTypes = {
sidebarStatic: PropTypes.bool,
sidebarOpened: PropTypes.bool,
dashboardTheme: PropTypes.string,
dispatch: PropTypes.func.isRequired,
};
static defaultProps = {
sidebarStatic: false,
sidebarOpened: false,
dashboardTheme: DashboardThemes.DARK
};
constructor(props) {
super(props);
this.handleSwipe = this.handleSwipe.bind(this);
}
}
handleSwipe(e) {
if ('ontouchstart' in window) {
this.props.dispatch(openSidebar());
return;
async componentDidMount() {
const staticSidebar = JSON.parse(localStorage.getItem('staticSidebar'));
if (staticSidebar && window.innerWidth > 768) {
this.props.dispatch(toggleSidebar());
} else if (this.props.sidebarOpened) {
setTimeout(() => {
this.props.dispatch(closeSidebar());
this.props.dispatch(changeActiveSidebarItem(null));
}, 2500);
}
if (e.direction === 2 && this.props.sidebarOpened) {
this.props.dispatch(closeSidebar());
return;
this.handleResize();
window.addEventListener('resize', this.handleResize.bind(this));
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize.bind(this));
}
handleResize() {
if (window.innerWidth <= 768 && this.props.sidebarStatic) {
this.props.dispatch(toggleSidebar());
}
}
render() {
return (
<div
className={[
s.root,
this.props.sidebarStatic ? s.sidebarStatic : '',
!this.props.sidebarOpened ? s.sidebarClose : '',
'sing-dashboard',
'dashboard-' + this.props.dashboardTheme,
].join(' ')}
>
<Sidebar />
<div className={s.wrap}>
<Hammer onSwipe={this.handleSwipe}>
<main className={s.content}>
<TransitionGroup>
<CSSTransition
key={this.props.location.pathname}
classNames="fade"
timeout={200}
>
<Switch>
<Route path="/app/main/" exact component={Main} />
<Route path="/app/subject" exact component={Subject} />
</Switch>
</CSSTransition>
</TransitionGroup>
<footer className={s.contentFooter}>
OSS project
</footer>
</main>
</Hammer>
}
handleSwipe(e) {
if ('ontouchstart' in window) {
this.props.dispatch(openSidebar());
return;
}
if (e.direction === 2 && this.props.sidebarOpened) {
this.props.dispatch(closeSidebar());
return;
}
}
render() {
return (
<div
className={[
s.root,
this.props.sidebarStatic ? s.sidebarStatic : '',
!this.props.sidebarOpened ? s.sidebarClose : '',
'video emergency analysis',
'video emergency-' + this.props.dashboardTheme,
].join(' ')}
>
<Sidebar />
<div className={s.wrap}>
<Hammer onSwipe={this.handleSwipe}>
<main className={s.content}>
<TransitionGroup>
<CSSTransition
key={this.props.location.pathname}
classNames="fade"
timeout={200}
>
<Switch>
<Route path="/app/main/" exact component={Main} />
<Route path="/app/subject" exact component={Subject} />
</Switch>
</CSSTransition>
</TransitionGroup>
<footer className={s.contentFooter}>
OSS project
</footer>
</main>
</Hammer>
</div>
</div>
</div>
);
);
}
}
}
function mapStateToProps(store) {
return {
sidebarOpened: store.navigation.sidebarOpened,
sidebarStatic: store.navigation.sidebarStatic,
dashboardTheme: store.layout.dashboardTheme,
labelDataGroup: store.labelDataGroup,
};
}
export default withRouter(connect(mapStateToProps)(Layout));
function mapStateToProps(store) {
return {
sidebarOpened: store.navigation.sidebarOpened,
sidebarStatic: store.navigation.sidebarStatic,
dashboardTheme: store.layout.dashboardTheme,
labelDataGroup: store.labelDataGroup,
};
}
export default withRouter(connect(mapStateToProps)(Layout));
\ No newline at end of file
......
{
"name": "Layout",
"version": "0.0.0",
"private": true,
"main": "./Layout.js"
}
{
"name": "Loader",
"version": "0.0.0",
"private": true,
"main": "./Loader.js"
}
......@@ -73,7 +73,7 @@ class LinksGroup extends Component {
target={this.props.target}
>
<span className={classnames('icon', s.icon)}>
<i className={`fi ${this.props.iconName}`} />
<i className={this.props.iconName} />
</span>
{this.props.header} {this.props.label && <sup className={`${s.headerLabel} text-${this.props.labelColor || 'warning'}`}>{this.props.label}</sup>}
{this.props.badge && <Badge className={s.badge} color="warning" pill>9</Badge>}
......@@ -99,7 +99,7 @@ class LinksGroup extends Component {
</NavLink>
</li>
);
}
}
/* eslint-disable */
return (
<Route
......@@ -114,7 +114,7 @@ class LinksGroup extends Component {
>
{this.props.isHeader ?
<span className={classnames('icon', s.icon)}>
<i className={`fi ${this.props.iconName}`} />
<i className={this.props.iconName} />
</span> : null
}
{this.props.header} {this.props.label && <sup className={`${s.headerLabel} text-${this.props.labelColor || 'warning'} ml-1`}>{this.props.label}</sup>}
......
......@@ -78,14 +78,14 @@
&:hover {
color: $sidebar-item-active-color;
}
.icon {
border-radius: 50%;
background-color: $sidebar-item-active-color;
background-color: #ffc247;
opacity: 1;
i {
color: var(--sidebar-bg-color);
color: #313947;
}
}
}
......@@ -124,6 +124,7 @@
}
}
ul {
background: var(--sidebar-action-bg);
padding: $spacer;
......
......@@ -54,7 +54,7 @@ class Sidebar extends React.Component {
className={[s.root, this.props.sidebarStatic ? s.staticSidebar : '', !this.props.sidebarOpened ? s.sidebarClose : ''].join(' ')}
>
<header className={s.logo}>
<img src="/images/emergency.png" style={{width: '112px', padding: '7px'}} alt="Emergency Inc. logo"/>
<img src="/images/emergency.png" style={{width: '130px', padding: '7px'}} alt="Emergency Inc. logo"/>
</header>
<ul className={s.nav}>
<LinksGroup
......@@ -62,24 +62,24 @@ class Sidebar extends React.Component {
activeItem={this.props.activeItem}
header="영상 분석"
isHeader
iconName="flaticon-record"
iconName="fas fa-camera"
link="/app/main"
index="main"
childrenLinks={[
{
header: 'Phone', link: '/app/file/phone',
},
{
header: 'RaspberryPi', link: '/app/file/raspberrypi',
},
]}
// childrenLinks={[
// {
// header: 'Phone', link: '/app/file/phone',
// },
// {
// header: 'RaspberryPi', link: '/app/file/raspberrypi',
// },
// ]}
/>
<LinksGroup
onActiveSidebarItemChange={activeItem => this.props.dispatch(changeActiveSidebarItem(activeItem))}
activeItem={this.props.activeItem}
header="사진 등록"
isHeader
iconName="flaticon-user"
iconName="fas fa-user"
link="/app/subject"
index="subject"
/>
......
......@@ -7,8 +7,8 @@
top: 0;
bottom: 0;
border-right: $sidebar-border;
background-color: var(--sidebar-bg-color);
color: var(--sidebar-color);
background-color: #313947;
color: #a6b2c1;
overflow-y: auto;
@include scroll-bar($sidebar-scrollbar-bg);
......
import React from 'react';
import PropTypes from 'prop-types';
import jQuery from 'jquery';
import { UncontrolledTooltip } from 'reactstrap';
import 'imports-loader?window.jQuery=jquery,this=>window!widgster'; // eslint-disable-line
import s from './Widget.module.scss';
import Loader from '../Loader'; // eslint-disable-line css-modules/no-unused-class
import Loader from '../Loader/Loader';
class Widget extends React.Component {
static propTypes = {
......@@ -14,17 +11,7 @@ class Widget extends React.Component {
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
close: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
fullscreen: PropTypes.bool,
collapse: PropTypes.bool,
refresh: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
settings: PropTypes.bool,
settingsInverse: PropTypes.bool,
tooltipPlacement: PropTypes.string,
showTooltip: PropTypes.bool,
bodyClass: PropTypes.string,
customControls: PropTypes.node,
options: PropTypes.object, //eslint-disable-line,
fetchingData: PropTypes.bool
};
......@@ -32,17 +19,7 @@ class Widget extends React.Component {
title: null,
className: '',
children: [],
close: false,
fullscreen: false,
collapse: false,
refresh: false,
settings: false,
settingsInverse: false,
tooltipPlacement: 'bottom',
showTooltip: false,
bodyClass: '',
customControls: null,
options: {},
fetchingData: false
};
......@@ -53,33 +30,15 @@ class Widget extends React.Component {
};
}
componentDidMount() {
const options = this.props.options;
options.bodySelector = '.widget-body';
jQuery(this.el).widgster(options);
}
render() {
const {
title,
className,
children,
close,
fullscreen,
collapse,
refresh,
settings,
settingsInverse,
tooltipPlacement,
showTooltip,
bodyClass,
customControls,
fetchingData,
options, //eslint-disable-line
...attributes
} = this.props;
const randomId = this.state.randomId;
const mainControls = !!(close || fullscreen || collapse || refresh || settings || settingsInverse);
return (
<section
className={['widget', s.widget, className].join(' ')}
......@@ -92,101 +51,6 @@ class Widget extends React.Component {
: <header className={s.title}>{title}</header>
)
}
{
!customControls && mainControls && (
<div className={`${s.widgetControls} widget-controls`}>
{settings && (
<button><i className="la la-cog" /></button>
)}
{settingsInverse && (
<button className={`bg-gray-transparent ${s.inverse}`}><i
className="la la-cog text-white"
/></button>
)}
{refresh && (
<button data-widgster="load" id={`reloadId-${randomId}`}>
{typeof refresh === 'string' ?
<strong className="text-gray-light">{refresh}</strong> :
<i className="la la-refresh" />}
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`reloadId-${randomId}`}
>Reload</UncontrolledTooltip>
)}
</button>
)}
{fullscreen && (
<button data-widgster="fullscreen" id={`fullscreenId-${randomId}`}>
<i className="glyphicon glyphicon-resize-full" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`fullscreenId-${randomId}`}
>Fullscreen</UncontrolledTooltip>
)}
</button>
)}
{fullscreen && (
<button data-widgster="restore" id={`restoreId-${randomId}`}>
<i className="glyphicon glyphicon-resize-small" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`restoreId-${randomId}`}
>Restore</UncontrolledTooltip>
)}
</button>
)}
{collapse && (
<span>
<button data-widgster="collapse" id={`collapseId-${randomId}`}>
<i className="la la-angle-down" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`collapseId-${randomId}`}
>Collapse</UncontrolledTooltip>
)}
</button>
</span>
)}
{collapse && (
<span>
<button data-widgster="expand" id={`expandId-${randomId}`}>
<i className="la la-angle-up" />
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`expandId-${randomId}`}
>Expand</UncontrolledTooltip>
)}
</button>
</span>
)}
{close && (
<button data-widgster="close" id={`closeId-${randomId}`}>
{typeof close === 'string' ?
<strong className="text-gray-light">{close}</strong> :
<i className="la la-remove" />}
{showTooltip && (
<UncontrolledTooltip
placement={tooltipPlacement}
target={`closeId-${randomId}`}
>Close</UncontrolledTooltip>
)}
</button>
)}
</div>
)}
{
customControls && (
<div className={`${s.widgetControls} widget-controls`}>
{customControls}
</div>
)
}
<div className={`${s.widgetBody} widget-body ${bodyClass}`}>
{fetchingData ? <Loader className={s.widgetLoader} size={40}/> : children}
</div>
......@@ -195,4 +59,4 @@ class Widget extends React.Component {
}
}
export default Widget;
export default Widget;
\ No newline at end of file
......
......@@ -7,10 +7,6 @@
@include clearfix();
}
:global .widget.collapsed {
min-height: unset;
}
.widget {
display: block;
position: relative;
......@@ -76,51 +72,6 @@
}
}
.widgetControls + .widgetBody {
margin-top: $widget-padding-vertical;
}
.widgetControls,
:global(.widget-controls) {
position: absolute;
z-index: 1;
top: 0;
right: 0;
padding: 14px;
font-size: $font-size-sm;
button {
padding: 1px 4px;
border-radius: 4px;
color: rgba($black, 0.4);
background: transparent;
border: none;
@include transition(color 0.15s ease-in-out);
&:hover {
color: rgba($black, 0.1);
text-decoration: none;
}
&:active,
&:focus {
outline: none;
}
:global {
.la {
position: relative;
top: 2px;
}
.glyphicon {
font-size: 0.7rem;
}
}
}
}
.inverse {
top: 2px;
position: relative;
......
{
"name": "Widget",
"version": "0.0.0",
"private": true,
"main": "./Widget.js"
}
const hostApi = process.env.NODE_ENV === "development" ? "http://localhost" : "http://localhost";
const portApi = process.env.NODE_ENV === "development" ? 8080 : 4000;
const baseURLApi = `${hostApi}${portApi ? `:${portApi}` : ``}`;
export default {
hostApi,
portApi,
baseURLApi
};
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<g id="Слой_1">
<rect x="0" y="0" width="13.9" height="30"/>
</g>
<g id="Слой_1__x28_копия_x29_">
<rect x="16.1" y="0" width="13.9" height="30"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<g id="Слой_1">
<rect x="0" y="0" width="8.3" height="30"/>
</g>
<g id="Слой_1__x28_копия_x29_">
<rect x="21.7" y="0" width="8.3" height="30"/>
</g>
<g id="Слой_1__x28_копия2_x29_">
<rect x="10.8" y="0" width="8.3" height="30"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<g id="Слой_1">
<rect x="0" y="0" width="6.2" height="30"/>
</g>
<g id="Слой_1__x28_копия_x29_">
<rect x="23.8" y="0" width="6.2" height="30"/>
</g>
<g id="Слой_1__x28_копия2_x29_">
<rect x="15.9" y="0" width="6.2" height="30"/>
</g>
<g id="Слой_1__x28_копия3_x29_">
<rect x="8" y="0" width="6.2" height="30"/>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 49.94 49.94" style="enable-background:new 0 0 49.94 49.94;" xml:space="preserve" width="512px" height="512px">
<path d="M48.856,22.73c0.983-0.958,1.33-2.364,0.906-3.671c-0.425-1.307-1.532-2.24-2.892-2.438l-12.092-1.757 c-0.515-0.075-0.96-0.398-1.19-0.865L28.182,3.043c-0.607-1.231-1.839-1.996-3.212-1.996c-1.372,0-2.604,0.765-3.211,1.996 L16.352,14c-0.23,0.467-0.676,0.79-1.191,0.865L3.069,16.622c-1.359,0.197-2.467,1.131-2.892,2.438 c-0.424,1.307-0.077,2.713,0.906,3.671l8.749,8.528c0.373,0.364,0.544,0.888,0.456,1.4L8.224,44.701 c-0.183,1.06,0.095,2.091,0.781,2.904c1.066,1.267,2.927,1.653,4.415,0.871l10.814-5.686c0.452-0.237,1.021-0.235,1.472,0 l10.815,5.686c0.526,0.277,1.087,0.417,1.666,0.417c1.057,0,2.059-0.47,2.748-1.288c0.687-0.813,0.964-1.846,0.781-2.904 l-2.065-12.042c-0.088-0.513,0.083-1.036,0.456-1.4L48.856,22.73z" fill="#363f4e"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 49.94 49.94" style="enable-background:new 0 0 49.94 49.94;" xml:space="preserve" width="512px" height="512px">
<path d="M48.856,22.731c0.983-0.958,1.33-2.364,0.906-3.671c-0.425-1.307-1.532-2.24-2.892-2.438l-12.092-1.757 c-0.515-0.075-0.96-0.398-1.19-0.865L28.182,3.043c-0.607-1.231-1.839-1.996-3.212-1.996c-1.372,0-2.604,0.765-3.211,1.996 L16.352,14c-0.23,0.467-0.676,0.79-1.191,0.865L3.069,16.623C1.71,16.82,0.603,17.753,0.178,19.06 c-0.424,1.307-0.077,2.713,0.906,3.671l8.749,8.528c0.373,0.364,0.544,0.888,0.456,1.4L8.224,44.702 c-0.232,1.353,0.313,2.694,1.424,3.502c1.11,0.809,2.555,0.914,3.772,0.273l10.814-5.686c0.461-0.242,1.011-0.242,1.472,0 l10.815,5.686c0.528,0.278,1.1,0.415,1.669,0.415c0.739,0,1.475-0.231,2.103-0.688c1.111-0.808,1.656-2.149,1.424-3.502 L39.651,32.66c-0.088-0.513,0.083-1.036,0.456-1.4L48.856,22.731z M37.681,32.998l2.065,12.042c0.104,0.606-0.131,1.185-0.629,1.547 c-0.499,0.361-1.12,0.405-1.665,0.121l-10.815-5.687c-0.521-0.273-1.095-0.411-1.667-0.411s-1.145,0.138-1.667,0.412l-10.813,5.686 c-0.547,0.284-1.168,0.24-1.666-0.121c-0.498-0.362-0.732-0.94-0.629-1.547l2.065-12.042c0.199-1.162-0.186-2.348-1.03-3.17 L2.48,21.299c-0.441-0.43-0.591-1.036-0.4-1.621c0.19-0.586,0.667-0.988,1.276-1.077l12.091-1.757 c1.167-0.169,2.176-0.901,2.697-1.959l5.407-10.957c0.272-0.552,0.803-0.881,1.418-0.881c0.616,0,1.146,0.329,1.419,0.881 l5.407,10.957c0.521,1.058,1.529,1.79,2.696,1.959l12.092,1.757c0.609,0.089,1.086,0.491,1.276,1.077 c0.19,0.585,0.041,1.191-0.4,1.621l-8.749,8.528C37.866,30.65,37.481,31.835,37.681,32.998z" fill="#363f4e"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
......@@ -3,14 +3,11 @@ import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux'
import ReduxThunk from 'redux-thunk'
import axios from 'axios';
import App from './components/App';
import config from './config';
import reducers from './reducers';
axios.defaults.baseURL = config.baseURLApi;
axios.defaults.headers.common['Content-Type'] = "application/json";
import * as serviceWorker from './serviceWorker';
const store = createStore(
reducers,
......@@ -18,8 +15,13 @@ const store = createStore(
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
......
import React from 'react';
import {
Container,
Form,
FormGroup,
Input,
Button,
} from 'reactstrap';
import { Link } from 'react-router-dom';
import s from './ErrorPage.module.scss';
class ErrorPage extends React.Component {
render() {
return (
<div className={s.errorPage}>
<Container>
<div className={`${s.errorContainer} mx-auto`}>
<h1 className={s.errorCode}>404</h1>
<p className={s.errorInfo}>
Opps, it seems that this page does not exist.
</p>
<p className={[s.errorHelp, 'mb-3'].join(' ')}>
If you are sure it should, search for it.
</p>
<Form method="get">
<FormGroup>
<Input className="input-no-border" type="text" placeholder="Search Pages" />
</FormGroup>
<Link to="app/extra/search">
<Button className={s.errorBtn} type="submit" color="inverse">
Search <i className="fa fa-search text-warning ml-xs" />
</Button>
</Link>
</Form>
</div>
<footer className={s.pageFooter}>
2019 &copy; Sing App - React Admin Dashboard Template.
</footer>
</Container>
</div>
);
}
}
export default ErrorPage;
@import '../../styles/app';
.errorPage {
padding-top: 5%;
height: 100vh;
}
.errorContainer {
width: 365px;
text-align: center;
}
.errorBtn {
padding-left: 35px;
padding-right: 35px;
}
.errorCode {
margin: 20px;
font-size: 80px;
font-weight: $font-weight-normal;
color: $gray-800;
@include media-breakpoint-up(md) {
font-size: 180px;
}
}
.errorInfo {
font-size: 20px;
color: $gray-800;
}
.errorHelp {
font-size: 14px;
}
.pageFooter {
position: absolute;
bottom: 30px;
left: 0;
right: 0;
width: 100%;
font-size: $font-size-mini;
color: $text-muted;
text-align: center;
}
{
"name": "error",
"version": "0.0.0",
"private": true,
"main": "./ErrorPage.js"
}
This diff is collapsed. Click to expand it.
import React from 'react';
import {
Breadcrumb,
BreadcrumbItem,
Row,
Col,
Table,
Button,
} from 'reactstrap';
import Widget from '../../../../components/Widget';
const tableData = [
{
id: 0,
state: 'Success',
usage: ['text-success', 'btn-success'],
},
{
id: 1,
state: 'Warning',
usage: ['badge-warning', 'bg-warning'],
},
{
id: 2,
state: 'Danger',
usage: ['btn-danger', 'text-danger'],
},
{
id: 3,
state: 'Info',
usage: ['alert-info', 'badge-info'],
},
{
id: 4,
state: 'Primary',
usage: ['bg-primary', 'text-primary'],
},
{
id: 5,
state: 'Secondary',
usage: ['bg-secondary'],
},
];
const Colors = () => (
<div>
<Breadcrumb>
<BreadcrumbItem>YOU ARE HERE</BreadcrumbItem>
<BreadcrumbItem active>Colors</BreadcrumbItem>
</Breadcrumb>
<h1 className="page-title">Colors</h1>
<Row>
<Col>
<Widget
title={<h5>States <span className="fw-semi-bold">Colors</span></h5>}
close collapse
>
<p>Sing comes with a number of state colors that can be applied to
the most of elements and components. It reuses Bootstrap&apos;s original 6 states:</p>
<Table>
<thead>
<tr>
<th>STATE</th>
<th>PREVIEW</th>
<th>CLASS POSTFIX</th>
<th>USAGE EXAMPLE</th>
</tr>
</thead>
<tbody>
{tableData.map(({ state, usage, id }) =>
<tr key={id}>
<th scope="row" className="fw-thin">{state}</th>
<td><span className={`circle bg-${state.toLowerCase()}`}>&nbsp;</span></td>
<td><code>*-{state.toLowerCase()}</code></td>
<td>{usage.map(item => <code key={item} className="mr-xs">{item}</code>)}</td>
</tr>,
)}
</tbody>
</Table>
</Widget>
</Col>
</Row>
<Row>
<Col xs={12} md={6}>
<Widget
title={<h5>Text <span className="fw-semi-bold">Colors</span></h5>}
close collapse
>
<p>Convey meaning through color with a handful of color utility classes.
Includes support for styling links with hover states, too. Use <code>text-*</code> class to fill text.</p>
<div className="widget-padding-md border rounded w-100 h-100 text-left">
<h1 className="text-danger">h1. Heading</h1>
<h2 className="text-warning">h2. Heading</h2>
<h3 className="text-success">h3. Heading</h3>
<h4 className="text-primary">h4. Heading</h4>
<h5 className="text-info">h5. Heading</h5>
<h6 className="text-inverse">h6. Heading</h6>
</div>
</Widget>
</Col>
<Col xs={12} md={6}>
<Widget
title={<h5>Example <span className="fw-semi-bold">Buttons</span></h5>}
close collapse
>
<p>Use any of the available button classes to quickly create a styled button.
Semantically distinguishable beauty.</p>
<Button className="width-100 mb-xs mr-xs" color="default">Default</Button>
<Button className="width-100 mb-xs mr-xs" color="primary">Primary</Button>
<Button className="width-100 mb-xs mr-xs" color="info">Info</Button>
<Button className="width-100 mb-xs mr-xs" color="success">Success</Button>
<Button className="width-100 mb-xs mr-xs" color="warning">Warning</Button>
<Button className="width-100 mb-xs mr-xs" color="danger">Danger</Button>
<Button className="width-100 mb-xs mr-xs" color="gray">Gray</Button>
<Button className="width-100 mb-xs mr-xs" color="inverse">Inverse</Button>
</Widget>
</Col>
</Row>
</div>
);
export default Colors;
{
"name": "Colors",
"version": "0.0.0",
"main": "./Colors.js",
"private": true
}
This diff is collapsed. Click to expand it.
{
"name": "Grid",
"version": "0.0.0",
"main": "./Grid.js",
"private": true
}
import React from 'react';
import {
Breadcrumb,
BreadcrumbItem,
Row,
Col,
} from 'reactstrap';
import Widget from '../../../../components/Widget';
const Typography = () => (
<div>
<Breadcrumb>
<BreadcrumbItem>YOU ARE HERE</BreadcrumbItem>
<BreadcrumbItem active>Typography</BreadcrumbItem>
</Breadcrumb>
<h1 className="page-title">Typography - <span className="fw-semi-bold">Texts & Display</span></h1>
<Row>
<Col xs={12} md={6}>
<Widget
title={<h5>Headings <small className="text-muted">Default and customized</small></h5>}
close collapse
>
<h4>Default headings</h4>
<p>Basic headings for everyday use</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<Row>
<Col sm={6}>
<h1>h1. Heading</h1>
<h2>h2. Heading</h2>
<h3>h3. Heading</h3>
<h4>h4. Heading</h4>
<h5>h5. Heading</h5>
<h6>h6. Heading</h6>
</Col>
<Col sm={6}>
<h1 className="text-danger">h1. Heading</h1>
<h2 className="text-warning">h2. Heading</h2>
<h3 className="text-success">h3. Heading</h3>
<h4 className="text-primary">h4. Heading</h4>
<h5 className="text-info">h5. Heading</h5>
<h6 className="text-inverse">h6. Heading</h6>
</Col>
</Row>
</div>
<h4 className="mt-5">Customized headings</h4>
<p>Enhanced with additional text</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<h3>
Headings <small>And some clarification text</small>
</h3>
</div>
<h4 className="mt-5">Display</h4>
<p>Headings to stand out</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<h1 className="display-1">Display 1</h1>
<h1 className="display-2">Display 2</h1>
<h1 className="display-3">Display 3</h1>
<h1 className="display-4">Display 4</h1>
</div>
<h4 className="mt-5">Lead</h4>
<p>Make a paragraph stand out by adding <code className="highlighter-rouge">.lead</code>.</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<p className="lead">Sing App is admin dashboard template built with Bootstrap</p>
</div>
</Widget>
</Col>
<Col xs={12} md={6}>
<Widget
title={<h5>Body texts <small className="text-muted">Variations</small></h5>}
close collapse
>
<h4>Basic texts</h4>
<p>Styling for common texts</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<p>You can use the mark tag to <mark>highlight</mark> text.</p>
<p><del>This line of text is meant to be treated as deleted text.</del></p>
<p><ins>This line of text is meant to be treated as an addition to the document.</ins></p>
<p><small>This line of text is meant to be treated as fine print.</small></p>
<p><em>This line rendered as italicized text.</em></p>
<p><strong>This line rendered as bold text.</strong></p>
</div>
<h4 className="mt-5">Font weights</h4>
<p>Various font weights supported</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<p>Thin (default) font weight</p>
<p className="fw-normal">Normal font weight</p>
<p className="fw-semi-bold">Semi bold to empasize important thing</p>
<p className="fw-bold">Bold font as a high priority</p>
</div>
<h4 className="mt-5">Colors</h4>
<p>Bootstrap state colors can be applied to texts too</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<p className="text-danger">Some danger text</p>
<p className="text-warning">Some warning text</p>
<p className="text-success">Some succes text</p>
<p className="text-primary">Some primary text</p>
<p className="text-info">Some info text</p>
</div>
<h4 className="mt-5">Blockquotes</h4>
<p>Citing someone is really easy</p>
<div className="widget-padding-md w-100 h-100 text-left border rounded">
<blockquote className="blockquote">
<p>Don&apos;t get set into one form, adapt it and build your own, and let
it grow, be like water. Empty your mind, be formless, shapeless like water.
Now you put water in a cup, it becomes the cup; You put water into a bottle it
becomes the bottle; You put it in a teapot it becomes the teapot. Now water can
flow or it can crash. Be water, my friend.</p>
<footer className="blockquote-footer">Bruce Lee in <cite title="A Warrior's Journey">A Warrior&apos;s Journey</cite></footer>
</blockquote>
</div>
</Widget>
</Col>
</Row>
</div>
);
export default Typography;
{
"name": "Typography",
"version": "0.0.0",
"main": "./Typography.js",
"private": true
}
import React, { Component } from 'react';
import cx from 'classnames';
import {
Breadcrumb,
BreadcrumbItem,
Alert,
} from 'reactstrap';
import Filters from './components/Filters/Filters';
import MessageTable from './components/MessageTable/MessageTable';
import s from './Email.module.scss';
class Email extends Component {
state = {
isNotificationOpen: true,
filter: null,
openedMessage: null,
compose: false,
composeData: null,
alertAfter: false,
}
componentDidMount() {
setTimeout(() => { this.fixAlert(); }, 0);
}
fixAlert() {
this.setState({ alertAfter: true });
}
filter = (filter) => {
this.setState({ filter, compose: false, composeData: null });
}
closeNotification() {
this.setState({ isNotificationOpen: false });
}
openMessage = (id) => {
this.setState(pvState => ({
openedMessage: id,
compose: id === null ? false : pvState.compose,
composeData: id === null ? null : pvState.composeData,
}));
}
changeCompose = (compose, data) => {
this.setState({ compose });
if (data) {
this.setState({ composeData: data });
}
}
render() {
const {
isNotificationOpen,
filter,
openedMessage,
alertAfter,
compose,
composeData,
} = this.state;
return (
<div>
<Breadcrumb>
<BreadcrumbItem>YOU ARE HERE</BreadcrumbItem>
<BreadcrumbItem active>Email</BreadcrumbItem>
</Breadcrumb>
<div className="page-top-line">
<h1 className="page-title">Email - <span className="fw-semi-bold">Inbox</span></h1>
<Alert
isOpen={isNotificationOpen}
color="success"
toggle={() => this.closeNotification()}
className={cx(s.alert, { [s.alertAfter]: alertAfter })}
>
Hey! This is a <span className="fw-semi-bold">real app</span> with CRUD and Search functions. Have fun!
</Alert>
</div>
<div className={s.view}>
<Filters
filter={this.filter}
openMessage={this.openMessage}
compose={this.changeCompose}
/>
<MessageTable
filter={filter}
openedMessage={openedMessage}
openMessage={this.openMessage}
compose={compose}
changeCompose={this.changeCompose}
composeData={composeData}
/>
</div>
</div>
);
}
}
export default Email;
.view {
display: flex;
@media screen and (max-width: 1125px) {
flex-direction: column;
}
}
.alert {
transition: 0.6s;
transition-timing-function: ease;
transform: translateX(-130vw);
}
.alertAfter {
transform: translateX(0);
}
import React from 'react';
import PropTypes from 'prop-types';
import { Editor } from 'react-draft-wysiwyg';
import { Input, Button } from 'reactstrap';
import Widget from '../../../../../components/Widget';
import s from './Compose.module.scss';
const Compose = ({ data }) => (
<Widget>
<div className={s.compose}>
<h4>Compose <span className="fw-semi-bold">New</span></h4>
<Input type="text" placeholder="To" defaultValue={data && data.from} />
<Input type="text" placeholder="Subject" defaultValue={data && data.theme} />
<Editor
wrapperClassName={s.wysiwygWrapper}
editorClassName={s.wysiwygEditor}
toolbarClassName={s.wysiwygToolbar}
/>
<div className="text-md-right mt-xs">
<Button color="gray">Discard</Button>
<Button color="gray">Save</Button>
<Button color="danger">Send</Button>
</div>
</div>
</Widget>
);
Compose.propTypes = {
data: PropTypes.shape({
from: PropTypes.string,
to: PropTypes.string,
}),
};
Compose.defaultProps = {
data: {
from: null,
to: null,
},
};
export default Compose;
@import '../../../../../styles/app';
:global {
@import '../../../../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg';
}
.compose {
h4 {
margin-bottom: 20px;
}
input {
margin-bottom: 15px;
}
button {
margin-left: 7.5px;
}
}
.wysiwygWrapper {
border: 1px solid #ccc !important;
overflow: visible;
height: 270px;
margin-bottom: 15px;
}
.wysiwygToolbar {
color: $gray-800 !important;
background-color: #ddd !important;
border-color: transparent !important;
:global {
.rdw-option-wrapper {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
height: 30px;
min-width: 30px;
margin: 0;
background: #f8f8f8;
}
.rdw-dropdown-wrapper {
background: #f8f8f8;
}
}
}
.wysiwygEditor {
position: relative !important;
overflow: hidden !important;
height: 150px;
line-height: 0.1;
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Badge } from 'reactstrap';
import s from './Filters.module.scss';
class Filters extends Component {
state = { activeButtonId: 0 }
handleButtonClick(id, filterCond) {
const { filter, openMessage } = this.props;
this.setState({ activeButtonId: id });
openMessage(null);
filter(filterCond);
}
render() {
const mainButtons = [
{ id: 0, title: 'Inbox', notifications: 2, filter: null },
{ id: 1, title: 'Starred', filter: 'starred' },
{ id: 2, title: 'Sent Mail', filter: 'sent' },
{ id: 3, title: 'Draft', notifications: 3, lable: 'danger', filter: 'draft' },
{ id: 4, title: 'Trash', filter: 'trash' },
];
const quickViewButton = [
{ id: 0, title: 'Work', colour: 'danger' },
{ id: 1, title: 'Private', colour: 'white' },
{ id: 2, title: 'Saved', colour: '' },
];
const { activeButtonId } = this.state;
const { compose } = this.props;
return (
<div className={s.filters}>
<button
className="btn btn-danger btn-block"
onClick={() => compose(true)}
>
Compose
</button>
<div className={s.mainFilterButtons}>
{mainButtons.map(button =>
<button
className={cx('btn', s.button, { [s.buttonActive]: button.id === activeButtonId })}
key={button.id}
onClick={() => this.handleButtonClick(button.id, button.filter)}
>
{button.title}
{button.notifications &&
<Badge color={button.lable || 'default'} pill>{button.notifications}</Badge>}
</button>,
)}
</div>
<div>
<h6>QUICK VIEW</h6>
{quickViewButton.map(button =>
<button className={cx('btn', s.button)} key={button.id}>
{button.title}
<i className={cx('fa fa-circle', { [`text-${button.colour}`]: true })} />
</button>,
)}
</div>
</div>
);
}
}
Filters.propTypes = {
filter: PropTypes.func.isRequired,
openMessage: PropTypes.func.isRequired,
compose: PropTypes.func.isRequired,
};
export default Filters;
@import '../../../../../styles/app';
.filters {
width: 16%;
padding-right: 15px;
@media screen and (max-width: 1125px) {
width: 100%;
padding-right: 0;
}
}
.mainFilterButtons {
margin: 15px 0;
}
.button {
width: 100%;
padding: 10px 14px !important;
display: flex !important;
justify-content: space-between;
align-items: center;
font-weight: $font-weight-normal;
border-radius: 0.2rem;
color: #868e96;
background: transparent;
&:hover {
background-color: #e5e5e5;
color: $gray-700;
}
& :global .badge {
width: 20px;
height: 20px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
line-height: 10px;
}
}
.buttonActive {
background-color: $white;
color: #555;
font-weight: 600;
}
import React from 'react';
import PropTypes from 'prop-types';
import Widget from '../../../../../components/Widget';
import MessageHeader from '../MessageHeader/MessageHeader';
import MessageAttachments from '../MessageAttachments/MessageAttachments';
const Message = ({ message, compose }) => (
<Widget>
<MessageHeader
title={message.theme}
name={message.from}
email={message.fromEmail}
to={message.to}
date={message.date}
compose={compose}
/>
{/* eslint-disable */}
<div
dangerouslySetInnerHTML={{ __html: message.content }}
/>
{/* eslint-enable */}
{message.attachments && <MessageAttachments attachments={message.attachments} />}
</Widget>
);
Message.propTypes = {
message: PropTypes.shape({
theme: PropTypes.string,
from: PropTypes.string,
fromEmail: PropTypes.string,
to: PropTypes.string,
date: PropTypes.string,
}).isRequired,
compose: PropTypes.func.isRequired,
};
export default Message;
import React from 'react';
import PropTypes from 'prop-types';
import s from './MessageAttachments.module.scss';
const MessageAttachments = ({ attachments }) => (
<div className={s.messageAttachments}>
<hr />
<div className={s.attachmentsInfo}>
<strong>{attachments.length} attachments</strong> -
<button className="btn-link">Download all attachments</button>
<button className="btn-link">View all attachments</button>
</div>
{attachments.map(att =>
<div className={s.attachment} key={att.id}>
<img src={att.photo} alt="attachment" />
<h5>{att.photoName}</h5>
<div className={s.attachmentButtons}>
{att.weight}
<button className="btn-link">View</button>
<button className="btn-link">Download</button>
</div>
</div>,
)}
</div>
);
MessageAttachments.propTypes = {
attachments: PropTypes.arrayOf(PropTypes.shape({
photo: PropTypes.string,
photoName: PropTypes.string,
weight: PropTypes.string,
})).isRequired,
};
export default MessageAttachments;
@import '../../../../../styles/app';
.messageAttachments {
width: 50%;
@media screen and (max-width: 576px) {
width: 100%;
}
}
.attachmentsInfo {
margin: -5px 0 10px;
a {
margin-left: 5px;
}
}
.attachment {
max-width: 100%;
img {
width: 100%;
}
h5 {
font-weight: $font-weight-semi-bold;
}
}
.attachmentButtons {
margin: -5px 0 15px;
a {
margin-left: 10px;
}
}
import React from 'react';
import PropTypes from 'prop-types';
import ReplyDropdown from '../ReplyDropdown/ReplyDropdown';
import userPhoto from '../../../../../images/people/a5.jpg';
import s from './MessageHeader.module.scss';
const MessageHeader = ({ title, name, email, to, date, compose }) => (
<div className={s.messageHeader}>
<h3>{title}</h3>
<div className={s.messageHeaderLine}>
<div className={s.messageFrom}>
<img src={userPhoto} alt="user" className="rounded-circle" />
<div className={s.messageFromInfo}>
<span>
<strong>{name}</strong>
<span className={s.email}>
{`<${email}>`}
</span>
</span>
<span className={s.to}>to {to}</span>
</div>
</div>
<div className={s.messageHeaderDate}>
{date}
<ReplyDropdown compose={() => compose(true, { from: name, theme: title })} />
</div>
</div>
</div>
);
MessageHeader.propTypes = {
title: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
to: PropTypes.string.isRequired,
date: PropTypes.string.isRequired,
compose: PropTypes.func.isRequired,
};
export default MessageHeader;
@import '../../../../../styles/app';
.messageHeader {
width: 100%;
}
.messageHeaderLine {
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px 0;
flex-wrap: wrap;
}
.messageFrom {
display: flex;
align-items: center;
img {
height: 30px;
width: 30px;
margin-right: 5px;
}
}
.messageFromInfo {
display: flex;
flex-direction: column;
line-height: 1.1;
}
.email {
color: #868e96;
font-size: $font-size-mini;
margin-left: 5px;
}
.to {
color: #868e96;
}
.messageHeaderDate {
padding: 15px 0;
& :global .btn-group {
margin-left: 10px;
button {
font-size: 12px;
i {
margin-right: 3px;
}
}
}
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { Table, Input, FormGroup, Label } from 'reactstrap';
import Widget from '../../../../../components/Widget';
import MessageTableHeader from '../MessageTableHeader/MessageTableHeader';
import Pagination from '../Pagination/Pagination';
import Compose from '../Compose/Compose';
import Message from '../Message/Message';
import mock from '../../mock';
import s from './MessageTable.module.scss';
class MessageTable extends Component {
state = {
messages: mock,
checkedIds: [],
searchString: '',
}
componentWillReceiveProps(nextProps) {
const { filter } = this.props;
if (filter !== nextProps.filter) {
this.chooseNone();
this.setState({ openedMessage: null });
}
}
chooseAll = () => {
const { messages } = this.state;
const { filter } = this.props;
const newCheckedIds = [];
if (filter) {
messages
.filter(message => message[filter])
.forEach(message => newCheckedIds.push(message.id));
} else {
messages.forEach(message => newCheckedIds.push(message.id));
}
this.setState({ checkedIds: newCheckedIds });
}
chooseNone = () => {
this.setState({ checkedIds: [] });
}
chooseRead = () => {
const { messages } = this.state;
const newCheckedIds = [];
messages.forEach((message) => {
if (!message.unreaded) {
newCheckedIds.push(message.id);
}
});
this.setState({
checkedIds: newCheckedIds,
});
}
chooseUnread = () => {
const { messages } = this.state;
const newCheckedIds = [];
messages.forEach((message) => {
if (message.unreaded) {
newCheckedIds.push(message.id);
}
});
this.setState({
checkedIds: newCheckedIds,
});
}
choose(id) {
const { checkedIds } = this.state;
const indexOfId = checkedIds.indexOf(id);
if (indexOfId === -1) {
this.setState({ checkedIds: [...checkedIds, id] });
} else {
const newCheckedIds = [...checkedIds];
newCheckedIds.splice(indexOfId, 1);
this.setState({ checkedIds: newCheckedIds });
}
}
markUnread = () => {
const { messages, checkedIds } = this.state;
const newMessages = [...messages];
newMessages.map((message) => {
if (checkedIds.indexOf(message.id) !== -1) {
message.unreaded = true;
}
return message;
});
this.setState({ messages: newMessages });
}
markRead = () => {
const { messages, checkedIds } = this.state;
const newMessages = [...messages];
newMessages.map((message) => {
if (checkedIds.indexOf(message.id) !== -1) {
message.unreaded = false;
}
return message;
});
this.setState({ messages: newMessages });
}
delete = () => {
const { messages, checkedIds } = this.state;
const newMessages = [...messages];
newMessages.map((message) => {
if (checkedIds.indexOf(message.id) !== -1) {
message.deleted = true;
}
return message;
});
this.setState({
messages: newMessages.filter(message => !message.deleted),
checkedIds: [],
});
}
starItem(id) {
const { messages } = this.state;
const isAlreadyStarred = messages.find(m => m.id === id).starred;
const newMessages = [...messages];
newMessages.map((message) => {
if (message.id === id) {
message.starred = !isAlreadyStarred;
}
return message;
});
this.setState({ messages: newMessages });
}
handleOpenMessage(id) {
const newMessages = [...this.state.messages];
newMessages.map((message) => {
if (message.id === id) {
message.unreaded = false;
}
return message;
});
this.setState({ messages: newMessages });
this.props.openMessage(id);
}
search = (value) => {
this.setState({ searchString: value.toLowerCase() });
}
_searchable(m) {
const { searchString } = this.state;
if (searchString) {
return (m.content.toLowerCase().indexOf(searchString) !== -1 ||
m.from.toLowerCase().indexOf(searchString) !== -1 ||
m.theme.toLowerCase().indexOf(searchString) !== -1);
}
return true;
}
render() {
const { messages, checkedIds } = this.state;
const { filter, openedMessage, openMessage, compose, composeData, changeCompose } = this.props;
const filteredMessages = messages.filter(message => message[filter]);
const dataToDisplay = filter ? filteredMessages : messages;
return (
<div className={s.messages}>
{openedMessage === null && !compose
? <Pagination />
: <button className={cx('btn btn-default', s.backButton)} onClick={() => openMessage(null)}>
<i className="fa fa-angle-left fa-lg" />
</button>
}
{/* eslint-disable */}
{openedMessage === null && !compose
? <Widget>
<MessageTableHeader
all={this.chooseAll}
none={this.chooseNone}
read={this.chooseRead}
unread={this.chooseUnread}
markRead={this.markRead}
markUnread={this.markUnread}
deleteItems={this.delete}
search={this.search}
/>
<Table striped hover>
<thead>
<tr>
<th>
<FormGroup className="checkbox abc-checkbox" check>
<Input
id="checkbox-main"
type="checkbox"
onChange={dataToDisplay.length !== checkedIds.length ? this.chooseAll : this.chooseNone}
checked={dataToDisplay.length !== 0 && checkedIds.length === dataToDisplay.length}
/>{' '}
<Label for="checkbox-main" check />
</FormGroup>
</th>
</tr>
</thead>
<tbody>
{dataToDisplay
.filter((m) => this._searchable(m))
.map(message =>
(<tr
key={message.id}
className={cx({ [s.unreadedMessage]: message.unreaded })}
>
<td className={s.messageCheckbox} >
<FormGroup className="checkbox abc-checkbox" check>
<Input
id={`checkbox${message.id}`}
type="checkbox"
checked={checkedIds.indexOf(message.id) !== -1}
onChange={() => this.choose(message.id)}
/>{' '}
<Label for={`checkbox${message.id}`} check />
</FormGroup>
</td>
<td
className={s.messageStar}
onClick={() => this.starItem(message.id)}>{message.starred
? <span className={s.messageStarred}><i className="fa fa-star" /></span>
: <span><i className="fa fa-star-o" /></span>}
</td>
<td
className={s.messageFrom}
onClick={() => this.handleOpenMessage(message.id)}
>{message.from}</td>
<td onClick={() => this.handleOpenMessage(message.id)}>{message.theme}</td>
<td className={s.messageClip}>{message.attachments && <i className="fa fa-paperclip" />}</td>
<td className={s.messageDate}>{message.date}</td>
</tr>),
)}
</tbody>
</Table>
</Widget>
: compose
? <Compose data={composeData} />
: <Message message={messages[openedMessage]} compose={changeCompose} />
}
{/* eslint-enable */}
</div>
);
}
}
MessageTable.propTypes = {
filter: PropTypes.string,
openedMessage: PropTypes.number,
openMessage: PropTypes.func.isRequired,
compose: PropTypes.bool.isRequired,
composeData: PropTypes.shape({
from: PropTypes.string,
theme: PropTypes.string,
}),
changeCompose: PropTypes.func.isRequired,
};
MessageTable.defaultProps = {
filter: null,
openedMessage: null,
composeData: null,
};
export default MessageTable;
@import '../../../../../styles/app';
.messages {
width: 84%;
border-radius: 0.2rem;
@media screen and (max-width: 1125px) {
width: 100%;
}
& :global .form-check-input {
margin: 0;
position: relative;
}
& :global .table {
margin-bottom: 0;
}
}
.unreadedMessage {
td {
font-weight: $font-weight-semi-bold;
}
}
.messageCheckbox {
width: 50px;
padding-right: 0;
:global .form-check {
margin-bottom: 0;
}
}
.messageStar {
left: 25px;
margin-left: -10px;
}
.messageStarred {
color: theme-color('warning');
}
.messageFrom,
.messageClip {
@media screen and (max-width: 768px) {
display: none;
}
}
.messageDate {
display: flex;
justify-content: flex-end;
@media screen and (max-width: 768px) {
width: 65px;
}
}
.backButton {
margin-bottom: 15px;
}
import React from 'react';
import PropTypes from 'prop-types';
import {
UncontrolledButtonDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
Input,
} from 'reactstrap';
import s from './MessageTableHeader.module.scss';
const MessageTableHeader = (props) => {
const { all, none, read, unread, markRead, markUnread, deleteItems, search } = props;
const select = [
{ id: 0, title: 'All', onClick: all },
{ id: 1, title: 'None', onClick: none },
{ id: 2 },
{ id: 3, title: 'Read', onClick: read },
{ id: 4, title: 'Unread', onClick: unread },
];
const action = [
{ id: 1, title: 'Reply' },
{ id: 2, title: 'Forward' },
{ id: 3, title: 'Archive' },
{ id: 4 },
{ id: 5, title: 'Mark As Read', onClick: markRead },
{ id: 6, title: 'Mark As Unread', onClick: markUnread },
{ id: 7 },
{ id: 8, title: 'Delete', onClick: deleteItems },
];
return (
<div className={s.messageTableHeader}>
<div>
<UncontrolledButtonDropdown size="sm">
<DropdownToggle
caret color="default"
className="dropdown-toggle-split mr-xs"
>
Select
</DropdownToggle>
<DropdownMenu>
{select.map(item =>
(Object.keys(item).length > 1
? <DropdownItem key={item.id} onClick={item.onClick}>{item.title}</DropdownItem>
: <DropdownItem key={item.id} divider />),
)}
</DropdownMenu>
</UncontrolledButtonDropdown >
<UncontrolledButtonDropdown size="sm">
<DropdownToggle
caret color="default"
className="dropdown-toggle-split mr-xs"
>
Actions
</DropdownToggle>
<DropdownMenu>
{action.map(item =>
(Object.keys(item).length > 1
? <DropdownItem key={item.id} onClick={item.onClick}>{item.title}</DropdownItem>
: <DropdownItem key={item.id} divider />),
)}
</DropdownMenu>
</UncontrolledButtonDropdown>
</div>
<Input placeholder="Search Messages" size="sm" onChange={e => search(e.target.value)} />
</div>
);
};
MessageTableHeader.propTypes = {
all: PropTypes.func.isRequired,
none: PropTypes.func.isRequired,
read: PropTypes.func.isRequired,
unread: PropTypes.func.isRequired,
markRead: PropTypes.func.isRequired,
markUnread: PropTypes.func.isRequired,
deleteItems: PropTypes.func.isRequired,
search: PropTypes.func.isRequired,
};
export default MessageTableHeader;
.messageTableHeader {
display: flex;
justify-content: space-between;
align-items: center;
& :global .form-control {
width: auto;
}
}
import React from 'react';
import cx from 'classnames';
import s from './Pagination.module.scss';
const Pagination = () => (
<div className={s.pagination}>
<span className={s.paginationText}>Showing 1 - 10 of 96 messages</span>
<div className={s.paginationPages}>
<button className={cx(s.button, s.buttonDisabled)}><i className="fa fa-chevron-left" /></button>
<button className={cx(s.button, s.buttonActive)}>1</button>
<button className={s.button}>2</button>
<button className={s.button}><i className="fa fa-chevron-right" /></button>
</div>
</div>
);
export default Pagination;
@import '../../../../../styles/app';
.pagination {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
margin-bottom: 15px;
}
.paginationText {
color: #868e96;
font-size: $font-size-mini;
}
.paginationPages {
border-left: 1px solid #868e96;
padding-left: 11px;
margin-left: 10px;
display: flex;
button {
margin-left: 4px;
}
}
.button {
transition: 0.3s;
padding: 0.45rem 0.75rem;
display: flex;
justify-content: space-between;
align-items: center;
font-weight: $font-weight-normal;
border-radius: 0.2rem;
color: #888;
background: #fff;
border: none;
&:hover {
background-color: transparent;
}
}
.buttonActive {
background: $gray-300;
}
.buttonDisabled {
&:hover {
background-color: #fff;
}
}
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
ButtonDropdown,
Button,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from 'reactstrap';
class ReplyDropdown extends Component {
state = { open: false };
toggle() {
this.setState(pvState => ({ open: !pvState.open }));
}
render() {
const { open } = this.state;
const { compose } = this.props;
return (
<ButtonDropdown isOpen={open} toggle={() => this.toggle()}>
<Button size="sm" id="dropdownFour" color="default" onClick={() => compose()}>
<i className="fa fa-reply" /> Reply
</Button>
<DropdownToggle size="sm" color="default" className="dropdown-toggle-split">
<i className="fa fa-angle-down" />
</DropdownToggle>
<DropdownMenu>
<DropdownItem><i className="fa fa-reply" /> Reply</DropdownItem>
<DropdownItem><i className="fa fa-arrow-right" /> Forward</DropdownItem>
<DropdownItem><i className="fa fa-print" /> Print</DropdownItem>
<DropdownItem divider />
<DropdownItem><i className="fa fa-ban" /> Spam</DropdownItem>
<DropdownItem><i className="fa fa-trash" /> Delete</DropdownItem>
</DropdownMenu>
</ButtonDropdown>
);
}
}
ReplyDropdown.propTypes = {
compose: PropTypes.func.isRequired,
};
export default ReplyDropdown;
import photo1 from '../../../images/tables/1.png';
import photo2 from '../../../images/tables/2.png';
import photo3 from '../../../images/tables/3.png';
export default [
{
id: 0,
starred: true,
from: 'Philip Horbachuski',
fromEmail: 'philip.horbachuski@example.com',
to: 'Wrapbootstrap',
theme: 'Hi, Welcom to Google Mail',
date: '18:31',
unreaded: true,
content: `<p>Projecting surrounded literature yet delightful alteration but bed men. Open are from long why cold.
If must snug by upon sang loud left. As me do preference entreaties compliment motionless ye literature.
Day behaviour explained law remainder.</p>
<p><strong>On then sake home</strong> is am leaf. Of suspicion do departure at extremely he believing.
Do know said mind do rent they oh hope of. General enquire picture letters
garrets on offices of no on.</p>
<p>All the best,</p>
<p>Vitaut the Great, CEO, <br />
Fooby Inc. </p>`,
attachments: [
{
photo: photo1,
photoName: 'some-cool-photo1.jpg',
weight: '568K',
id: 0,
},
{
photo: photo2,
photoName: 'some-cool-photo2.jpg',
weight: '568K',
id: 1,
},
],
},
{
id: 1,
starred: true,
from: 'StackExchange',
theme: 'New Python questions for this week',
fromEmail: 'stackexchange@example.com',
to: 'Wrapbootstrap',
date: 'Aug 14',
unreaded: false,
draft: true,
content: '<h1>THIS IS HTML!!!!</h1>',
attachments: [
{
photo: photo3,
photoName: 'some-cool-photo1.jpg',
weight: '568K',
id: 0,
},
],
},
{
id: 2,
starred: false,
from: 'Facebook',
theme: 'Someone just commented on your photo!',
fromEmail: 'notification@facebook.com',
to: 'Wrapbootstrap',
date: 'Aug 7',
unreaded: true,
sent: true,
content: 'Someone just commented on your photo!',
},
{
id: 3,
starred: false,
from: 'Twitter',
theme: '@hackernews is now following you on Twitter',
fromEmail: 'notification@twitter.com',
to: 'Wrapbootstrap',
date: 'Jul 31',
unreaded: false,
sent: true,
content: '@hackernews is now following you on Twitter',
},
];
{
"name": "email",
"version": "0.0.0",
"private": true,
"main": "./Email.js"
}
\ No newline at end of file
import React from 'react';
import {
Row,
Col,
ButtonGroup,
Button,
} from 'reactstrap';
import 'fullcalendar/dist/fullcalendar';
import 'jquery-ui/ui/widgets/draggable';
import moment from 'moment/moment';
import $ from 'jquery';
import s from './Calendar.module.scss';
import Widget from '../../../../components/Widget';
class Calendar extends React.Component {
constructor(props) {
super(props);
this.state = {
calendarView: 'month',
currentMonth: moment().format('MMM YYYY'),
currentDay: moment().format('dddd'),
};
const date = new Date();
const d = date.getDate();
const m = date.getMonth();
const y = date.getFullYear();
this.calendarOptions = {
header: {
left: '',
center: '',
right: '',
},
events: [
{
title: 'All Day Event',
start: new Date(y, m, 1),
backgroundColor: '#79A5F0',
textColor: '#fff',
description: 'Will be busy throughout the whole day',
},
{
title: 'Long Event',
start: new Date(y, m, d + 5),
end: new Date(y, m, d + 7),
description: 'This conference should be worse visiting',
},
{
id: 999,
title: 'Blah Blah Car',
start: new Date(y, m, d - 3, 16, 0),
allDay: false,
description: 'Agree with this guy on arrival time',
},
{
id: 1000,
title: 'Buy this template',
start: new Date(y, m, d + 3, 12, 0),
allDay: false,
backgroundColor: '#555',
textColor: '#fff',
description: 'Make sure everything is consistent first',
},
{
title: 'Got to school',
start: new Date(y, m, d + 16, 12, 0),
end: new Date(y, m, d + 16, 13, 0),
backgroundColor: '#64bd63',
textColor: '#fff',
description: 'Time to go back',
},
{
title: 'Study some Node',
start: new Date(y, m, d + 18, 12, 0),
end: new Date(y, m, d + 18, 13, 0),
backgroundColor: '#79A5F0',
textColor: '#fff',
description: 'Node.js is a platform built ' +
'on Chrome\'s JavaScript runtime for easily' +
' building fast, scalable network applications.' +
' Node.js uses an event-driven, non-blocking' +
' I/O model that makes it lightweight and' +
' efficient, perfect for data-intensive real-time' +
' applications that run across distributed devices.',
},
{
title: 'Click for Flatlogic',
start: new Date(y, m, 28),
end: new Date(y, m, 29),
url: 'http://flatlogic.com/',
backgroundColor: '#e5603b',
textColor: '#fff',
description: 'Creative solutions',
},
],
selectable: true,
selectHelper: true,
select: (start, end, allDay) => {
this.createEvent = () => {
const title = this.event.title;
if (title) {
this.$calendar.fullCalendar('renderEvent',
{
title,
start,
end,
allDay,
backgroundColor: '#64bd63',
textColor: '#fff',
},
true, // make the event "stick"
);
}
this.$calendar.fullCalendar('unselect');
$('#create-event-modal').modal('hide');
};
$('#create-event-modal').modal('show');
},
eventClick: (event) => {
this.event = event;
$('#show-event-modal').modal('show');
},
editable: true,
droppable: true,
drop: (dateItem, event) => { // this function is called when something is dropped
// retrieve the dropped element's stored Event Object
const originalEventObject = {
// use the element's text as the event title
title: $.trim($(event.target).text()),
};
// we need to copy it, so that multiple events don't have a reference to the same object
const copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = dateItem;
copiedEventObject.allDay = !dateItem.hasTime();
const $categoryClass = $(event.target).data('event-class');
if ($categoryClass) {
copiedEventObject.className = [$categoryClass];
}
// render the event on the calendar
// the last `true` argument determines if
// the event 'sticks'
// http://arshaw.com/fullcalendar/docs/event_rendering/renderEvent/)
this.$calendar.fullCalendar('renderEvent', copiedEventObject, true);
$(event.target).remove();
},
};
this.dragOptions = { zIndex: 999, revert: true, revertDuration: 0 };
this.prev = this.prev.bind(this);
this.next = this.next.bind(this);
this.today = this.today.bind(this);
this.changeView = this.changeView.bind(this);
this.getCurrentMonth = this.getCurrentMonth.bind(this);
this.getCurrentDay = this.getCurrentDay.bind(this);
}
componentDidMount() {
this.$calendar = $('#calendar');
this.$calendar.fullCalendar(this.calendarOptions);
$('.draggable').draggable(this.dragOptions);
}
getCurrentMonth() {
return moment(this.$calendar.fullCalendar('getDate')).format('MMM YYYY');
}
getCurrentDay() {
return moment(this.$calendar.fullCalendar('getDate')).format('dddd');
}
prev() {
this.$calendar.fullCalendar('prev');
}
next() {
this.$calendar.fullCalendar('next');
}
today() {
this.$calendar.fullCalendar('today');
}
changeView(view) {
this.$calendar.fullCalendar('changeView', view);
this.setState({ calendarView: view });
}
render() {
return (
<div className={s.root}>
<Row>
<Col lg={4} xs={12} md={6}>
<ol className="breadcrumb">
<li className="breadcrumb-item">YOU ARE HERE</li>
<li className="breadcrumb-item active">Calendar</li>
</ol>
<h1 className="page-title">
{this.state.currentMonth} - <span className="fw-semi-bold">{this.state.currentDay}</span>
</h1>
<h3>Draggable <span className="fw-semi-bold">Events</span></h3>
<p>Just drap and drop events from there directly into the calendar.</p>
<div className="calendar-external-events mb-lg">
<div className="external-event draggable" data-event-class="bg-success text-white">
<i className="fa fa-circle fa-fw text-success ml-xs mr-xs" />
Make a tea
</div>
<div className="external-event draggable" data-event-class="bg-warning text-white">
<i className="fa fa-circle fa-fw text-warning ml-xs mr-xs" />
Open windows
</div>
<div className="external-event draggable" data-event-class="bg-gray text-white">
<i className="fa fa-circle-o fa-fw text-gray-light ml-xs mr-xs" />
Some stuff
</div>
<div className="external-event draggable" data-event-class="bg-danger text-white">
<i className="fa fa-square fa-fw text-danger ml-xs mr-xs" />
Study UX engineering
</div>
<div className="external-event draggable" data-event-class="bg-gray text-white">
<i className="fa fa-circle-o fa-fw text-gray-light ml-xs mr-xs" />
Another stuff
</div>
</div>
</Col>
<Col md={6} lg={8} xs={12}>
<Widget>
<Row className="calendar-controls">
<Col md={3}>
<ButtonGroup className="mr-sm">
<Button color="default" onClick={this.prev}>
<i className="fa fa-angle-left" />
</Button>
<Button color="default" onClick={this.next}>
<i className="fa fa-angle-right" />
</Button>
</ButtonGroup>
</Col>
<Col md={9} className="calendar-controls text-right">
<ButtonGroup>
<Button
color="default" onClick={() => this.changeView('month')}
active={this.state.calendarView === 'month'}
>Month</Button>
<Button
color="default" onClick={() => this.changeView('agendaWeek')}
active={this.state.calendarView === 'agendaWeek'}
>Week</Button>
<Button
color="default" onClick={() => this.changeView('agendaDay')}
active={this.state.calendarView === 'agendaDay'}
>Day</Button>
</ButtonGroup>
</Col>
</Row>
<div id="calendar" className="calendar" />
</Widget>
</Col>
</Row>
</div>
);
}
}
export default Calendar;
@import '../../../../styles/app';
:global {
@import '../../../../../node_modules/fullcalendar/dist/fullcalendar';
}
.root {
h4 {
font-size: 14px;
}
:global {
.fc-grid th {
text-transform: uppercase;
}
.fc-day-grid-event {
margin: 0;
padding: 0;
}
.fc-event {
border: none;
font-weight: $font-weight-normal;
background-color: $gray-200;
color: $text-color;
}
.fc-today {
background-color: #fff1b8;
}
a.fc-event {
height: auto;
line-height: $line-height-base;
width: 100%;
}
/* **** Full Calendar Custom **** */
.full-calendar {
margin-top: 10px;
}
.calendar-controls {
.btn {
font-size: $font-size-mini;
}
}
.calendar-external-events {
margin-top: 20px;
.external-event {
margin: 10px 0;
padding: 6px;
font-size: $font-size-mini;
cursor: pointer;
border-radius: $border-radius;
background-color: $white;
border: 1px solid #ccc;
box-shadow: var(--widget-shadow);
}
}
.widget-calendar {
@include media-breakpoint-up(xl) {
margin-top: -100px;
}
}
}
}
{
"name": "calendar",
"version": "0.0.0",
"private": true,
"main": "./Calendar.js"
}
import React from 'react';
import {
Button,
ButtonGroup,
Breadcrumb,
BreadcrumbItem,
} from 'reactstrap';
import Lightbox from 'react-images';
import s from './Gallery.module.scss';
import pic1 from '../../../../images/pictures/1.jpg';
import pic2 from '../../../../images/pictures/2.jpg';
import pic3 from '../../../../images/pictures/3.jpg';
import pic4 from '../../../../images/pictures/4.jpg';
import pic5 from '../../../../images/pictures/5.jpg';
import pic6 from '../../../../images/pictures/6.jpg';
import pic8 from '../../../../images/pictures/8.jpg';
import pic9 from '../../../../images/pictures/9.jpg';
import pic10 from '../../../../images/pictures/10.jpg';
import pic11 from '../../../../images/pictures/11.jpg';
import pic13 from '../../../../images/pictures/13.jpg';
import pic14 from '../../../../images/pictures/14.jpg';
const items = [
{
name: 'Mountains',
groups: [
'nature',
],
src: pic1,
date: '10 mins',
},
{
name: 'Empire State Pigeon',
groups: [
'people',
],
src: pic2,
date: '1 hour',
like: true,
},
{
name: 'Big Lake',
groups: [
'nature',
],
src: pic3,
date: '2 mins',
like: true,
},
{
name: 'Forest',
groups: [
'nature',
],
src: pic4,
date: '2 mins',
like: true,
},
{
name: 'Smile',
groups: [
'people',
],
src: pic5,
date: '2 mins',
},
{
name: 'Smile',
groups: [
'people',
],
src: pic6,
date: '1 hour',
like: true,
},
{
name: 'Fog',
groups: [
'nature',
],
src: pic8,
date: '2 mins',
like: true,
},
{
name: 'Beach',
groups: [
'people',
],
src: pic9,
date: '2 mins',
},
{
name: 'Pause',
groups: [
'people',
],
src: pic10,
date: '3 hour',
like: true,
},
{
name: 'Space',
groups: [
'space',
],
src: pic11,
date: '3 hour',
like: true,
},
{
name: 'Shuttle',
groups: [
'space',
],
src: pic13,
date: '35 mins',
like: true,
},
{
name: 'Sky',
groups: [
'space',
],
src: pic14,
date: '2 mins',
},
];
class Gallery extends React.Component {
constructor() {
super();
this.state = {
currentImage: 0,
lightboxIsOpen: false,
children: items,
activeGroup: 'all',
order: 'asc',
theme: {
arrow: {
':focus': {
outline: 0,
},
},
close: {
':focus': {
outline: 0,
},
},
},
};
this.closeLightbox = this.closeLightbox.bind(this);
this.gotoNext = this.gotoNext.bind(this);
this.gotoPrevious = this.gotoPrevious.bind(this);
this.gotoImage = this.gotoImage.bind(this);
this.handleClickImage = this.handleClickImage.bind(this);
this.openLightbox = this.openLightbox.bind(this);
}
openLightbox(index, event) {
event.preventDefault();
this.setState({
currentImage: index,
lightboxIsOpen: true,
});
}
gotoPrevious() {
this.setState({
currentImage: this.state.currentImage - 1,
});
}
gotoImage(index) {
this.setState({
currentImage: index,
});
}
gotoNext() {
this.setState({
currentImage: this.state.currentImage + 1,
});
}
closeLightbox() {
this.setState({
currentImage: 0,
lightboxIsOpen: false,
});
}
handleClickImage() {
if (this.state.currentImage === this.state.children.length - 1) return;
this.gotoNext();
}
filterChildren(type) {
this.setState({
children: type === 'all' ? items : items.filter((child) => {
const group = child.groups.find(item => item === type);
return !!group;
}),
activeGroup: type,
});
}
orderChildren(order) {
const children = this.state.children.sort((a, b) => {
const nameA = a.name.toLowerCase();
const nameB = b.name.toLowerCase();
if (nameA < nameB) {
return order === 'asc' ? -1 : 1;
}
if (nameA > nameB) {
return order === 'asc' ? 1 : -1;
}
return 0;
});
this.setState({ children, order });
}
render() {
return (
<div className={s.root}>
<Breadcrumb>
<BreadcrumbItem>YOU ARE HERE</BreadcrumbItem>
<BreadcrumbItem active>Gallery</BreadcrumbItem>
</Breadcrumb>
<h1 className="page-title">Media - <span className="fw-semi-bold">Images</span>
</h1>
<div className={s.galleryControls}>
<ButtonGroup id="shuffle-buttons">
<Button color="default" onClick={() => this.filterChildren('all')} active={this.state.activeGroup === 'all'}>All</Button>
<Button color="default" onClick={() => this.filterChildren('nature')} active={this.state.activeGroup === 'nature'}>Nature</Button>
<Button color="default" onClick={() => this.filterChildren('people')} active={this.state.activeGroup === 'people'}>People</Button>
<Button color="default" onClick={() => this.filterChildren('space')} active={this.state.activeGroup === 'space'}>Space</Button>
</ButtonGroup>
<ButtonGroup id="order-buttons">
<Button color="default" onClick={() => this.orderChildren('asc')} active={this.state.order === 'asc'}><i className="fa fa-sort-numeric-asc" /></Button>
<Button color="default" onClick={() => this.orderChildren('desc')} active={this.state.order === 'desc'}><i className="fa fa-sort-numeric-desc" /></Button>
</ButtonGroup>
</div>
<div className={s.gallery}>
{this.state.children.map((item, index) => {
const key = item.name + index;
return (
<div key={key} className={`${s.picture} card`}>
<a href={item.src} onClick={e => this.openLightbox(index, e)}><img className="figure-img" src={item.src} alt="..." /></a>
<div className={s.description}>
<h6 className="mt-0 mb-xs">{item.name}</h6>
<ul className="post-links">
<li><button className="btn-link">{item.date}</button></li>
<li><button className="btn-link"><span className="text-danger"><i className={`fa ${item.like ? 'fa-heart' : 'fa-heart-o'}`} /> Like</span></button></li>
<li><button className="btn-link">Details</button></li>
</ul>
</div>
</div>
);
})}
</div>
<Lightbox
currentImage={this.state.currentImage}
images={this.state.children}
isOpen={this.state.lightboxIsOpen}
onClickPrev={this.gotoPrevious}
onClickNext={this.gotoNext}
onClose={this.closeLightbox}
onClickImage={this.handleClickImage}
onClickThumbnail={this.gotoImage}
backdropClosesModal
enableKeyboardInput
theme={this.state.theme}
/>
</div>);
}
}
export default Gallery;
@import '../../../../styles/app';
.root {
:global .tile {
display: inline-block;
}
}
.galleryControls {
display: flex;
justify-content: space-between;
margin-bottom: $spacer;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-gap: 15px;
}
.picture {
padding: 3px;
border-radius: $border-radius;
background-color: $white;
> a {
overflow: hidden;
}
:global .figure-img {
width: 100%;
transition: $transition-base;
}
&:hover {
:global .figure-img {
transform: scale(1.1, 1.1);
}
}
}
.description {
padding: ($spacer * 0.85) ($spacer * 0.5);
}
{
"name": "invoice",
"version": "0.0.0",
"private": true,
"main": "./Gallery.js"
}
/* eslint class-methods-use-this: ["error", { "exceptMethods": ["printInvoice"] }] */
import React from 'react';
import {
Row,
Col,
Table,
ButtonToolbar,
Button,
} from 'reactstrap';
import s from './Invoice.module.scss';
import Widget from '../../../../components/Widget';
import iLogo from '../../../../images/invoice-logo.png';
class Stats extends React.Component {
printInvoice() {
window.print();
}
render() {
return (
<Row>
<Col lg={11}>
<Row className={s.root}>
<Col xs={12}>
<Widget>
<div className="widget">
<header>
<Row>
<Col md="6" xs="12" className="col-print-6">
<img src={iLogo} alt="Logo" className={s.invoiceLogo} />
</Col>
<Col md="6" xs="12" className="col-print-6">
<h4 className="text-right">
#<span className="fw-semi-bold">9.45613</span> /
<small>17 May 2014</small>
</h4>
<div className="text-muted fs-larger text-right">
Some Invoice number description or whatever
</div>
</Col>
</Row>
</header>
<section className={s.invoiceBody}>
<Row className="mb-lg">
<Col sm={6} className="col-print-6">
<h5 className="text-muted no-margin">Company Information</h5>
<h3 className="company-name m-t-1">
Wrapbootstrap LLC
</h3>
<address>
<strong>2 Infinite Loop</strong><br />
Minsk, Belarus 220004<br />
088.253.5345<br />
<abbr title="Work email">e-mail:</abbr> <a href="mailto:#">email@example.com</a><br />
<abbr title="Work Phone">phone:</abbr> (012) 345-678-901<br />
<abbr title="Work Fax">fax:</abbr> (012) 678-132-901
</address>
</Col>
<Col sm={6} className="col-print-6 text-right">
<h5 className="text-muted no-margin">Client Information</h5>
<h3 className="client-name m-t-1">
Veronica Niasvizhskaja
</h3>
<address>
<strong>Consultant</strong> at
{/* eslint-disable */}
<a href="#">Allspana</a><br />
{/* eslint-enable */}
<abbr title="Work email">e-mail:</abbr> <a href="mailto:#">maryna@allspana.by</a><br />
<abbr title="Work Phone">phone:</abbr> (012) 345-678-901<br />
<abbr title="Work Fax">fax:</abbr> (012) 678-132-901
<p className="no-margin"><strong>Note:</strong></p>
<p className="text-muted">Some nights I stay up cashing in my bad luck.
Some nights I call it a draw</p>
</address>
</Col>
</Row>
<Table className="table-striped">
<thead>
<tr>
<th>#</th>
<th>Item</th>
<th className="hidden-sm-down d-print-none">Description</th>
<th>Quantity</th>
<th className="hidden-sm-down d-print-none">Price per Unit</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Brand-new 27 monitor</td>
<td className="hidden-sm-down d-print-none">2,560x1,440-pixel (WQHD) resolution supported!</td>
<td>2</td>
<td className="hidden-sm-down d-print-none">700</td>
<td>1,400.00</td>
</tr>
<tr>
<td>2</td>
<td>Domain: okendoken.com</td>
<td className="hidden-sm-down d-print-none">6-month registration</td>
<td>1</td>
<td className="hidden-sm-down d-print-none">10.99</td>
<td>21.88</td>
</tr>
<tr>
<td>3</td>
<td>Atlas Shrugged</td>
<td className="hidden-sm-down d-print-none">Novel by Ayn Rand, first published in 1957 in the
United
States
</td>
<td>5</td>
<td className="hidden-sm-down d-print-none">35</td>
<td>175.00</td>
</tr>
<tr>
<td>4</td>
<td>New Song by Dr. Pre</td>
<td className="hidden-sm-down d-print-none">Lyrics: praesent blandit augue non sapien ornare
imperdiet
</td>
<td>1</td>
<td className="hidden-sm-down d-print-none">2</td>
<td>2.00</td>
</tr>
</tbody>
</Table>
<Row>
<Col xs={12} md={8} className="col-print-6">
<p>
<strong>Note:</strong>
Thank you for your business. Keep in mind, sometimes bad things happen. But it&#39;s just
sometimes.
</p>
</Col>
<Col md={4} xs={12} className="col-print-6">
<Row className="text-right justify-content-end">
<Col xs={6} />
<Col sm={3}>
<p>Subtotal</p>
<p>Tax(10%)</p>
<p className="no-margin"><strong>Total</strong></p>
</Col>
<Col sm={3}>
<p>1,598.88</p>
<p>159.89</p>
<p className="no-margin"><strong>1,758.77</strong></p>
</Col>
</Row>
</Col>
</Row>
<p className="text-right mt-lg mb-xs">
Marketing Consultant
</p>
<p className="text-right">
<span className="fw-semi-bold">Bob Smith</span>
</p>
<ButtonToolbar className="mt-lg justify-content-end d-print-none">
<Button onClick={this.printInvoice} color="inverse" className="mr-2">
<i className="fa fa-print" />
&nbsp;&nbsp;
Print
</Button>
<Button color="danger">
Proceed with Payment
&nbsp;
<span className="circle bg-white">
<i className="fa fa-arrow-right text-danger" />
</span>
</Button>
</ButtonToolbar>
</section>
</div>
</Widget>
</Col>
</Row>
</Col>
</Row>);
}
}
export default Stats;
@import '../../../../styles/app';
.root {
.invoiceLogo {
max-height: 50px;
}
.invoiceBody {
margin-top: 70px;
}
:global {
.widget {
padding: 10px 20px;
}
}
}
{
"name": "invoice",
"version": "0.0.0",
"private": true,
"main": "./Invoice.js"
}
This diff is collapsed. Click to expand it.
@import '../../../../styles/app';
.root {
.searchResultCategories {
> li > a {
color: $gray-600;
font-weight: $font-weight-normal;
&:hover {
color: $gray-700;
background-color: $gray-400;
}
}
}
.searchResultsCount {
margin-top: 10px;
}
.searchResultItem {
padding: 20px;
background-color: $white;
border-radius: $border-radius;
box-shadow: var(--widget-shadow);
&:first-of-type {
overflow: hidden;
}
@include clearfix();
.imageLink {
display: block;
overflow: hidden;
border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius;
@include media-breakpoint-up(md) {
display: inline-block;
margin: -20px 0 -20px -20px;
float: left;
width: 200px;
}
@include media-breakpoint-down(sm) {
max-height: 200px;
}
}
.image {
max-width: 100%;
}
.info {
margin-top: 2px;
font-size: $font-size-sm;
color: $text-muted;
}
.description {
font-size: $font-size-mini;
margin-bottom: -5px;
}
+ .searchResultItem {
margin-top: 20px;
}
.searchResultItemBody {
height: auto;
@include media-breakpoint-down(sm) {
margin-top: 10px;
}
@include media-breakpoint-up(md) {
margin-left: 200px;
}
}
.searchResultItemHeading {
font-weight: $font-weight-normal;
> a {
color: $text-color;
}
@include media-breakpoint-up(md) {
margin: 0;
}
}
}
}
{
"name": "search",
"version": "0.0.0",
"private": true,
"main": "./Search.js"
}
This diff is collapsed. Click to expand it.
@import '../../../../styles/app';
/* Post Comments */
.postComments {
font-size: $font-size-sm;
padding-left: 0;
@include clearfix();
.postLinks + & {
margin-top: $spacer / 2;
}
> li {
padding: 10px;
border-top: 1px solid #e7e7e7;
list-style: none;
@include clearfix();
&:last-child {
padding-bottom: 0;
}
}
p:last-child {
margin-bottom: 0;
}
.avatar {
margin-top: 1px;
}
.author {
margin-top: 0;
margin-bottom: 2px;
color: #7ca9dd;
}
.commentBody {
overflow: auto;
}
h6.author > small {
font-size: 11px;
}
:global {
.widget > footer & {
margin-left: -$widget-padding-horizontal;
margin-right: -$widget-padding-horizontal;
}
}
}
/* Post Links */
.postLinks {
margin-bottom: 0;
font-size: $font-size-sm;
padding-left: 0;
@include clearfix();
> li {
float: left;
list-style: none;
+ li {
&::before {
color: #999;
content: '\25cf';
padding: 0 8px;
}
}
> a {
text-decoration: none;
color: $text-muted;
:hover {
color: $text-muted;
}
}
}
:global {
.no-separator > li + li {
margin-left: 12px;
&::before {
content: normal;
}
}
}
}
/* Time Line */
.timeline {
position: relative;
min-height: 100%;
list-style: none;
padding-left: 0;
margin-bottom: -40px; /* content padding bottom */
padding-bottom: 80px;
> li {
@include clearfix();
+ li {
margin-top: 30px;
}
}
/* the time line :) */
&::before {
position: absolute;
top: 0;
bottom: 0;
left: 24%;
width: 8px;
content: ' ';
margin-left: -4px;
background-color: $white;
@include media-breakpoint-up(lg) {
left: 50%;
margin-left: -4px;
}
}
}
.event {
background: $white;
border-radius: $border-radius;
padding: 20px 20px 0;
position: relative;
box-shadow: var(--widget-shadow);
.timeline & {
float: right;
width: 68%;
&::before {
right: 100%;
content: ' ';
height: 0;
width: 0;
position: absolute;
border: 10px solid rgba(0, 0, 0, 0);
border-right-color: $white;
top: 15px;
}
}
.postComments {
margin-left: -20px;
margin-right: -20px;
}
> footer {
margin: 20px -20px 0;
padding: 10px 20px;
border-bottom-left-radius: $border-radius;
border-bottom-right-radius: $border-radius;
background-color: #fafafa;
@include clearfix();
:global {
.thumb {
margin-left: 10px;
}
}
}
@include media-breakpoint-up(lg) {
.timeline & {
width: 45%;
}
.timeline > li.onLeft & {
float: left;
&::before {
right: auto;
left: 100%;
border-right-color: rgba(0, 0, 0, 0);
border-left-color: $white;
}
}
}
}
.eventTime {
.timeline & {
float: left;
width: 18%;
margin-top: 5px;
text-align: right;
> .date {
display: block;
font-size: $font-size-larger;
}
> .time {
display: block;
font-size: $font-size-lg;
font-weight: $font-weight-normal;
}
}
@include media-breakpoint-up(lg) {
.timeline & {
width: 46%;
}
.timeline > li.onLeft & {
float: right;
text-align: left;
}
}
}
.eventIcon {
:global {
.glyphicon {
top: -2px;
}
}
.timeline & {
position: absolute;
left: 24%;
width: 50px;
height: 50px;
line-height: 37px;
margin-left: -25px;
background-color: $white;
border: 7px solid $white;
border-radius: 50%;
text-align: center;
box-shadow: var(--widget-shadow);
&.eventIconDanger {
background-color: theme-color('danger');
border-color: lighten(theme-color('danger'), 7%);
}
&.eventIconWarning {
background-color: theme-color('warning');
border-color: lighten(theme-color('warning'), 7%);
}
&.eventIconSuccess {
background-color: theme-color('success');
border-color: lighten(theme-color('success'), 7%);
}
&.eventIconInfo {
background-color: theme-color('info');
border-color: lighten(theme-color('info'), 7%);
}
&.eventIconPrimary {
background-color: theme-color('primary');
border-color: lighten(theme-color('primary'), 7%);
}
&.eventIconDanger,
&.eventIconWarning,
&.eventIconSuccess,
&.eventIconInfo,
&.eventIconPrimary {
color: $white;
}
@include media-breakpoint-up(lg) {
left: 50%;
}
> img {
width: 36px;
height: 36px;
margin-top: -4px;
}
}
}
.eventHeading {
margin: 0 0 2px;
font-weight: $font-weight-semi-bold;
> a {
text-decoration: none;
color: #7ca9dd;
}
> small {
font-weight: $font-weight-semi-bold;
> a {
text-decoration: none;
color: $text-muted;
}
}
}
.eventMap {
display: block;
height: 200px;
margin: 0 -20px -20px;
overflow: visible !important;
}
.eventImage {
margin: 0 -20px -20px;
max-height: 260px;
overflow: hidden;
> img {
max-width: 100%;
}
}
{
"name": "timeline",
"version": "0.0.0",
"main": "./Timeline.js",
"private": true
}
This diff is collapsed. Click to expand it.
@import '../../../../styles/app';
:global {
@import '../../../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg';
@import '../../../../../node_modules/react-select2-wrapper/css/select2';
@import '../../../../../node_modules/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox';
@import '../../../../../node_modules/react-datetime/css/react-datetime';
@import '../../../../../node_modules/rc-color-picker/dist/rc-color-picker';
@import '../../../../../node_modules/bootstrap-slider/dist/css/bootstrap-slider';
@import '../../../../../node_modules/jasny-bootstrap/dist/css/jasny-bootstrap';
@import '../../../../../node_modules/react-mde/lib/styles/scss/react-mde-all';
}
.autogrow {
overflow: hidden;
resize: none;
}
.wysiwygWrapper {
border: 1px solid #ccc !important;
overflow: visible;
height: 270px;
}
.wysiwygToolbar {
color: $gray-800 !important;
background-color: #ddd !important;
border-color: transparent !important;
:global {
.rdw-option-wrapper {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
height: 30px;
min-width: 30px;
margin: 0;
background: #f8f8f8;
}
.rdw-dropdown-wrapper {
background: #f8f8f8;
}
}
}
.wysiwygEditor {
position: relative !important;
overflow: hidden !important;
height: 150px;
line-height: 0.1;
}
.select2 {
:global {
.select2-container {
width: 100% !important;
}
.select2-selection--single {
border-color: $input-border-color;
&,
& :global .select2-selection__arrow {
height: $input-height;
}
& :global .select2-selection__rendered {
line-height: $input-height;
}
}
}
}
.root {
:global {
/*
* Switchery.
*/
.abc-checkbox,
.abc-radio {
.form-check-input {
position: relative;
margin: 0;
}
}
.display-inline-block {
display: inline-block;
}
.display-none {
display: none;
}
.switch {
box-sizing: content-box;
}
.switch input {
display: none;
}
.switch i {
display: inline-block;
cursor: pointer;
padding-right: 20px;
transition: all ease 0.2s;
-webkit-transition: all ease 0.2s;
border-radius: 20px;
box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.5);
}
.switch i::before {
display: block;
content: '';
width: 30px;
height: 30px;
padding: 1px;
border-radius: 20px;
background: white;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.switch :checked + i {
padding-right: 0;
padding-left: 20px;
background: rgb(100, 189, 99);
}
/* Datepicker */
.datepicker {
.input-group-addon {
display: inline-block;
position: relative;
top: -2px;
left: -2px;
}
i.glyphicon {
vertical-align: top;
}
.rdt {
display: inline-block;
}
}
/* slider */
$slider-line-height: 8px;
$slider-handle-size: 26px;
.slider {
display: inline-block;
vertical-align: middle;
position: relative;
.slider-handle {
position: absolute;
width: $slider-handle-size;
height: $slider-handle-size;
background: $white;
border: 0 solid transparent;
@include box-shadow(inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 3px rgba(0, 0, 0, 5));
&:focus {
outline: 0;
}
&.round {
border-radius: 50%;
}
&.triangle {
background: transparent none;
}
}
&.slider-horizontal {
width: 210px;
height: $slider-line-height;
.slider-track {
height: $slider-line-height/2;
width: 100%;
margin-top: -$slider-line-height/4;
top: 50%;
left: 0;
}
.slider-selection {
height: 100%;
top: 0;
bottom: 0;
}
.slider-handle {
margin-left: -$slider-handle-size/2;
margin-top: -$slider-handle-size*3/8;
&.triangle {
border-width: 0 $slider-line-height/2 $slider-line-height/2 $slider-line-height/2;
width: 0;
height: 0;
border-bottom-color: #0480be;
margin-top: 0;
}
}
}
&.slider-vertical {
height: 210px;
width: $slider-line-height;
.slider-track {
width: $slider-line-height/2;
height: 100%;
margin-left: -$slider-line-height/4;
left: 50%;
top: 0;
}
.slider-selection {
width: 100%;
left: 0;
top: 0;
bottom: 0;
}
.slider-handle {
margin-left: -$slider-handle-size*3/8;
margin-top: -$slider-handle-size/2;
&.triangle {
border-width: $slider-line-height/2 0 $slider-line-height/2 $slider-line-height/2;
width: 1px;
height: 1px;
border-left-color: #0480be;
margin-left: 0;
}
}
}
&.slider-disabled {
.slider-handle {
// @include gradient-y(#dfdfdf, #bebebe);
}
.slider-track {
@include gradient-y(#e5e5e5, #e9e9e9);
cursor: not-allowed;
}
}
input {
display: none;
}
.tooltip-inner {
white-space: nowrap;
}
}
.slider-selection {
position: absolute;
background: theme-color('primary');
@include box-shadow(inset 0 -1px 0 rgba(0, 0, 0, 0.15));
box-sizing: border-box;
border-radius: $border-radius;
}
.slider-danger .slider .slider-selection {
background: theme-color('danger'); // $brand-danger;
}
.slider-success .slider .slider-selection {
background: theme-color('success'); // $brand-success;
}
.slider-warning .slider .slider-selection {
background: theme-color('warning'); // $brand-warning;
}
.slider-info .slider .slider-selection {
background: theme-color('info'); // $brand-info;
}
.slider-inverse .slider .slider-selection {
background: $gray-700; // $gray;
}
.slider-track {
position: absolute;
cursor: pointer;
border-radius: $border-radius;
@include gradient-y(#eee, #f8f8f8);
@include box-shadow(inset 0 1px 2px rgba(0, 0, 0, 0.1));
}
/* file input */
.fileinput.fileinput-new {
.thumbnail {
padding: $thumbnail-padding;
line-height: $line-height-base;
background-color: $thumbnail-bg;
border: $thumbnail-border-width solid $thumbnail-border-color;
border-radius: $thumbnail-border-radius;
transition: all 0.2s ease-in-out;
@include box-shadow(0 1px 2px rgba(0, 0, 0, 0.075));
}
&.fileinput-fix {
width: 200px;
height: 150px;
}
}
.btn {
label {
margin-bottom: 0;
}
}
.fileinput-preview.fileinput-exists {
border: 1px solid $input-border-color;
border-radius: $border-radius;
padding: 5px;
}
.fileinput.input-group {
display: flex;
}
.fileinput-new.input-group .btn-file,
.fileinput-new .input-group .btn-file {
border-radius: 0 $border-radius $border-radius 0;
&.btn-xs,
&.btn-sm {
border-radius: 0 $border-radius-sm $border-radius-sm 0;
}
&.btn-lg {
border-radius: 0 $border-radius-lg $border-radius-lg 0;
}
}
.form-group.has-warning .fileinput {
.fileinput-preview {
color: #fff;
}
.thumbnail {
border-color: theme-color('warning');
}
}
.form-group.has-error .fileinput {
.fileinput-preview {
color: #fff;
}
.thumbnail {
border-color: theme-color('danger');
}
}
.form-group.has-success .fileinput {
.fileinput-preview {
color: #fff;
}
.thumbnail {
border-color: theme-color('success');
}
}
.btn-label {
background: transparent;
left: 2px;
padding: 1px 6px;
}
// Opposite alignment of blockquote
.blockquote {
padding: ($spacer / 2) $spacer;
margin-bottom: $spacer;
font-size: $blockquote-font-size;
border-left: 0.25rem solid $gray-300;
}
.blockquote footer {
display: block;
font-size: 80%; // back to default font-size
color: $blockquote-small-color;
&::before {
content: '\2014 \00A0'; // em dash, nbsp
}
}
.blockquote-reverse {
padding-right: $spacer;
padding-left: 0;
text-align: right;
border-right: 0.25rem solid $gray-300;
border-left: 0;
}
.blockquote-reverse footer {
&::before {
content: '';
}
&::after {
content: '\00A0 \2014'; // nbsp, em dash
}
}
}
}
.dropzone {
width: 100%;
text-align: center;
padding: 40px 10px;
height: 200px;
border: 2px dashed #ccc;
@include border-radius($border-radius);
img {
max-height: 100px;
max-width: 150px;
border-radius: 5px;
}
}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.