diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..e8d01750 --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [["es2015", {"modules": false}], "react", "stage-1"], + "plugins": ["transform-regenerator", "react-hot-loader/babel", "transform-decorators-legacy"], + "env": { + "start": { + "presets": [ + "react-hmre" + ] + } + } +} \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..45e28d22 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +node_modules/* +dist/* +src/public/* +src/server/* +config/* +.vscode/* +webpack* \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..7ea9f66f --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,43 @@ +{ + "extends": "airbnb", + "env": { + "es6": true, + "browser": true, + "node": false, + "jquery": false, + "mocha": true + }, + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 6, + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + }, + "sourceType": "module" + }, + "plugins": [ + "import" + ], + "rules": { + "indent": [2, 2], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ], + "no-console": 1, + "prefer-const": "error", + "no-var": "error" + }, + "settings": { + "import/resolver": { + "webpack": { + "config": "webpack.common.js" + } + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..45b8b8ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +dist +node_modules +*.DS_Store +.vscode +yarn.lock +package-lock.json +config \ No newline at end of file diff --git a/README.md b/README.md index 7168fcbb..a635a036 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # opla-front + Opla.ai Frontend using Node es7 react and redux # Getting started + To deploy/use Opla.ai use /opla repository instead. # licence + GPL v2.0+ diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..29239fec --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "ES6" + }, + "files": [ + "src/" + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..7403db29 --- /dev/null +++ b/package.json @@ -0,0 +1,70 @@ +{ + "name": "opla-front", + "version": "1.3.2", + "description": "The admin dashboard for bots", + "main": "index.js", + "repository": { + "url": "git@gitlab.zoapp.com:mik/opla-dashboard", + "type": "git" + }, + "author": "mik ", + "license": "UNLICENSED", + "scripts": { + "start:node": "NODE_PATH=$NODE_PATH:./shared node --harmony ./dist", + "start:dev": "webpack-dev-server --env=dev --inline", + "lint:prod": "eslint src --ext=js --ext=jsx", + "lint:dev": "eslint src --rule 'no-console: off' --ext=js --ext=jsx --fix", + "build:dev": "webpack --env=dev --progress --profile --colors", + "build:prod": "webpack --env=prod --progress --profile --colors" + }, + "dependencies": { + "babel-runtime": "^6.26.0", + "chart.js": "2.7.1", + "css-loader": "^0.28.7", + "json-loader": "0.5.4", + "mdl-selectfield": "^1.0.4", + "prop-types": "15.6.0", + "react": "16.2.0", + "react-chartjs-2": "2.6.4", + "react-dnd": "2.5.4", + "react-dnd-html5-backend": "2.5.4", + "react-dom": "16.2.0", + "react-hot-loader": "3.1.3", + "react-mdl": "1.11.0", + "react-redux": "5.0.6", + "react-router": "^4.2.0", + "react-router-dom": "^4.2.2", + "redux": "3.7.2", + "redux-devtools": "3.4.1", + "redux-devtools-dock-monitor": "1.1.2", + "redux-devtools-log-monitor": "1.4.0", + "redux-saga": "0.16.0", + "style-loader": "^0.19.1", + "zoapp-common": "0.1.0", + "zoapp-ui": "0.1.5" + }, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-core": "^6.26.0", + "babel-eslint": "^8.0.3", + "babel-loader": "^7.1.2", + "babel-plugin-transform-decorators": "^6.24.1", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-regenerator": "6.26.0", + "babel-plugin-transform-runtime": "^6.23.0", + "babel-polyfill": "^6.26.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-0": "^6.24.1", + "copy-webpack-plugin": "4.3.0", + "eslint": "^4.13.1", + "eslint-config-airbnb": "16.1.0", + "eslint-import-resolver-webpack": "0.8.4", + "eslint-plugin-import": "2.8.0", + "eslint-plugin-jsx-a11y": "6.0.3", + "eslint-plugin-react": "^7.5.1", + "webpack": "^3.10.0", + "webpack-dev-server": "^2.11.0", + "webpack-merge": "^4.1.1" + } +} diff --git a/src/client/index.jsx b/src/client/index.jsx new file mode 100644 index 00000000..ad6fd219 --- /dev/null +++ b/src/client/index.jsx @@ -0,0 +1,109 @@ +import React from "react"; +import { render } from "react-dom"; +import { Provider } from "react-redux"; +import { BrowserRouter } from "react-router-dom"; +import { AppContainer } from "react-hot-loader"; +import { DialogManager } from "zoapp-ui"; + +import configureStore from "OplaLibs/store"; +import App from "OplaContainers/app"; + +// import DevTools from "../shared/containers/DevTools"; +/* eslint-enable no-unused-vars */ + +const store = configureStore(); + +DialogManager.init(store); + +/* eslint-enable no-restricted-syntax */ +const mountNode = document.getElementById("app"); + +/* const deleteScript = (filename) => { + const scripts = [...document.getElementsByTagName("script")]; + scripts.find((script) => { + if (script.getAttribute("src") === filename) { + script.parentNode.removeChild(script); + return true; + } + return false; + }); +}; + +const loadScript = (filename, callback) => { + const script = document.createElement("script"); + script.setAttribute("type", "text/javascript"); + script.setAttribute("src", filename); + script.onload = callback; + const body = document.getElementsByTagName("body")[0]; + body.appendChild(script); +}; */ + +const renderApp = (Root) => { + render( + + + + + + + , + mountNode, + ); +}; + +/* global module */ +if (module.hot) { + /* eslint-disable global-require */ + /* eslint-disable no-undef */ + // const rootPath = "./shared/container/app"; + module.hot.accept("OplaContainers/app", () => { + console.log("HMR app"); + /* ReactDOM.unmountComponentAtNode(mountNode); + const parent = mountNode.parentNode; + parent.removeChild(mountNode); + mountNode = document.createElement("div"); + mountNode.id = "app"; + parent.insertBefore(mountNode, parent.firstChild); + deleteScript("js/material.js"); + deleteScript("js/material.ext.js"); + window.componentHandler = null; + window.MaterialButton = null; + window.MaterialCheckbox = null; + window.MaterialIconToggle = null; + window.MaterialMenu = null; + window.MaterialProgress = null; + window.MaterialRadio = null; + window.MaterialSlider = null; + window.MaterialSnackbar = null; + window.MaterialSpinner = null; + window.MaterialSwitch = null; + window.MaterialTabs = null; + window.MaterialTextfield = null; + window.MaterialTooltip = null; + window.MaterialLayout = null; + window.MaterialLayoutTab = null; + window.MaterialDataTable = null; + window.MaterialRipple = null; + + loadScript("js/material.js", () => { + loadScript("js/material.ext.js", () => { + const newApp = require("OplaContainers/app").default; + renderApp(newApp); + }); + }); */ + const newApp = require("OplaContainers/app").default; + renderApp(newApp); + }); + /* eslint-enable no-undef */ + /* eslint-enable global-require */ + // module.hot.accept(); +} + +renderApp(App); + +/* + // global // process // require +if (process.env.NODE_ENV !== "production") { + const showDevTools = require("./showDevTools"); + showDevTools(store); +} */ diff --git a/src/client/showDevTools.jsx b/src/client/showDevTools.jsx new file mode 100644 index 00000000..1b05ee22 --- /dev/null +++ b/src/client/showDevTools.jsx @@ -0,0 +1,17 @@ +/* eslint-disable no-unused-vars */ +import React from "react"; +import { render } from "react-dom"; +import DevTools from "../shared/containers/devTools"; +/* eslint-enable no-unused-vars */ + +/* global window setTimeout */ +export default function showDevTools(store) { + const popup = window.open(null, "Redux DevTools", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no"); + // Reload in case it already exists + popup.location.reload(); + + setTimeout(() => { + popup.document.write("
"); + render(, popup.document.getElementById("react-devtools-root")); + }, 10); +} diff --git a/src/plugins/app-connector/appSettings.jsx b/src/plugins/app-connector/appSettings.jsx new file mode 100644 index 00000000..9a6001cf --- /dev/null +++ b/src/plugins/app-connector/appSettings.jsx @@ -0,0 +1,100 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; + +export default class AppSettings extends Component { + onAction = (action) => { + if (action === "Build") { + console.log("onAction Build TODO"); + } + this.props.onAction(action); + } + + renderCreateApp() { + const { instance } = this.props; + console.log("instance=", instance); + const app = instance.application; + let appId = ""; + let appSecret = ""; + if (app) { + appId = app.id; + appSecret = app.secret; + } + let botUrl = ""; + if (instance.url) { + botUrl = ( + {instance.url} + ); + } + const botId = instance.origin; + + return ( +
+
Link to webapp :
+
{botUrl} +
+ +
Or install SDK and set these parameters :
+
botId : {botId} +
+
appId : {appId} +
+
appSecret : {appSecret} +
+ +
); + } + + render() { + const style = { + height: "200px", + width: "502px", + position: "relative", + }; + let container =
Loading...
; + if (this.props.instance && this.props.instance.application) { + container = this.renderCreateApp(); + } + return ( +
+
+ {container} +
+
); + } +} + +AppSettings.propTypes = { + onAction: PropTypes.func.isRequired, + instance: PropTypes.shape({ application: PropTypes.shape({}) }).isRequired, +}; diff --git a/src/plugins/app-connector/appTemplate.jsx b/src/plugins/app-connector/appTemplate.jsx new file mode 100644 index 00000000..57794933 --- /dev/null +++ b/src/plugins/app-connector/appTemplate.jsx @@ -0,0 +1,152 @@ +import React, { Component } from "react"; +import { Button } from "react-mdl"; +import PropTypes from "prop-types"; +import { Stepper } from "zoapp-ui"; + + +export default class AppTemplate extends Component { + static renderConnectApp() { + return ( +
+
Run your app to connect and test it, now.
+
); + } + + constructor() { + super(); + this.state = { + steps: [ + { + id: "1", title: "Create App", editable: true, active: true, + }, + { + id: "2", title: "Connect App", + }, + { + id: "3", title: "Interactions", optional: true, + }, + { + id: "4", title: "Publish", optional: true, + }, + ], + selectedStep: 0, + }; + } + + onAction = (action) => { + if (action === "Build") { + this.setSelectedStep(1, true); + } + this.props.onAction(action); + } + + setSelectedStep(index, editable = false) { + const steps = [...this.state.steps]; + let step = null; + if (index > -1 && index < steps.length) { + for (let i = 0; i < index; i += 1) { + steps[i].editable = false; + steps[i].active = true; + } + for (let i = index + 1; i < steps.length; i += 1) { + if (steps[i].editable) { + steps[i].editable = false; + } + } + step.id = `${index}`; + step = steps[index]; + step.editable = editable; + step.active = true; + this.setState({ steps, selectedStep: index }); + } + return step; + } + + renderCreateApp() { + return ( +
+
Download a code template :
+
+ + + +
+
Or install SDK and set appId / appSecret :
+
appId : cMty8cGsUI2hQfqinzAwMqtPEZ8rUIIuOlYldbZMUHOR4Wx9rSHRbqHFE4CO9HSh +
+
appSecret : sDi8tEAh3qXzlsN1TQeh4p8NcsBCULTA84SUZmLcTty260I9ji9y6ra2p9v34u6E +
+ +
); + } + + render() { + const style = { + height: "200px", + width: "502px", + position: "relative", + }; + const { steps, selectedStep } = this.state; + let container = (
TODO
); + if (selectedStep === 0) { + container = this.renderCreateApp(); + } else { + container = AppTemplate.renderConnectApp(); + } + return ( +
+ { this.setSelectedStep(index, true); }} /> +
+ {container} +
+
); + } +} + +AppTemplate.propTypes = { + onAction: PropTypes.func.isRequired, +}; diff --git a/src/plugins/app-connector/index.jsx b/src/plugins/app-connector/index.jsx new file mode 100644 index 00000000..fb9b048a --- /dev/null +++ b/src/plugins/app-connector/index.jsx @@ -0,0 +1,64 @@ +import React from "react"; +import AppSettings from "./appSettings"; +import AppTemplate from "./appTemplate"; + +export default class ExternalAppPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "app-connector", + title: "Native/Web App", + icon: "devices", + color: "gray", + type: "MessengerConnector", + isActive: true, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + onAction = (action) => { + console.log("onAction=", action); + } + + renderSettings(instance, onAction = null, publicUrl = null) { + let oa = onAction; + if (!oa) { + oa = this.onAction; + } + this.params.onAction = oa; + this.params.publicUrl = publicUrl; + return (); + } + + renderTemplate() { + return (); + } +} diff --git a/src/plugins/dummy-plugin/index.jsx b/src/plugins/dummy-plugin/index.jsx new file mode 100644 index 00000000..ede875af --- /dev/null +++ b/src/plugins/dummy-plugin/index.jsx @@ -0,0 +1,39 @@ +import React from "react"; + +export default class DummyPlugin { + constructor(connector, params) { + this.connector = connector; + this.params = params; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon || "images/robot.svg"; + } + + getColor() { + return this.params.color || "gray"; + } + + isActive() { + // TODO + return this.params.isActive; + } + + isType(type) { + return type === this.params.type; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/email-connector/index.jsx b/src/plugins/email-connector/index.jsx new file mode 100644 index 00000000..62906975 --- /dev/null +++ b/src/plugins/email-connector/index.jsx @@ -0,0 +1,50 @@ +import React from "react"; + +export default class EmailPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "email-connector", + title: "Email", + icon: "email", + color: "orange", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/fb-messenger/fbContainer.jsx b/src/plugins/fb-messenger/fbContainer.jsx new file mode 100644 index 00000000..de5a3614 --- /dev/null +++ b/src/plugins/fb-messenger/fbContainer.jsx @@ -0,0 +1,264 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, Textfield } from "react-mdl"; + +export default class FBContainer extends Component { + constructor() { + super(); + this.state = { + /* pages: null, */ + fbInit: false, + isStarted: false, + isConnected: false, + message: "You need to connect your Facebook account. Or you could set a manual connection.", + }; + } + + componentDidMount() { + window.fbAsyncInit = (() => { + window.FB.init({ + appId: this.props.appId, + cookie: true, + xfbml: true, + version: "v2.8", + }); + window.FB.AppEvents.logPageView(); + + window.FB.Event.subscribe("auth.logout", this.onLogout.bind(this)); + window.FB.Event.subscribe("auth.statusChange", this.onStatusChange.bind(this)); + this.setState({ fbInit: true }); + this.start(); + }); + + // Load the SDK asynchronously + (((d, s, id) => { + let js = null; + const fjs = d.getElementsByTagName(s)[0]; + if (d.getElementById(id)) { + this.start(); + this.setState({ fbInit: true }); + return; + } + js = d.createElement(s); js.id = id; + js.src = "//connect.facebook.net/en_US/sdk.js"; + fjs.parentNode.insertBefore(js, fjs); + })(document, "script", "facebook-jssdk")); + } + + onStatusChange(response) { + console.log(response); + if (response.status === "connected") { + this.connected(); + } + } + + onLogout() { + this.setState({ message: "" }); + } + + onButtonAction(action) { + console.log("buttonAction=", action); + if (action === "Login") { + this.login(); + } else if (action === "Manual") { + this.manualConnection(); + } else if (action === "Logout") { + this.logout(); + } + } + + getPages() { + const that = this; + // https://developers.facebook.com/docs/graph-api/reference/user/accounts/ + window.FB.api("/me/accounts", (response) => { + console.log("getPages =", response); + if (response && response.data) { + that.setState({ pages: response.data }); + } else { + const message = "Error can't get pages "; + that.setState({ message }); + } + }); + } + + start() { + if (this.state.isStarted) return; + + console.log("started"); + this.setState({ isStarted: true }); + window.FB.getLoginStatus((response) => { + console.log("start=", response); + if (response.status === "connected") { + this.connected(); + } + }); + } + + connected() { + if (this.state.isConnected) return; + + console.log("connected"); + this.setState({ isConnected: true }); + const that = this; + window.FB.api("/me", (response) => { + const message = `Welcome ${response.name}`; + that.setState({ message }); + that.getPages(); + }); + } + + login() { + const that = this; + window.FB.login((response) => { + if (response.authResponse) { + console.log("Welcome! Fetching your information.... "); + that.connected(); + } else { + console.log("User cancelled login or did not fully authorize."); + } + }, { scope: "public_profile,manage_pages" }); + } + + logout() { + window.FB.logout(() => { + console.log("Logout"); + this.setState({ isConnected: false }); + }); + } + + manualConnection() { + // TODO + this.props.onAction("Manual"); + } + + renderLogin(visibility) { + const action = this.state.isConnected ? "Logout" : "Login"; + return ( +
+
{}} + onClick={(event) => { + event.stopPropagation(); + this.onButtonAction(action); + }} + > +
+ + + +
+
{action}
+
+
{this.state.message}
+ +
); + } + + renderConnect(visibility) { + return ( +
+ { this.textField1 = input; }} + /> + { this.textField2 = input; }} + /> +
); + } + + render() { + const visibility = this.state.fbInit ? "visible" : "hidden"; + const { selectedStep } = this.props; + if (selectedStep === 0) { + return this.renderLogin(visibility); + } else if (selectedStep === 1) { + return this.renderConnect(visibility); + } + return ( +
{selectedStep} TODO +
); + } +} + +FBContainer.propTypes = { + appId: PropTypes.string.isRequired, + selectedStep: PropTypes.number.isRequired, + onAction: PropTypes.func.isRequired, +}; diff --git a/src/plugins/fb-messenger/fbSettings.jsx b/src/plugins/fb-messenger/fbSettings.jsx new file mode 100644 index 00000000..4d87e3d6 --- /dev/null +++ b/src/plugins/fb-messenger/fbSettings.jsx @@ -0,0 +1,96 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Textfield, IconButton } from "react-mdl"; + +export default class FBSettings extends Component { + onAction = (action) => { + if (action === "Manual") { + // TODO + } + this.props.onAction(action); + } + + render() { + const instance = this.props.instance || {}; + const style = { + width: "502px", + position: "relative", + }; + // TODO set better patterns + return ( +
+
+ { }} + spellCheck={false} + style={{ width: "320px" }} + required + ref={(input) => { this.tfBotName = input; }} + /> + { }} + spellCheck={false} + style={{ width: "320px" }} + required + ref={(input) => { this.tfAccessToken = input; }} + /> + { }} + spellCheck={false} + style={{ width: "320px" }} + required + ref={(input) => { this.tfVerifyToken = input; }} + /> +
{ this.tfCallback = input; }} + /> +
+
+ +
); + } +} + +FBSettings.defaultProps = { + instance: null, + onAction: () => { }, +}; + +FBSettings.propTypes = { + instance: PropTypes.shape({}), + onAction: PropTypes.func, +}; diff --git a/src/plugins/fb-messenger/fbTemplate.jsx b/src/plugins/fb-messenger/fbTemplate.jsx new file mode 100644 index 00000000..a27a12a9 --- /dev/null +++ b/src/plugins/fb-messenger/fbTemplate.jsx @@ -0,0 +1,72 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Stepper } from "zoapp-ui"; +import { FBContainer } from "./fbContainer"; + +export default class FBTemplate extends Component { + constructor() { + super(); + this.state = { + steps: [ + { title: "Fb login", editable: true, active: true }, + { title: "Connect page" }, + { title: "Interactions", optional: true }, + { title: "Publish", optional: true }, + ], + selectedStep: 0, + }; + } + + onAction = (action) => { + if (action === "Manual") { + this.setSelectedStep(1, true); + } + this.props.onAction(action); + } + + setSelectedStep(index, editable = false) { + const steps = [...this.state.steps]; + let step = null; + if (index > -1 && index < steps.length) { + for (let i = 0; i < index; i += 1) { + steps[i].editable = false; + steps[i].active = true; + } + for (let i = index + 1; i < steps.length; i += 1) { + if (steps[i].editable) { + steps[i].editable = false; + } + } + step = steps[index]; + step.editable = editable; + step.active = true; + this.setState({ steps, selectedStep: index }); + } + return step; + } + + render() { + const style = { + height: "200px", + width: "502px", + position: "relative", + }; + const { steps, selectedStep } = this.state; + return ( +
+ { this.setSelectedStep(index, true); }} /> +
+ +
+
); + } +} + +FBTemplate.propTypes = { + appId: PropTypes.string.isRequired, + onAction: PropTypes.func.isRequired, +}; diff --git a/src/plugins/fb-messenger/index.jsx b/src/plugins/fb-messenger/index.jsx new file mode 100644 index 00000000..06a85580 --- /dev/null +++ b/src/plugins/fb-messenger/index.jsx @@ -0,0 +1,63 @@ +import React from "react"; +import FBSettings from "./fbSettings"; +import FBTemplate from "./fbTemplate"; + +export default class FBMessengerPlugin { + constructor(connector, config = {}) { + this.connector = connector; + this.config = config; + this.name = "fb-messenger"; + this.title = "Facebook Messenger"; + // from https://simpleicons.org/ + this.icon = "images/messenger.svg"; + this.color = "#0084FF"; + this.active = true; + this.type = "MessengerConnector"; + } + + getName() { + return this.name; + } + + getTitle() { + return this.title; + } + + getIcon() { + return this.icon; + } + + getColor() { + return this.color; + } + + isActive() { + // TODO + return this.active; + } + + getType() { + return this.type; + } + + isType(type) { + return type === this.getType(); + } + + onAction(action) { + console.log("onAction=", action, this.active); + } + + renderTemplate() { + return (); + } + + renderSettings(instance, onAction, publicUrl = null) { + return (); + } +} diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 00000000..da9d7cae --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,42 @@ +import FBMessengerPlugin from "./fb-messenger"; +import ExternalAppPlugin from "./app-connector"; +import WPPlugin from "./wp-connector"; +import SlackPlugin from "./slack-connector"; +import SMSPlugin from "./sms-connector"; +import TwitterPlugin from "./twitter-connector"; +import EmailPlugin from "./email-connector"; +import SkypePlugin from "./skype-connector"; +import TelegramPlugin from "./telegram-connector"; + +import OplaAIPlugin from "./opla-ai"; + +import DummyPlugin from "./dummy-plugin"; + +export default (manager, callback) => { +// TODO dynamic importing plugins + callback(new FBMessengerPlugin(manager, { appId: "1908982232707706" })); + callback(new ExternalAppPlugin(manager)); + callback(new SlackPlugin(manager)); + callback(new WPPlugin(manager)); + callback(new SMSPlugin(manager)); + callback(new TwitterPlugin(manager)); + callback(new EmailPlugin(manager)); + callback(new SkypePlugin(manager)); + callback(new TelegramPlugin(manager)); + + callback(new OplaAIPlugin(manager)); + callback(new DummyPlugin(manager, { + name: "simple-nlu", title: "Simple NLU", type: "AIProvider", icon: "images/robot2.svg", + })); + callback(new DummyPlugin(manager, { name: "rasa-nlu", title: "RASA NLU", type: "AIProvider" })); + callback(new DummyPlugin(manager, { name: "watson-ai", title: "Watson AI", type: "AIProvider" })); + callback(new DummyPlugin(manager, { name: "wit-ai", title: "Wit.AI", type: "AIProvider" })); + callback(new DummyPlugin(manager, { name: "api-ai", title: "Api.AI", type: "AIProvider" })); + callback(new DummyPlugin(manager, { name: "lex-ai", title: "Amazon Lex", type: "AIProvider" })); + callback(new DummyPlugin(manager, { name: "luis-ai", title: "MS Luis", type: "AIProvider" })); + + callback(new DummyPlugin(manager, { name: "gdoc-plugins", title: "Google Docs", type: "WebServices" })); + callback(new DummyPlugin(manager, { name: "msoffice-plugins", title: "MS Office", type: "WebServices" })); + callback(new DummyPlugin(manager, { name: "salesforce-plugins", title: "Salesforce", type: "WebServices" })); + callback(new DummyPlugin(manager, { name: "ifttt-plugin", title: "IFTTT", type: "WebServices" })); +}; diff --git a/src/plugins/opla-ai/index.js b/src/plugins/opla-ai/index.js new file mode 100644 index 00000000..7b7687f5 --- /dev/null +++ b/src/plugins/opla-ai/index.js @@ -0,0 +1,47 @@ +import Settings from "./settings"; + +export default class OplaAIPlugin { + constructor(connector) { + this.connector = connector; + this.name = "opla-ai"; + this.title = "Opla NLU"; + this.icon = "images/opla-bubble.svg"; + this.color = "dark"; + this.active = true; + this.type = "AIProvider"; + } + + getName() { + return this.name; + } + + getTitle() { + return this.title; + } + + getIcon() { + return this.title; + } + + getColor() { + return this.color; + } + + isActive() { + // TODO + return this.active; + } + + getType() { + return this.type; + } + + isType(type) { + return type === this.getType(); + } + + renderSettings() { + this.todo = {}; + return Settings(); + } +} diff --git a/src/plugins/opla-ai/settings.jsx b/src/plugins/opla-ai/settings.jsx new file mode 100644 index 00000000..deb41167 --- /dev/null +++ b/src/plugins/opla-ai/settings.jsx @@ -0,0 +1,7 @@ +import React from "react"; + +const OAISettings = () => ( +
TODO
+); +const renderSettings = () => ; +export default renderSettings; diff --git a/src/plugins/skype-connector/index.jsx b/src/plugins/skype-connector/index.jsx new file mode 100644 index 00000000..fca5824d --- /dev/null +++ b/src/plugins/skype-connector/index.jsx @@ -0,0 +1,51 @@ +import React from "react"; + +export default class SkypePlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "skype-connector", + title: "Skype", + // from https://simpleicons.org/ + icon: "images/skype.svg", + color: "#00AFF0", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/slack-connector/index.jsx b/src/plugins/slack-connector/index.jsx new file mode 100644 index 00000000..07747e56 --- /dev/null +++ b/src/plugins/slack-connector/index.jsx @@ -0,0 +1,51 @@ +import React from "react"; + +export default class SlackPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "slack-connector", + title: "Slack", + // from https://simpleicons.org/ + icon: "images/slack.svg", + color: "#56B68B", + type: "MessengerConnector", + isActive: true, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/sms-connector/index.jsx b/src/plugins/sms-connector/index.jsx new file mode 100644 index 00000000..f144bd45 --- /dev/null +++ b/src/plugins/sms-connector/index.jsx @@ -0,0 +1,50 @@ +import React from "react"; + +export default class SMSPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "sms-connector", + title: "SMS", + icon: "sms", + color: "green", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/telegram-connector/index.jsx b/src/plugins/telegram-connector/index.jsx new file mode 100644 index 00000000..cd240f66 --- /dev/null +++ b/src/plugins/telegram-connector/index.jsx @@ -0,0 +1,50 @@ +import React from "react"; + +export default class TelegramPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "telegram-connector", + title: "Telegram", + icon: "images/telegram.svg", + color: "#2CA5E0", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/twitter-connector/index.jsx b/src/plugins/twitter-connector/index.jsx new file mode 100644 index 00000000..72e31047 --- /dev/null +++ b/src/plugins/twitter-connector/index.jsx @@ -0,0 +1,50 @@ +import React from "react"; + +export default class TwitterPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "twitter-connector", + title: "Twitter", + icon: "images/twitter.svg", + color: "#1DA1F2", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/plugins/wp-connector/index.jsx b/src/plugins/wp-connector/index.jsx new file mode 100644 index 00000000..2c031065 --- /dev/null +++ b/src/plugins/wp-connector/index.jsx @@ -0,0 +1,51 @@ +import React from "react"; + +export default class WPPlugin { + constructor(connector) { + this.connector = connector; + this.params = { + name: "wp-connector", + title: "Wordpress", + // from https://simpleicons.org/ + icon: "images/wordpress.svg", + color: "#21759B", + type: "MessengerConnector", + isActive: false, + }; + } + + getName() { + return this.params.name; + } + + getTitle() { + return this.params.title; + } + + getIcon() { + return this.params.icon; + } + + getColor() { + return this.params.color; + } + + getType() { + return this.params.type; + } + + isType(type) { + return type === this.getType(); + } + + isActive() { + // TODO + return this.params.isActive; + } + + renderSettings(instance, onAction = null, publicUrl = null) { + this.params.onAction = onAction; + this.params.publicUrl = publicUrl; + return (
TODO
); + } +} diff --git a/src/public/css/animate.min.css b/src/public/css/animate.min.css new file mode 100644 index 00000000..df8188ae --- /dev/null +++ b/src/public/css/animate.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8";/*! +Animate.css - http://daneden.me/animate +Licensed under the MIT license - http://opensource.org/licenses/MIT + +Copyright (c) 2014 Daniel Eden +*/.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}@-webkit-keyframes bounce{0%,100%,20%,53%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,100%,20%,53%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;-ms-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,100%,50%{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,100%,50%{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;-ms-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes bounceIn{0%,100%,20%,40%,60%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{0%,100%,20%,40%,60%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceInDown{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{0%{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideInDown{0%{-webkit-transform:translateY(-100%);transform:translateY(-100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translateX(100%);transform:translateX(100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight{0%{-webkit-transform:translateX(100%);transform:translateX(100%);visibility:visible}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes slideInUp{0%{-webkit-transform:translateY(100%);transform:translateY(100%);visibility:visible}100%{-webkit-transform:translateY(0);transform:translateY(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(100%);transform:translateY(100%)}}@keyframes slideOutDown{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(100%);transform:translateY(100%)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes slideOutLeft{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes slideOutRight{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{visibility:hidden;-webkit-transform:translateX(100%);transform:translateX(100%)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@keyframes slideOutUp{0%{-webkit-transform:translateY(0);transform:translateY(0)}100%{visibility:hidden;-webkit-transform:translateY(-100%);transform:translateY(-100%)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp} \ No newline at end of file diff --git a/src/public/css/dialog-polyfill.css b/src/public/css/dialog-polyfill.css new file mode 100644 index 00000000..4b13625e --- /dev/null +++ b/src/public/css/dialog-polyfill.css @@ -0,0 +1,46 @@ +dialog { + position: absolute; + left: 0; right: 0; + width: -moz-fit-content; + width: -webkit-fit-content; + width: fit-content; + height: -moz-fit-content; + height: -webkit-fit-content; + height: fit-content; + margin: auto; + border: solid; + padding: 1em; + background: white; + color: black; + display: none; +} + +dialog[open] { + display: block; +} + +dialog + .backdrop { + position: fixed; + top: 0; right: 0; bottom: 0; left: 0; + background: rgba(0,0,0,0.1); +} + +/* for small devices, modal dialogs go full-screen */ +@media screen and (max-width: 540px) { + dialog[_polyfill_modal] { /* TODO: implement */ + top: 0; + width: auto; + margin: 1em; + } +} + +._dialog_overlay { + position: fixed; + top: 0; right: 0; bottom: 0; left: 0; +} + +dialog.fixed { + position: fixed; + top: 50%; + transform: translate(0, -50%); +} \ No newline at end of file diff --git a/src/public/css/main.css b/src/public/css/main.css new file mode 100644 index 00000000..efb529a0 --- /dev/null +++ b/src/public/css/main.css @@ -0,0 +1,612 @@ +@import url(https://fonts.googleapis.com/icon?family=Material+Icons); + +html, body { + font-family: "Roboto","Helvetica", "Arial", sans-serif; +} + +.gray_dot { + height: 12px; + width: 12px; + background-color: #757575; + border-radius: 50%; + margin-right: 8px; + display: inline-block; +} + +.mdl-textfield__input { + font-family: "Roboto","Helvetica", "Arial", sans-serif; +} + +/*.mdl-list_action { + height: 58px !important; +}*/ + +.fileInput { + overflow: hidden; + position: relative; +} + +.fileInput [type=file] { + cursor: inherit; + display: block; + font-size: 999px; + filter: alpha(opacity=0); + min-height: 100%; + min-width: 100%; + opacity: 0; + position: absolute; + right: 0; + text-align: right; + top: 0; +} + +a { + color: rgba(34, 190, 196, 1); + font-weight: 500; +} + +.mdl-layout__drawer > .mdl-layout__title, .mdl-layout__drawer > .mdl-layout-title { + font-weight: 900; + color: rgb(85, 38, 130); +} + +.mdl-layout__tab-bar { + background-color: transparent; + padding: 32px 300px 0px 0px; + height: 100%; + width: 480px; +} +.mdl-layout__drawer .mdl-navigation .mdl-navigation__link { + padding-left: 48px; +} +.mdl-layout__drawer .mdl-navigation .mdl-navigation__link > i { + position: absolute; + left: 10px; +} + +.mdl-navigation__selectedlink { + background: rgba(34, 190, 196, 1); + color: white !important; + font-weight: 500; +} + +.mdl-layout__drawer .mdl-navigation .mdl-navigation__link:hover { + background: rgb(85, 38, 130); + color: white; +} + +.mdl-layout__drawer .mdl-navigation { + padding-top: 0px; +} + +.mdl-layout.is-upgraded .mdl-layout__tab.is-active { + color: #757575; +} + +.mdl-layout__tab { + color: rgb(221, 221, 221); +} + +.mdl-layout.is-upgraded .mdl-layout__tab.is-active::after { + background: rgb(85, 38, 130); +} + +/* Example stylistic flourishes */ + +.fileInput { + background: #bbb; + border-radius: 40px; + padding: 20px; + margin: 30px 60px; + width: 40px; + height: 40px; +} + +.fileInput [type=file] { + cursor: pointer; +} + +[contenteditable]:focus { + outline: 0px solid transparent; +} + +.mdl-chip__text_ex { + font-size: 13px; + vertical-align: inherit; + display: inline-block; +} + +.dialog_bg { + width: 100%; + height: 100%; + /*position: fixed;*/ +} + + +.mdl-list__item .mdl-list__item-primary-content .mdl-list__item-icon { + color: rgb(221,221,221); +} + +.mrb-panel { + min-width: 150px; +} + +.mrb-panel-header { + padding: 0px; + background: white; + color: #757575; + font-size: 18px; + line-height: 48px; + height: 48px; + min-height: 48px; + border-bottom: 1px solid #e1e1e1; +} + +.mrb-panel-empty { + background: linear-gradient(to bottom, + rgba(255, 255, 255, 0.95) 0%, + rgba(255, 255, 255, 0.85) 70%, + rgba(255, 255, 255, 0.75) 100%); +} + +.mrb-panel-empty::before { + content: ' '; + display: block; + position: absolute; + width: 64.5%; + height: 80%; + z-index: -1; + background-position: 100% 0; + /*background-image: url("../images/bot-builder.gif");*/ + background-repeat: no-repeat; +} + +.mrb-panel-header-icon { + font-size: 24px; + line-height: 48px; + width:32px; + float: left; + margin-right: 2px; + margin-left: 8px; + color: rgb(221,221,221); +} + +.mrb-panel-header-title { + float: left; + font-weight: bold; +} + +.mrb-panel-header .mdl-layout__header-row { + height: 48px; + padding: 0px; +} + +.mrb-panel-header__actions { + height: 48px; + float: right; + padding-right: 16px; +} + +.mrb-panel .mdl-list { + margin-top: 0px; + padding-top: 0px; +} + +.messenger-box-test { + width: 100%; + margin: 0px; +} + +.mrb-action-button { + min-width: 320px; + background-color: #F2F2F2; +} + +.mrb-action-button-mid { + min-width: 200px; + background-color: #F2F2F2; +} + +.mdl-list__item .mdl-list__item-primary-content { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.mdl-chip__text { + vertical-align: initial; +} + +.mdl-list__item--two-line .mdl-list__item-primary-content { + height: initial; +} + +.selectedListItem { + background: rgba(34, 190, 196, 0.10); + font-weight: bold; +} + +.selectedListItem span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.selectedListItem:hover { + background: rgba(85,38,130, 0.10); + cursor: pointer; +} + +.selectableListItem { + color: #757575; +} + +.selectableListItem:hover { + background: rgba(85,38,130, 0.10); + cursor: pointer; +} + +.onFocusAction > .mdl-list__item-secondary-content { + display: none; +} + +.onFocusAction:hover > .mdl-list__item-secondary-content { + display: flex; +} + +.onFocusAction:hover > span > span { + color: #757575 !important; +} + +.onFocusAction:hover > span > i { + color: #757575 !important; +} + +.mdl-switch.is-checked .mdl-switch__track { + background: rgba(85,38,130, 0.5); +} +.mdl-switch.is-checked .mdl-switch__thumb { + background: #552682; +} + +.mdl-tabs.is-upgraded .mdl-tabs__tab.is-active:after { + background: #552682; +} + +.mdl-checkbox.is-checked .mdl-checkbox__box-outline { + border: 2px solid #552682; +} + +.mdl-checkbox__ripple-container .mdl-ripple { + background: #552682; +} + +.mrb-sublist .mdl-list { + margin: 0px; + padding: 0px; +} + +.mrb-subheader { + text-transform: capitalize; + height: 48px; +} +.mrb-subheader > div { + padding-left: 18px; + line-height: 48px; + font-size: 15px; + color: rgba(0,0,0, 0.87); +} + +.list-content > .mdl-list__item { + font-size: 14px; +} + +.mrb-subheader-right { + float: right; + margin-right: 16px; + margin-top: 4px; + color: rgba(0,0,0,0.38); +} + +.mrb-subheader-right i { + line-height: 32px; +} + +.mrb-subheader-menu { + left: 20px; +} + +.mrb-sublist { + padding-top: 0px; +} + +.mrb-sublist h4 { + padding-left: 24px; + margin: 0px; + font-size: 16px; + color: #757575; +} + +.mdl-button--accent.mdl-button--accent.mdl-button--raised, .mdl-button--accent.mdl-button--accent.mdl-button--fab { + color: rgb(255,255,255); + background-color: rgba(34, 190, 196, 1); +} + +.mdl-layout__header .mdl-layout__drawer-button { + color: rgba(0,0,0, 0.87); +} +.mdl-layout__header { + color: #212121; + background-color: rgba(255, 255, 255, 1); +} +.mdl-layout__header-row { + color: #212121; +} + +.mdl-layout__drawer { + border-right: 1px solid rgba(66, 66, 66, 0.25); + background: #263238; +} +.mdl-layout__drawer > .mdl-layout__title, .mdl-layout__drawer > .mdl-layout-title { + background-color: #fcea20; +} + +.mdl-dialog-extended { + width: 550px; +} + +.mdl-dialog-list { + width: 320px; +} + +.mdl-dialog-list > .mdl-dialog_inner > .mdl-dialog__content { + padding: 0px 0px 24px 0px; +} + +.mdl-dialog_inner { + background-color: #552682; +} + +.mdl-dialog__title { + font-size: 20px; + font-weight: 400; + line-height: 24px; + color: white; + padding-bottom: 20px; +} + +.mdl-dialog__content { + font-size: 15px; + background-color: white; +} + +.mdl-dialog__actions { + background-color: white; +} + +dialog { + padding: 0px; +} + +.mdl-button--raised.mdl-button--colored { + background-color: #552682; + color: white; +} +.mdl-button--raised.mdl-button--colored:hover { + background-color: #552682; + color: white; +} +.mdl-button.mdl-button--colored > i { + color: #552682; +} +.mdl-textfield--floating-label.is-focused .mdl-textfield__label, +.mdl-textfield--floating-label.is-dirty .mdl-textfield__label, +.mdl-textfield--floating-label.has-placeholder .mdl-textfield__label { + color: #552682; +} +.mdl-textfield__label:after { + background-color: #552682; +} +.mdl-checkbox.is-upgraded { + padding-left: 20px; +} + +hr { + /* For white theme */ + border-top: 1px solid #e1e1e1; + -webkit-margin-before: 0; + -webkit-margin-after: 0; +} + +.mdl-layout__content { + height: 100%; +} + +.mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-icon { + height: 100%; +} +.mdl-list__item .mdl-list__item-primary-content { + width:92%; +} + +.bear-icon { + background-image: url(../images/bear.png); + background-size: 80%; + background-position: 3px; + background-repeat: no-repeat; + margin-left: 10px; +} + +.opla-icon { + background-image: url(../images/opla-bubble.svg); + background-size: 80%; + background-position: 5px; + background-repeat: no-repeat; + margin-left: 10px; +} + +.list-box { + height:84vh; +} + +.list-content { + position: relative; + overflow-x: hidden; + overflow-y: auto; + height: 100%; +} + +.service_start i { + color: green !important; +} + +.service_stop i { + color: rgb(117,117,117) !important; +} + +.service_error i { + color: red !important; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step { + width: 25%; + /* 100 / no_of_steps */ +} + + +/* Begin actual mdl-stepper css styles */ + +.mdl-stepper-horizontal-alternative { + display: table; + width: 100%; + margin: 0 auto; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step { + display: table-cell; + position: relative; + padding: 24px; +} + +.active-step { + cursor: pointer; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:hover, +.mdl-stepper-horizontal-alternative .mdl-stepper-step:active { + background-color: rgba(0, 0, 0, .06); +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:active { + border-radius: 15% / 75%; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:first-child:active { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:last-child:active { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:hover .mdl-stepper-circle { + background-color: #757575; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step:first-child .mdl-stepper-bar-left, +.mdl-stepper-horizontal-alternative .mdl-stepper-step:last-child .mdl-stepper-bar-right { + display: none; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-circle { + width: 24px; + height: 24px; + margin: 0 auto; + background-color: #9E9E9E; + border-radius: 50%; + text-align: center; + line-height: 2em; + font-size: 12px; + color: white; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.active-step .mdl-stepper-circle { + background-color: rgb(33, 150, 243); +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.step-done .mdl-stepper-circle:before { + content: "\2714"; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.step-done .mdl-stepper-circle *, +.mdl-stepper-horizontal-alternative .mdl-stepper-step.editable-step .mdl-stepper-circle * { + display: none; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.editable-step .mdl-stepper-circle { + -moz-transform: scaleX(-1); + /* Gecko */ + -o-transform: scaleX(-1); + /* Opera */ + -webkit-transform: scaleX(-1); + /* Webkit */ + transform: scaleX(-1); + /* Standard */ +} + +/* From https://codepen.io/sharafat_8271/pen/KVWMXP */ +.mdl-stepper-horizontal-alternative .mdl-stepper-step.editable-step .mdl-stepper-circle:before { + content: "\270E"; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-title { + margin-top: 16px; + font-size: 14px; + font-weight: normal; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-title, +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-optional { + text-align: center; + color: rgba(0, 0, 0, .26); +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.active-step .mdl-stepper-title { + font-weight: 500; + color: rgba(0, 0, 0, .87); +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.active-step.step-done .mdl-stepper-title, +.mdl-stepper-horizontal-alternative .mdl-stepper-step.active-step.editable-step .mdl-stepper-title { + font-weight: 300; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-optional { + font-size: 12px; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step.active-step .mdl-stepper-optional { + color: rgba(0, 0, 0, .54); +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-bar-left, +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-bar-right { + position: absolute; + top: 36px; + height: 1px; + border-top: 1px solid #BDBDBD; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-bar-right { + right: 0; + left: 50%; + margin-left: 20px; +} + +.mdl-stepper-horizontal-alternative .mdl-stepper-step .mdl-stepper-bar-left { + left: 0; + right: 50%; + margin-right: 20px; +} \ No newline at end of file diff --git a/src/public/css/material.css b/src/public/css/material.css new file mode 100644 index 00000000..ef84ee61 --- /dev/null +++ b/src/public/css/material.css @@ -0,0 +1,11466 @@ +/** + * material-design-lite - Material Design Components in CSS, JS and HTML + * @version v1.2.1 + * @license Apache-2.0 + * @copyright 2015 Google, Inc. + * @link https://github.com/google/material-design-lite + */ +@charset "UTF-8"; +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Material Design Lite */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/* + * What follows is the result of much research on cross-browser styling. + * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, + * Kroc Camen, and the H5BP dev community and team. + */ +/* ========================================================================== + Base styles: opinionated defaults + ========================================================================== */ +html { + color: rgba(0,0,0, 0.87); + font-size: 1em; + line-height: 1.4; } + +/* + * Remove text-shadow in selection highlight: + * https://twitter.com/miketaylr/status/12228805301 + * + * These selection rule sets have to be separate. + * Customize the background color to match your design. + */ +::-moz-selection { + background: #b3d4fc; + text-shadow: none; } +::selection { + background: #b3d4fc; + text-shadow: none; } + +/* + * A better looking default horizontal rule + */ +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; } + +/* + * Remove the gap between audio, canvas, iframes, + * images, videos and the bottom of their containers: + * https://github.com/h5bp/html5-boilerplate/issues/440 + */ +audio, +canvas, +iframe, +img, +svg, +video { + vertical-align: middle; } + +/* + * Remove default fieldset styles. + */ +fieldset { + border: 0; + margin: 0; + padding: 0; } + +/* + * Allow only vertical resizing of textareas. + */ +textarea { + resize: vertical; } + +/* ========================================================================== + Browser Upgrade Prompt + ========================================================================== */ +.browserupgrade { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; } + +/* ========================================================================== + Author's custom styles + ========================================================================== */ +/* ========================================================================== + Helper classes + ========================================================================== */ +/* + * Hide visually and from screen readers: + */ +.hidden { + display: none !important; } + +/* + * Hide only visually, but have it available for screen readers: + * http://snook.ca/archives/html_and_css/hiding-content-for-accessibility + */ +.visuallyhidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +/* + * Extends the .visuallyhidden class to allow the element + * to be focusable when navigated to via the keyboard: + * https://www.drupal.org/node/897638 + */ +.visuallyhidden.focusable:active, +.visuallyhidden.focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; } + +/* + * Hide visually and from screen readers, but maintain layout + */ +.invisible { + visibility: hidden; } + +/* + * Clearfix: contain floats + * + * For modern browsers + * 1. The space content is one way to avoid an Opera bug when the + * `contenteditable` attribute is included anywhere else in the document. + * Otherwise it causes space to appear at the top and bottom of elements + * that receive the `clearfix` class. + * 2. The use of `table` rather than `block` is only necessary if using + * `:before` to contain the top-margins of child elements. + */ +.clearfix:before, +.clearfix:after { + content: " "; + /* 1 */ + display: table; + /* 2 */ } + +.clearfix:after { + clear: both; } + +/* ========================================================================== + EXAMPLE Media Queries for Responsive Design. + These examples override the primary ('mobile first') styles. + Modify as content requires. + ========================================================================== */ +@media only screen and (min-width: 35em) { + /* Style adjustments for viewports that meet the condition */ } + +@media print, (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 1.25dppx), (min-resolution: 120dpi) { + /* Style adjustments for high resolution devices */ } + +/* ========================================================================== + Print styles. + Inlined to avoid the additional HTTP request: + http://www.phpied.com/delay-loading-your-print-css/ + ========================================================================== */ +@media print { + *, + *:before, + *:after, + *:first-letter { + background: transparent !important; + color: #000 !important; + /* Black prints faster: http://www.sanbeiji.com/archives/953 */ + box-shadow: none !important; } + a, + a:visited { + text-decoration: underline; } + a[href]:after { + content: " (" attr(href) ")"; } + abbr[title]:after { + content: " (" attr(title) ")"; } + /* + * Don't show links that are fragment identifiers, + * or use the `javascript:` pseudo protocol + */ + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; } + /* + * Printing Tables: + * http://css-discuss.incutio.com/wiki/Printing_Tables + */ + thead { + display: table-header-group; } + tr, + img { + page-break-inside: avoid; } + img { + max-width: 100% !important; } + p, + h2, + h3 { + orphans: 3; + widows: 3; } + h2, + h3 { + page-break-after: avoid; } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Remove the unwanted box around FAB buttons */ +/* More info: http://goo.gl/IPwKi */ +a, .mdl-accordion, .mdl-button, .mdl-card, .mdl-checkbox, .mdl-dropdown-menu, +.mdl-icon-toggle, .mdl-item, .mdl-radio, .mdl-slider, .mdl-switch, .mdl-tabs__tab { + -webkit-tap-highlight-color: transparent; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); } + +/* + * Make html take up the entire screen + * Then set touch-action to avoid touch delay on mobile IE + */ +html { + width: 100%; + height: 100%; + -ms-touch-action: manipulation; + touch-action: manipulation; } + +/* +* Make body take up the entire screen +* Remove body margin so layout containers don't cause extra overflow. +*/ +body { + width: 100%; + min-height: 100%; + margin: 0; } + +/* + * Main display reset for IE support. + * Source: http://weblog.west-wind.com/posts/2015/Jan/12/main-HTML5-Tag-not-working-in-Internet-Explorer-91011 + */ +main { + display: block; } + +/* +* Apply no display to elements with the hidden attribute. +* IE 9 and 10 support. +*/ +*[hidden] { + display: none !important; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +html, body { + font-family: "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 20px; } + +h1, h2, h3, h4, h5, h6, p { + margin: 0; + padding: 0; } + +/** + * Styles for HTML elements + */ +h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 56px; + font-weight: 400; + line-height: 1.35; + letter-spacing: -0.02em; + opacity: 0.54; + font-size: 0.6em; } + +h1 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 56px; + font-weight: 400; + line-height: 1.35; + letter-spacing: -0.02em; + margin-top: 24px; + margin-bottom: 24px; } + +h2 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 45px; + font-weight: 400; + line-height: 48px; + margin-top: 24px; + margin-bottom: 24px; } + +h3 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 34px; + font-weight: 400; + line-height: 40px; + margin-top: 24px; + margin-bottom: 24px; } + +h4 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 24px; + font-weight: 400; + line-height: 32px; + -moz-osx-font-smoothing: grayscale; + margin-top: 24px; + margin-bottom: 16px; } + +h5 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1; + letter-spacing: 0.02em; + margin-top: 24px; + margin-bottom: 16px; } + +h6 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.04em; + margin-top: 24px; + margin-bottom: 16px; } + +p { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + margin-bottom: 16px; } + +a { + color: rgb(255,64,129); + font-weight: 500; } + +blockquote { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + position: relative; + font-size: 24px; + font-weight: 300; + font-style: italic; + line-height: 1.35; + letter-spacing: 0.08em; } + blockquote:before { + position: absolute; + left: -0.5em; + content: '“'; } + blockquote:after { + content: '”'; + margin-left: -0.05em; } + +mark { + background-color: #f4ff81; } + +dt { + font-weight: 700; } + +address { + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; + font-style: normal; } + +ul, ol { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; } + +/** + * Class Name Styles + */ +.mdl-typography--display-4 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 112px; + font-weight: 300; + line-height: 1; + letter-spacing: -0.04em; } + +.mdl-typography--display-4-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 112px; + font-weight: 300; + line-height: 1; + letter-spacing: -0.04em; + opacity: 0.54; } + +.mdl-typography--display-3 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 56px; + font-weight: 400; + line-height: 1.35; + letter-spacing: -0.02em; } + +.mdl-typography--display-3-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 56px; + font-weight: 400; + line-height: 1.35; + letter-spacing: -0.02em; + opacity: 0.54; } + +.mdl-typography--display-2 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 45px; + font-weight: 400; + line-height: 48px; } + +.mdl-typography--display-2-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 45px; + font-weight: 400; + line-height: 48px; + opacity: 0.54; } + +.mdl-typography--display-1 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 34px; + font-weight: 400; + line-height: 40px; } + +.mdl-typography--display-1-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 34px; + font-weight: 400; + line-height: 40px; + opacity: 0.54; } + +.mdl-typography--headline { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 24px; + font-weight: 400; + line-height: 32px; + -moz-osx-font-smoothing: grayscale; } + +.mdl-typography--headline-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 24px; + font-weight: 400; + line-height: 32px; + -moz-osx-font-smoothing: grayscale; + opacity: 0.87; } + +.mdl-typography--title { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1; + letter-spacing: 0.02em; } + +.mdl-typography--title-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1; + letter-spacing: 0.02em; + opacity: 0.87; } + +.mdl-typography--subhead { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.04em; } + +.mdl-typography--subhead-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.04em; + opacity: 0.87; } + +.mdl-typography--body-2 { + font-size: 14px; + font-weight: bold; + line-height: 24px; + letter-spacing: 0; } + +.mdl-typography--body-2-color-contrast { + font-size: 14px; + font-weight: bold; + line-height: 24px; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--body-1 { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; } + +.mdl-typography--body-1-color-contrast { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--body-2-force-preferred-font { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0; } + +.mdl-typography--body-2-force-preferred-font-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--body-1-force-preferred-font { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; } + +.mdl-typography--body-1-force-preferred-font-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--caption { + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; } + +.mdl-typography--caption-force-preferred-font { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; } + +.mdl-typography--caption-color-contrast { + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; + opacity: 0.54; } + +.mdl-typography--caption-force-preferred-font-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; + opacity: 0.54; } + +.mdl-typography--menu { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 1; + letter-spacing: 0; } + +.mdl-typography--menu-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + line-height: 1; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--button { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; + letter-spacing: 0; } + +.mdl-typography--button-color-contrast { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; + letter-spacing: 0; + opacity: 0.87; } + +.mdl-typography--text-left { + text-align: left; } + +.mdl-typography--text-right { + text-align: right; } + +.mdl-typography--text-center { + text-align: center; } + +.mdl-typography--text-justify { + text-align: justify; } + +.mdl-typography--text-nowrap { + white-space: nowrap; } + +.mdl-typography--text-lowercase { + text-transform: lowercase; } + +.mdl-typography--text-uppercase { + text-transform: uppercase; } + +.mdl-typography--text-capitalize { + text-transform: capitalize; } + +.mdl-typography--font-thin { + font-weight: 200 !important; } + +.mdl-typography--font-light { + font-weight: 300 !important; } + +.mdl-typography--font-regular { + font-weight: 400 !important; } + +.mdl-typography--font-medium { + font-weight: 500 !important; } + +.mdl-typography--font-bold { + font-weight: 700 !important; } + +.mdl-typography--font-black { + font-weight: 900 !important; } + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + word-wrap: normal; + -moz-font-feature-settings: 'liga'; + font-feature-settings: 'liga'; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-color-text--red { + color: rgb(244,67,54) !important; } + +.mdl-color--red { + background-color: rgb(244,67,54) !important; } + +.mdl-color-text--red-50 { + color: rgb(255,235,238) !important; } + +.mdl-color--red-50 { + background-color: rgb(255,235,238) !important; } + +.mdl-color-text--red-100 { + color: rgb(255,205,210) !important; } + +.mdl-color--red-100 { + background-color: rgb(255,205,210) !important; } + +.mdl-color-text--red-200 { + color: rgb(239,154,154) !important; } + +.mdl-color--red-200 { + background-color: rgb(239,154,154) !important; } + +.mdl-color-text--red-300 { + color: rgb(229,115,115) !important; } + +.mdl-color--red-300 { + background-color: rgb(229,115,115) !important; } + +.mdl-color-text--red-400 { + color: rgb(239,83,80) !important; } + +.mdl-color--red-400 { + background-color: rgb(239,83,80) !important; } + +.mdl-color-text--red-500 { + color: rgb(244,67,54) !important; } + +.mdl-color--red-500 { + background-color: rgb(244,67,54) !important; } + +.mdl-color-text--red-600 { + color: rgb(229,57,53) !important; } + +.mdl-color--red-600 { + background-color: rgb(229,57,53) !important; } + +.mdl-color-text--red-700 { + color: rgb(211,47,47) !important; } + +.mdl-color--red-700 { + background-color: rgb(211,47,47) !important; } + +.mdl-color-text--red-800 { + color: rgb(198,40,40) !important; } + +.mdl-color--red-800 { + background-color: rgb(198,40,40) !important; } + +.mdl-color-text--red-900 { + color: rgb(183,28,28) !important; } + +.mdl-color--red-900 { + background-color: rgb(183,28,28) !important; } + +.mdl-color-text--red-A100 { + color: rgb(255,138,128) !important; } + +.mdl-color--red-A100 { + background-color: rgb(255,138,128) !important; } + +.mdl-color-text--red-A200 { + color: rgb(255,82,82) !important; } + +.mdl-color--red-A200 { + background-color: rgb(255,82,82) !important; } + +.mdl-color-text--red-A400 { + color: rgb(255,23,68) !important; } + +.mdl-color--red-A400 { + background-color: rgb(255,23,68) !important; } + +.mdl-color-text--red-A700 { + color: rgb(213,0,0) !important; } + +.mdl-color--red-A700 { + background-color: rgb(213,0,0) !important; } + +.mdl-color-text--pink { + color: rgb(233,30,99) !important; } + +.mdl-color--pink { + background-color: rgb(233,30,99) !important; } + +.mdl-color-text--pink-50 { + color: rgb(252,228,236) !important; } + +.mdl-color--pink-50 { + background-color: rgb(252,228,236) !important; } + +.mdl-color-text--pink-100 { + color: rgb(248,187,208) !important; } + +.mdl-color--pink-100 { + background-color: rgb(248,187,208) !important; } + +.mdl-color-text--pink-200 { + color: rgb(244,143,177) !important; } + +.mdl-color--pink-200 { + background-color: rgb(244,143,177) !important; } + +.mdl-color-text--pink-300 { + color: rgb(240,98,146) !important; } + +.mdl-color--pink-300 { + background-color: rgb(240,98,146) !important; } + +.mdl-color-text--pink-400 { + color: rgb(236,64,122) !important; } + +.mdl-color--pink-400 { + background-color: rgb(236,64,122) !important; } + +.mdl-color-text--pink-500 { + color: rgb(233,30,99) !important; } + +.mdl-color--pink-500 { + background-color: rgb(233,30,99) !important; } + +.mdl-color-text--pink-600 { + color: rgb(216,27,96) !important; } + +.mdl-color--pink-600 { + background-color: rgb(216,27,96) !important; } + +.mdl-color-text--pink-700 { + color: rgb(194,24,91) !important; } + +.mdl-color--pink-700 { + background-color: rgb(194,24,91) !important; } + +.mdl-color-text--pink-800 { + color: rgb(173,20,87) !important; } + +.mdl-color--pink-800 { + background-color: rgb(173,20,87) !important; } + +.mdl-color-text--pink-900 { + color: rgb(136,14,79) !important; } + +.mdl-color--pink-900 { + background-color: rgb(136,14,79) !important; } + +.mdl-color-text--pink-A100 { + color: rgb(255,128,171) !important; } + +.mdl-color--pink-A100 { + background-color: rgb(255,128,171) !important; } + +.mdl-color-text--pink-A200 { + color: rgb(255,64,129) !important; } + +.mdl-color--pink-A200 { + background-color: rgb(255,64,129) !important; } + +.mdl-color-text--pink-A400 { + color: rgb(245,0,87) !important; } + +.mdl-color--pink-A400 { + background-color: rgb(245,0,87) !important; } + +.mdl-color-text--pink-A700 { + color: rgb(197,17,98) !important; } + +.mdl-color--pink-A700 { + background-color: rgb(197,17,98) !important; } + +.mdl-color-text--purple { + color: rgb(156,39,176) !important; } + +.mdl-color--purple { + background-color: rgb(156,39,176) !important; } + +.mdl-color-text--purple-50 { + color: rgb(243,229,245) !important; } + +.mdl-color--purple-50 { + background-color: rgb(243,229,245) !important; } + +.mdl-color-text--purple-100 { + color: rgb(225,190,231) !important; } + +.mdl-color--purple-100 { + background-color: rgb(225,190,231) !important; } + +.mdl-color-text--purple-200 { + color: rgb(206,147,216) !important; } + +.mdl-color--purple-200 { + background-color: rgb(206,147,216) !important; } + +.mdl-color-text--purple-300 { + color: rgb(186,104,200) !important; } + +.mdl-color--purple-300 { + background-color: rgb(186,104,200) !important; } + +.mdl-color-text--purple-400 { + color: rgb(171,71,188) !important; } + +.mdl-color--purple-400 { + background-color: rgb(171,71,188) !important; } + +.mdl-color-text--purple-500 { + color: rgb(156,39,176) !important; } + +.mdl-color--purple-500 { + background-color: rgb(156,39,176) !important; } + +.mdl-color-text--purple-600 { + color: rgb(142,36,170) !important; } + +.mdl-color--purple-600 { + background-color: rgb(142,36,170) !important; } + +.mdl-color-text--purple-700 { + color: rgb(123,31,162) !important; } + +.mdl-color--purple-700 { + background-color: rgb(123,31,162) !important; } + +.mdl-color-text--purple-800 { + color: rgb(106,27,154) !important; } + +.mdl-color--purple-800 { + background-color: rgb(106,27,154) !important; } + +.mdl-color-text--purple-900 { + color: rgb(74,20,140) !important; } + +.mdl-color--purple-900 { + background-color: rgb(74,20,140) !important; } + +.mdl-color-text--purple-A100 { + color: rgb(234,128,252) !important; } + +.mdl-color--purple-A100 { + background-color: rgb(234,128,252) !important; } + +.mdl-color-text--purple-A200 { + color: rgb(224,64,251) !important; } + +.mdl-color--purple-A200 { + background-color: rgb(224,64,251) !important; } + +.mdl-color-text--purple-A400 { + color: rgb(213,0,249) !important; } + +.mdl-color--purple-A400 { + background-color: rgb(213,0,249) !important; } + +.mdl-color-text--purple-A700 { + color: rgb(170,0,255) !important; } + +.mdl-color--purple-A700 { + background-color: rgb(170,0,255) !important; } + +.mdl-color-text--deep-purple { + color: rgb(103,58,183) !important; } + +.mdl-color--deep-purple { + background-color: rgb(103,58,183) !important; } + +.mdl-color-text--deep-purple-50 { + color: rgb(237,231,246) !important; } + +.mdl-color--deep-purple-50 { + background-color: rgb(237,231,246) !important; } + +.mdl-color-text--deep-purple-100 { + color: rgb(209,196,233) !important; } + +.mdl-color--deep-purple-100 { + background-color: rgb(209,196,233) !important; } + +.mdl-color-text--deep-purple-200 { + color: rgb(179,157,219) !important; } + +.mdl-color--deep-purple-200 { + background-color: rgb(179,157,219) !important; } + +.mdl-color-text--deep-purple-300 { + color: rgb(149,117,205) !important; } + +.mdl-color--deep-purple-300 { + background-color: rgb(149,117,205) !important; } + +.mdl-color-text--deep-purple-400 { + color: rgb(126,87,194) !important; } + +.mdl-color--deep-purple-400 { + background-color: rgb(126,87,194) !important; } + +.mdl-color-text--deep-purple-500 { + color: rgb(103,58,183) !important; } + +.mdl-color--deep-purple-500 { + background-color: rgb(103,58,183) !important; } + +.mdl-color-text--deep-purple-600 { + color: rgb(94,53,177) !important; } + +.mdl-color--deep-purple-600 { + background-color: rgb(94,53,177) !important; } + +.mdl-color-text--deep-purple-700 { + color: rgb(81,45,168) !important; } + +.mdl-color--deep-purple-700 { + background-color: rgb(81,45,168) !important; } + +.mdl-color-text--deep-purple-800 { + color: rgb(69,39,160) !important; } + +.mdl-color--deep-purple-800 { + background-color: rgb(69,39,160) !important; } + +.mdl-color-text--deep-purple-900 { + color: rgb(49,27,146) !important; } + +.mdl-color--deep-purple-900 { + background-color: rgb(49,27,146) !important; } + +.mdl-color-text--deep-purple-A100 { + color: rgb(179,136,255) !important; } + +.mdl-color--deep-purple-A100 { + background-color: rgb(179,136,255) !important; } + +.mdl-color-text--deep-purple-A200 { + color: rgb(124,77,255) !important; } + +.mdl-color--deep-purple-A200 { + background-color: rgb(124,77,255) !important; } + +.mdl-color-text--deep-purple-A400 { + color: rgb(101,31,255) !important; } + +.mdl-color--deep-purple-A400 { + background-color: rgb(101,31,255) !important; } + +.mdl-color-text--deep-purple-A700 { + color: rgb(98,0,234) !important; } + +.mdl-color--deep-purple-A700 { + background-color: rgb(98,0,234) !important; } + +.mdl-color-text--indigo { + color: rgb(63,81,181) !important; } + +.mdl-color--indigo { + background-color: rgb(63,81,181) !important; } + +.mdl-color-text--indigo-50 { + color: rgb(232,234,246) !important; } + +.mdl-color--indigo-50 { + background-color: rgb(232,234,246) !important; } + +.mdl-color-text--indigo-100 { + color: rgb(197,202,233) !important; } + +.mdl-color--indigo-100 { + background-color: rgb(197,202,233) !important; } + +.mdl-color-text--indigo-200 { + color: rgb(159,168,218) !important; } + +.mdl-color--indigo-200 { + background-color: rgb(159,168,218) !important; } + +.mdl-color-text--indigo-300 { + color: rgb(121,134,203) !important; } + +.mdl-color--indigo-300 { + background-color: rgb(121,134,203) !important; } + +.mdl-color-text--indigo-400 { + color: rgb(92,107,192) !important; } + +.mdl-color--indigo-400 { + background-color: rgb(92,107,192) !important; } + +.mdl-color-text--indigo-500 { + color: rgb(63,81,181) !important; } + +.mdl-color--indigo-500 { + background-color: rgb(63,81,181) !important; } + +.mdl-color-text--indigo-600 { + color: rgb(57,73,171) !important; } + +.mdl-color--indigo-600 { + background-color: rgb(57,73,171) !important; } + +.mdl-color-text--indigo-700 { + color: rgb(48,63,159) !important; } + +.mdl-color--indigo-700 { + background-color: rgb(48,63,159) !important; } + +.mdl-color-text--indigo-800 { + color: rgb(40,53,147) !important; } + +.mdl-color--indigo-800 { + background-color: rgb(40,53,147) !important; } + +.mdl-color-text--indigo-900 { + color: rgb(26,35,126) !important; } + +.mdl-color--indigo-900 { + background-color: rgb(26,35,126) !important; } + +.mdl-color-text--indigo-A100 { + color: rgb(140,158,255) !important; } + +.mdl-color--indigo-A100 { + background-color: rgb(140,158,255) !important; } + +.mdl-color-text--indigo-A200 { + color: rgb(83,109,254) !important; } + +.mdl-color--indigo-A200 { + background-color: rgb(83,109,254) !important; } + +.mdl-color-text--indigo-A400 { + color: rgb(61,90,254) !important; } + +.mdl-color--indigo-A400 { + background-color: rgb(61,90,254) !important; } + +.mdl-color-text--indigo-A700 { + color: rgb(48,79,254) !important; } + +.mdl-color--indigo-A700 { + background-color: rgb(48,79,254) !important; } + +.mdl-color-text--blue { + color: rgb(33,150,243) !important; } + +.mdl-color--blue { + background-color: rgb(33,150,243) !important; } + +.mdl-color-text--blue-50 { + color: rgb(227,242,253) !important; } + +.mdl-color--blue-50 { + background-color: rgb(227,242,253) !important; } + +.mdl-color-text--blue-100 { + color: rgb(187,222,251) !important; } + +.mdl-color--blue-100 { + background-color: rgb(187,222,251) !important; } + +.mdl-color-text--blue-200 { + color: rgb(144,202,249) !important; } + +.mdl-color--blue-200 { + background-color: rgb(144,202,249) !important; } + +.mdl-color-text--blue-300 { + color: rgb(100,181,246) !important; } + +.mdl-color--blue-300 { + background-color: rgb(100,181,246) !important; } + +.mdl-color-text--blue-400 { + color: rgb(66,165,245) !important; } + +.mdl-color--blue-400 { + background-color: rgb(66,165,245) !important; } + +.mdl-color-text--blue-500 { + color: rgb(33,150,243) !important; } + +.mdl-color--blue-500 { + background-color: rgb(33,150,243) !important; } + +.mdl-color-text--blue-600 { + color: rgb(30,136,229) !important; } + +.mdl-color--blue-600 { + background-color: rgb(30,136,229) !important; } + +.mdl-color-text--blue-700 { + color: rgb(25,118,210) !important; } + +.mdl-color--blue-700 { + background-color: rgb(25,118,210) !important; } + +.mdl-color-text--blue-800 { + color: rgb(21,101,192) !important; } + +.mdl-color--blue-800 { + background-color: rgb(21,101,192) !important; } + +.mdl-color-text--blue-900 { + color: rgb(13,71,161) !important; } + +.mdl-color--blue-900 { + background-color: rgb(13,71,161) !important; } + +.mdl-color-text--blue-A100 { + color: rgb(130,177,255) !important; } + +.mdl-color--blue-A100 { + background-color: rgb(130,177,255) !important; } + +.mdl-color-text--blue-A200 { + color: rgb(68,138,255) !important; } + +.mdl-color--blue-A200 { + background-color: rgb(68,138,255) !important; } + +.mdl-color-text--blue-A400 { + color: rgb(41,121,255) !important; } + +.mdl-color--blue-A400 { + background-color: rgb(41,121,255) !important; } + +.mdl-color-text--blue-A700 { + color: rgb(41,98,255) !important; } + +.mdl-color--blue-A700 { + background-color: rgb(41,98,255) !important; } + +.mdl-color-text--light-blue { + color: rgb(3,169,244) !important; } + +.mdl-color--light-blue { + background-color: rgb(3,169,244) !important; } + +.mdl-color-text--light-blue-50 { + color: rgb(225,245,254) !important; } + +.mdl-color--light-blue-50 { + background-color: rgb(225,245,254) !important; } + +.mdl-color-text--light-blue-100 { + color: rgb(179,229,252) !important; } + +.mdl-color--light-blue-100 { + background-color: rgb(179,229,252) !important; } + +.mdl-color-text--light-blue-200 { + color: rgb(129,212,250) !important; } + +.mdl-color--light-blue-200 { + background-color: rgb(129,212,250) !important; } + +.mdl-color-text--light-blue-300 { + color: rgb(79,195,247) !important; } + +.mdl-color--light-blue-300 { + background-color: rgb(79,195,247) !important; } + +.mdl-color-text--light-blue-400 { + color: rgb(41,182,246) !important; } + +.mdl-color--light-blue-400 { + background-color: rgb(41,182,246) !important; } + +.mdl-color-text--light-blue-500 { + color: rgb(3,169,244) !important; } + +.mdl-color--light-blue-500 { + background-color: rgb(3,169,244) !important; } + +.mdl-color-text--light-blue-600 { + color: rgb(3,155,229) !important; } + +.mdl-color--light-blue-600 { + background-color: rgb(3,155,229) !important; } + +.mdl-color-text--light-blue-700 { + color: rgb(2,136,209) !important; } + +.mdl-color--light-blue-700 { + background-color: rgb(2,136,209) !important; } + +.mdl-color-text--light-blue-800 { + color: rgb(2,119,189) !important; } + +.mdl-color--light-blue-800 { + background-color: rgb(2,119,189) !important; } + +.mdl-color-text--light-blue-900 { + color: rgb(1,87,155) !important; } + +.mdl-color--light-blue-900 { + background-color: rgb(1,87,155) !important; } + +.mdl-color-text--light-blue-A100 { + color: rgb(128,216,255) !important; } + +.mdl-color--light-blue-A100 { + background-color: rgb(128,216,255) !important; } + +.mdl-color-text--light-blue-A200 { + color: rgb(64,196,255) !important; } + +.mdl-color--light-blue-A200 { + background-color: rgb(64,196,255) !important; } + +.mdl-color-text--light-blue-A400 { + color: rgb(0,176,255) !important; } + +.mdl-color--light-blue-A400 { + background-color: rgb(0,176,255) !important; } + +.mdl-color-text--light-blue-A700 { + color: rgb(0,145,234) !important; } + +.mdl-color--light-blue-A700 { + background-color: rgb(0,145,234) !important; } + +.mdl-color-text--cyan { + color: rgb(0,188,212) !important; } + +.mdl-color--cyan { + background-color: rgb(0,188,212) !important; } + +.mdl-color-text--cyan-50 { + color: rgb(224,247,250) !important; } + +.mdl-color--cyan-50 { + background-color: rgb(224,247,250) !important; } + +.mdl-color-text--cyan-100 { + color: rgb(178,235,242) !important; } + +.mdl-color--cyan-100 { + background-color: rgb(178,235,242) !important; } + +.mdl-color-text--cyan-200 { + color: rgb(128,222,234) !important; } + +.mdl-color--cyan-200 { + background-color: rgb(128,222,234) !important; } + +.mdl-color-text--cyan-300 { + color: rgb(77,208,225) !important; } + +.mdl-color--cyan-300 { + background-color: rgb(77,208,225) !important; } + +.mdl-color-text--cyan-400 { + color: rgb(38,198,218) !important; } + +.mdl-color--cyan-400 { + background-color: rgb(38,198,218) !important; } + +.mdl-color-text--cyan-500 { + color: rgb(0,188,212) !important; } + +.mdl-color--cyan-500 { + background-color: rgb(0,188,212) !important; } + +.mdl-color-text--cyan-600 { + color: rgb(0,172,193) !important; } + +.mdl-color--cyan-600 { + background-color: rgb(0,172,193) !important; } + +.mdl-color-text--cyan-700 { + color: rgb(0,151,167) !important; } + +.mdl-color--cyan-700 { + background-color: rgb(0,151,167) !important; } + +.mdl-color-text--cyan-800 { + color: rgb(0,131,143) !important; } + +.mdl-color--cyan-800 { + background-color: rgb(0,131,143) !important; } + +.mdl-color-text--cyan-900 { + color: rgb(0,96,100) !important; } + +.mdl-color--cyan-900 { + background-color: rgb(0,96,100) !important; } + +.mdl-color-text--cyan-A100 { + color: rgb(132,255,255) !important; } + +.mdl-color--cyan-A100 { + background-color: rgb(132,255,255) !important; } + +.mdl-color-text--cyan-A200 { + color: rgb(24,255,255) !important; } + +.mdl-color--cyan-A200 { + background-color: rgb(24,255,255) !important; } + +.mdl-color-text--cyan-A400 { + color: rgb(0,229,255) !important; } + +.mdl-color--cyan-A400 { + background-color: rgb(0,229,255) !important; } + +.mdl-color-text--cyan-A700 { + color: rgb(0,184,212) !important; } + +.mdl-color--cyan-A700 { + background-color: rgb(0,184,212) !important; } + +.mdl-color-text--teal { + color: rgb(0,150,136) !important; } + +.mdl-color--teal { + background-color: rgb(0,150,136) !important; } + +.mdl-color-text--teal-50 { + color: rgb(224,242,241) !important; } + +.mdl-color--teal-50 { + background-color: rgb(224,242,241) !important; } + +.mdl-color-text--teal-100 { + color: rgb(178,223,219) !important; } + +.mdl-color--teal-100 { + background-color: rgb(178,223,219) !important; } + +.mdl-color-text--teal-200 { + color: rgb(128,203,196) !important; } + +.mdl-color--teal-200 { + background-color: rgb(128,203,196) !important; } + +.mdl-color-text--teal-300 { + color: rgb(77,182,172) !important; } + +.mdl-color--teal-300 { + background-color: rgb(77,182,172) !important; } + +.mdl-color-text--teal-400 { + color: rgb(38,166,154) !important; } + +.mdl-color--teal-400 { + background-color: rgb(38,166,154) !important; } + +.mdl-color-text--teal-500 { + color: rgb(0,150,136) !important; } + +.mdl-color--teal-500 { + background-color: rgb(0,150,136) !important; } + +.mdl-color-text--teal-600 { + color: rgb(0,137,123) !important; } + +.mdl-color--teal-600 { + background-color: rgb(0,137,123) !important; } + +.mdl-color-text--teal-700 { + color: rgb(0,121,107) !important; } + +.mdl-color--teal-700 { + background-color: rgb(0,121,107) !important; } + +.mdl-color-text--teal-800 { + color: rgb(0,105,92) !important; } + +.mdl-color--teal-800 { + background-color: rgb(0,105,92) !important; } + +.mdl-color-text--teal-900 { + color: rgb(0,77,64) !important; } + +.mdl-color--teal-900 { + background-color: rgb(0,77,64) !important; } + +.mdl-color-text--teal-A100 { + color: rgb(167,255,235) !important; } + +.mdl-color--teal-A100 { + background-color: rgb(167,255,235) !important; } + +.mdl-color-text--teal-A200 { + color: rgb(100,255,218) !important; } + +.mdl-color--teal-A200 { + background-color: rgb(100,255,218) !important; } + +.mdl-color-text--teal-A400 { + color: rgb(29,233,182) !important; } + +.mdl-color--teal-A400 { + background-color: rgb(29,233,182) !important; } + +.mdl-color-text--teal-A700 { + color: rgb(0,191,165) !important; } + +.mdl-color--teal-A700 { + background-color: rgb(0,191,165) !important; } + +.mdl-color-text--green { + color: rgb(76,175,80) !important; } + +.mdl-color--green { + background-color: rgb(76,175,80) !important; } + +.mdl-color-text--green-50 { + color: rgb(232,245,233) !important; } + +.mdl-color--green-50 { + background-color: rgb(232,245,233) !important; } + +.mdl-color-text--green-100 { + color: rgb(200,230,201) !important; } + +.mdl-color--green-100 { + background-color: rgb(200,230,201) !important; } + +.mdl-color-text--green-200 { + color: rgb(165,214,167) !important; } + +.mdl-color--green-200 { + background-color: rgb(165,214,167) !important; } + +.mdl-color-text--green-300 { + color: rgb(129,199,132) !important; } + +.mdl-color--green-300 { + background-color: rgb(129,199,132) !important; } + +.mdl-color-text--green-400 { + color: rgb(102,187,106) !important; } + +.mdl-color--green-400 { + background-color: rgb(102,187,106) !important; } + +.mdl-color-text--green-500 { + color: rgb(76,175,80) !important; } + +.mdl-color--green-500 { + background-color: rgb(76,175,80) !important; } + +.mdl-color-text--green-600 { + color: rgb(67,160,71) !important; } + +.mdl-color--green-600 { + background-color: rgb(67,160,71) !important; } + +.mdl-color-text--green-700 { + color: rgb(56,142,60) !important; } + +.mdl-color--green-700 { + background-color: rgb(56,142,60) !important; } + +.mdl-color-text--green-800 { + color: rgb(46,125,50) !important; } + +.mdl-color--green-800 { + background-color: rgb(46,125,50) !important; } + +.mdl-color-text--green-900 { + color: rgb(27,94,32) !important; } + +.mdl-color--green-900 { + background-color: rgb(27,94,32) !important; } + +.mdl-color-text--green-A100 { + color: rgb(185,246,202) !important; } + +.mdl-color--green-A100 { + background-color: rgb(185,246,202) !important; } + +.mdl-color-text--green-A200 { + color: rgb(105,240,174) !important; } + +.mdl-color--green-A200 { + background-color: rgb(105,240,174) !important; } + +.mdl-color-text--green-A400 { + color: rgb(0,230,118) !important; } + +.mdl-color--green-A400 { + background-color: rgb(0,230,118) !important; } + +.mdl-color-text--green-A700 { + color: rgb(0,200,83) !important; } + +.mdl-color--green-A700 { + background-color: rgb(0,200,83) !important; } + +.mdl-color-text--light-green { + color: rgb(139,195,74) !important; } + +.mdl-color--light-green { + background-color: rgb(139,195,74) !important; } + +.mdl-color-text--light-green-50 { + color: rgb(241,248,233) !important; } + +.mdl-color--light-green-50 { + background-color: rgb(241,248,233) !important; } + +.mdl-color-text--light-green-100 { + color: rgb(220,237,200) !important; } + +.mdl-color--light-green-100 { + background-color: rgb(220,237,200) !important; } + +.mdl-color-text--light-green-200 { + color: rgb(197,225,165) !important; } + +.mdl-color--light-green-200 { + background-color: rgb(197,225,165) !important; } + +.mdl-color-text--light-green-300 { + color: rgb(174,213,129) !important; } + +.mdl-color--light-green-300 { + background-color: rgb(174,213,129) !important; } + +.mdl-color-text--light-green-400 { + color: rgb(156,204,101) !important; } + +.mdl-color--light-green-400 { + background-color: rgb(156,204,101) !important; } + +.mdl-color-text--light-green-500 { + color: rgb(139,195,74) !important; } + +.mdl-color--light-green-500 { + background-color: rgb(139,195,74) !important; } + +.mdl-color-text--light-green-600 { + color: rgb(124,179,66) !important; } + +.mdl-color--light-green-600 { + background-color: rgb(124,179,66) !important; } + +.mdl-color-text--light-green-700 { + color: rgb(104,159,56) !important; } + +.mdl-color--light-green-700 { + background-color: rgb(104,159,56) !important; } + +.mdl-color-text--light-green-800 { + color: rgb(85,139,47) !important; } + +.mdl-color--light-green-800 { + background-color: rgb(85,139,47) !important; } + +.mdl-color-text--light-green-900 { + color: rgb(51,105,30) !important; } + +.mdl-color--light-green-900 { + background-color: rgb(51,105,30) !important; } + +.mdl-color-text--light-green-A100 { + color: rgb(204,255,144) !important; } + +.mdl-color--light-green-A100 { + background-color: rgb(204,255,144) !important; } + +.mdl-color-text--light-green-A200 { + color: rgb(178,255,89) !important; } + +.mdl-color--light-green-A200 { + background-color: rgb(178,255,89) !important; } + +.mdl-color-text--light-green-A400 { + color: rgb(118,255,3) !important; } + +.mdl-color--light-green-A400 { + background-color: rgb(118,255,3) !important; } + +.mdl-color-text--light-green-A700 { + color: rgb(100,221,23) !important; } + +.mdl-color--light-green-A700 { + background-color: rgb(100,221,23) !important; } + +.mdl-color-text--lime { + color: rgb(205,220,57) !important; } + +.mdl-color--lime { + background-color: rgb(205,220,57) !important; } + +.mdl-color-text--lime-50 { + color: rgb(249,251,231) !important; } + +.mdl-color--lime-50 { + background-color: rgb(249,251,231) !important; } + +.mdl-color-text--lime-100 { + color: rgb(240,244,195) !important; } + +.mdl-color--lime-100 { + background-color: rgb(240,244,195) !important; } + +.mdl-color-text--lime-200 { + color: rgb(230,238,156) !important; } + +.mdl-color--lime-200 { + background-color: rgb(230,238,156) !important; } + +.mdl-color-text--lime-300 { + color: rgb(220,231,117) !important; } + +.mdl-color--lime-300 { + background-color: rgb(220,231,117) !important; } + +.mdl-color-text--lime-400 { + color: rgb(212,225,87) !important; } + +.mdl-color--lime-400 { + background-color: rgb(212,225,87) !important; } + +.mdl-color-text--lime-500 { + color: rgb(205,220,57) !important; } + +.mdl-color--lime-500 { + background-color: rgb(205,220,57) !important; } + +.mdl-color-text--lime-600 { + color: rgb(192,202,51) !important; } + +.mdl-color--lime-600 { + background-color: rgb(192,202,51) !important; } + +.mdl-color-text--lime-700 { + color: rgb(175,180,43) !important; } + +.mdl-color--lime-700 { + background-color: rgb(175,180,43) !important; } + +.mdl-color-text--lime-800 { + color: rgb(158,157,36) !important; } + +.mdl-color--lime-800 { + background-color: rgb(158,157,36) !important; } + +.mdl-color-text--lime-900 { + color: rgb(130,119,23) !important; } + +.mdl-color--lime-900 { + background-color: rgb(130,119,23) !important; } + +.mdl-color-text--lime-A100 { + color: rgb(244,255,129) !important; } + +.mdl-color--lime-A100 { + background-color: rgb(244,255,129) !important; } + +.mdl-color-text--lime-A200 { + color: rgb(238,255,65) !important; } + +.mdl-color--lime-A200 { + background-color: rgb(238,255,65) !important; } + +.mdl-color-text--lime-A400 { + color: rgb(198,255,0) !important; } + +.mdl-color--lime-A400 { + background-color: rgb(198,255,0) !important; } + +.mdl-color-text--lime-A700 { + color: rgb(174,234,0) !important; } + +.mdl-color--lime-A700 { + background-color: rgb(174,234,0) !important; } + +.mdl-color-text--yellow { + color: rgb(255,235,59) !important; } + +.mdl-color--yellow { + background-color: rgb(255,235,59) !important; } + +.mdl-color-text--yellow-50 { + color: rgb(255,253,231) !important; } + +.mdl-color--yellow-50 { + background-color: rgb(255,253,231) !important; } + +.mdl-color-text--yellow-100 { + color: rgb(255,249,196) !important; } + +.mdl-color--yellow-100 { + background-color: rgb(255,249,196) !important; } + +.mdl-color-text--yellow-200 { + color: rgb(255,245,157) !important; } + +.mdl-color--yellow-200 { + background-color: rgb(255,245,157) !important; } + +.mdl-color-text--yellow-300 { + color: rgb(255,241,118) !important; } + +.mdl-color--yellow-300 { + background-color: rgb(255,241,118) !important; } + +.mdl-color-text--yellow-400 { + color: rgb(255,238,88) !important; } + +.mdl-color--yellow-400 { + background-color: rgb(255,238,88) !important; } + +.mdl-color-text--yellow-500 { + color: rgb(255,235,59) !important; } + +.mdl-color--yellow-500 { + background-color: rgb(255,235,59) !important; } + +.mdl-color-text--yellow-600 { + color: rgb(253,216,53) !important; } + +.mdl-color--yellow-600 { + background-color: rgb(253,216,53) !important; } + +.mdl-color-text--yellow-700 { + color: rgb(251,192,45) !important; } + +.mdl-color--yellow-700 { + background-color: rgb(251,192,45) !important; } + +.mdl-color-text--yellow-800 { + color: rgb(249,168,37) !important; } + +.mdl-color--yellow-800 { + background-color: rgb(249,168,37) !important; } + +.mdl-color-text--yellow-900 { + color: rgb(245,127,23) !important; } + +.mdl-color--yellow-900 { + background-color: rgb(245,127,23) !important; } + +.mdl-color-text--yellow-A100 { + color: rgb(255,255,141) !important; } + +.mdl-color--yellow-A100 { + background-color: rgb(255,255,141) !important; } + +.mdl-color-text--yellow-A200 { + color: rgb(255,255,0) !important; } + +.mdl-color--yellow-A200 { + background-color: rgb(255,255,0) !important; } + +.mdl-color-text--yellow-A400 { + color: rgb(255,234,0) !important; } + +.mdl-color--yellow-A400 { + background-color: rgb(255,234,0) !important; } + +.mdl-color-text--yellow-A700 { + color: rgb(255,214,0) !important; } + +.mdl-color--yellow-A700 { + background-color: rgb(255,214,0) !important; } + +.mdl-color-text--amber { + color: rgb(255,193,7) !important; } + +.mdl-color--amber { + background-color: rgb(255,193,7) !important; } + +.mdl-color-text--amber-50 { + color: rgb(255,248,225) !important; } + +.mdl-color--amber-50 { + background-color: rgb(255,248,225) !important; } + +.mdl-color-text--amber-100 { + color: rgb(255,236,179) !important; } + +.mdl-color--amber-100 { + background-color: rgb(255,236,179) !important; } + +.mdl-color-text--amber-200 { + color: rgb(255,224,130) !important; } + +.mdl-color--amber-200 { + background-color: rgb(255,224,130) !important; } + +.mdl-color-text--amber-300 { + color: rgb(255,213,79) !important; } + +.mdl-color--amber-300 { + background-color: rgb(255,213,79) !important; } + +.mdl-color-text--amber-400 { + color: rgb(255,202,40) !important; } + +.mdl-color--amber-400 { + background-color: rgb(255,202,40) !important; } + +.mdl-color-text--amber-500 { + color: rgb(255,193,7) !important; } + +.mdl-color--amber-500 { + background-color: rgb(255,193,7) !important; } + +.mdl-color-text--amber-600 { + color: rgb(255,179,0) !important; } + +.mdl-color--amber-600 { + background-color: rgb(255,179,0) !important; } + +.mdl-color-text--amber-700 { + color: rgb(255,160,0) !important; } + +.mdl-color--amber-700 { + background-color: rgb(255,160,0) !important; } + +.mdl-color-text--amber-800 { + color: rgb(255,143,0) !important; } + +.mdl-color--amber-800 { + background-color: rgb(255,143,0) !important; } + +.mdl-color-text--amber-900 { + color: rgb(255,111,0) !important; } + +.mdl-color--amber-900 { + background-color: rgb(255,111,0) !important; } + +.mdl-color-text--amber-A100 { + color: rgb(255,229,127) !important; } + +.mdl-color--amber-A100 { + background-color: rgb(255,229,127) !important; } + +.mdl-color-text--amber-A200 { + color: rgb(255,215,64) !important; } + +.mdl-color--amber-A200 { + background-color: rgb(255,215,64) !important; } + +.mdl-color-text--amber-A400 { + color: rgb(255,196,0) !important; } + +.mdl-color--amber-A400 { + background-color: rgb(255,196,0) !important; } + +.mdl-color-text--amber-A700 { + color: rgb(255,171,0) !important; } + +.mdl-color--amber-A700 { + background-color: rgb(255,171,0) !important; } + +.mdl-color-text--orange { + color: rgb(255,152,0) !important; } + +.mdl-color--orange { + background-color: rgb(255,152,0) !important; } + +.mdl-color-text--orange-50 { + color: rgb(255,243,224) !important; } + +.mdl-color--orange-50 { + background-color: rgb(255,243,224) !important; } + +.mdl-color-text--orange-100 { + color: rgb(255,224,178) !important; } + +.mdl-color--orange-100 { + background-color: rgb(255,224,178) !important; } + +.mdl-color-text--orange-200 { + color: rgb(255,204,128) !important; } + +.mdl-color--orange-200 { + background-color: rgb(255,204,128) !important; } + +.mdl-color-text--orange-300 { + color: rgb(255,183,77) !important; } + +.mdl-color--orange-300 { + background-color: rgb(255,183,77) !important; } + +.mdl-color-text--orange-400 { + color: rgb(255,167,38) !important; } + +.mdl-color--orange-400 { + background-color: rgb(255,167,38) !important; } + +.mdl-color-text--orange-500 { + color: rgb(255,152,0) !important; } + +.mdl-color--orange-500 { + background-color: rgb(255,152,0) !important; } + +.mdl-color-text--orange-600 { + color: rgb(251,140,0) !important; } + +.mdl-color--orange-600 { + background-color: rgb(251,140,0) !important; } + +.mdl-color-text--orange-700 { + color: rgb(245,124,0) !important; } + +.mdl-color--orange-700 { + background-color: rgb(245,124,0) !important; } + +.mdl-color-text--orange-800 { + color: rgb(239,108,0) !important; } + +.mdl-color--orange-800 { + background-color: rgb(239,108,0) !important; } + +.mdl-color-text--orange-900 { + color: rgb(230,81,0) !important; } + +.mdl-color--orange-900 { + background-color: rgb(230,81,0) !important; } + +.mdl-color-text--orange-A100 { + color: rgb(255,209,128) !important; } + +.mdl-color--orange-A100 { + background-color: rgb(255,209,128) !important; } + +.mdl-color-text--orange-A200 { + color: rgb(255,171,64) !important; } + +.mdl-color--orange-A200 { + background-color: rgb(255,171,64) !important; } + +.mdl-color-text--orange-A400 { + color: rgb(255,145,0) !important; } + +.mdl-color--orange-A400 { + background-color: rgb(255,145,0) !important; } + +.mdl-color-text--orange-A700 { + color: rgb(255,109,0) !important; } + +.mdl-color--orange-A700 { + background-color: rgb(255,109,0) !important; } + +.mdl-color-text--deep-orange { + color: rgb(255,87,34) !important; } + +.mdl-color--deep-orange { + background-color: rgb(255,87,34) !important; } + +.mdl-color-text--deep-orange-50 { + color: rgb(251,233,231) !important; } + +.mdl-color--deep-orange-50 { + background-color: rgb(251,233,231) !important; } + +.mdl-color-text--deep-orange-100 { + color: rgb(255,204,188) !important; } + +.mdl-color--deep-orange-100 { + background-color: rgb(255,204,188) !important; } + +.mdl-color-text--deep-orange-200 { + color: rgb(255,171,145) !important; } + +.mdl-color--deep-orange-200 { + background-color: rgb(255,171,145) !important; } + +.mdl-color-text--deep-orange-300 { + color: rgb(255,138,101) !important; } + +.mdl-color--deep-orange-300 { + background-color: rgb(255,138,101) !important; } + +.mdl-color-text--deep-orange-400 { + color: rgb(255,112,67) !important; } + +.mdl-color--deep-orange-400 { + background-color: rgb(255,112,67) !important; } + +.mdl-color-text--deep-orange-500 { + color: rgb(255,87,34) !important; } + +.mdl-color--deep-orange-500 { + background-color: rgb(255,87,34) !important; } + +.mdl-color-text--deep-orange-600 { + color: rgb(244,81,30) !important; } + +.mdl-color--deep-orange-600 { + background-color: rgb(244,81,30) !important; } + +.mdl-color-text--deep-orange-700 { + color: rgb(230,74,25) !important; } + +.mdl-color--deep-orange-700 { + background-color: rgb(230,74,25) !important; } + +.mdl-color-text--deep-orange-800 { + color: rgb(216,67,21) !important; } + +.mdl-color--deep-orange-800 { + background-color: rgb(216,67,21) !important; } + +.mdl-color-text--deep-orange-900 { + color: rgb(191,54,12) !important; } + +.mdl-color--deep-orange-900 { + background-color: rgb(191,54,12) !important; } + +.mdl-color-text--deep-orange-A100 { + color: rgb(255,158,128) !important; } + +.mdl-color--deep-orange-A100 { + background-color: rgb(255,158,128) !important; } + +.mdl-color-text--deep-orange-A200 { + color: rgb(255,110,64) !important; } + +.mdl-color--deep-orange-A200 { + background-color: rgb(255,110,64) !important; } + +.mdl-color-text--deep-orange-A400 { + color: rgb(255,61,0) !important; } + +.mdl-color--deep-orange-A400 { + background-color: rgb(255,61,0) !important; } + +.mdl-color-text--deep-orange-A700 { + color: rgb(221,44,0) !important; } + +.mdl-color--deep-orange-A700 { + background-color: rgb(221,44,0) !important; } + +.mdl-color-text--brown { + color: rgb(121,85,72) !important; } + +.mdl-color--brown { + background-color: rgb(121,85,72) !important; } + +.mdl-color-text--brown-50 { + color: rgb(239,235,233) !important; } + +.mdl-color--brown-50 { + background-color: rgb(239,235,233) !important; } + +.mdl-color-text--brown-100 { + color: rgb(215,204,200) !important; } + +.mdl-color--brown-100 { + background-color: rgb(215,204,200) !important; } + +.mdl-color-text--brown-200 { + color: rgb(188,170,164) !important; } + +.mdl-color--brown-200 { + background-color: rgb(188,170,164) !important; } + +.mdl-color-text--brown-300 { + color: rgb(161,136,127) !important; } + +.mdl-color--brown-300 { + background-color: rgb(161,136,127) !important; } + +.mdl-color-text--brown-400 { + color: rgb(141,110,99) !important; } + +.mdl-color--brown-400 { + background-color: rgb(141,110,99) !important; } + +.mdl-color-text--brown-500 { + color: rgb(121,85,72) !important; } + +.mdl-color--brown-500 { + background-color: rgb(121,85,72) !important; } + +.mdl-color-text--brown-600 { + color: rgb(109,76,65) !important; } + +.mdl-color--brown-600 { + background-color: rgb(109,76,65) !important; } + +.mdl-color-text--brown-700 { + color: rgb(93,64,55) !important; } + +.mdl-color--brown-700 { + background-color: rgb(93,64,55) !important; } + +.mdl-color-text--brown-800 { + color: rgb(78,52,46) !important; } + +.mdl-color--brown-800 { + background-color: rgb(78,52,46) !important; } + +.mdl-color-text--brown-900 { + color: rgb(62,39,35) !important; } + +.mdl-color--brown-900 { + background-color: rgb(62,39,35) !important; } + +.mdl-color-text--grey { + color: rgb(158,158,158) !important; } + +.mdl-color--grey { + background-color: rgb(158,158,158) !important; } + +.mdl-color-text--grey-50 { + color: rgb(250,250,250) !important; } + +.mdl-color--grey-50 { + background-color: rgb(250,250,250) !important; } + +.mdl-color-text--grey-100 { + color: rgb(245,245,245) !important; } + +.mdl-color--grey-100 { + background-color: rgb(245,245,245) !important; } + +.mdl-color-text--grey-200 { + color: rgb(238,238,238) !important; } + +.mdl-color--grey-200 { + background-color: rgb(238,238,238) !important; } + +.mdl-color-text--grey-300 { + color: rgb(224,224,224) !important; } + +.mdl-color--grey-300 { + background-color: rgb(224,224,224) !important; } + +.mdl-color-text--grey-400 { + color: rgb(189,189,189) !important; } + +.mdl-color--grey-400 { + background-color: rgb(189,189,189) !important; } + +.mdl-color-text--grey-500 { + color: rgb(158,158,158) !important; } + +.mdl-color--grey-500 { + background-color: rgb(158,158,158) !important; } + +.mdl-color-text--grey-600 { + color: rgb(117,117,117) !important; } + +.mdl-color--grey-600 { + background-color: rgb(117,117,117) !important; } + +.mdl-color-text--grey-700 { + color: rgb(97,97,97) !important; } + +.mdl-color--grey-700 { + background-color: rgb(97,97,97) !important; } + +.mdl-color-text--grey-800 { + color: rgb(66,66,66) !important; } + +.mdl-color--grey-800 { + background-color: rgb(66,66,66) !important; } + +.mdl-color-text--grey-900 { + color: rgb(33,33,33) !important; } + +.mdl-color--grey-900 { + background-color: rgb(33,33,33) !important; } + +.mdl-color-text--blue-grey { + color: rgb(96,125,139) !important; } + +.mdl-color--blue-grey { + background-color: rgb(96,125,139) !important; } + +.mdl-color-text--blue-grey-50 { + color: rgb(236,239,241) !important; } + +.mdl-color--blue-grey-50 { + background-color: rgb(236,239,241) !important; } + +.mdl-color-text--blue-grey-100 { + color: rgb(207,216,220) !important; } + +.mdl-color--blue-grey-100 { + background-color: rgb(207,216,220) !important; } + +.mdl-color-text--blue-grey-200 { + color: rgb(176,190,197) !important; } + +.mdl-color--blue-grey-200 { + background-color: rgb(176,190,197) !important; } + +.mdl-color-text--blue-grey-300 { + color: rgb(144,164,174) !important; } + +.mdl-color--blue-grey-300 { + background-color: rgb(144,164,174) !important; } + +.mdl-color-text--blue-grey-400 { + color: rgb(120,144,156) !important; } + +.mdl-color--blue-grey-400 { + background-color: rgb(120,144,156) !important; } + +.mdl-color-text--blue-grey-500 { + color: rgb(96,125,139) !important; } + +.mdl-color--blue-grey-500 { + background-color: rgb(96,125,139) !important; } + +.mdl-color-text--blue-grey-600 { + color: rgb(84,110,122) !important; } + +.mdl-color--blue-grey-600 { + background-color: rgb(84,110,122) !important; } + +.mdl-color-text--blue-grey-700 { + color: rgb(69,90,100) !important; } + +.mdl-color--blue-grey-700 { + background-color: rgb(69,90,100) !important; } + +.mdl-color-text--blue-grey-800 { + color: rgb(55,71,79) !important; } + +.mdl-color--blue-grey-800 { + background-color: rgb(55,71,79) !important; } + +.mdl-color-text--blue-grey-900 { + color: rgb(38,50,56) !important; } + +.mdl-color--blue-grey-900 { + background-color: rgb(38,50,56) !important; } + +.mdl-color--black { + background-color: rgb(0,0,0) !important; } + +.mdl-color-text--black { + color: rgb(0,0,0) !important; } + +.mdl-color--white { + background-color: rgb(255,255,255) !important; } + +.mdl-color-text--white { + color: rgb(255,255,255) !important; } + +.mdl-color--primary { + background-color: rgb(63,81,181) !important; } + +.mdl-color--primary-contrast { + background-color: rgb(255,255,255) !important; } + +.mdl-color--primary-dark { + background-color: rgb(48,63,159) !important; } + +.mdl-color--accent { + background-color: rgb(255,64,129) !important; } + +.mdl-color--accent-contrast { + background-color: rgb(255,255,255) !important; } + +.mdl-color-text--primary { + color: rgb(63,81,181) !important; } + +.mdl-color-text--primary-contrast { + color: rgb(255,255,255) !important; } + +.mdl-color-text--primary-dark { + color: rgb(48,63,159) !important; } + +.mdl-color-text--accent { + color: rgb(255,64,129) !important; } + +.mdl-color-text--accent-contrast { + color: rgb(255,255,255) !important; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-ripple { + background: rgb(0,0,0); + border-radius: 50%; + height: 50px; + left: 0; + opacity: 0; + pointer-events: none; + position: absolute; + top: 0; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + width: 50px; + overflow: hidden; } + .mdl-ripple.is-animating { + transition: width 0.3s cubic-bezier(0, 0, 0.2, 1), height 0.3s cubic-bezier(0, 0, 0.2, 1), opacity 0.6s cubic-bezier(0, 0, 0.2, 1), -webkit-transform 0.3s cubic-bezier(0, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1), width 0.3s cubic-bezier(0, 0, 0.2, 1), height 0.3s cubic-bezier(0, 0, 0.2, 1), opacity 0.6s cubic-bezier(0, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1), width 0.3s cubic-bezier(0, 0, 0.2, 1), height 0.3s cubic-bezier(0, 0, 0.2, 1), opacity 0.6s cubic-bezier(0, 0, 0.2, 1), -webkit-transform 0.3s cubic-bezier(0, 0, 0.2, 1); } + .mdl-ripple.is-visible { + opacity: 0.3; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-animation--default { + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } + +.mdl-animation--fast-out-slow-in { + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } + +.mdl-animation--linear-out-slow-in { + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } + +.mdl-animation--fast-out-linear-in { + transition-timing-function: cubic-bezier(0.4, 0, 1, 1); } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-badge { + position: relative; + white-space: nowrap; + margin-right: 24px; } + .mdl-badge:not([data-badge]) { + margin-right: auto; } + .mdl-badge[data-badge]:after { + content: attr(data-badge); + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + position: absolute; + top: -11px; + right: -24px; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-weight: 600; + font-size: 12px; + width: 22px; + height: 22px; + border-radius: 50%; + background: rgb(255,64,129); + color: rgb(255,255,255); } + .mdl-button .mdl-badge[data-badge]:after { + top: -10px; + right: -5px; } + .mdl-badge.mdl-badge--no-background[data-badge]:after { + color: rgb(255,64,129); + background: rgba(255,255,255,0.2); + box-shadow: 0 0 1px gray; } + .mdl-badge.mdl-badge--overlap { + margin-right: 10px; } + .mdl-badge.mdl-badge--overlap:after { + right: -10px; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-button { + background: transparent; + border: none; + border-radius: 2px; + color: rgb(0,0,0); + position: relative; + height: 36px; + margin: 0; + min-width: 64px; + padding: 0 16px; + display: inline-block; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; + letter-spacing: 0; + overflow: hidden; + will-change: box-shadow; + transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1); + outline: none; + cursor: pointer; + text-decoration: none; + text-align: center; + line-height: 36px; + vertical-align: middle; } + .mdl-button::-moz-focus-inner { + border: 0; } + .mdl-button:hover { + background-color: rgba(158,158,158, 0.20); } + .mdl-button:focus:not(:active) { + background-color: rgba(0,0,0, 0.12); } + .mdl-button:active { + background-color: rgba(158,158,158, 0.40); } + .mdl-button.mdl-button--colored { + color: rgb(63,81,181); } + .mdl-button.mdl-button--colored:focus:not(:active) { + background-color: rgba(0,0,0, 0.12); } + +input.mdl-button[type="submit"] { + -webkit-appearance: none; } + +.mdl-button--raised { + background: rgba(158,158,158, 0.20); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } + .mdl-button--raised:active { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2); + background-color: rgba(158,158,158, 0.40); } + .mdl-button--raised:focus:not(:active) { + box-shadow: 0 0 8px rgba(0, 0, 0, 0.18), 0 8px 16px rgba(0, 0, 0, 0.36); + background-color: rgba(158,158,158, 0.40); } + .mdl-button--raised.mdl-button--colored { + background: rgb(63,81,181); + color: rgb(255,255,255); } + .mdl-button--raised.mdl-button--colored:hover { + background-color: rgb(63,81,181); } + .mdl-button--raised.mdl-button--colored:active { + background-color: rgb(63,81,181); } + .mdl-button--raised.mdl-button--colored:focus:not(:active) { + background-color: rgb(63,81,181); } + .mdl-button--raised.mdl-button--colored .mdl-ripple { + background: rgb(255,255,255); } + +.mdl-button--fab { + border-radius: 50%; + font-size: 24px; + height: 56px; + margin: auto; + min-width: 56px; + width: 56px; + padding: 0; + overflow: hidden; + background: rgba(158,158,158, 0.20); + box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); + position: relative; + line-height: normal; } + .mdl-button--fab .material-icons { + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-12px, -12px); + transform: translate(-12px, -12px); + line-height: 24px; + width: 24px; } + .mdl-button--fab.mdl-button--mini-fab { + height: 40px; + min-width: 40px; + width: 40px; } + .mdl-button--fab .mdl-button__ripple-container { + border-radius: 50%; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); } + .mdl-button--fab:active { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2); + background-color: rgba(158,158,158, 0.40); } + .mdl-button--fab:focus:not(:active) { + box-shadow: 0 0 8px rgba(0, 0, 0, 0.18), 0 8px 16px rgba(0, 0, 0, 0.36); + background-color: rgba(158,158,158, 0.40); } + .mdl-button--fab.mdl-button--colored { + background: rgb(255,64,129); + color: rgb(255,255,255); } + .mdl-button--fab.mdl-button--colored:hover { + background-color: rgb(255,64,129); } + .mdl-button--fab.mdl-button--colored:focus:not(:active) { + background-color: rgb(255,64,129); } + .mdl-button--fab.mdl-button--colored:active { + background-color: rgb(255,64,129); } + .mdl-button--fab.mdl-button--colored .mdl-ripple { + background: rgb(255,255,255); } + +.mdl-button--icon { + border-radius: 50%; + font-size: 24px; + height: 32px; + margin-left: 0; + margin-right: 0; + min-width: 32px; + width: 32px; + padding: 0; + overflow: hidden; + color: inherit; + line-height: normal; } + .mdl-button--icon .material-icons { + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-12px, -12px); + transform: translate(-12px, -12px); + line-height: 24px; + width: 24px; } + .mdl-button--icon.mdl-button--mini-icon { + height: 24px; + min-width: 24px; + width: 24px; } + .mdl-button--icon.mdl-button--mini-icon .material-icons { + top: 0px; + left: 0px; } + .mdl-button--icon .mdl-button__ripple-container { + border-radius: 50%; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); } + +.mdl-button__ripple-container { + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; + z-index: 0; + overflow: hidden; } + .mdl-button[disabled] .mdl-button__ripple-container .mdl-ripple, + .mdl-button.mdl-button--disabled .mdl-button__ripple-container .mdl-ripple { + background-color: transparent; } + +.mdl-button--primary.mdl-button--primary { + color: rgb(63,81,181); } + .mdl-button--primary.mdl-button--primary .mdl-ripple { + background: rgb(255,255,255); } + .mdl-button--primary.mdl-button--primary.mdl-button--raised, .mdl-button--primary.mdl-button--primary.mdl-button--fab { + color: rgb(255,255,255); + background-color: rgb(63,81,181); } + +.mdl-button--accent.mdl-button--accent { + color: rgb(255,64,129); } + .mdl-button--accent.mdl-button--accent .mdl-ripple { + background: rgb(255,255,255); } + .mdl-button--accent.mdl-button--accent.mdl-button--raised, .mdl-button--accent.mdl-button--accent.mdl-button--fab { + color: rgb(255,255,255); + background-color: rgb(255,64,129); } + +.mdl-button[disabled][disabled], .mdl-button.mdl-button--disabled.mdl-button--disabled { + color: rgba(0,0,0, 0.26); + cursor: default; + background-color: transparent; } + +.mdl-button--fab[disabled][disabled], .mdl-button--fab.mdl-button--disabled.mdl-button--disabled { + background-color: rgba(0,0,0, 0.12); + color: rgba(0,0,0, 0.26); } + +.mdl-button--raised[disabled][disabled], .mdl-button--raised.mdl-button--disabled.mdl-button--disabled { + background-color: rgba(0,0,0, 0.12); + color: rgba(0,0,0, 0.26); + box-shadow: none; } + +.mdl-button--colored[disabled][disabled], .mdl-button--colored.mdl-button--disabled.mdl-button--disabled { + color: rgba(0,0,0, 0.26); } + +.mdl-button .material-icons { + vertical-align: middle; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-card { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + font-size: 16px; + font-weight: 400; + min-height: 200px; + overflow: hidden; + width: 330px; + z-index: 1; + position: relative; + background: rgb(255,255,255); + border-radius: 2px; + box-sizing: border-box; } + +.mdl-card__media { + background-color: rgb(255,64,129); + background-repeat: repeat; + background-position: 50% 50%; + background-size: cover; + background-origin: padding-box; + background-attachment: scroll; + box-sizing: border-box; } + +.mdl-card__title { + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + color: rgb(0,0,0); + display: block; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: stretch; + -ms-flex-pack: stretch; + justify-content: stretch; + line-height: normal; + padding: 16px 16px; + -webkit-perspective-origin: 165px 56px; + perspective-origin: 165px 56px; + -webkit-transform-origin: 165px 56px; + transform-origin: 165px 56px; + box-sizing: border-box; } + .mdl-card__title.mdl-card--border { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); } + +.mdl-card__title-text { + -webkit-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; + color: inherit; + display: block; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + font-size: 24px; + font-weight: 300; + line-height: normal; + overflow: hidden; + -webkit-transform-origin: 149px 48px; + transform-origin: 149px 48px; + margin: 0; } + +.mdl-card__subtitle-text { + font-size: 14px; + color: rgba(0,0,0, 0.54); + margin: 0; } + +.mdl-card__supporting-text { + color: rgba(0,0,0, 0.54); + font-size: 1rem; + line-height: 18px; + overflow: hidden; + padding: 16px 16px; + width: 90%; } + +.mdl-card__actions { + font-size: 16px; + line-height: normal; + width: 100%; + background-color: transparent; + padding: 8px; + box-sizing: border-box; } + .mdl-card__actions.mdl-card--border { + border-top: 1px solid rgba(0, 0, 0, 0.1); } + +.mdl-card--expand { + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; } + +.mdl-card__menu { + position: absolute; + right: 16px; + top: 16px; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-checkbox { + position: relative; + z-index: 1; + vertical-align: middle; + display: inline-block; + box-sizing: border-box; + width: 100%; + height: 24px; + margin: 0; + padding: 0; } + .mdl-checkbox.is-upgraded { + padding-left: 24px; } + +.mdl-checkbox__input { + line-height: 24px; } + .mdl-checkbox.is-upgraded .mdl-checkbox__input { + position: absolute; + width: 0; + height: 0; + margin: 0; + padding: 0; + opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + border: none; } + +.mdl-checkbox__box-outline { + position: absolute; + top: 3px; + left: 0; + display: inline-block; + box-sizing: border-box; + width: 16px; + height: 16px; + margin: 0; + cursor: pointer; + overflow: hidden; + border: 2px solid rgba(0,0,0, 0.54); + border-radius: 2px; + z-index: 2; } + .mdl-checkbox.is-checked .mdl-checkbox__box-outline { + border: 2px solid rgb(63,81,181); } + fieldset[disabled] .mdl-checkbox .mdl-checkbox__box-outline, + .mdl-checkbox.is-disabled .mdl-checkbox__box-outline { + border: 2px solid rgba(0,0,0, 0.26); + cursor: auto; } + +.mdl-checkbox__focus-helper { + position: absolute; + top: 3px; + left: 0; + display: inline-block; + box-sizing: border-box; + width: 16px; + height: 16px; + border-radius: 50%; + background-color: transparent; } + .mdl-checkbox.is-focused .mdl-checkbox__focus-helper { + box-shadow: 0 0 0px 8px rgba(0, 0, 0, 0.1); + background-color: rgba(0, 0, 0, 0.1); } + .mdl-checkbox.is-focused.is-checked .mdl-checkbox__focus-helper { + box-shadow: 0 0 0px 8px rgba(63,81,181, 0.26); + background-color: rgba(63,81,181, 0.26); } + +.mdl-checkbox__tick-outline { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + -webkit-mask: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8ZGVmcz4KICAgIDxjbGlwUGF0aCBpZD0iY2xpcCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIDAsMSAxLDEgMSwwIDAsMCB6IE0gMC44NTM0Mzc1LDAuMTY3MTg3NSAwLjk1OTY4NzUsMC4yNzMxMjUgMC40MjkzNzUsMC44MDM0Mzc1IDAuMzIzMTI1LDAuOTA5Njg3NSAwLjIxNzE4NzUsMC44MDM0Mzc1IDAuMDQwMzEyNSwwLjYyNjg3NSAwLjE0NjU2MjUsMC41MjA2MjUgMC4zMjMxMjUsMC42OTc1IDAuODUzNDM3NSwwLjE2NzE4NzUgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgICA8bWFzayBpZD0ibWFzayIgbWFza1VuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgbWFza0NvbnRlbnRVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giPgogICAgICA8cGF0aAogICAgICAgICBkPSJNIDAsMCAwLDEgMSwxIDEsMCAwLDAgeiBNIDAuODUzNDM3NSwwLjE2NzE4NzUgMC45NTk2ODc1LDAuMjczMTI1IDAuNDI5Mzc1LDAuODAzNDM3NSAwLjMyMzEyNSwwLjkwOTY4NzUgMC4yMTcxODc1LDAuODAzNDM3NSAwLjA0MDMxMjUsMC42MjY4NzUgMC4xNDY1NjI1LDAuNTIwNjI1IDAuMzIzMTI1LDAuNjk3NSAwLjg1MzQzNzUsMC4xNjcxODc1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0CiAgICAgd2lkdGg9IjEiCiAgICAgaGVpZ2h0PSIxIgogICAgIHg9IjAiCiAgICAgeT0iMCIKICAgICBjbGlwLXBhdGg9InVybCgjY2xpcCkiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KPC9zdmc+Cg=="); + mask: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8ZGVmcz4KICAgIDxjbGlwUGF0aCBpZD0iY2xpcCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIDAsMSAxLDEgMSwwIDAsMCB6IE0gMC44NTM0Mzc1LDAuMTY3MTg3NSAwLjk1OTY4NzUsMC4yNzMxMjUgMC40MjkzNzUsMC44MDM0Mzc1IDAuMzIzMTI1LDAuOTA5Njg3NSAwLjIxNzE4NzUsMC44MDM0Mzc1IDAuMDQwMzEyNSwwLjYyNjg3NSAwLjE0NjU2MjUsMC41MjA2MjUgMC4zMjMxMjUsMC42OTc1IDAuODUzNDM3NSwwLjE2NzE4NzUgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgICA8bWFzayBpZD0ibWFzayIgbWFza1VuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgbWFza0NvbnRlbnRVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giPgogICAgICA8cGF0aAogICAgICAgICBkPSJNIDAsMCAwLDEgMSwxIDEsMCAwLDAgeiBNIDAuODUzNDM3NSwwLjE2NzE4NzUgMC45NTk2ODc1LDAuMjczMTI1IDAuNDI5Mzc1LDAuODAzNDM3NSAwLjMyMzEyNSwwLjkwOTY4NzUgMC4yMTcxODc1LDAuODAzNDM3NSAwLjA0MDMxMjUsMC42MjY4NzUgMC4xNDY1NjI1LDAuNTIwNjI1IDAuMzIzMTI1LDAuNjk3NSAwLjg1MzQzNzUsMC4xNjcxODc1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0CiAgICAgd2lkdGg9IjEiCiAgICAgaGVpZ2h0PSIxIgogICAgIHg9IjAiCiAgICAgeT0iMCIKICAgICBjbGlwLXBhdGg9InVybCgjY2xpcCkiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KPC9zdmc+Cg=="); + background: transparent; + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: background; } + .mdl-checkbox.is-checked .mdl-checkbox__tick-outline { + background: rgb(63,81,181) url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K"); } + fieldset[disabled] .mdl-checkbox.is-checked .mdl-checkbox__tick-outline, + .mdl-checkbox.is-checked.is-disabled .mdl-checkbox__tick-outline { + background: rgba(0,0,0, 0.26) url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K"); } + +.mdl-checkbox__label { + position: relative; + cursor: pointer; + font-size: 16px; + line-height: 24px; + margin: 0; } + fieldset[disabled] .mdl-checkbox .mdl-checkbox__label, + .mdl-checkbox.is-disabled .mdl-checkbox__label { + color: rgba(0,0,0, 0.26); + cursor: auto; } + +.mdl-checkbox__ripple-container { + position: absolute; + z-index: 2; + top: -6px; + left: -10px; + box-sizing: border-box; + width: 36px; + height: 36px; + border-radius: 50%; + cursor: pointer; + overflow: hidden; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); } + .mdl-checkbox__ripple-container .mdl-ripple { + background: rgb(63,81,181); } + fieldset[disabled] .mdl-checkbox .mdl-checkbox__ripple-container, + .mdl-checkbox.is-disabled .mdl-checkbox__ripple-container { + cursor: auto; } + fieldset[disabled] .mdl-checkbox .mdl-checkbox__ripple-container .mdl-ripple, + .mdl-checkbox.is-disabled .mdl-checkbox__ripple-container .mdl-ripple { + background: transparent; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-chip { + height: 32px; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + line-height: 32px; + padding: 0 12px; + border: 0; + border-radius: 16px; + background-color: #dedede; + display: inline-block; + color: rgba(0,0,0, 0.87); + margin: 2px 0; + font-size: 0; + white-space: nowrap; } + .mdl-chip__text { + font-size: 13px; + vertical-align: middle; + display: inline-block; } + .mdl-chip__action { + height: 24px; + width: 24px; + background: transparent; + opacity: 0.54; + display: inline-block; + cursor: pointer; + text-align: center; + vertical-align: middle; + padding: 0; + margin: 0 0 0 4px; + font-size: 13px; + text-decoration: none; + color: rgba(0,0,0, 0.87); + border: none; + outline: none; + overflow: hidden; } + .mdl-chip__contact { + height: 32px; + width: 32px; + border-radius: 16px; + display: inline-block; + vertical-align: middle; + margin-right: 8px; + overflow: hidden; + text-align: center; + font-size: 18px; + line-height: 32px; } + .mdl-chip:focus { + outline: 0; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } + .mdl-chip:active { + background-color: #d6d6d6; } + .mdl-chip--deletable { + padding-right: 4px; } + .mdl-chip--contact { + padding-left: 0; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-data-table { + position: relative; + border: 1px solid rgba(0, 0, 0, 0.12); + border-collapse: collapse; + white-space: nowrap; + font-size: 13px; + background-color: rgb(255,255,255); } + .mdl-data-table thead { + padding-bottom: 3px; } + .mdl-data-table thead .mdl-data-table__select { + margin-top: 0; } + .mdl-data-table tbody tr { + position: relative; + height: 48px; + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: background-color; } + .mdl-data-table tbody tr.is-selected { + background-color: #e0e0e0; } + .mdl-data-table tbody tr:hover { + background-color: #eeeeee; } + .mdl-data-table td, .mdl-data-table th { + padding: 0 18px 12px 18px; + text-align: right; } + .mdl-data-table td:first-of-type, .mdl-data-table th:first-of-type { + padding-left: 24px; } + .mdl-data-table td:last-of-type, .mdl-data-table th:last-of-type { + padding-right: 24px; } + .mdl-data-table td { + position: relative; + vertical-align: middle; + height: 48px; + border-top: 1px solid rgba(0, 0, 0, 0.12); + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + padding-top: 12px; + box-sizing: border-box; } + .mdl-data-table td .mdl-data-table__select { + vertical-align: middle; } + .mdl-data-table th { + position: relative; + vertical-align: bottom; + text-overflow: ellipsis; + font-size: 14px; + font-weight: bold; + line-height: 24px; + letter-spacing: 0; + height: 48px; + font-size: 12px; + color: rgba(0, 0, 0, 0.54); + padding-bottom: 8px; + box-sizing: border-box; } + .mdl-data-table th.mdl-data-table__header--sorted-ascending, .mdl-data-table th.mdl-data-table__header--sorted-descending { + color: rgba(0, 0, 0, 0.87); } + .mdl-data-table th.mdl-data-table__header--sorted-ascending:before, .mdl-data-table th.mdl-data-table__header--sorted-descending:before { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + word-wrap: normal; + -moz-font-feature-settings: 'liga'; + font-feature-settings: 'liga'; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; + font-size: 16px; + content: "\e5d8"; + margin-right: 5px; + vertical-align: sub; } + .mdl-data-table th.mdl-data-table__header--sorted-ascending:hover, .mdl-data-table th.mdl-data-table__header--sorted-descending:hover { + cursor: pointer; } + .mdl-data-table th.mdl-data-table__header--sorted-ascending:hover:before, .mdl-data-table th.mdl-data-table__header--sorted-descending:hover:before { + color: rgba(0, 0, 0, 0.26); } + .mdl-data-table th.mdl-data-table__header--sorted-descending:before { + content: "\e5db"; } + +.mdl-data-table__select { + width: 16px; } + +.mdl-data-table__cell--non-numeric.mdl-data-table__cell--non-numeric { + text-align: left; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 280px; } + .mdl-dialog__title { + padding: 24px 24px 0; + margin: 0; + font-size: 2.5rem; } + .mdl-dialog__actions { + padding: 8px 8px 8px 24px; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row-reverse; + -ms-flex-direction: row-reverse; + flex-direction: row-reverse; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; } + .mdl-dialog__actions > * { + margin-right: 8px; + height: 36px; } + .mdl-dialog__actions > *:first-child { + margin-right: 0; } + .mdl-dialog__actions--full-width { + padding: 0 0 8px 0; } + .mdl-dialog__actions--full-width > * { + height: 48px; + -webkit-flex: 0 0 100%; + -ms-flex: 0 0 100%; + flex: 0 0 100%; + padding-right: 16px; + margin-right: 0; + text-align: right; } + .mdl-dialog__content { + padding: 20px 24px 24px 24px; + color: rgba(0,0,0, 0.54); } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-mega-footer { + padding: 16px 40px; + color: rgb(158,158,158); + background-color: rgb(66,66,66); } + +.mdl-mega-footer--top-section:after, +.mdl-mega-footer--middle-section:after, +.mdl-mega-footer--bottom-section:after, +.mdl-mega-footer__top-section:after, +.mdl-mega-footer__middle-section:after, +.mdl-mega-footer__bottom-section:after { + content: ''; + display: block; + clear: both; } + +.mdl-mega-footer--left-section, +.mdl-mega-footer__left-section { + margin-bottom: 16px; } + +.mdl-mega-footer--right-section, +.mdl-mega-footer__right-section { + margin-bottom: 16px; } + +.mdl-mega-footer--right-section a, +.mdl-mega-footer__right-section a { + display: block; + margin-bottom: 16px; + color: inherit; + text-decoration: none; } + +@media screen and (min-width: 760px) { + .mdl-mega-footer--left-section, + .mdl-mega-footer__left-section { + float: left; } + .mdl-mega-footer--right-section, + .mdl-mega-footer__right-section { + float: right; } + .mdl-mega-footer--right-section a, + .mdl-mega-footer__right-section a { + display: inline-block; + margin-left: 16px; + line-height: 36px; + vertical-align: middle; } } + +.mdl-mega-footer--social-btn, +.mdl-mega-footer__social-btn { + width: 36px; + height: 36px; + padding: 0; + margin: 0; + background-color: rgb(158,158,158); + border: none; } + +.mdl-mega-footer--drop-down-section, +.mdl-mega-footer__drop-down-section { + display: block; + position: relative; } + +@media screen and (min-width: 760px) { + .mdl-mega-footer--drop-down-section, + .mdl-mega-footer__drop-down-section { + width: 33%; } + .mdl-mega-footer--drop-down-section:nth-child(1), + .mdl-mega-footer--drop-down-section:nth-child(2), + .mdl-mega-footer__drop-down-section:nth-child(1), + .mdl-mega-footer__drop-down-section:nth-child(2) { + float: left; } + .mdl-mega-footer--drop-down-section:nth-child(3), + .mdl-mega-footer__drop-down-section:nth-child(3) { + float: right; } + .mdl-mega-footer--drop-down-section:nth-child(3):after, + .mdl-mega-footer__drop-down-section:nth-child(3):after { + clear: right; } + .mdl-mega-footer--drop-down-section:nth-child(4), + .mdl-mega-footer__drop-down-section:nth-child(4) { + clear: right; + float: right; } + .mdl-mega-footer--middle-section:after, + .mdl-mega-footer__middle-section:after { + content: ''; + display: block; + clear: both; } + .mdl-mega-footer--bottom-section, + .mdl-mega-footer__bottom-section { + padding-top: 0; } } + +@media screen and (min-width: 1024px) { + .mdl-mega-footer--drop-down-section, + .mdl-mega-footer--drop-down-section:nth-child(3), + .mdl-mega-footer--drop-down-section:nth-child(4), + .mdl-mega-footer__drop-down-section, + .mdl-mega-footer__drop-down-section:nth-child(3), + .mdl-mega-footer__drop-down-section:nth-child(4) { + width: 24%; + float: left; } } + +.mdl-mega-footer--heading-checkbox, +.mdl-mega-footer__heading-checkbox { + position: absolute; + width: 100%; + height: 55.8px; + padding: 32px; + margin: 0; + margin-top: -16px; + cursor: pointer; + z-index: 1; + opacity: 0; } + .mdl-mega-footer--heading-checkbox + .mdl-mega-footer--heading:after, + .mdl-mega-footer--heading-checkbox + .mdl-mega-footer__heading:after, + .mdl-mega-footer__heading-checkbox + .mdl-mega-footer--heading:after, + .mdl-mega-footer__heading-checkbox + .mdl-mega-footer__heading:after { + font-family: 'Material Icons'; + content: '\E5CE'; } + +.mdl-mega-footer--heading-checkbox:checked ~ .mdl-mega-footer--link-list, +.mdl-mega-footer--heading-checkbox:checked ~ .mdl-mega-footer__link-list, +.mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer--heading + .mdl-mega-footer--link-list, +.mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer__heading + .mdl-mega-footer__link-list, +.mdl-mega-footer__heading-checkbox:checked ~ .mdl-mega-footer--link-list, +.mdl-mega-footer__heading-checkbox:checked ~ .mdl-mega-footer__link-list, +.mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer--heading + .mdl-mega-footer--link-list, +.mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer__heading + .mdl-mega-footer__link-list { + display: none; } + +.mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer--heading:after, +.mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer__heading:after, +.mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer--heading:after, +.mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer__heading:after { + font-family: 'Material Icons'; + content: '\E5CF'; } + +.mdl-mega-footer--heading, +.mdl-mega-footer__heading { + position: relative; + width: 100%; + padding-right: 39.8px; + margin-bottom: 16px; + box-sizing: border-box; + font-size: 14px; + line-height: 23.8px; + font-weight: 500; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + color: rgb(224,224,224); } + +.mdl-mega-footer--heading:after, +.mdl-mega-footer__heading:after { + content: ''; + position: absolute; + top: 0; + right: 0; + display: block; + width: 23.8px; + height: 23.8px; + background-size: cover; } + +.mdl-mega-footer--link-list, +.mdl-mega-footer__link-list { + list-style: none; + margin: 0; + padding: 0; + margin-bottom: 32px; } + .mdl-mega-footer--link-list:after, + .mdl-mega-footer__link-list:after { + clear: both; + display: block; + content: ''; } + +.mdl-mega-footer--link-list li, +.mdl-mega-footer__link-list li { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + line-height: 20px; } + +.mdl-mega-footer--link-list a, +.mdl-mega-footer__link-list a { + color: inherit; + text-decoration: none; + white-space: nowrap; } + +@media screen and (min-width: 760px) { + .mdl-mega-footer--heading-checkbox, + .mdl-mega-footer__heading-checkbox { + display: none; } + .mdl-mega-footer--heading-checkbox + .mdl-mega-footer--heading:after, + .mdl-mega-footer--heading-checkbox + .mdl-mega-footer__heading:after, + .mdl-mega-footer__heading-checkbox + .mdl-mega-footer--heading:after, + .mdl-mega-footer__heading-checkbox + .mdl-mega-footer__heading:after { + content: ''; } + .mdl-mega-footer--heading-checkbox:checked ~ .mdl-mega-footer--link-list, + .mdl-mega-footer--heading-checkbox:checked ~ .mdl-mega-footer__link-list, + .mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer__heading + .mdl-mega-footer__link-list, + .mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer--heading + .mdl-mega-footer--link-list, + .mdl-mega-footer__heading-checkbox:checked ~ .mdl-mega-footer--link-list, + .mdl-mega-footer__heading-checkbox:checked ~ .mdl-mega-footer__link-list, + .mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer__heading + .mdl-mega-footer__link-list, + .mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer--heading + .mdl-mega-footer--link-list { + display: block; } + .mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer--heading:after, + .mdl-mega-footer--heading-checkbox:checked + .mdl-mega-footer__heading:after, + .mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer--heading:after, + .mdl-mega-footer__heading-checkbox:checked + .mdl-mega-footer__heading:after { + content: ''; } } + +.mdl-mega-footer--bottom-section, +.mdl-mega-footer__bottom-section { + padding-top: 16px; + margin-bottom: 16px; } + +.mdl-logo { + margin-bottom: 16px; + color: white; } + +.mdl-mega-footer--bottom-section .mdl-mega-footer--link-list li, +.mdl-mega-footer__bottom-section .mdl-mega-footer__link-list li { + float: left; + margin-bottom: 0; + margin-right: 16px; } + +@media screen and (min-width: 760px) { + .mdl-logo { + float: left; + margin-bottom: 0; + margin-right: 16px; } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-mini-footer { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 32px 16px; + color: rgb(158,158,158); + background-color: rgb(66,66,66); } + .mdl-mini-footer:after { + content: ''; + display: block; } + .mdl-mini-footer .mdl-logo { + line-height: 36px; } + +.mdl-mini-footer--link-list, +.mdl-mini-footer__link-list { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row nowrap; + -ms-flex-flow: row nowrap; + flex-flow: row nowrap; + list-style: none; + margin: 0; + padding: 0; } + .mdl-mini-footer--link-list li, + .mdl-mini-footer__link-list li { + margin-bottom: 0; + margin-right: 16px; } + @media screen and (min-width: 760px) { + .mdl-mini-footer--link-list li, + .mdl-mini-footer__link-list li { + line-height: 36px; } } + .mdl-mini-footer--link-list a, + .mdl-mini-footer__link-list a { + color: inherit; + text-decoration: none; + white-space: nowrap; } + +.mdl-mini-footer--left-section, +.mdl-mini-footer__left-section { + display: inline-block; + -webkit-order: 0; + -ms-flex-order: 0; + order: 0; } + +.mdl-mini-footer--right-section, +.mdl-mini-footer__right-section { + display: inline-block; + -webkit-order: 1; + -ms-flex-order: 1; + order: 1; } + +.mdl-mini-footer--social-btn, +.mdl-mini-footer__social-btn { + width: 36px; + height: 36px; + padding: 0; + margin: 0; + background-color: rgb(158,158,158); + border: none; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-icon-toggle { + position: relative; + z-index: 1; + vertical-align: middle; + display: inline-block; + height: 32px; + margin: 0; + padding: 0; } + +.mdl-icon-toggle__input { + line-height: 32px; } + .mdl-icon-toggle.is-upgraded .mdl-icon-toggle__input { + position: absolute; + width: 0; + height: 0; + margin: 0; + padding: 0; + opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + border: none; } + +.mdl-icon-toggle__label { + display: inline-block; + position: relative; + cursor: pointer; + height: 32px; + width: 32px; + min-width: 32px; + color: rgb(97,97,97); + border-radius: 50%; + padding: 0; + margin-left: 0; + margin-right: 0; + text-align: center; + background-color: transparent; + will-change: background-color; + transition: background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-icon-toggle__label.material-icons { + line-height: 32px; + font-size: 24px; } + .mdl-icon-toggle.is-checked .mdl-icon-toggle__label { + color: rgb(63,81,181); } + .mdl-icon-toggle.is-disabled .mdl-icon-toggle__label { + color: rgba(0,0,0, 0.26); + cursor: auto; + transition: none; } + .mdl-icon-toggle.is-focused .mdl-icon-toggle__label { + background-color: rgba(0,0,0, 0.12); } + .mdl-icon-toggle.is-focused.is-checked .mdl-icon-toggle__label { + background-color: rgba(63,81,181, 0.26); } + +.mdl-icon-toggle__ripple-container { + position: absolute; + z-index: 2; + top: -2px; + left: -2px; + box-sizing: border-box; + width: 36px; + height: 36px; + border-radius: 50%; + cursor: pointer; + overflow: hidden; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); } + .mdl-icon-toggle__ripple-container .mdl-ripple { + background: rgb(97,97,97); } + .mdl-icon-toggle.is-disabled .mdl-icon-toggle__ripple-container { + cursor: auto; } + .mdl-icon-toggle.is-disabled .mdl-icon-toggle__ripple-container .mdl-ripple { + background: transparent; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-list { + display: block; + padding: 8px 0; + list-style: none; } + +.mdl-list__item { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 16px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.04em; + line-height: 1; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + min-height: 48px; + box-sizing: border-box; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + padding: 16px; + cursor: default; + color: rgba(0,0,0, 0.87); + overflow: hidden; } + .mdl-list__item .mdl-list__item-primary-content { + -webkit-order: 0; + -ms-flex-order: 0; + order: 0; + -webkit-flex-grow: 2; + -ms-flex-positive: 2; + flex-grow: 2; + text-decoration: none; + box-sizing: border-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; } + .mdl-list__item .mdl-list__item-primary-content .mdl-list__item-icon { + margin-right: 32px; } + .mdl-list__item .mdl-list__item-primary-content .mdl-list__item-avatar { + margin-right: 16px; } + .mdl-list__item .mdl-list__item-secondary-content { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: column; + -ms-flex-flow: column; + flex-flow: column; + -webkit-align-items: flex-end; + -ms-flex-align: end; + align-items: flex-end; + margin-left: 16px; } + .mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-secondary-action label { + display: inline; } + .mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-secondary-info { + font-size: 12px; + font-weight: 400; + line-height: 1; + letter-spacing: 0; + color: rgba(0,0,0, 0.54); } + .mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-sub-header { + padding: 0 0 0 16px; } + +.mdl-list__item-icon, +.mdl-list__item-icon.material-icons { + height: 24px; + width: 24px; + font-size: 24px; + box-sizing: border-box; + color: rgb(117,117,117); } + +.mdl-list__item-avatar, +.mdl-list__item-avatar.material-icons { + height: 40px; + width: 40px; + box-sizing: border-box; + border-radius: 50%; + background-color: rgb(117,117,117); + font-size: 40px; + color: white; } + +.mdl-list__item--two-line { + height: 72px; } + .mdl-list__item--two-line .mdl-list__item-primary-content { + height: 36px; + line-height: 20px; + display: block; } + .mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-avatar { + float: left; } + .mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-icon { + float: left; + margin-top: 6px; } + .mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-secondary-content { + height: 36px; } + .mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-sub-title { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + line-height: 18px; + color: rgba(0,0,0, 0.54); + display: block; + padding: 0; } + +.mdl-list__item--three-line { + height: 88px; } + .mdl-list__item--three-line .mdl-list__item-primary-content { + height: 52px; + line-height: 20px; + display: block; } + .mdl-list__item--three-line .mdl-list__item-primary-content .mdl-list__item-avatar, + .mdl-list__item--three-line .mdl-list__item-primary-content .mdl-list__item-icon { + float: left; } + .mdl-list__item--three-line .mdl-list__item-secondary-content { + height: 52px; } + .mdl-list__item--three-line .mdl-list__item-text-body { + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + line-height: 18px; + height: 52px; + color: rgba(0,0,0, 0.54); + display: block; + padding: 0; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-menu__container { + display: block; + margin: 0; + padding: 0; + border: none; + position: absolute; + overflow: visible; + height: 0; + width: 0; + visibility: hidden; + z-index: -1; } + .mdl-menu__container.is-visible, .mdl-menu__container.is-animating { + z-index: 999; + visibility: visible; } + +.mdl-menu__outline { + display: block; + background: rgb(255,255,255); + margin: 0; + padding: 0; + border: none; + border-radius: 2px; + position: absolute; + top: 0; + left: 0; + overflow: hidden; + opacity: 0; + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + will-change: transform; + transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + z-index: -1; } + .mdl-menu__container.is-visible .mdl-menu__outline { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + z-index: 999; } + .mdl-menu__outline.mdl-menu--bottom-right { + -webkit-transform-origin: 100% 0; + transform-origin: 100% 0; } + .mdl-menu__outline.mdl-menu--top-left { + -webkit-transform-origin: 0 100%; + transform-origin: 0 100%; } + .mdl-menu__outline.mdl-menu--top-right { + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; } + +.mdl-menu { + position: absolute; + list-style: none; + top: 0; + left: 0; + height: auto; + width: auto; + min-width: 124px; + padding: 8px 0; + margin: 0; + opacity: 0; + clip: rect(0 0 0 0); + z-index: -1; } + .mdl-menu__container.is-visible .mdl-menu { + opacity: 1; + z-index: 999; } + .mdl-menu.is-animating { + transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1), clip 0.3s cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-menu.mdl-menu--bottom-right { + left: auto; + right: 0; } + .mdl-menu.mdl-menu--top-left { + top: auto; + bottom: 0; } + .mdl-menu.mdl-menu--top-right { + top: auto; + left: auto; + bottom: 0; + right: 0; } + .mdl-menu.mdl-menu--unaligned { + top: auto; + left: auto; } + +.mdl-menu__item { + display: block; + border: none; + color: rgba(0,0,0, 0.87); + background-color: transparent; + text-align: left; + margin: 0; + padding: 0 16px; + outline-color: rgb(189,189,189); + position: relative; + overflow: hidden; + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + text-decoration: none; + cursor: pointer; + height: 48px; + line-height: 48px; + white-space: nowrap; + opacity: 0; + transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + .mdl-menu__container.is-visible .mdl-menu__item { + opacity: 1; } + .mdl-menu__item::-moz-focus-inner { + border: 0; } + .mdl-menu__item--full-bleed-divider { + border-bottom: 1px solid rgba(0,0,0, 0.12); } + .mdl-menu__item[disabled], .mdl-menu__item[data-mdl-disabled] { + color: rgb(189,189,189); + background-color: transparent; + cursor: auto; } + .mdl-menu__item[disabled]:hover, .mdl-menu__item[data-mdl-disabled]:hover { + background-color: transparent; } + .mdl-menu__item[disabled]:focus, .mdl-menu__item[data-mdl-disabled]:focus { + background-color: transparent; } + .mdl-menu__item[disabled] .mdl-ripple, .mdl-menu__item[data-mdl-disabled] .mdl-ripple { + background: transparent; } + .mdl-menu__item:hover { + background-color: rgb(238,238,238); } + .mdl-menu__item:focus { + outline: none; + background-color: rgb(238,238,238); } + .mdl-menu__item:active { + background-color: rgb(224,224,224); } + +.mdl-menu__item--ripple-container { + display: block; + height: 100%; + left: 0px; + position: absolute; + top: 0px; + width: 100%; + z-index: 0; + overflow: hidden; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-progress { + display: block; + position: relative; + height: 4px; + width: 500px; + max-width: 100%; } + +.mdl-progress > .bar { + display: block; + position: absolute; + top: 0; + bottom: 0; + width: 0%; + transition: width 0.2s cubic-bezier(0.4, 0, 0.2, 1); } + +.mdl-progress > .progressbar { + background-color: rgb(63,81,181); + z-index: 1; + left: 0; } + +.mdl-progress > .bufferbar { + background-image: linear-gradient(to right, rgba(255,255,255, 0.7), rgba(255,255,255, 0.7)), linear-gradient(to right, rgb(63,81,181), rgb(63,81,181)); + z-index: 0; + left: 0; } + +.mdl-progress > .auxbar { + right: 0; } + +@supports (-webkit-appearance: none) { + .mdl-progress:not(.mdl-progress--indeterminate):not(.mdl-progress--indeterminate) > .auxbar, + .mdl-progress:not(.mdl-progress__indeterminate):not(.mdl-progress__indeterminate) > .auxbar { + background-image: linear-gradient(to right, rgba(255,255,255, 0.7), rgba(255,255,255, 0.7)), linear-gradient(to right, rgb(63,81,181), rgb(63,81,181)); + -webkit-mask: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjEyIiBoZWlnaHQ9IjQiIHZpZXdQb3J0PSIwIDAgMTIgNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxlbGxpcHNlIGN4PSIyIiBjeT0iMiIgcng9IjIiIHJ5PSIyIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN4IiBmcm9tPSIyIiB0bz0iLTEwIiBkdXI9IjAuNnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvZWxsaXBzZT4KICA8ZWxsaXBzZSBjeD0iMTQiIGN5PSIyIiByeD0iMiIgcnk9IjIiIGNsYXNzPSJsb2FkZXIiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3giIGZyb209IjE0IiB0bz0iMiIgZHVyPSIwLjZzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L2VsbGlwc2U+Cjwvc3ZnPgo="); + mask: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjEyIiBoZWlnaHQ9IjQiIHZpZXdQb3J0PSIwIDAgMTIgNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxlbGxpcHNlIGN4PSIyIiBjeT0iMiIgcng9IjIiIHJ5PSIyIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN4IiBmcm9tPSIyIiB0bz0iLTEwIiBkdXI9IjAuNnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvZWxsaXBzZT4KICA8ZWxsaXBzZSBjeD0iMTQiIGN5PSIyIiByeD0iMiIgcnk9IjIiIGNsYXNzPSJsb2FkZXIiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3giIGZyb209IjE0IiB0bz0iMiIgZHVyPSIwLjZzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L2VsbGlwc2U+Cjwvc3ZnPgo="); } } + +.mdl-progress:not(.mdl-progress--indeterminate) > .auxbar, +.mdl-progress:not(.mdl-progress__indeterminate) > .auxbar { + background-image: linear-gradient(to right, rgba(255,255,255, 0.9), rgba(255,255,255, 0.9)), linear-gradient(to right, rgb(63,81,181), rgb(63,81,181)); } + +.mdl-progress.mdl-progress--indeterminate > .bar1, +.mdl-progress.mdl-progress__indeterminate > .bar1 { + background-color: rgb(63,81,181); + -webkit-animation-name: indeterminate1; + animation-name: indeterminate1; + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; } + +.mdl-progress.mdl-progress--indeterminate > .bar3, +.mdl-progress.mdl-progress__indeterminate > .bar3 { + background-image: none; + background-color: rgb(63,81,181); + -webkit-animation-name: indeterminate2; + animation-name: indeterminate2; + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; } + +@-webkit-keyframes indeterminate1 { + 0% { + left: 0%; + width: 0%; } + 50% { + left: 25%; + width: 75%; } + 75% { + left: 100%; + width: 0%; } } + +@keyframes indeterminate1 { + 0% { + left: 0%; + width: 0%; } + 50% { + left: 25%; + width: 75%; } + 75% { + left: 100%; + width: 0%; } } + +@-webkit-keyframes indeterminate2 { + 0% { + left: 0%; + width: 0%; } + 50% { + left: 0%; + width: 0%; } + 75% { + left: 0%; + width: 25%; } + 100% { + left: 100%; + width: 0%; } } + +@keyframes indeterminate2 { + 0% { + left: 0%; + width: 0%; } + 50% { + left: 0%; + width: 0%; } + 75% { + left: 0%; + width: 25%; } + 100% { + left: 100%; + width: 0%; } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-navigation { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + box-sizing: border-box; } + +.mdl-navigation__link { + color: rgb(66,66,66); + text-decoration: none; + margin: 0; + font-size: 14px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0; + opacity: 0.87; } + .mdl-navigation__link .material-icons { + vertical-align: middle; } + +.mdl-layout { + position: absolute; + width: 100%; + height: 100%; } + +.mdl-layout.is-small-screen .mdl-layout--large-screen-only { + display: none; } + +.mdl-layout:not(.is-small-screen) .mdl-layout--small-screen-only { + display: none; } + +.mdl-layout__inner-container { + width: 100%; + height: 100%; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + overflow-y: auto; + overflow-x: hidden; + position: relative; + -webkit-overflow-scrolling: touch; } + +.mdl-layout__title, +.mdl-layout-title { + display: block; + position: relative; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 20px; + font-weight: 500; + line-height: 1; + letter-spacing: 0.02em; + font-weight: 400; + box-sizing: border-box; } + +.mdl-layout-spacer { + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; } + +.mdl-layout__drawer { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + width: 240px; + height: 100%; + max-height: 100%; + position: absolute; + top: 0; + left: 0; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + box-sizing: border-box; + border-right: 1px solid rgb(224,224,224); + background: rgb(250,250,250); + -webkit-transform: translateX(-250px); + transform: translateX(-250px); + -webkit-transform-style: preserve-3d; + transform-style: preserve-3d; + will-change: transform; + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + color: rgb(66,66,66); + overflow: visible; + overflow-y: auto; + z-index: 5; } + .mdl-layout__drawer.is-visible { + -webkit-transform: translateX(0); + transform: translateX(0); } + .mdl-layout__drawer.is-visible ~ .mdl-layout__content.mdl-layout__content { + overflow: hidden; } + .mdl-layout__drawer > * { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; } + .mdl-layout__drawer > .mdl-layout__title, + .mdl-layout__drawer > .mdl-layout-title { + line-height: 64px; + padding-left: 40px; } + @media screen and (max-width: 1024px) { + .mdl-layout__drawer > .mdl-layout__title, + .mdl-layout__drawer > .mdl-layout-title { + line-height: 56px; + padding-left: 16px; } } + .mdl-layout__drawer .mdl-navigation { + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: stretch; + -ms-flex-align: stretch; + -ms-grid-row-align: stretch; + align-items: stretch; + padding-top: 16px; } + .mdl-layout__drawer .mdl-navigation .mdl-navigation__link { + display: block; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + padding: 16px 40px; + margin: 0; + color: #757575; } + @media screen and (max-width: 1024px) { + .mdl-layout__drawer .mdl-navigation .mdl-navigation__link { + padding: 16px 16px; } } + .mdl-layout__drawer .mdl-navigation .mdl-navigation__link:hover { + background-color: rgb(224,224,224); } + .mdl-layout__drawer .mdl-navigation .mdl-navigation__link--current { + background-color: rgb(224,224,224); + color: rgb(0,0,0); } + @media screen and (min-width: 1025px) { + .mdl-layout--fixed-drawer > .mdl-layout__inner-container > .mdl-layout__drawer { + -webkit-transform: translateX(0); + transform: translateX(0); } } + +.mdl-layout__drawer-button { + display: block; + position: absolute; + height: 48px; + width: 48px; + border: 0; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + overflow: hidden; + text-align: center; + cursor: pointer; + font-size: 26px; + line-height: 56px; + font-family: Helvetica, Arial, sans-serif; + margin: 8px 12px; + top: 0; + left: 0; + color: rgb(255,255,255); + z-index: 4; } + .mdl-layout__header .mdl-layout__drawer-button { + position: absolute; + color: rgb(255,255,255); + background-color: inherit; } + @media screen and (max-width: 1024px) { + .mdl-layout__header .mdl-layout__drawer-button { + margin: 4px; } } + @media screen and (max-width: 1024px) { + .mdl-layout__drawer-button { + margin: 4px; + color: rgba(0, 0, 0, 0.5); } } + @media screen and (min-width: 1025px) { + .mdl-layout__drawer-button { + line-height: 54px; } + .mdl-layout--no-desktop-drawer-button .mdl-layout__drawer-button, + .mdl-layout--fixed-drawer > .mdl-layout__inner-container > .mdl-layout__drawer-button, + .mdl-layout--no-drawer-button .mdl-layout__drawer-button { + display: none; } } + +.mdl-layout__header { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + box-sizing: border-box; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: 100%; + margin: 0; + padding: 0; + border: none; + min-height: 64px; + max-height: 1000px; + z-index: 3; + background-color: rgb(63,81,181); + color: rgb(255,255,255); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: max-height, box-shadow; } + @media screen and (max-width: 1024px) { + .mdl-layout__header { + min-height: 56px; } } + .mdl-layout--fixed-drawer.is-upgraded:not(.is-small-screen) > .mdl-layout__inner-container > .mdl-layout__header { + margin-left: 240px; + width: calc(100% - 240px); } + @media screen and (min-width: 1025px) { + .mdl-layout--fixed-drawer > .mdl-layout__inner-container > .mdl-layout__header .mdl-layout__header-row { + padding-left: 40px; } } + .mdl-layout__header > .mdl-layout-icon { + position: absolute; + left: 40px; + top: 16px; + height: 32px; + width: 32px; + overflow: hidden; + z-index: 3; + display: block; } + @media screen and (max-width: 1024px) { + .mdl-layout__header > .mdl-layout-icon { + left: 16px; + top: 12px; } } + .mdl-layout.has-drawer .mdl-layout__header > .mdl-layout-icon { + display: none; } + .mdl-layout__header.is-compact { + max-height: 64px; } + @media screen and (max-width: 1024px) { + .mdl-layout__header.is-compact { + max-height: 56px; } } + .mdl-layout__header.is-compact.has-tabs { + height: 112px; } + @media screen and (max-width: 1024px) { + .mdl-layout__header.is-compact.has-tabs { + min-height: 104px; } } + @media screen and (max-width: 1024px) { + .mdl-layout__header { + display: none; } + .mdl-layout--fixed-header > .mdl-layout__inner-container > .mdl-layout__header { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; } } + +.mdl-layout__header--transparent.mdl-layout__header--transparent { + background-color: transparent; + box-shadow: none; } + +.mdl-layout__header--seamed { + box-shadow: none; } + +.mdl-layout__header--scroll { + box-shadow: none; } + +.mdl-layout__header--waterfall { + box-shadow: none; + overflow: hidden; } + .mdl-layout__header--waterfall.is-casting-shadow { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } + .mdl-layout__header--waterfall.mdl-layout__header--waterfall-hide-top { + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; } + +.mdl-layout__header-row { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + flex-wrap: nowrap; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + box-sizing: border-box; + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + height: 64px; + margin: 0; + padding: 0 40px 0 80px; } + .mdl-layout--no-drawer-button .mdl-layout__header-row { + padding-left: 40px; } + @media screen and (min-width: 1025px) { + .mdl-layout--no-desktop-drawer-button .mdl-layout__header-row { + padding-left: 40px; } } + @media screen and (max-width: 1024px) { + .mdl-layout__header-row { + height: 56px; + padding: 0 16px 0 72px; } + .mdl-layout--no-drawer-button .mdl-layout__header-row { + padding-left: 16px; } } + .mdl-layout__header-row > * { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; } + .mdl-layout__header--scroll .mdl-layout__header-row { + width: 100%; } + .mdl-layout__header-row .mdl-navigation { + margin: 0; + padding: 0; + height: 64px; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -ms-flex-align: center; + -ms-grid-row-align: center; + align-items: center; } + @media screen and (max-width: 1024px) { + .mdl-layout__header-row .mdl-navigation { + height: 56px; } } + .mdl-layout__header-row .mdl-navigation__link { + display: block; + color: rgb(255,255,255); + line-height: 64px; + padding: 0 24px; } + @media screen and (max-width: 1024px) { + .mdl-layout__header-row .mdl-navigation__link { + line-height: 56px; + padding: 0 16px; } } + +.mdl-layout__obfuscator { + background-color: transparent; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 4; + visibility: hidden; + transition-property: background-color; + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-layout__obfuscator.is-visible { + background-color: rgba(0, 0, 0, 0.5); + visibility: visible; } + @supports (pointer-events: auto) { + .mdl-layout__obfuscator { + background-color: rgba(0, 0, 0, 0.5); + opacity: 0; + transition-property: opacity; + visibility: visible; + pointer-events: none; } + .mdl-layout__obfuscator.is-visible { + pointer-events: auto; + opacity: 1; } } + +.mdl-layout__content { + -ms-flex: 0 1 auto; + position: relative; + display: inline-block; + overflow-y: auto; + overflow-x: hidden; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + z-index: 1; + -webkit-overflow-scrolling: touch; } + .mdl-layout--fixed-drawer > .mdl-layout__inner-container > .mdl-layout__content { + margin-left: 240px; } + .mdl-layout.has-scrolling-header .mdl-layout__content { + overflow: visible; } + @media screen and (max-width: 1024px) { + .mdl-layout--fixed-drawer > .mdl-layout__inner-container > .mdl-layout__content { + margin-left: 0; } + .mdl-layout.has-scrolling-header .mdl-layout__content { + overflow-y: auto; + overflow-x: hidden; } } + +.mdl-layout__tab-bar { + height: 96px; + margin: 0; + width: calc(100% - 112px); + padding: 0 0 0 56px; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + background-color: rgb(63,81,181); + overflow-y: hidden; + overflow-x: scroll; } + .mdl-layout__tab-bar::-webkit-scrollbar { + display: none; } + .mdl-layout--no-drawer-button .mdl-layout__tab-bar { + padding-left: 16px; + width: calc(100% - 32px); } + @media screen and (min-width: 1025px) { + .mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar { + padding-left: 16px; + width: calc(100% - 32px); } } + @media screen and (max-width: 1024px) { + .mdl-layout__tab-bar { + width: calc(100% - 60px); + padding: 0 0 0 60px; } + .mdl-layout--no-drawer-button .mdl-layout__tab-bar { + width: calc(100% - 8px); + padding-left: 4px; } } + .mdl-layout--fixed-tabs .mdl-layout__tab-bar { + padding: 0; + overflow: hidden; + width: 100%; } + +.mdl-layout__tab-bar-container { + position: relative; + height: 48px; + width: 100%; + border: none; + margin: 0; + z-index: 2; + -webkit-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + overflow: hidden; } + .mdl-layout__container > .mdl-layout__tab-bar-container { + position: absolute; + top: 0; + left: 0; } + +.mdl-layout__tab-bar-button { + display: inline-block; + position: absolute; + top: 0; + height: 48px; + width: 56px; + z-index: 4; + text-align: center; + background-color: rgb(63,81,181); + color: transparent; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + .mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar-button, + .mdl-layout--no-drawer-button .mdl-layout__tab-bar-button { + width: 16px; } + .mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar-button .material-icons, + .mdl-layout--no-drawer-button .mdl-layout__tab-bar-button .material-icons { + position: relative; + left: -4px; } + @media screen and (max-width: 1024px) { + .mdl-layout__tab-bar-button { + width: 60px; } } + .mdl-layout--fixed-tabs .mdl-layout__tab-bar-button { + display: none; } + .mdl-layout__tab-bar-button .material-icons { + line-height: 48px; } + .mdl-layout__tab-bar-button.is-active { + color: rgb(255,255,255); } + +.mdl-layout__tab-bar-left-button { + left: 0; } + +.mdl-layout__tab-bar-right-button { + right: 0; } + +.mdl-layout__tab { + margin: 0; + border: none; + padding: 0 24px 0 24px; + float: left; + position: relative; + display: block; + -webkit-flex-grow: 0; + -ms-flex-positive: 0; + flex-grow: 0; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + text-decoration: none; + height: 48px; + line-height: 48px; + text-align: center; + font-weight: 500; + font-size: 14px; + text-transform: uppercase; + color: rgba(255,255,255, 0.6); + overflow: hidden; } + @media screen and (max-width: 1024px) { + .mdl-layout__tab { + padding: 0 12px 0 12px; } } + .mdl-layout--fixed-tabs .mdl-layout__tab { + float: none; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + padding: 0; } + .mdl-layout.is-upgraded .mdl-layout__tab.is-active { + color: rgb(255,255,255); } + .mdl-layout.is-upgraded .mdl-layout__tab.is-active::after { + height: 2px; + width: 100%; + display: block; + content: " "; + bottom: 0; + left: 0; + position: absolute; + background: rgb(255,64,129); + -webkit-animation: border-expand 0.2s cubic-bezier(0.4, 0, 0.4, 1) 0.01s alternate forwards; + animation: border-expand 0.2s cubic-bezier(0.4, 0, 0.4, 1) 0.01s alternate forwards; + transition: all 1s cubic-bezier(0.4, 0, 1, 1); } + .mdl-layout__tab .mdl-layout__tab-ripple-container { + display: block; + position: absolute; + height: 100%; + width: 100%; + left: 0; + top: 0; + z-index: 1; + overflow: hidden; } + .mdl-layout__tab .mdl-layout__tab-ripple-container .mdl-ripple { + background-color: rgb(255,255,255); } + +.mdl-layout__tab-panel { + display: block; } + .mdl-layout.is-upgraded .mdl-layout__tab-panel { + display: none; } + .mdl-layout.is-upgraded .mdl-layout__tab-panel.is-active { + display: block; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-radio { + position: relative; + font-size: 16px; + line-height: 24px; + display: inline-block; + box-sizing: border-box; + margin: 0; + padding-left: 0; } + .mdl-radio.is-upgraded { + padding-left: 24px; } + +.mdl-radio__button { + line-height: 24px; } + .mdl-radio.is-upgraded .mdl-radio__button { + position: absolute; + width: 0; + height: 0; + margin: 0; + padding: 0; + opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + border: none; } + +.mdl-radio__outer-circle { + position: absolute; + top: 4px; + left: 0; + display: inline-block; + box-sizing: border-box; + width: 16px; + height: 16px; + margin: 0; + cursor: pointer; + border: 2px solid rgba(0,0,0, 0.54); + border-radius: 50%; + z-index: 2; } + .mdl-radio.is-checked .mdl-radio__outer-circle { + border: 2px solid rgb(63,81,181); } + .mdl-radio__outer-circle fieldset[disabled] .mdl-radio, + .mdl-radio.is-disabled .mdl-radio__outer-circle { + border: 2px solid rgba(0,0,0, 0.26); + cursor: auto; } + +.mdl-radio__inner-circle { + position: absolute; + z-index: 1; + margin: 0; + top: 8px; + left: 4px; + box-sizing: border-box; + width: 8px; + height: 8px; + cursor: pointer; + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + -webkit-transform: scale3d(0, 0, 0); + transform: scale3d(0, 0, 0); + border-radius: 50%; + background: rgb(63,81,181); } + .mdl-radio.is-checked .mdl-radio__inner-circle { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); } + fieldset[disabled] .mdl-radio .mdl-radio__inner-circle, + .mdl-radio.is-disabled .mdl-radio__inner-circle { + background: rgba(0,0,0, 0.26); + cursor: auto; } + .mdl-radio.is-focused .mdl-radio__inner-circle { + box-shadow: 0 0 0px 10px rgba(0, 0, 0, 0.1); } + +.mdl-radio__label { + cursor: pointer; } + fieldset[disabled] .mdl-radio .mdl-radio__label, + .mdl-radio.is-disabled .mdl-radio__label { + color: rgba(0,0,0, 0.26); + cursor: auto; } + +.mdl-radio__ripple-container { + position: absolute; + z-index: 2; + top: -9px; + left: -13px; + box-sizing: border-box; + width: 42px; + height: 42px; + border-radius: 50%; + cursor: pointer; + overflow: hidden; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); } + .mdl-radio__ripple-container .mdl-ripple { + background: rgb(63,81,181); } + fieldset[disabled] .mdl-radio .mdl-radio__ripple-container, + .mdl-radio.is-disabled .mdl-radio__ripple-container { + cursor: auto; } + fieldset[disabled] .mdl-radio .mdl-radio__ripple-container .mdl-ripple, + .mdl-radio.is-disabled .mdl-radio__ripple-container .mdl-ripple { + background: transparent; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +_:-ms-input-placeholder, :root .mdl-slider.mdl-slider.is-upgraded { + -ms-appearance: none; + height: 32px; + margin: 0; } + +.mdl-slider { + width: calc(100% - 40px); + margin: 0 20px; } + .mdl-slider.is-upgraded { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 2px; + background: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: 0; + padding: 0; + color: rgb(63,81,181); + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; + z-index: 1; + cursor: pointer; + /**************************** Tracks ****************************/ + /**************************** Thumbs ****************************/ + /**************************** 0-value ****************************/ + /**************************** Disabled ****************************/ } + .mdl-slider.is-upgraded::-moz-focus-outer { + border: 0; } + .mdl-slider.is-upgraded::-ms-tooltip { + display: none; } + .mdl-slider.is-upgraded::-webkit-slider-runnable-track { + background: transparent; } + .mdl-slider.is-upgraded::-moz-range-track { + background: transparent; + border: none; } + .mdl-slider.is-upgraded::-ms-track { + background: none; + color: transparent; + height: 2px; + width: 100%; + border: none; } + .mdl-slider.is-upgraded::-ms-fill-lower { + padding: 0; + background: linear-gradient(to right, transparent, transparent 16px, rgb(63,81,181) 16px, rgb(63,81,181) 0); } + .mdl-slider.is-upgraded::-ms-fill-upper { + padding: 0; + background: linear-gradient(to left, transparent, transparent 16px, rgba(0,0,0, 0.26) 16px, rgba(0,0,0, 0.26) 0); } + .mdl-slider.is-upgraded::-webkit-slider-thumb { + -webkit-appearance: none; + width: 12px; + height: 12px; + box-sizing: border-box; + border-radius: 50%; + background: rgb(63,81,181); + border: none; + transition: border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-slider.is-upgraded::-moz-range-thumb { + -moz-appearance: none; + width: 12px; + height: 12px; + box-sizing: border-box; + border-radius: 50%; + background-image: none; + background: rgb(63,81,181); + border: none; } + .mdl-slider.is-upgraded:focus:not(:active)::-webkit-slider-thumb { + box-shadow: 0 0 0 10px rgba(63,81,181, 0.26); } + .mdl-slider.is-upgraded:focus:not(:active)::-moz-range-thumb { + box-shadow: 0 0 0 10px rgba(63,81,181, 0.26); } + .mdl-slider.is-upgraded:active::-webkit-slider-thumb { + background-image: none; + background: rgb(63,81,181); + -webkit-transform: scale(1.5); + transform: scale(1.5); } + .mdl-slider.is-upgraded:active::-moz-range-thumb { + background-image: none; + background: rgb(63,81,181); + transform: scale(1.5); } + .mdl-slider.is-upgraded::-ms-thumb { + width: 32px; + height: 32px; + border: none; + border-radius: 50%; + background: rgb(63,81,181); + transform: scale(0.375); + transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1); + transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.18s cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-slider.is-upgraded:focus:not(:active)::-ms-thumb { + background: radial-gradient(circle closest-side, rgb(63,81,181) 0%, rgb(63,81,181) 37.5%, rgba(63,81,181, 0.26) 37.5%, rgba(63,81,181, 0.26) 100%); + transform: scale(1); } + .mdl-slider.is-upgraded:active::-ms-thumb { + background: rgb(63,81,181); + transform: scale(0.5625); } + .mdl-slider.is-upgraded.is-lowest-value::-webkit-slider-thumb { + border: 2px solid rgba(0,0,0, 0.26); + background: transparent; } + .mdl-slider.is-upgraded.is-lowest-value::-moz-range-thumb { + border: 2px solid rgba(0,0,0, 0.26); + background: transparent; } + .mdl-slider.is-upgraded.is-lowest-value + +.mdl-slider__background-flex > .mdl-slider__background-upper { + left: 6px; } + .mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-webkit-slider-thumb { + box-shadow: 0 0 0 10px rgba(0,0,0, 0.12); + background: rgba(0,0,0, 0.12); } + .mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-moz-range-thumb { + box-shadow: 0 0 0 10px rgba(0,0,0, 0.12); + background: rgba(0,0,0, 0.12); } + .mdl-slider.is-upgraded.is-lowest-value:active::-webkit-slider-thumb { + border: 1.6px solid rgba(0,0,0, 0.26); + -webkit-transform: scale(1.5); + transform: scale(1.5); } + .mdl-slider.is-upgraded.is-lowest-value:active + +.mdl-slider__background-flex > .mdl-slider__background-upper { + left: 9px; } + .mdl-slider.is-upgraded.is-lowest-value:active::-moz-range-thumb { + border: 1.5px solid rgba(0,0,0, 0.26); + transform: scale(1.5); } + .mdl-slider.is-upgraded.is-lowest-value::-ms-thumb { + background: radial-gradient(circle closest-side, transparent 0%, transparent 66.67%, rgba(0,0,0, 0.26) 66.67%, rgba(0,0,0, 0.26) 100%); } + .mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-ms-thumb { + background: radial-gradient(circle closest-side, rgba(0,0,0, 0.12) 0%, rgba(0,0,0, 0.12) 25%, rgba(0,0,0, 0.26) 25%, rgba(0,0,0, 0.26) 37.5%, rgba(0,0,0, 0.12) 37.5%, rgba(0,0,0, 0.12) 100%); + transform: scale(1); } + .mdl-slider.is-upgraded.is-lowest-value:active::-ms-thumb { + transform: scale(0.5625); + background: radial-gradient(circle closest-side, transparent 0%, transparent 77.78%, rgba(0,0,0, 0.26) 77.78%, rgba(0,0,0, 0.26) 100%); } + .mdl-slider.is-upgraded.is-lowest-value::-ms-fill-lower { + background: transparent; } + .mdl-slider.is-upgraded.is-lowest-value::-ms-fill-upper { + margin-left: 6px; } + .mdl-slider.is-upgraded.is-lowest-value:active::-ms-fill-upper { + margin-left: 9px; } + .mdl-slider.is-upgraded:disabled:focus::-webkit-slider-thumb, .mdl-slider.is-upgraded:disabled:active::-webkit-slider-thumb, .mdl-slider.is-upgraded:disabled::-webkit-slider-thumb { + -webkit-transform: scale(0.667); + transform: scale(0.667); + background: rgba(0,0,0, 0.26); } + .mdl-slider.is-upgraded:disabled:focus::-moz-range-thumb, .mdl-slider.is-upgraded:disabled:active::-moz-range-thumb, .mdl-slider.is-upgraded:disabled::-moz-range-thumb { + transform: scale(0.667); + background: rgba(0,0,0, 0.26); } + .mdl-slider.is-upgraded:disabled + +.mdl-slider__background-flex > .mdl-slider__background-lower { + background-color: rgba(0,0,0, 0.26); + left: -6px; } + .mdl-slider.is-upgraded:disabled + +.mdl-slider__background-flex > .mdl-slider__background-upper { + left: 6px; } + .mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-webkit-slider-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled:active::-webkit-slider-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled::-webkit-slider-thumb { + border: 3px solid rgba(0,0,0, 0.26); + background: transparent; + -webkit-transform: scale(0.667); + transform: scale(0.667); } + .mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-moz-range-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled:active::-moz-range-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled::-moz-range-thumb { + border: 3px solid rgba(0,0,0, 0.26); + background: transparent; + transform: scale(0.667); } + .mdl-slider.is-upgraded.is-lowest-value:disabled:active + +.mdl-slider__background-flex > .mdl-slider__background-upper { + left: 6px; } + .mdl-slider.is-upgraded:disabled:focus::-ms-thumb, .mdl-slider.is-upgraded:disabled:active::-ms-thumb, .mdl-slider.is-upgraded:disabled::-ms-thumb { + transform: scale(0.25); + background: rgba(0,0,0, 0.26); } + .mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-ms-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled:active::-ms-thumb, .mdl-slider.is-upgraded.is-lowest-value:disabled::-ms-thumb { + transform: scale(0.25); + background: radial-gradient(circle closest-side, transparent 0%, transparent 50%, rgba(0,0,0, 0.26) 50%, rgba(0,0,0, 0.26) 100%); } + .mdl-slider.is-upgraded:disabled::-ms-fill-lower { + margin-right: 6px; + background: linear-gradient(to right, transparent, transparent 25px, rgba(0,0,0, 0.26) 25px, rgba(0,0,0, 0.26) 0); } + .mdl-slider.is-upgraded:disabled::-ms-fill-upper { + margin-left: 6px; } + .mdl-slider.is-upgraded.is-lowest-value:disabled:active::-ms-fill-upper { + margin-left: 6px; } + +.mdl-slider__ie-container { + height: 18px; + overflow: visible; + border: none; + margin: none; + padding: none; } + +.mdl-slider__container { + height: 18px; + position: relative; + background: none; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; } + +.mdl-slider__background-flex { + background: transparent; + position: absolute; + height: 2px; + width: calc(100% - 52px); + top: 50%; + left: 0; + margin: 0 26px; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + overflow: hidden; + border: 0; + padding: 0; + -webkit-transform: translate(0, -1px); + transform: translate(0, -1px); } + +.mdl-slider__background-lower { + background: rgb(63,81,181); + -webkit-flex: 0; + -ms-flex: 0; + flex: 0; + position: relative; + border: 0; + padding: 0; } + +.mdl-slider__background-upper { + background: rgba(0,0,0, 0.26); + -webkit-flex: 0; + -ms-flex: 0; + flex: 0; + position: relative; + border: 0; + padding: 0; + transition: left 0.18s cubic-bezier(0.4, 0, 0.2, 1); } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-snackbar { + position: fixed; + bottom: 0; + left: 50%; + cursor: default; + background-color: #323232; + z-index: 3; + display: block; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + will-change: transform; + -webkit-transform: translate(0, 80px); + transform: translate(0, 80px); + transition: -webkit-transform 0.25s cubic-bezier(0.4, 0, 1, 1); + transition: transform 0.25s cubic-bezier(0.4, 0, 1, 1); + transition: transform 0.25s cubic-bezier(0.4, 0, 1, 1), -webkit-transform 0.25s cubic-bezier(0.4, 0, 1, 1); + pointer-events: none; } + @media (max-width: 479px) { + .mdl-snackbar { + width: 100%; + left: 0; + min-height: 48px; + max-height: 80px; } } + @media (min-width: 480px) { + .mdl-snackbar { + min-width: 288px; + max-width: 568px; + border-radius: 2px; + -webkit-transform: translate(-50%, 80px); + transform: translate(-50%, 80px); } } + .mdl-snackbar--active { + -webkit-transform: translate(0, 0); + transform: translate(0, 0); + pointer-events: auto; + transition: -webkit-transform 0.25s cubic-bezier(0, 0, 0.2, 1); + transition: transform 0.25s cubic-bezier(0, 0, 0.2, 1); + transition: transform 0.25s cubic-bezier(0, 0, 0.2, 1), -webkit-transform 0.25s cubic-bezier(0, 0, 0.2, 1); } + @media (min-width: 480px) { + .mdl-snackbar--active { + -webkit-transform: translate(-50%, 0); + transform: translate(-50%, 0); } } + .mdl-snackbar__text { + padding: 14px 12px 14px 24px; + vertical-align: middle; + color: white; + float: left; } + .mdl-snackbar__action { + background: transparent; + border: none; + color: rgb(255,64,129); + float: right; + text-transform: uppercase; + padding: 14px 24px 14px 12px; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + text-transform: uppercase; + line-height: 1; + letter-spacing: 0; + overflow: hidden; + outline: none; + opacity: 0; + pointer-events: none; + cursor: pointer; + text-decoration: none; + text-align: center; + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; } + .mdl-snackbar__action::-moz-focus-inner { + border: 0; } + .mdl-snackbar__action:not([aria-hidden]) { + opacity: 1; + pointer-events: auto; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-spinner { + display: inline-block; + position: relative; + width: 28px; + height: 28px; } + .mdl-spinner:not(.is-upgraded).is-active:after { + content: "Loading..."; } + .mdl-spinner.is-upgraded.is-active { + -webkit-animation: mdl-spinner__container-rotate 1568.23529412ms linear infinite; + animation: mdl-spinner__container-rotate 1568.23529412ms linear infinite; } + +@-webkit-keyframes mdl-spinner__container-rotate { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +@keyframes mdl-spinner__container-rotate { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } + +.mdl-spinner__layer { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; } + +.mdl-spinner__layer-1 { + border-color: rgb(66,165,245); } + .mdl-spinner--single-color .mdl-spinner__layer-1 { + border-color: rgb(63,81,181); } + .mdl-spinner.is-active .mdl-spinner__layer-1 { + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + +.mdl-spinner__layer-2 { + border-color: rgb(244,67,54); } + .mdl-spinner--single-color .mdl-spinner__layer-2 { + border-color: rgb(63,81,181); } + .mdl-spinner.is-active .mdl-spinner__layer-2 { + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + +.mdl-spinner__layer-3 { + border-color: rgb(253,216,53); } + .mdl-spinner--single-color .mdl-spinner__layer-3 { + border-color: rgb(63,81,181); } + .mdl-spinner.is-active .mdl-spinner__layer-3 { + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + +.mdl-spinner__layer-4 { + border-color: rgb(76,175,80); } + .mdl-spinner--single-color .mdl-spinner__layer-4 { + border-color: rgb(63,81,181); } + .mdl-spinner.is-active .mdl-spinner__layer-4 { + -webkit-animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + +@-webkit-keyframes mdl-spinner__fill-unfill-rotate { + 12.5% { + -webkit-transform: rotate(135deg); + transform: rotate(135deg); } + 25% { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + 37.5% { + -webkit-transform: rotate(405deg); + transform: rotate(405deg); } + 50% { + -webkit-transform: rotate(540deg); + transform: rotate(540deg); } + 62.5% { + -webkit-transform: rotate(675deg); + transform: rotate(675deg); } + 75% { + -webkit-transform: rotate(810deg); + transform: rotate(810deg); } + 87.5% { + -webkit-transform: rotate(945deg); + transform: rotate(945deg); } + to { + -webkit-transform: rotate(1080deg); + transform: rotate(1080deg); } } + +@keyframes mdl-spinner__fill-unfill-rotate { + 12.5% { + -webkit-transform: rotate(135deg); + transform: rotate(135deg); } + 25% { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); } + 37.5% { + -webkit-transform: rotate(405deg); + transform: rotate(405deg); } + 50% { + -webkit-transform: rotate(540deg); + transform: rotate(540deg); } + 62.5% { + -webkit-transform: rotate(675deg); + transform: rotate(675deg); } + 75% { + -webkit-transform: rotate(810deg); + transform: rotate(810deg); } + 87.5% { + -webkit-transform: rotate(945deg); + transform: rotate(945deg); } + to { + -webkit-transform: rotate(1080deg); + transform: rotate(1080deg); } } + +/** +* HACK: Even though the intention is to have the current .mdl-spinner__layer-N +* at `opacity: 1`, we set it to `opacity: 0.99` instead since this forces Chrome +* to do proper subpixel rendering for the elements being animated. This is +* especially visible in Chrome 39 on Ubuntu 14.04. See: +* +* - https://github.com/Polymer/paper-spinner/issues/9 +* - https://code.google.com/p/chromium/issues/detail?id=436255 +*/ +@-webkit-keyframes mdl-spinner__layer-1-fade-in-out { + from { + opacity: 0.99; } + 25% { + opacity: 0.99; } + 26% { + opacity: 0; } + 89% { + opacity: 0; } + 90% { + opacity: 0.99; } + 100% { + opacity: 0.99; } } +@keyframes mdl-spinner__layer-1-fade-in-out { + from { + opacity: 0.99; } + 25% { + opacity: 0.99; } + 26% { + opacity: 0; } + 89% { + opacity: 0; } + 90% { + opacity: 0.99; } + 100% { + opacity: 0.99; } } + +@-webkit-keyframes mdl-spinner__layer-2-fade-in-out { + from { + opacity: 0; } + 15% { + opacity: 0; } + 25% { + opacity: 0.99; } + 50% { + opacity: 0.99; } + 51% { + opacity: 0; } } + +@keyframes mdl-spinner__layer-2-fade-in-out { + from { + opacity: 0; } + 15% { + opacity: 0; } + 25% { + opacity: 0.99; } + 50% { + opacity: 0.99; } + 51% { + opacity: 0; } } + +@-webkit-keyframes mdl-spinner__layer-3-fade-in-out { + from { + opacity: 0; } + 40% { + opacity: 0; } + 50% { + opacity: 0.99; } + 75% { + opacity: 0.99; } + 76% { + opacity: 0; } } + +@keyframes mdl-spinner__layer-3-fade-in-out { + from { + opacity: 0; } + 40% { + opacity: 0; } + 50% { + opacity: 0.99; } + 75% { + opacity: 0.99; } + 76% { + opacity: 0; } } + +@-webkit-keyframes mdl-spinner__layer-4-fade-in-out { + from { + opacity: 0; } + 65% { + opacity: 0; } + 75% { + opacity: 0.99; } + 90% { + opacity: 0.99; } + 100% { + opacity: 0; } } + +@keyframes mdl-spinner__layer-4-fade-in-out { + from { + opacity: 0; } + 65% { + opacity: 0; } + 75% { + opacity: 0.99; } + 90% { + opacity: 0.99; } + 100% { + opacity: 0; } } + +/** +* Patch the gap that appear between the two adjacent +* div.mdl-spinner__circle-clipper while the spinner is rotating +* (appears on Chrome 38, Safari 7.1, and IE 11). +* +* Update: the gap no longer appears on Chrome when .mdl-spinner__layer-N's +* opacity is 0.99, but still does on Safari and IE. +*/ +.mdl-spinner__gap-patch { + position: absolute; + box-sizing: border-box; + top: 0; + left: 45%; + width: 10%; + height: 100%; + overflow: hidden; + border-color: inherit; } + .mdl-spinner__gap-patch .mdl-spinner__circle { + width: 1000%; + left: -450%; } + +.mdl-spinner__circle-clipper { + display: inline-block; + position: relative; + width: 50%; + height: 100%; + overflow: hidden; + border-color: inherit; } + .mdl-spinner__circle-clipper .mdl-spinner__circle { + width: 200%; } + +.mdl-spinner__circle { + box-sizing: border-box; + height: 100%; + border-width: 3px; + border-style: solid; + border-color: inherit; + border-bottom-color: transparent !important; + border-radius: 50%; + -webkit-animation: none; + animation: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; } + .mdl-spinner__left .mdl-spinner__circle { + border-right-color: transparent !important; + -webkit-transform: rotate(129deg); + transform: rotate(129deg); } + .mdl-spinner.is-active .mdl-spinner__left .mdl-spinner__circle { + -webkit-animation: mdl-spinner__left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + .mdl-spinner__right .mdl-spinner__circle { + left: -100%; + border-left-color: transparent !important; + -webkit-transform: rotate(-129deg); + transform: rotate(-129deg); } + .mdl-spinner.is-active .mdl-spinner__right .mdl-spinner__circle { + -webkit-animation: mdl-spinner__right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: mdl-spinner__right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; } + +@-webkit-keyframes mdl-spinner__left-spin { + from { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } + 50% { + -webkit-transform: rotate(-5deg); + transform: rotate(-5deg); } + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } } + +@keyframes mdl-spinner__left-spin { + from { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } + 50% { + -webkit-transform: rotate(-5deg); + transform: rotate(-5deg); } + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); } } + +@-webkit-keyframes mdl-spinner__right-spin { + from { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } + 50% { + -webkit-transform: rotate(5deg); + transform: rotate(5deg); } + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } } + +@keyframes mdl-spinner__right-spin { + from { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } + 50% { + -webkit-transform: rotate(5deg); + transform: rotate(5deg); } + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-switch { + position: relative; + z-index: 1; + vertical-align: middle; + display: inline-block; + box-sizing: border-box; + width: 100%; + height: 24px; + margin: 0; + padding: 0; + overflow: visible; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + .mdl-switch.is-upgraded { + padding-left: 28px; } + +.mdl-switch__input { + line-height: 24px; } + .mdl-switch.is-upgraded .mdl-switch__input { + position: absolute; + width: 0; + height: 0; + margin: 0; + padding: 0; + opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + border: none; } + +.mdl-switch__track { + background: rgba(0,0,0, 0.26); + position: absolute; + left: 0; + top: 5px; + height: 14px; + width: 36px; + border-radius: 14px; + cursor: pointer; } + .mdl-switch.is-checked .mdl-switch__track { + background: rgba(63,81,181, 0.5); } + .mdl-switch__track fieldset[disabled] .mdl-switch, + .mdl-switch.is-disabled .mdl-switch__track { + background: rgba(0,0,0, 0.12); + cursor: auto; } + +.mdl-switch__thumb { + background: rgb(250,250,250); + position: absolute; + left: 0; + top: 2px; + height: 20px; + width: 20px; + border-radius: 50%; + cursor: pointer; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); + transition-duration: 0.28s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-property: left; } + .mdl-switch.is-checked .mdl-switch__thumb { + background: rgb(63,81,181); + left: 16px; + box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.2), 0 1px 8px 0 rgba(0, 0, 0, 0.12); } + .mdl-switch__thumb fieldset[disabled] .mdl-switch, + .mdl-switch.is-disabled .mdl-switch__thumb { + background: rgb(189,189,189); + cursor: auto; } + +.mdl-switch__focus-helper { + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-4px, -4px); + transform: translate(-4px, -4px); + display: inline-block; + box-sizing: border-box; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: transparent; } + .mdl-switch.is-focused .mdl-switch__focus-helper { + box-shadow: 0 0 0px 20px rgba(0, 0, 0, 0.1); + background-color: rgba(0, 0, 0, 0.1); } + .mdl-switch.is-focused.is-checked .mdl-switch__focus-helper { + box-shadow: 0 0 0px 20px rgba(63,81,181, 0.26); + background-color: rgba(63,81,181, 0.26); } + +.mdl-switch__label { + position: relative; + cursor: pointer; + font-size: 16px; + line-height: 24px; + margin: 0; + left: 24px; } + .mdl-switch__label fieldset[disabled] .mdl-switch, + .mdl-switch.is-disabled .mdl-switch__label { + color: rgb(189,189,189); + cursor: auto; } + +.mdl-switch__ripple-container { + position: absolute; + z-index: 2; + top: -12px; + left: -14px; + box-sizing: border-box; + width: 48px; + height: 48px; + border-radius: 50%; + cursor: pointer; + overflow: hidden; + -webkit-mask-image: -webkit-radial-gradient(circle, white, black); + transition-duration: 0.40s; + transition-timing-function: step-end; + transition-property: left; } + .mdl-switch__ripple-container .mdl-ripple { + background: rgb(63,81,181); } + .mdl-switch__ripple-container fieldset[disabled] .mdl-switch, + .mdl-switch.is-disabled .mdl-switch__ripple-container { + cursor: auto; } + fieldset[disabled] .mdl-switch .mdl-switch__ripple-container .mdl-ripple, + .mdl-switch.is-disabled .mdl-switch__ripple-container .mdl-ripple { + background: transparent; } + .mdl-switch.is-checked .mdl-switch__ripple-container { + left: 2px; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-tabs { + display: block; + width: 100%; } + +.mdl-tabs__tab-bar { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-content: space-between; + -ms-flex-line-pack: justify; + align-content: space-between; + -webkit-align-items: flex-start; + -ms-flex-align: start; + align-items: flex-start; + height: 48px; + padding: 0 0 0 0; + margin: 0; + border-bottom: 1px solid rgb(224,224,224); } + +.mdl-tabs__tab { + margin: 0; + border: none; + padding: 0 24px 0 24px; + float: left; + position: relative; + display: block; + text-decoration: none; + height: 48px; + line-height: 48px; + text-align: center; + font-weight: 500; + font-size: 14px; + text-transform: uppercase; + color: rgba(0,0,0, 0.54); + overflow: hidden; } + .mdl-tabs.is-upgraded .mdl-tabs__tab.is-active { + color: rgba(0,0,0, 0.87); } + .mdl-tabs.is-upgraded .mdl-tabs__tab.is-active:after { + height: 2px; + width: 100%; + display: block; + content: " "; + bottom: 0px; + left: 0px; + position: absolute; + background: rgb(63,81,181); + -webkit-animation: border-expand 0.2s cubic-bezier(0.4, 0, 0.4, 1) 0.01s alternate forwards; + animation: border-expand 0.2s cubic-bezier(0.4, 0, 0.4, 1) 0.01s alternate forwards; + transition: all 1s cubic-bezier(0.4, 0, 1, 1); } + .mdl-tabs__tab .mdl-tabs__ripple-container { + display: block; + position: absolute; + height: 100%; + width: 100%; + left: 0px; + top: 0px; + z-index: 1; + overflow: hidden; } + .mdl-tabs__tab .mdl-tabs__ripple-container .mdl-ripple { + background: rgb(63,81,181); } + +.mdl-tabs__panel { + display: block; } + .mdl-tabs.is-upgraded .mdl-tabs__panel { + display: none; } + .mdl-tabs.is-upgraded .mdl-tabs__panel.is-active { + display: block; } + +@-webkit-keyframes border-expand { + 0% { + opacity: 0; + width: 0; } + 100% { + opacity: 1; + width: 100%; } } + +@keyframes border-expand { + 0% { + opacity: 0; + width: 0; } + 100% { + opacity: 1; + width: 100%; } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-textfield { + position: relative; + font-size: 16px; + display: inline-block; + box-sizing: border-box; + width: 300px; + max-width: 100%; + margin: 0; + padding: 20px 0; } + .mdl-textfield .mdl-button { + position: absolute; + bottom: 20px; } + +.mdl-textfield--align-right { + text-align: right; } + +.mdl-textfield--full-width { + width: 100%; } + +.mdl-textfield--expandable { + min-width: 32px; + width: auto; + min-height: 32px; } + .mdl-textfield--expandable .mdl-button--icon { + top: 16px; } + +.mdl-textfield__input { + border: none; + border-bottom: 1px solid rgba(0,0,0, 0.12); + display: block; + font-size: 16px; + font-family: "Helvetica", "Arial", sans-serif; + margin: 0; + padding: 4px 0; + width: 100%; + background: none; + text-align: left; + color: inherit; } + .mdl-textfield__input[type="number"] { + -moz-appearance: textfield; } + .mdl-textfield__input[type="number"]::-webkit-inner-spin-button, .mdl-textfield__input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; } + .mdl-textfield.is-focused .mdl-textfield__input { + outline: none; } + .mdl-textfield.is-invalid .mdl-textfield__input { + border-color: rgb(213,0,0); + box-shadow: none; } + fieldset[disabled] .mdl-textfield .mdl-textfield__input, + .mdl-textfield.is-disabled .mdl-textfield__input { + background-color: transparent; + border-bottom: 1px dotted rgba(0,0,0, 0.12); + color: rgba(0,0,0, 0.26); } + +.mdl-textfield textarea.mdl-textfield__input { + display: block; } + +.mdl-textfield__label { + bottom: 0; + color: rgba(0,0,0, 0.26); + font-size: 16px; + left: 0; + right: 0; + pointer-events: none; + position: absolute; + display: block; + top: 24px; + width: 100%; + overflow: hidden; + white-space: nowrap; + text-align: left; } + .mdl-textfield.is-dirty .mdl-textfield__label, + .mdl-textfield.has-placeholder .mdl-textfield__label { + visibility: hidden; } + .mdl-textfield--floating-label .mdl-textfield__label { + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } + .mdl-textfield--floating-label.has-placeholder .mdl-textfield__label { + transition: none; } + fieldset[disabled] .mdl-textfield .mdl-textfield__label, + .mdl-textfield.is-disabled.is-disabled .mdl-textfield__label { + color: rgba(0,0,0, 0.26); } + .mdl-textfield--floating-label.is-focused .mdl-textfield__label, + .mdl-textfield--floating-label.is-dirty .mdl-textfield__label, + .mdl-textfield--floating-label.has-placeholder .mdl-textfield__label { + color: rgb(63,81,181); + font-size: 12px; + top: 4px; + visibility: visible; } + .mdl-textfield--floating-label.is-focused .mdl-textfield__expandable-holder .mdl-textfield__label, + .mdl-textfield--floating-label.is-dirty .mdl-textfield__expandable-holder .mdl-textfield__label, + .mdl-textfield--floating-label.has-placeholder .mdl-textfield__expandable-holder .mdl-textfield__label { + top: -16px; } + .mdl-textfield--floating-label.is-invalid .mdl-textfield__label { + color: rgb(213,0,0); + font-size: 12px; } + .mdl-textfield__label:after { + background-color: rgb(63,81,181); + bottom: 20px; + content: ''; + height: 2px; + left: 45%; + position: absolute; + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + visibility: hidden; + width: 10px; } + .mdl-textfield.is-focused .mdl-textfield__label:after { + left: 0; + visibility: visible; + width: 100%; } + .mdl-textfield.is-invalid .mdl-textfield__label:after { + background-color: rgb(213,0,0); } + +.mdl-textfield__error { + color: rgb(213,0,0); + position: absolute; + font-size: 12px; + margin-top: 3px; + visibility: hidden; + display: block; } + .mdl-textfield.is-invalid .mdl-textfield__error { + visibility: visible; } + +.mdl-textfield__expandable-holder { + display: inline-block; + position: relative; + margin-left: 32px; + transition-duration: 0.2s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + display: inline-block; + max-width: 0.1px; } + .mdl-textfield.is-focused .mdl-textfield__expandable-holder, .mdl-textfield.is-dirty .mdl-textfield__expandable-holder { + max-width: 600px; } + .mdl-textfield__expandable-holder .mdl-textfield__label:after { + bottom: 0; } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-tooltip { + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transform-origin: top center; + transform-origin: top center; + z-index: 999; + background: rgba(97,97,97, 0.9); + border-radius: 2px; + color: rgb(255,255,255); + display: inline-block; + font-size: 10px; + font-weight: 500; + line-height: 14px; + max-width: 170px; + position: fixed; + top: -500px; + left: -500px; + padding: 8px; + text-align: center; } + +.mdl-tooltip.is-active { + -webkit-animation: pulse 200ms cubic-bezier(0, 0, 0.2, 1) forwards; + animation: pulse 200ms cubic-bezier(0, 0, 0.2, 1) forwards; } + +.mdl-tooltip--large { + line-height: 14px; + font-size: 14px; + padding: 16px; } + +@-webkit-keyframes pulse { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + opacity: 0; } + 50% { + -webkit-transform: scale(0.99); + transform: scale(0.99); } + 100% { + -webkit-transform: scale(1); + transform: scale(1); + opacity: 1; + visibility: visible; } } + +@keyframes pulse { + 0% { + -webkit-transform: scale(0); + transform: scale(0); + opacity: 0; } + 50% { + -webkit-transform: scale(0.99); + transform: scale(0.99); } + 100% { + -webkit-transform: scale(1); + transform: scale(1); + opacity: 1; + visibility: visible; } } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Typography */ +/* Shadows */ +/* Animations */ +/* Dialog */ +.mdl-shadow--2dp { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); } + +.mdl-shadow--3dp { + box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.2), 0 1px 8px 0 rgba(0, 0, 0, 0.12); } + +.mdl-shadow--4dp { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2); } + +.mdl-shadow--6dp { + box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.2); } + +.mdl-shadow--8dp { + box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); } + +.mdl-shadow--16dp { + box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2); } + +.mdl-shadow--24dp { + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); } + +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +* NOTE: Some rules here are applied using duplicate selectors. +* This is on purpose to increase their specificity when applied. +* For example: `.mdl-cell--1-col-phone.mdl-cell--1-col-phone` +*/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*------------------------------------* $CONTENTS +\*------------------------------------*/ +/** + * STYLE GUIDE VARIABLES------------------Declarations of Sass variables + * -----Typography + * -----Colors + * -----Textfield + * -----Switch + * -----Spinner + * -----Radio + * -----Menu + * -----List + * -----Layout + * -----Icon toggles + * -----Footer + * -----Column + * -----Checkbox + * -----Card + * -----Button + * -----Animation + * -----Progress + * -----Badge + * -----Shadows + * -----Grid + * -----Data table + * -----Dialog + * -----Snackbar + * -----Tooltip + * -----Chip + * + * Even though all variables have the `!default` directive, most of them + * should not be changed as they are dependent one another. This can cause + * visual distortions (like alignment issues) that are hard to track down + * and fix. + */ +/* ========== TYPOGRAPHY ========== */ +/* We're splitting fonts into "preferred" and "performance" in order to optimize + page loading. For important text, such as the body, we want it to load + immediately and not wait for the web font load, whereas for other sections, + such as headers and titles, we're OK with things taking a bit longer to load. + We do have some optional classes and parameters in the mixins, in case you + definitely want to make sure you're using the preferred font and don't mind + the performance hit. + We should be able to improve on this once CSS Font Loading L3 becomes more + widely available. +*/ +/* ========== COLORS ========== */ +/** +* +* Material design color palettes. +* @see http://www.google.com/design/spec/style/color.html +* +**/ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== Color Palettes ========== */ +/* colors.scss */ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* ========== IMAGES ========== */ +/* ========== Color & Themes ========== */ +/* ========== Typography ========== */ +/* ========== Components ========== */ +/* ========== Standard Buttons ========== */ +/* ========== Icon Toggles ========== */ +/* ========== Radio Buttons ========== */ +/* ========== Ripple effect ========== */ +/* ========== Layout ========== */ +/* ========== Content Tabs ========== */ +/* ========== Checkboxes ========== */ +/* ========== Switches ========== */ +/* ========== Spinner ========== */ +/* ========== Text fields ========== */ +/* ========== Card ========== */ +/* ========== Sliders ========== */ +/* ========== Progress ========== */ +/* ========== List ========== */ +/* ========== Item ========== */ +/* ========== Dropdown menu ========== */ +/* ========== Tooltips ========== */ +/* ========== Footer ========== */ +/* TEXTFIELD */ +/* SWITCH */ +/* SPINNER */ +/* RADIO */ +/* MENU */ +/* LIST */ +/* LAYOUT */ +/* ICON TOGGLE */ +/* FOOTER */ +/*mega-footer*/ +/*mini-footer*/ +/* CHECKBOX */ +/* CARD */ +/* Card dimensions */ +/* Cover image */ +/* BUTTON */ +/** + * + * Dimensions + * + */ +/* ANIMATION */ +/* PROGRESS */ +/* BADGE */ +/* SHADOWS */ +/* GRID */ +/* DATA TABLE */ +/* DIALOG */ +/* SNACKBAR */ +/* TOOLTIP */ +/* CHIP */ +.mdl-grid { + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + margin: 0 auto 0 auto; + -webkit-align-items: stretch; + -ms-flex-align: stretch; + align-items: stretch; } + .mdl-grid.mdl-grid--no-spacing { + padding: 0; } + +.mdl-cell { + box-sizing: border-box; } + +.mdl-cell--top { + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; } + +.mdl-cell--middle { + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; } + +.mdl-cell--bottom { + -webkit-align-self: flex-end; + -ms-flex-item-align: end; + align-self: flex-end; } + +.mdl-cell--stretch { + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; } + +.mdl-grid.mdl-grid--no-spacing > .mdl-cell { + margin: 0; } + +.mdl-cell--order-1 { + -webkit-order: 1; + -ms-flex-order: 1; + order: 1; } + +.mdl-cell--order-2 { + -webkit-order: 2; + -ms-flex-order: 2; + order: 2; } + +.mdl-cell--order-3 { + -webkit-order: 3; + -ms-flex-order: 3; + order: 3; } + +.mdl-cell--order-4 { + -webkit-order: 4; + -ms-flex-order: 4; + order: 4; } + +.mdl-cell--order-5 { + -webkit-order: 5; + -ms-flex-order: 5; + order: 5; } + +.mdl-cell--order-6 { + -webkit-order: 6; + -ms-flex-order: 6; + order: 6; } + +.mdl-cell--order-7 { + -webkit-order: 7; + -ms-flex-order: 7; + order: 7; } + +.mdl-cell--order-8 { + -webkit-order: 8; + -ms-flex-order: 8; + order: 8; } + +.mdl-cell--order-9 { + -webkit-order: 9; + -ms-flex-order: 9; + order: 9; } + +.mdl-cell--order-10 { + -webkit-order: 10; + -ms-flex-order: 10; + order: 10; } + +.mdl-cell--order-11 { + -webkit-order: 11; + -ms-flex-order: 11; + order: 11; } + +.mdl-cell--order-12 { + -webkit-order: 12; + -ms-flex-order: 12; + order: 12; } + +@media (max-width: 479px) { + .mdl-grid { + padding: 8px; } + .mdl-cell { + margin: 8px; + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell { + width: 100%; } + .mdl-cell--hide-phone { + display: none !important; } + .mdl-cell--order-1-phone.mdl-cell--order-1-phone { + -webkit-order: 1; + -ms-flex-order: 1; + order: 1; } + .mdl-cell--order-2-phone.mdl-cell--order-2-phone { + -webkit-order: 2; + -ms-flex-order: 2; + order: 2; } + .mdl-cell--order-3-phone.mdl-cell--order-3-phone { + -webkit-order: 3; + -ms-flex-order: 3; + order: 3; } + .mdl-cell--order-4-phone.mdl-cell--order-4-phone { + -webkit-order: 4; + -ms-flex-order: 4; + order: 4; } + .mdl-cell--order-5-phone.mdl-cell--order-5-phone { + -webkit-order: 5; + -ms-flex-order: 5; + order: 5; } + .mdl-cell--order-6-phone.mdl-cell--order-6-phone { + -webkit-order: 6; + -ms-flex-order: 6; + order: 6; } + .mdl-cell--order-7-phone.mdl-cell--order-7-phone { + -webkit-order: 7; + -ms-flex-order: 7; + order: 7; } + .mdl-cell--order-8-phone.mdl-cell--order-8-phone { + -webkit-order: 8; + -ms-flex-order: 8; + order: 8; } + .mdl-cell--order-9-phone.mdl-cell--order-9-phone { + -webkit-order: 9; + -ms-flex-order: 9; + order: 9; } + .mdl-cell--order-10-phone.mdl-cell--order-10-phone { + -webkit-order: 10; + -ms-flex-order: 10; + order: 10; } + .mdl-cell--order-11-phone.mdl-cell--order-11-phone { + -webkit-order: 11; + -ms-flex-order: 11; + order: 11; } + .mdl-cell--order-12-phone.mdl-cell--order-12-phone { + -webkit-order: 12; + -ms-flex-order: 12; + order: 12; } + .mdl-cell--1-col, + .mdl-cell--1-col-phone.mdl-cell--1-col-phone { + width: calc(25% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--1-col, .mdl-grid--no-spacing > + .mdl-cell--1-col-phone.mdl-cell--1-col-phone { + width: 25%; } + .mdl-cell--2-col, + .mdl-cell--2-col-phone.mdl-cell--2-col-phone { + width: calc(50% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--2-col, .mdl-grid--no-spacing > + .mdl-cell--2-col-phone.mdl-cell--2-col-phone { + width: 50%; } + .mdl-cell--3-col, + .mdl-cell--3-col-phone.mdl-cell--3-col-phone { + width: calc(75% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--3-col, .mdl-grid--no-spacing > + .mdl-cell--3-col-phone.mdl-cell--3-col-phone { + width: 75%; } + .mdl-cell--4-col, + .mdl-cell--4-col-phone.mdl-cell--4-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--4-col, .mdl-grid--no-spacing > + .mdl-cell--4-col-phone.mdl-cell--4-col-phone { + width: 100%; } + .mdl-cell--5-col, + .mdl-cell--5-col-phone.mdl-cell--5-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--5-col, .mdl-grid--no-spacing > + .mdl-cell--5-col-phone.mdl-cell--5-col-phone { + width: 100%; } + .mdl-cell--6-col, + .mdl-cell--6-col-phone.mdl-cell--6-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--6-col, .mdl-grid--no-spacing > + .mdl-cell--6-col-phone.mdl-cell--6-col-phone { + width: 100%; } + .mdl-cell--7-col, + .mdl-cell--7-col-phone.mdl-cell--7-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--7-col, .mdl-grid--no-spacing > + .mdl-cell--7-col-phone.mdl-cell--7-col-phone { + width: 100%; } + .mdl-cell--8-col, + .mdl-cell--8-col-phone.mdl-cell--8-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--8-col, .mdl-grid--no-spacing > + .mdl-cell--8-col-phone.mdl-cell--8-col-phone { + width: 100%; } + .mdl-cell--9-col, + .mdl-cell--9-col-phone.mdl-cell--9-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--9-col, .mdl-grid--no-spacing > + .mdl-cell--9-col-phone.mdl-cell--9-col-phone { + width: 100%; } + .mdl-cell--10-col, + .mdl-cell--10-col-phone.mdl-cell--10-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--10-col, .mdl-grid--no-spacing > + .mdl-cell--10-col-phone.mdl-cell--10-col-phone { + width: 100%; } + .mdl-cell--11-col, + .mdl-cell--11-col-phone.mdl-cell--11-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--11-col, .mdl-grid--no-spacing > + .mdl-cell--11-col-phone.mdl-cell--11-col-phone { + width: 100%; } + .mdl-cell--12-col, + .mdl-cell--12-col-phone.mdl-cell--12-col-phone { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--12-col, .mdl-grid--no-spacing > + .mdl-cell--12-col-phone.mdl-cell--12-col-phone { + width: 100%; } + .mdl-cell--1-offset, + .mdl-cell--1-offset-phone.mdl-cell--1-offset-phone { + margin-left: calc(25% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--1-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--1-offset-phone.mdl-cell--1-offset-phone { + margin-left: 25%; } + .mdl-cell--2-offset, + .mdl-cell--2-offset-phone.mdl-cell--2-offset-phone { + margin-left: calc(50% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--2-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--2-offset-phone.mdl-cell--2-offset-phone { + margin-left: 50%; } + .mdl-cell--3-offset, + .mdl-cell--3-offset-phone.mdl-cell--3-offset-phone { + margin-left: calc(75% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--3-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--3-offset-phone.mdl-cell--3-offset-phone { + margin-left: 75%; } } + +@media (min-width: 480px) and (max-width: 839px) { + .mdl-grid { + padding: 8px; } + .mdl-cell { + margin: 8px; + width: calc(50% - 16px); } + .mdl-grid--no-spacing > .mdl-cell { + width: 50%; } + .mdl-cell--hide-tablet { + display: none !important; } + .mdl-cell--order-1-tablet.mdl-cell--order-1-tablet { + -webkit-order: 1; + -ms-flex-order: 1; + order: 1; } + .mdl-cell--order-2-tablet.mdl-cell--order-2-tablet { + -webkit-order: 2; + -ms-flex-order: 2; + order: 2; } + .mdl-cell--order-3-tablet.mdl-cell--order-3-tablet { + -webkit-order: 3; + -ms-flex-order: 3; + order: 3; } + .mdl-cell--order-4-tablet.mdl-cell--order-4-tablet { + -webkit-order: 4; + -ms-flex-order: 4; + order: 4; } + .mdl-cell--order-5-tablet.mdl-cell--order-5-tablet { + -webkit-order: 5; + -ms-flex-order: 5; + order: 5; } + .mdl-cell--order-6-tablet.mdl-cell--order-6-tablet { + -webkit-order: 6; + -ms-flex-order: 6; + order: 6; } + .mdl-cell--order-7-tablet.mdl-cell--order-7-tablet { + -webkit-order: 7; + -ms-flex-order: 7; + order: 7; } + .mdl-cell--order-8-tablet.mdl-cell--order-8-tablet { + -webkit-order: 8; + -ms-flex-order: 8; + order: 8; } + .mdl-cell--order-9-tablet.mdl-cell--order-9-tablet { + -webkit-order: 9; + -ms-flex-order: 9; + order: 9; } + .mdl-cell--order-10-tablet.mdl-cell--order-10-tablet { + -webkit-order: 10; + -ms-flex-order: 10; + order: 10; } + .mdl-cell--order-11-tablet.mdl-cell--order-11-tablet { + -webkit-order: 11; + -ms-flex-order: 11; + order: 11; } + .mdl-cell--order-12-tablet.mdl-cell--order-12-tablet { + -webkit-order: 12; + -ms-flex-order: 12; + order: 12; } + .mdl-cell--1-col, + .mdl-cell--1-col-tablet.mdl-cell--1-col-tablet { + width: calc(12.5% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--1-col, .mdl-grid--no-spacing > + .mdl-cell--1-col-tablet.mdl-cell--1-col-tablet { + width: 12.5%; } + .mdl-cell--2-col, + .mdl-cell--2-col-tablet.mdl-cell--2-col-tablet { + width: calc(25% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--2-col, .mdl-grid--no-spacing > + .mdl-cell--2-col-tablet.mdl-cell--2-col-tablet { + width: 25%; } + .mdl-cell--3-col, + .mdl-cell--3-col-tablet.mdl-cell--3-col-tablet { + width: calc(37.5% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--3-col, .mdl-grid--no-spacing > + .mdl-cell--3-col-tablet.mdl-cell--3-col-tablet { + width: 37.5%; } + .mdl-cell--4-col, + .mdl-cell--4-col-tablet.mdl-cell--4-col-tablet { + width: calc(50% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--4-col, .mdl-grid--no-spacing > + .mdl-cell--4-col-tablet.mdl-cell--4-col-tablet { + width: 50%; } + .mdl-cell--5-col, + .mdl-cell--5-col-tablet.mdl-cell--5-col-tablet { + width: calc(62.5% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--5-col, .mdl-grid--no-spacing > + .mdl-cell--5-col-tablet.mdl-cell--5-col-tablet { + width: 62.5%; } + .mdl-cell--6-col, + .mdl-cell--6-col-tablet.mdl-cell--6-col-tablet { + width: calc(75% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--6-col, .mdl-grid--no-spacing > + .mdl-cell--6-col-tablet.mdl-cell--6-col-tablet { + width: 75%; } + .mdl-cell--7-col, + .mdl-cell--7-col-tablet.mdl-cell--7-col-tablet { + width: calc(87.5% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--7-col, .mdl-grid--no-spacing > + .mdl-cell--7-col-tablet.mdl-cell--7-col-tablet { + width: 87.5%; } + .mdl-cell--8-col, + .mdl-cell--8-col-tablet.mdl-cell--8-col-tablet { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--8-col, .mdl-grid--no-spacing > + .mdl-cell--8-col-tablet.mdl-cell--8-col-tablet { + width: 100%; } + .mdl-cell--9-col, + .mdl-cell--9-col-tablet.mdl-cell--9-col-tablet { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--9-col, .mdl-grid--no-spacing > + .mdl-cell--9-col-tablet.mdl-cell--9-col-tablet { + width: 100%; } + .mdl-cell--10-col, + .mdl-cell--10-col-tablet.mdl-cell--10-col-tablet { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--10-col, .mdl-grid--no-spacing > + .mdl-cell--10-col-tablet.mdl-cell--10-col-tablet { + width: 100%; } + .mdl-cell--11-col, + .mdl-cell--11-col-tablet.mdl-cell--11-col-tablet { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--11-col, .mdl-grid--no-spacing > + .mdl-cell--11-col-tablet.mdl-cell--11-col-tablet { + width: 100%; } + .mdl-cell--12-col, + .mdl-cell--12-col-tablet.mdl-cell--12-col-tablet { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--12-col, .mdl-grid--no-spacing > + .mdl-cell--12-col-tablet.mdl-cell--12-col-tablet { + width: 100%; } + .mdl-cell--1-offset, + .mdl-cell--1-offset-tablet.mdl-cell--1-offset-tablet { + margin-left: calc(12.5% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--1-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--1-offset-tablet.mdl-cell--1-offset-tablet { + margin-left: 12.5%; } + .mdl-cell--2-offset, + .mdl-cell--2-offset-tablet.mdl-cell--2-offset-tablet { + margin-left: calc(25% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--2-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--2-offset-tablet.mdl-cell--2-offset-tablet { + margin-left: 25%; } + .mdl-cell--3-offset, + .mdl-cell--3-offset-tablet.mdl-cell--3-offset-tablet { + margin-left: calc(37.5% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--3-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--3-offset-tablet.mdl-cell--3-offset-tablet { + margin-left: 37.5%; } + .mdl-cell--4-offset, + .mdl-cell--4-offset-tablet.mdl-cell--4-offset-tablet { + margin-left: calc(50% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--4-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--4-offset-tablet.mdl-cell--4-offset-tablet { + margin-left: 50%; } + .mdl-cell--5-offset, + .mdl-cell--5-offset-tablet.mdl-cell--5-offset-tablet { + margin-left: calc(62.5% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--5-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--5-offset-tablet.mdl-cell--5-offset-tablet { + margin-left: 62.5%; } + .mdl-cell--6-offset, + .mdl-cell--6-offset-tablet.mdl-cell--6-offset-tablet { + margin-left: calc(75% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--6-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--6-offset-tablet.mdl-cell--6-offset-tablet { + margin-left: 75%; } + .mdl-cell--7-offset, + .mdl-cell--7-offset-tablet.mdl-cell--7-offset-tablet { + margin-left: calc(87.5% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--7-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--7-offset-tablet.mdl-cell--7-offset-tablet { + margin-left: 87.5%; } } + +@media (min-width: 840px) { + .mdl-grid { + padding: 8px; } + .mdl-cell { + margin: 8px; + width: calc(33.3333333333% - 16px); } + .mdl-grid--no-spacing > .mdl-cell { + width: 33.3333333333%; } + .mdl-cell--hide-desktop { + display: none !important; } + .mdl-cell--order-1-desktop.mdl-cell--order-1-desktop { + -webkit-order: 1; + -ms-flex-order: 1; + order: 1; } + .mdl-cell--order-2-desktop.mdl-cell--order-2-desktop { + -webkit-order: 2; + -ms-flex-order: 2; + order: 2; } + .mdl-cell--order-3-desktop.mdl-cell--order-3-desktop { + -webkit-order: 3; + -ms-flex-order: 3; + order: 3; } + .mdl-cell--order-4-desktop.mdl-cell--order-4-desktop { + -webkit-order: 4; + -ms-flex-order: 4; + order: 4; } + .mdl-cell--order-5-desktop.mdl-cell--order-5-desktop { + -webkit-order: 5; + -ms-flex-order: 5; + order: 5; } + .mdl-cell--order-6-desktop.mdl-cell--order-6-desktop { + -webkit-order: 6; + -ms-flex-order: 6; + order: 6; } + .mdl-cell--order-7-desktop.mdl-cell--order-7-desktop { + -webkit-order: 7; + -ms-flex-order: 7; + order: 7; } + .mdl-cell--order-8-desktop.mdl-cell--order-8-desktop { + -webkit-order: 8; + -ms-flex-order: 8; + order: 8; } + .mdl-cell--order-9-desktop.mdl-cell--order-9-desktop { + -webkit-order: 9; + -ms-flex-order: 9; + order: 9; } + .mdl-cell--order-10-desktop.mdl-cell--order-10-desktop { + -webkit-order: 10; + -ms-flex-order: 10; + order: 10; } + .mdl-cell--order-11-desktop.mdl-cell--order-11-desktop { + -webkit-order: 11; + -ms-flex-order: 11; + order: 11; } + .mdl-cell--order-12-desktop.mdl-cell--order-12-desktop { + -webkit-order: 12; + -ms-flex-order: 12; + order: 12; } + .mdl-cell--1-col, + .mdl-cell--1-col-desktop.mdl-cell--1-col-desktop { + width: calc(8.3333333333% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--1-col, .mdl-grid--no-spacing > + .mdl-cell--1-col-desktop.mdl-cell--1-col-desktop { + width: 8.3333333333%; } + .mdl-cell--2-col, + .mdl-cell--2-col-desktop.mdl-cell--2-col-desktop { + width: calc(16.6666666667% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--2-col, .mdl-grid--no-spacing > + .mdl-cell--2-col-desktop.mdl-cell--2-col-desktop { + width: 16.6666666667%; } + .mdl-cell--3-col, + .mdl-cell--3-col-desktop.mdl-cell--3-col-desktop { + width: calc(25% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--3-col, .mdl-grid--no-spacing > + .mdl-cell--3-col-desktop.mdl-cell--3-col-desktop { + width: 25%; } + .mdl-cell--4-col, + .mdl-cell--4-col-desktop.mdl-cell--4-col-desktop { + width: calc(33.3333333333% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--4-col, .mdl-grid--no-spacing > + .mdl-cell--4-col-desktop.mdl-cell--4-col-desktop { + width: 33.3333333333%; } + .mdl-cell--5-col, + .mdl-cell--5-col-desktop.mdl-cell--5-col-desktop { + width: calc(41.6666666667% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--5-col, .mdl-grid--no-spacing > + .mdl-cell--5-col-desktop.mdl-cell--5-col-desktop { + width: 41.6666666667%; } + .mdl-cell--6-col, + .mdl-cell--6-col-desktop.mdl-cell--6-col-desktop { + width: calc(50% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--6-col, .mdl-grid--no-spacing > + .mdl-cell--6-col-desktop.mdl-cell--6-col-desktop { + width: 50%; } + .mdl-cell--7-col, + .mdl-cell--7-col-desktop.mdl-cell--7-col-desktop { + width: calc(58.3333333333% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--7-col, .mdl-grid--no-spacing > + .mdl-cell--7-col-desktop.mdl-cell--7-col-desktop { + width: 58.3333333333%; } + .mdl-cell--8-col, + .mdl-cell--8-col-desktop.mdl-cell--8-col-desktop { + width: calc(66.6666666667% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--8-col, .mdl-grid--no-spacing > + .mdl-cell--8-col-desktop.mdl-cell--8-col-desktop { + width: 66.6666666667%; } + .mdl-cell--9-col, + .mdl-cell--9-col-desktop.mdl-cell--9-col-desktop { + width: calc(75% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--9-col, .mdl-grid--no-spacing > + .mdl-cell--9-col-desktop.mdl-cell--9-col-desktop { + width: 75%; } + .mdl-cell--10-col, + .mdl-cell--10-col-desktop.mdl-cell--10-col-desktop { + width: calc(83.3333333333% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--10-col, .mdl-grid--no-spacing > + .mdl-cell--10-col-desktop.mdl-cell--10-col-desktop { + width: 83.3333333333%; } + .mdl-cell--11-col, + .mdl-cell--11-col-desktop.mdl-cell--11-col-desktop { + width: calc(91.6666666667% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--11-col, .mdl-grid--no-spacing > + .mdl-cell--11-col-desktop.mdl-cell--11-col-desktop { + width: 91.6666666667%; } + .mdl-cell--12-col, + .mdl-cell--12-col-desktop.mdl-cell--12-col-desktop { + width: calc(100% - 16px); } + .mdl-grid--no-spacing > .mdl-cell--12-col, .mdl-grid--no-spacing > + .mdl-cell--12-col-desktop.mdl-cell--12-col-desktop { + width: 100%; } + .mdl-cell--1-offset, + .mdl-cell--1-offset-desktop.mdl-cell--1-offset-desktop { + margin-left: calc(8.3333333333% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--1-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--1-offset-desktop.mdl-cell--1-offset-desktop { + margin-left: 8.3333333333%; } + .mdl-cell--2-offset, + .mdl-cell--2-offset-desktop.mdl-cell--2-offset-desktop { + margin-left: calc(16.6666666667% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--2-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--2-offset-desktop.mdl-cell--2-offset-desktop { + margin-left: 16.6666666667%; } + .mdl-cell--3-offset, + .mdl-cell--3-offset-desktop.mdl-cell--3-offset-desktop { + margin-left: calc(25% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--3-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--3-offset-desktop.mdl-cell--3-offset-desktop { + margin-left: 25%; } + .mdl-cell--4-offset, + .mdl-cell--4-offset-desktop.mdl-cell--4-offset-desktop { + margin-left: calc(33.3333333333% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--4-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--4-offset-desktop.mdl-cell--4-offset-desktop { + margin-left: 33.3333333333%; } + .mdl-cell--5-offset, + .mdl-cell--5-offset-desktop.mdl-cell--5-offset-desktop { + margin-left: calc(41.6666666667% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--5-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--5-offset-desktop.mdl-cell--5-offset-desktop { + margin-left: 41.6666666667%; } + .mdl-cell--6-offset, + .mdl-cell--6-offset-desktop.mdl-cell--6-offset-desktop { + margin-left: calc(50% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--6-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--6-offset-desktop.mdl-cell--6-offset-desktop { + margin-left: 50%; } + .mdl-cell--7-offset, + .mdl-cell--7-offset-desktop.mdl-cell--7-offset-desktop { + margin-left: calc(58.3333333333% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--7-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--7-offset-desktop.mdl-cell--7-offset-desktop { + margin-left: 58.3333333333%; } + .mdl-cell--8-offset, + .mdl-cell--8-offset-desktop.mdl-cell--8-offset-desktop { + margin-left: calc(66.6666666667% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--8-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--8-offset-desktop.mdl-cell--8-offset-desktop { + margin-left: 66.6666666667%; } + .mdl-cell--9-offset, + .mdl-cell--9-offset-desktop.mdl-cell--9-offset-desktop { + margin-left: calc(75% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--9-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--9-offset-desktop.mdl-cell--9-offset-desktop { + margin-left: 75%; } + .mdl-cell--10-offset, + .mdl-cell--10-offset-desktop.mdl-cell--10-offset-desktop { + margin-left: calc(83.3333333333% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--10-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--10-offset-desktop.mdl-cell--10-offset-desktop { + margin-left: 83.3333333333%; } + .mdl-cell--11-offset, + .mdl-cell--11-offset-desktop.mdl-cell--11-offset-desktop { + margin-left: calc(91.6666666667% + 8px); } + .mdl-grid.mdl-grid--no-spacing > .mdl-cell--11-offset, .mdl-grid.mdl-grid--no-spacing > + .mdl-cell--11-offset-desktop.mdl-cell--11-offset-desktop { + margin-left: 91.6666666667%; } } \ No newline at end of file diff --git a/src/public/css/material.ext.css b/src/public/css/material.ext.css new file mode 100644 index 00000000..acd7885b --- /dev/null +++ b/src/public/css/material.ext.css @@ -0,0 +1,28 @@ +.mdl-selectfield{position:relative;font-size:16px;display:inline-block;box-sizing:border-box;width:300px;max-width:100%;margin:0;padding:20px 0}.mdl-selectfield--align-right{text-align:right}.mdl-selectfield--full-width{width:100%}.mdl-selectfield__select{display:block;width:100%;padding:4px 0;margin:0;color:inherit;background:transparent;font-size:16px;text-align:left;border:none;border-bottom:1px solid rgba(0,0,0, 0.12);border-radius:0;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none}.mdl-selectfield__select::-ms-expand{display:none}.mdl-selectfield.is-focused .mdl-selectfield__select{outline:none}.mdl-selectfield.is-invalid .mdl-selectfield__select{border-color:rgb(222, 50, 38);box-shadow:none}fieldset[disabled] .mdl-selectfield .mdl-selectfield__select,.mdl-selectfield.is-disabled .mdl-selectfield__select{background-color:transparent;border-bottom:1px dotted rgba(0,0,0, 0.12);color:rgba(0,0,0, 0.26)}.mdl-selectfield__label{bottom:0;color:rgba(0,0,0, 0.26);font-size:16px;left:0;right:0;pointer-events:none;position:absolute;display:block;top:24px;width:100%;overflow:hidden;white-space:nowrap;text-align:left}.mdl-selectfield.is-dirty .mdl-selectfield__label{visibility:hidden}.mdl-selectfield--floating-label .mdl-selectfield__label{transition-duration:0.2s;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1)}fieldset[disabled] .mdl-selectfield .mdl-selectfield__label,.mdl-selectfield.is-disabled.is-disabled .mdl-selectfield__label{color:rgba(0,0,0, 0.26)}.mdl-selectfield--floating-label.is-focused .mdl-selectfield__label,.mdl-selectfield--floating-label.is-dirty .mdl-selectfield__label{color:rgb(63,81,181);font-size:12px;top:4px;visibility:visible}.mdl-selectfield--floating-label.is-invalid .mdl-selectfield__label{color:rgb(222, 50, 38);font-size:12px}.mdl-selectfield__label:after{background-color:rgb(63,81,181);bottom:20px;content:'';height:2px;left:45%;position:absolute;transition-duration:0.2s;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);visibility:hidden;width:10px}.mdl-selectfield.is-focused .mdl-selectfield__label:after{left:0;visibility:visible;width:100%}.mdl-selectfield.is-invalid .mdl-selectfield__label:after{background-color:rgb(222, 50, 38)}.mdl-selectfield__error{color:rgb(222, 50, 38);position:absolute;font-size:12px;margin-top:3px;visibility:hidden;display:block}.mdl-selectfield.is-invalid .mdl-selectfield__error{visibility:visible}.mdl-selectfield__icon{bottom:20px;cursor:pointer;color:rgba(0,0,0, 0.26);padding:4px 0;position:absolute;top:20px;right:0;pointer-events:none}.mdl-selectfield__icon>i{outline:0}.mdl-selectfield.is-dirty .mdl-selectfield__icon{color:inherit}fieldset[disabled] .mdl-selectfield .mdl-selectfield__icon,.mdl-selectfield.is-disabled.is-disabled .mdl-selectfield__icon{color:rgba(0,0,0, 0.26)}.mdl-selectfield--floating-label.is-invalid .mdl-selectfield__icon{color:rgb(222, 50, 38)} + +.mdl-button--file input { + cursor: pointer; + height: 100%; + right: 0; + opacity: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 4; +} +/* https://codepen.io/mupkie/pen/LkdaEV */ +.mdl-select__arrow { + background: + linear-gradient(45deg, transparent 50%, rgba(0,0,0, 0.26) 50%), + linear-gradient(135deg, rgba(0,0,0, 0.26) 50%, transparent 50%), + linear-gradient(to right, transparent, transparent); + background-position: + calc(100% - 10px) calc(1em - 4px), + calc(100% - 5px) calc(1em - 4px), + 100% 0; + background-size: + 5px 5px, 5px 5px; + background-repeat: no-repeat; +} + +/*# sourceMappingURL=mdl-selectfield.min.css.map */ \ No newline at end of file diff --git a/src/public/css/messenger.css b/src/public/css/messenger.css new file mode 100644 index 00000000..64040c57 --- /dev/null +++ b/src/public/css/messenger.css @@ -0,0 +1,272 @@ + + +.opla-icon { + background-image: url("../images/opla-icon.svg"); + background-size: 30px; + background-repeat: no-repeat; + background-position-x: 13px; + background-position-y: 10px; + color: transparent; + width: 50px; + height: 50px; +} + +.messenger-box { + /*overflow: scroll;*/ + height: 79vh; + /*min-height: 560px; + padding-top: 0px;*/ + background: #f2f2f2; + /*-ms-overflow-style: none; + overflow: -moz-scrollbars-none;*/ +} +.messenger-box::-webkit-scrollbar { + width: 0 !important; +} + +.messenger-content { + padding: 0px; + position: relative; + overflow-x: hidden; + overflow-y: auto; + height: 100%; + /*margin-bottom: 32px;*/ +} + +.messenger-box__actions { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + flex: 1; + -webkit-box-ordinal-group: 3; + -webkit-order: 2; + -ms-flex-order: 2; + order: 2; + box-sizing: border-box; + padding: 6px 16px 6px 16px; + margin-top: 0px; + margin-bottom: 0px; + min-height: 40px; +} +.messenger-box__actions .mdl-textfield { + padding: 4px 0; + width: 100%; + margin-left: 8px; +} +.messenger-box__actions .mdl-textfield__label { + top: 6px; +} +.messenger-box__actions .mdl-textfield__label:after { + bottom: 2px; +} + +.messenger-box__actions .mdl-button { + position: relative; + margin: 0px; +} + +.messenger-box__actions .mdl-button-right { + margin-left: 16px; +} + +.messenger-box__actions .mdl-button-left { + color: gray; +} + +.message { + position: relative; + overflow: hidden; + /*width: 100%;*/ + margin-top: 20px; + margin-bottom: 20px; + margin-left: 8px; + margin-right: 8px; + padding-top: 4px; + padding-right: 10px; + padding-bottom: 0px; + padding-left: 10px; +} +.next { + margin-top: 2px; + padding: 0px 10px; +} +.message .circle-wrapper { + height: 42px; + width: 42px; + border-radius: 50%; +} +.next .circle-wrapper { + visibility: hidden; +} +.message .text-wrapper { + padding: 14px; + min-height: 48px; + width: 70%; + margin: 0 10px; + box-shadow: 0px 1px 0px 0px rgba(50, 50, 50, 0.3); + border-radius: 2px; + font-weight: 200; + font-size:18px; + position: relative; + /* word-break: break-all; */ + opacity: 0; +} + +.message .text-wrapper:before { + content: ''; + width: 0; + height: 0; + border-style: solid; +} +.message.from .circle-wrapper, .message.from .text-wrapper { + background: #fcea20; + font-weight: 300; + float: left; + text-align: left; + color: #000; +} +.message.from .circle-wrapper { + background-image: url("../images/opla-avatar.png"); + background-size: 100%; +} + +.message.from .text-wrapper:before { + border-width: 0 10px 10px 0; + border-color: transparent #fcea20 transparent transparent; + position: absolute; + top: 0; + left: -9px; +} + +.message.from.next .text-wrapper:before { + visibility: hidden; +} + +.message.you .circle-wrapper, .message.you .text-wrapper { + background: transparent; + font-weight: 300; + float: right; + text-align: right; + color: #333333; +} + +.message.you .circle-wrapper { + background-image: url("../images/default-avatar.png"); + background-size: 100%; +} + +.message.you .text-wrapper { + background: #ffffff; +} +.message.you .text-wrapper:before { + border-width: 10px 10px 0 0; + border-color: #ffffff transparent transparent transparent; + position: absolute; + top: 0; + right: -9px; +} + +.message.you.default .circle-wrapper { + background-image: url("../images/default-avatar.png"); + background-size: 100%; +} + +.message.you.bear .circle-wrapper { + background-image: url("../images/bear.png"); + background-size: 100%; +} + +.message.you.boar .circle-wrapper { + background-image: url("../images/boar.png"); + background-size: 100%; +} + +.message.you.deer .circle-wrapper { + background-image: url("../images/deer.png"); + background-size: 100%; +} + +.message.you.fox .circle-wrapper { + background-image: url("../images/fox.png"); + background-size: 100%; +} + +.message.you.giraffe .circle-wrapper { + background-image: url("../images/giraffe.png"); + background-size: 100%; +} + +.message.you.lion .circle-wrapper { + background-image: url("../images/lion.png"); + background-size: 100%; +} + +.message.you.racoon .circle-wrapper { + background-image: url("../images/racoon.png"); + background-size: 100%; +} + +.message.you .text-wrapper { + background: #ffffff; +} +.message.you .text-wrapper:before { + border-width: 10px 10px 0 0; + border-color: #ffffff transparent transparent transparent; + position: absolute; + top: 0; + right: -9px; +} + +.text-wrapper > a > img { + width: 80%; + padding-bottom: 16px; +} +.message_error { + color: white; + background: #FF8A80; +} +.message_error_header { + margin: 0; + padding: 8px 16px; + color: white; + background: #F44336; +} + +.message_welcome { + margin: 0px; + padding: 16px; + color: #ffffff; + font-size: 18px; + font-weight: 300; + background: #22bec4; +} +.message_error button { + margin: 8px 16px 8px 16px; +} + +@media screen and (max-width: 1024px) { + .mdl-dialog-container .mdl-dialog .mdl-dialog__content { + padding: 0px; + } + .wrapper { + width: 100%; + height: 100%; + height: 100vh; + top: 0; + left: 0; + -webkit-transform: translateX(0); + transform: translateX(0); + } + .wrapper .inner { + height: 100%; + height: 100vh; + } + .message .circle-wrapper { + visibility: hidden; + } + .message .text-wrapper { + padding: 8px; + width: 90%; + } +} diff --git a/src/public/images/bear.png b/src/public/images/bear.png new file mode 100644 index 00000000..8a9cfa35 Binary files /dev/null and b/src/public/images/bear.png differ diff --git a/src/public/images/bg.jpg b/src/public/images/bg.jpg new file mode 100644 index 00000000..83343cd1 Binary files /dev/null and b/src/public/images/bg.jpg differ diff --git a/src/public/images/boar.png b/src/public/images/boar.png new file mode 100644 index 00000000..fd613716 Binary files /dev/null and b/src/public/images/boar.png differ diff --git a/src/public/images/bot-builder.gif b/src/public/images/bot-builder.gif new file mode 100644 index 00000000..1ef1c6f6 Binary files /dev/null and b/src/public/images/bot-builder.gif differ diff --git a/src/public/images/bot-builder.png b/src/public/images/bot-builder.png new file mode 100644 index 00000000..1ad923e5 Binary files /dev/null and b/src/public/images/bot-builder.png differ diff --git a/src/public/images/deer.png b/src/public/images/deer.png new file mode 100644 index 00000000..b346dd9a Binary files /dev/null and b/src/public/images/deer.png differ diff --git a/src/public/images/default-avatar.png b/src/public/images/default-avatar.png new file mode 100644 index 00000000..288a2168 Binary files /dev/null and b/src/public/images/default-avatar.png differ diff --git a/src/public/images/fox.png b/src/public/images/fox.png new file mode 100644 index 00000000..744c3689 Binary files /dev/null and b/src/public/images/fox.png differ diff --git a/src/public/images/giraffe.png b/src/public/images/giraffe.png new file mode 100644 index 00000000..2c860b7e Binary files /dev/null and b/src/public/images/giraffe.png differ diff --git a/src/public/images/lion.png b/src/public/images/lion.png new file mode 100644 index 00000000..0cc09aec Binary files /dev/null and b/src/public/images/lion.png differ diff --git a/src/public/images/messenger.svg b/src/public/images/messenger.svg new file mode 100644 index 00000000..7b24b1fd --- /dev/null +++ b/src/public/images/messenger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/images/opla-avatar.png b/src/public/images/opla-avatar.png new file mode 100644 index 00000000..b7429502 Binary files /dev/null and b/src/public/images/opla-avatar.png differ diff --git a/src/public/images/opla-bubble.svg b/src/public/images/opla-bubble.svg new file mode 100644 index 00000000..4b3a48ad --- /dev/null +++ b/src/public/images/opla-bubble.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/src/public/images/opla-icon.png b/src/public/images/opla-icon.png new file mode 100644 index 00000000..4b06c4d7 Binary files /dev/null and b/src/public/images/opla-icon.png differ diff --git a/src/public/images/opla-icon.svg b/src/public/images/opla-icon.svg new file mode 100644 index 00000000..93f579f6 --- /dev/null +++ b/src/public/images/opla-icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/public/images/opla-logo.png b/src/public/images/opla-logo.png new file mode 100644 index 00000000..cd82ab16 Binary files /dev/null and b/src/public/images/opla-logo.png differ diff --git a/src/public/images/opla-white.png b/src/public/images/opla-white.png new file mode 100644 index 00000000..3e905b82 Binary files /dev/null and b/src/public/images/opla-white.png differ diff --git a/src/public/images/racoon.png b/src/public/images/racoon.png new file mode 100644 index 00000000..b7d3ec3a Binary files /dev/null and b/src/public/images/racoon.png differ diff --git a/src/public/images/robot.svg b/src/public/images/robot.svg new file mode 100644 index 00000000..9d916c69 --- /dev/null +++ b/src/public/images/robot.svg @@ -0,0 +1 @@ +Created by Darrin Loeligerfrom the Noun Project \ No newline at end of file diff --git a/src/public/images/robot2.svg b/src/public/images/robot2.svg new file mode 100644 index 00000000..c6663116 --- /dev/null +++ b/src/public/images/robot2.svg @@ -0,0 +1 @@ +Created by Hea Poh Linfrom the Noun Project \ No newline at end of file diff --git a/src/public/images/robots/001-robot-99.svg b/src/public/images/robots/001-robot-99.svg new file mode 100644 index 00000000..3215c4ea --- /dev/null +++ b/src/public/images/robots/001-robot-99.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/002-robot-98.svg b/src/public/images/robots/002-robot-98.svg new file mode 100644 index 00000000..810c5214 --- /dev/null +++ b/src/public/images/robots/002-robot-98.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/003-robot-97.svg b/src/public/images/robots/003-robot-97.svg new file mode 100644 index 00000000..fa030b14 --- /dev/null +++ b/src/public/images/robots/003-robot-97.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/004-robot-96.svg b/src/public/images/robots/004-robot-96.svg new file mode 100644 index 00000000..30fc7c84 --- /dev/null +++ b/src/public/images/robots/004-robot-96.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/005-robot-95.svg b/src/public/images/robots/005-robot-95.svg new file mode 100644 index 00000000..e1bbd9f4 --- /dev/null +++ b/src/public/images/robots/005-robot-95.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/006-robot-94.svg b/src/public/images/robots/006-robot-94.svg new file mode 100644 index 00000000..1a86096c --- /dev/null +++ b/src/public/images/robots/006-robot-94.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/007-robot-93.svg b/src/public/images/robots/007-robot-93.svg new file mode 100644 index 00000000..fc705843 --- /dev/null +++ b/src/public/images/robots/007-robot-93.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/008-robot-92.svg b/src/public/images/robots/008-robot-92.svg new file mode 100644 index 00000000..2a54242a --- /dev/null +++ b/src/public/images/robots/008-robot-92.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/009-robot-91.svg b/src/public/images/robots/009-robot-91.svg new file mode 100644 index 00000000..fc767883 --- /dev/null +++ b/src/public/images/robots/009-robot-91.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/010-robot-90.svg b/src/public/images/robots/010-robot-90.svg new file mode 100644 index 00000000..3217e80b --- /dev/null +++ b/src/public/images/robots/010-robot-90.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/011-robot-89.svg b/src/public/images/robots/011-robot-89.svg new file mode 100644 index 00000000..71164394 --- /dev/null +++ b/src/public/images/robots/011-robot-89.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/012-robot-88.svg b/src/public/images/robots/012-robot-88.svg new file mode 100644 index 00000000..bb8e0f5a --- /dev/null +++ b/src/public/images/robots/012-robot-88.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/013-robot-87.svg b/src/public/images/robots/013-robot-87.svg new file mode 100644 index 00000000..2eccb33b --- /dev/null +++ b/src/public/images/robots/013-robot-87.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/014-robot-86.svg b/src/public/images/robots/014-robot-86.svg new file mode 100644 index 00000000..a47ebec5 --- /dev/null +++ b/src/public/images/robots/014-robot-86.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/015-robot-85.svg b/src/public/images/robots/015-robot-85.svg new file mode 100644 index 00000000..6ca6b1ac --- /dev/null +++ b/src/public/images/robots/015-robot-85.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/016-robot-84.svg b/src/public/images/robots/016-robot-84.svg new file mode 100644 index 00000000..fe66fa2c --- /dev/null +++ b/src/public/images/robots/016-robot-84.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/017-robot-83.svg b/src/public/images/robots/017-robot-83.svg new file mode 100644 index 00000000..1022f874 --- /dev/null +++ b/src/public/images/robots/017-robot-83.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/018-robot-82.svg b/src/public/images/robots/018-robot-82.svg new file mode 100644 index 00000000..50f01741 --- /dev/null +++ b/src/public/images/robots/018-robot-82.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/019-robot-81.svg b/src/public/images/robots/019-robot-81.svg new file mode 100644 index 00000000..23ff1967 --- /dev/null +++ b/src/public/images/robots/019-robot-81.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/020-robot-80.svg b/src/public/images/robots/020-robot-80.svg new file mode 100644 index 00000000..a9157241 --- /dev/null +++ b/src/public/images/robots/020-robot-80.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/021-robot-79.svg b/src/public/images/robots/021-robot-79.svg new file mode 100644 index 00000000..a4ae8f2a --- /dev/null +++ b/src/public/images/robots/021-robot-79.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/022-robot-78.svg b/src/public/images/robots/022-robot-78.svg new file mode 100644 index 00000000..5af05744 --- /dev/null +++ b/src/public/images/robots/022-robot-78.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/023-robot-77.svg b/src/public/images/robots/023-robot-77.svg new file mode 100644 index 00000000..c66d0f17 --- /dev/null +++ b/src/public/images/robots/023-robot-77.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/024-robot-76.svg b/src/public/images/robots/024-robot-76.svg new file mode 100644 index 00000000..b2864b0a --- /dev/null +++ b/src/public/images/robots/024-robot-76.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/025-robot-75.svg b/src/public/images/robots/025-robot-75.svg new file mode 100644 index 00000000..2692af58 --- /dev/null +++ b/src/public/images/robots/025-robot-75.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/026-robot-74.svg b/src/public/images/robots/026-robot-74.svg new file mode 100644 index 00000000..65c737a3 --- /dev/null +++ b/src/public/images/robots/026-robot-74.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/027-robot-73.svg b/src/public/images/robots/027-robot-73.svg new file mode 100644 index 00000000..1818f1e0 --- /dev/null +++ b/src/public/images/robots/027-robot-73.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/028-robot-72.svg b/src/public/images/robots/028-robot-72.svg new file mode 100644 index 00000000..702e66ec --- /dev/null +++ b/src/public/images/robots/028-robot-72.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/029-robot-71.svg b/src/public/images/robots/029-robot-71.svg new file mode 100644 index 00000000..83c01cd2 --- /dev/null +++ b/src/public/images/robots/029-robot-71.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/030-robot-70.svg b/src/public/images/robots/030-robot-70.svg new file mode 100644 index 00000000..0edaede1 --- /dev/null +++ b/src/public/images/robots/030-robot-70.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/031-robot-69.svg b/src/public/images/robots/031-robot-69.svg new file mode 100644 index 00000000..c2abbf90 --- /dev/null +++ b/src/public/images/robots/031-robot-69.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/032-robot-68.svg b/src/public/images/robots/032-robot-68.svg new file mode 100644 index 00000000..322a6493 --- /dev/null +++ b/src/public/images/robots/032-robot-68.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/033-robot-67.svg b/src/public/images/robots/033-robot-67.svg new file mode 100644 index 00000000..fb9bfac0 --- /dev/null +++ b/src/public/images/robots/033-robot-67.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/034-robot-66.svg b/src/public/images/robots/034-robot-66.svg new file mode 100644 index 00000000..d39735d9 --- /dev/null +++ b/src/public/images/robots/034-robot-66.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/035-robot-65.svg b/src/public/images/robots/035-robot-65.svg new file mode 100644 index 00000000..5d3937dd --- /dev/null +++ b/src/public/images/robots/035-robot-65.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/036-robot-64.svg b/src/public/images/robots/036-robot-64.svg new file mode 100644 index 00000000..ff1f5bd8 --- /dev/null +++ b/src/public/images/robots/036-robot-64.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/037-robot-63.svg b/src/public/images/robots/037-robot-63.svg new file mode 100644 index 00000000..6858a25f --- /dev/null +++ b/src/public/images/robots/037-robot-63.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/038-robot-62.svg b/src/public/images/robots/038-robot-62.svg new file mode 100644 index 00000000..f5f6ee40 --- /dev/null +++ b/src/public/images/robots/038-robot-62.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/039-robot-61.svg b/src/public/images/robots/039-robot-61.svg new file mode 100644 index 00000000..fe03922d --- /dev/null +++ b/src/public/images/robots/039-robot-61.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/040-robot-60.svg b/src/public/images/robots/040-robot-60.svg new file mode 100644 index 00000000..1b59dd57 --- /dev/null +++ b/src/public/images/robots/040-robot-60.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/041-robot-59.svg b/src/public/images/robots/041-robot-59.svg new file mode 100644 index 00000000..d38aca82 --- /dev/null +++ b/src/public/images/robots/041-robot-59.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/042-robot-58.svg b/src/public/images/robots/042-robot-58.svg new file mode 100644 index 00000000..283cf892 --- /dev/null +++ b/src/public/images/robots/042-robot-58.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/043-robot-57.svg b/src/public/images/robots/043-robot-57.svg new file mode 100644 index 00000000..2c225b67 --- /dev/null +++ b/src/public/images/robots/043-robot-57.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/044-robot-56.svg b/src/public/images/robots/044-robot-56.svg new file mode 100644 index 00000000..d9a2403f --- /dev/null +++ b/src/public/images/robots/044-robot-56.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/045-robot-55.svg b/src/public/images/robots/045-robot-55.svg new file mode 100644 index 00000000..c0f38060 --- /dev/null +++ b/src/public/images/robots/045-robot-55.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/046-robot-54.svg b/src/public/images/robots/046-robot-54.svg new file mode 100644 index 00000000..8df8e487 --- /dev/null +++ b/src/public/images/robots/046-robot-54.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/047-robot-53.svg b/src/public/images/robots/047-robot-53.svg new file mode 100644 index 00000000..bbecb2b1 --- /dev/null +++ b/src/public/images/robots/047-robot-53.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/048-robot-52.svg b/src/public/images/robots/048-robot-52.svg new file mode 100644 index 00000000..f71345c8 --- /dev/null +++ b/src/public/images/robots/048-robot-52.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/049-robot-51.svg b/src/public/images/robots/049-robot-51.svg new file mode 100644 index 00000000..9c54e21a --- /dev/null +++ b/src/public/images/robots/049-robot-51.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/050-robot-50.svg b/src/public/images/robots/050-robot-50.svg new file mode 100644 index 00000000..89f9fa3b --- /dev/null +++ b/src/public/images/robots/050-robot-50.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/051-robot-49.svg b/src/public/images/robots/051-robot-49.svg new file mode 100644 index 00000000..5b994294 --- /dev/null +++ b/src/public/images/robots/051-robot-49.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/052-robot-48.svg b/src/public/images/robots/052-robot-48.svg new file mode 100644 index 00000000..b93394b5 --- /dev/null +++ b/src/public/images/robots/052-robot-48.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/053-robot-47.svg b/src/public/images/robots/053-robot-47.svg new file mode 100644 index 00000000..bb00fbe8 --- /dev/null +++ b/src/public/images/robots/053-robot-47.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/054-robot-46.svg b/src/public/images/robots/054-robot-46.svg new file mode 100644 index 00000000..28127840 --- /dev/null +++ b/src/public/images/robots/054-robot-46.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/055-robot-45.svg b/src/public/images/robots/055-robot-45.svg new file mode 100644 index 00000000..e8396aa9 --- /dev/null +++ b/src/public/images/robots/055-robot-45.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/056-robot-44.svg b/src/public/images/robots/056-robot-44.svg new file mode 100644 index 00000000..702473ec --- /dev/null +++ b/src/public/images/robots/056-robot-44.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/057-robot-43.svg b/src/public/images/robots/057-robot-43.svg new file mode 100644 index 00000000..96b6ec86 --- /dev/null +++ b/src/public/images/robots/057-robot-43.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/058-robot-42.svg b/src/public/images/robots/058-robot-42.svg new file mode 100644 index 00000000..efb19724 --- /dev/null +++ b/src/public/images/robots/058-robot-42.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/059-robot-41.svg b/src/public/images/robots/059-robot-41.svg new file mode 100644 index 00000000..be2e8c30 --- /dev/null +++ b/src/public/images/robots/059-robot-41.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/060-robot-40.svg b/src/public/images/robots/060-robot-40.svg new file mode 100644 index 00000000..3de9caf1 --- /dev/null +++ b/src/public/images/robots/060-robot-40.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/061-robot-39.svg b/src/public/images/robots/061-robot-39.svg new file mode 100644 index 00000000..308f426a --- /dev/null +++ b/src/public/images/robots/061-robot-39.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/062-robot-38.svg b/src/public/images/robots/062-robot-38.svg new file mode 100644 index 00000000..e410e4ef --- /dev/null +++ b/src/public/images/robots/062-robot-38.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/063-robot-37.svg b/src/public/images/robots/063-robot-37.svg new file mode 100644 index 00000000..fef26de1 --- /dev/null +++ b/src/public/images/robots/063-robot-37.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/064-robot-36.svg b/src/public/images/robots/064-robot-36.svg new file mode 100644 index 00000000..0222e823 --- /dev/null +++ b/src/public/images/robots/064-robot-36.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/065-robot-35.svg b/src/public/images/robots/065-robot-35.svg new file mode 100644 index 00000000..9b0af961 --- /dev/null +++ b/src/public/images/robots/065-robot-35.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/066-robot-34.svg b/src/public/images/robots/066-robot-34.svg new file mode 100644 index 00000000..a184d159 --- /dev/null +++ b/src/public/images/robots/066-robot-34.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/067-robot-33.svg b/src/public/images/robots/067-robot-33.svg new file mode 100644 index 00000000..159a0fc7 --- /dev/null +++ b/src/public/images/robots/067-robot-33.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/068-robot-32.svg b/src/public/images/robots/068-robot-32.svg new file mode 100644 index 00000000..61bfc6ae --- /dev/null +++ b/src/public/images/robots/068-robot-32.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/069-robot-31.svg b/src/public/images/robots/069-robot-31.svg new file mode 100644 index 00000000..a582a4a1 --- /dev/null +++ b/src/public/images/robots/069-robot-31.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/070-robot-30.svg b/src/public/images/robots/070-robot-30.svg new file mode 100644 index 00000000..c6fbbac9 --- /dev/null +++ b/src/public/images/robots/070-robot-30.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/071-robot-29.svg b/src/public/images/robots/071-robot-29.svg new file mode 100644 index 00000000..9b03cb9a --- /dev/null +++ b/src/public/images/robots/071-robot-29.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/072-robot-28.svg b/src/public/images/robots/072-robot-28.svg new file mode 100644 index 00000000..6d9c819c --- /dev/null +++ b/src/public/images/robots/072-robot-28.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/073-robot-27.svg b/src/public/images/robots/073-robot-27.svg new file mode 100644 index 00000000..9cc8f7dc --- /dev/null +++ b/src/public/images/robots/073-robot-27.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/074-robot-26.svg b/src/public/images/robots/074-robot-26.svg new file mode 100644 index 00000000..2aa5b17e --- /dev/null +++ b/src/public/images/robots/074-robot-26.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/075-robot-25.svg b/src/public/images/robots/075-robot-25.svg new file mode 100644 index 00000000..e4e14dd3 --- /dev/null +++ b/src/public/images/robots/075-robot-25.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/076-robot-24.svg b/src/public/images/robots/076-robot-24.svg new file mode 100644 index 00000000..9904ceff --- /dev/null +++ b/src/public/images/robots/076-robot-24.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/077-robot-23.svg b/src/public/images/robots/077-robot-23.svg new file mode 100644 index 00000000..11cc7494 --- /dev/null +++ b/src/public/images/robots/077-robot-23.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/078-robot-22.svg b/src/public/images/robots/078-robot-22.svg new file mode 100644 index 00000000..1cdaa26e --- /dev/null +++ b/src/public/images/robots/078-robot-22.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/079-robot-21.svg b/src/public/images/robots/079-robot-21.svg new file mode 100644 index 00000000..86fff7fc --- /dev/null +++ b/src/public/images/robots/079-robot-21.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/080-robot-20.svg b/src/public/images/robots/080-robot-20.svg new file mode 100644 index 00000000..9b163205 --- /dev/null +++ b/src/public/images/robots/080-robot-20.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/081-robot-19.svg b/src/public/images/robots/081-robot-19.svg new file mode 100644 index 00000000..d0498e2f --- /dev/null +++ b/src/public/images/robots/081-robot-19.svg @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/082-robot-18.svg b/src/public/images/robots/082-robot-18.svg new file mode 100644 index 00000000..0b33f55d --- /dev/null +++ b/src/public/images/robots/082-robot-18.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/083-robot-17.svg b/src/public/images/robots/083-robot-17.svg new file mode 100644 index 00000000..286ffacd --- /dev/null +++ b/src/public/images/robots/083-robot-17.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/084-robot-16.svg b/src/public/images/robots/084-robot-16.svg new file mode 100644 index 00000000..9cd32b2d --- /dev/null +++ b/src/public/images/robots/084-robot-16.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/085-robot-15.svg b/src/public/images/robots/085-robot-15.svg new file mode 100644 index 00000000..494b84af --- /dev/null +++ b/src/public/images/robots/085-robot-15.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/086-robot-14.svg b/src/public/images/robots/086-robot-14.svg new file mode 100644 index 00000000..aabec6c4 --- /dev/null +++ b/src/public/images/robots/086-robot-14.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/087-robot-13.svg b/src/public/images/robots/087-robot-13.svg new file mode 100644 index 00000000..1ffcbb54 --- /dev/null +++ b/src/public/images/robots/087-robot-13.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/088-robot-12.svg b/src/public/images/robots/088-robot-12.svg new file mode 100644 index 00000000..514f88ab --- /dev/null +++ b/src/public/images/robots/088-robot-12.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/089-robot-11.svg b/src/public/images/robots/089-robot-11.svg new file mode 100644 index 00000000..3dd5c3f6 --- /dev/null +++ b/src/public/images/robots/089-robot-11.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/090-robot-10.svg b/src/public/images/robots/090-robot-10.svg new file mode 100644 index 00000000..48e905b0 --- /dev/null +++ b/src/public/images/robots/090-robot-10.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/091-robot-9.svg b/src/public/images/robots/091-robot-9.svg new file mode 100644 index 00000000..042d633e --- /dev/null +++ b/src/public/images/robots/091-robot-9.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/092-robot-8.svg b/src/public/images/robots/092-robot-8.svg new file mode 100644 index 00000000..c87ef9f7 --- /dev/null +++ b/src/public/images/robots/092-robot-8.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/093-robot-7.svg b/src/public/images/robots/093-robot-7.svg new file mode 100644 index 00000000..d3e15413 --- /dev/null +++ b/src/public/images/robots/093-robot-7.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/094-robot-6.svg b/src/public/images/robots/094-robot-6.svg new file mode 100644 index 00000000..a5bd563d --- /dev/null +++ b/src/public/images/robots/094-robot-6.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/095-robot-5.svg b/src/public/images/robots/095-robot-5.svg new file mode 100644 index 00000000..1ae25415 --- /dev/null +++ b/src/public/images/robots/095-robot-5.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/robot-0.svg b/src/public/images/robots/robot-0.svg new file mode 100644 index 00000000..89f8c2fc --- /dev/null +++ b/src/public/images/robots/robot-0.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/robot-1.svg b/src/public/images/robots/robot-1.svg new file mode 100644 index 00000000..932b6152 --- /dev/null +++ b/src/public/images/robots/robot-1.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/robot-2.svg b/src/public/images/robots/robot-2.svg new file mode 100644 index 00000000..cf6053e6 --- /dev/null +++ b/src/public/images/robots/robot-2.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/robot-3.svg b/src/public/images/robots/robot-3.svg new file mode 100644 index 00000000..798f8aac --- /dev/null +++ b/src/public/images/robots/robot-3.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/robots/robot-4.svg b/src/public/images/robots/robot-4.svg new file mode 100644 index 00000000..3380a3eb --- /dev/null +++ b/src/public/images/robots/robot-4.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/public/images/skype.svg b/src/public/images/skype.svg new file mode 100644 index 00000000..f307a4dc --- /dev/null +++ b/src/public/images/skype.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/images/slack.svg b/src/public/images/slack.svg new file mode 100644 index 00000000..b58f6900 --- /dev/null +++ b/src/public/images/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/images/steampunk-robot.jpg b/src/public/images/steampunk-robot.jpg new file mode 100644 index 00000000..a5f3afad Binary files /dev/null and b/src/public/images/steampunk-robot.jpg differ diff --git a/src/public/images/steampunk-robot1.jpg b/src/public/images/steampunk-robot1.jpg new file mode 100644 index 00000000..3b871982 Binary files /dev/null and b/src/public/images/steampunk-robot1.jpg differ diff --git a/src/public/images/telegram.svg b/src/public/images/telegram.svg new file mode 100644 index 00000000..6b73318d --- /dev/null +++ b/src/public/images/telegram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/images/twitter.svg b/src/public/images/twitter.svg new file mode 100644 index 00000000..bb8354e9 --- /dev/null +++ b/src/public/images/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/images/wordpress.svg b/src/public/images/wordpress.svg new file mode 100644 index 00000000..1ce54992 --- /dev/null +++ b/src/public/images/wordpress.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/public/index.html b/src/public/index.html new file mode 100644 index 00000000..59f057ef --- /dev/null +++ b/src/public/index.html @@ -0,0 +1,22 @@ + + + + + Opla.ai + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/src/public/js/dialog-polyfill.js b/src/public/js/dialog-polyfill.js new file mode 100644 index 00000000..88e23d4e --- /dev/null +++ b/src/public/js/dialog-polyfill.js @@ -0,0 +1,533 @@ +(function() { + + var supportCustomEvent = window.CustomEvent; + if (!supportCustomEvent || typeof supportCustomEvent == 'object') { + supportCustomEvent = function CustomEvent(event, x) { + x = x || {}; + var ev = document.createEvent('CustomEvent'); + ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null); + return ev; + }; + supportCustomEvent.prototype = window.Event.prototype; + } + + /** + * Finds the nearest from the passed element. + * + * @param {Element} el to search from + * @return {HTMLDialogElement} dialog found + */ + function findNearestDialog(el) { + while (el) { + if (el.nodeName.toUpperCase() == 'DIALOG') { + return /** @type {HTMLDialogElement} */ (el); + } + el = el.parentElement; + } + return null; + } + + /** + * Blur the specified element, as long as it's not the HTML body element. + * This works around an IE9/10 bug - blurring the body causes Windows to + * blur the whole application. + * + * @param {Element} el to blur + */ + function safeBlur(el) { + if (el && el.blur && el != document.body) { + el.blur(); + } + } + + /** + * @param {!NodeList} nodeList to search + * @param {Node} node to find + * @return {boolean} whether node is inside nodeList + */ + function inNodeList(nodeList, node) { + for (var i = 0; i < nodeList.length; ++i) { + if (nodeList[i] == node) { + return true; + } + } + return false; + } + + /** + * @param {!HTMLDialogElement} dialog to upgrade + * @constructor + */ + function dialogPolyfillInfo(dialog) { + this.dialog_ = dialog; + this.replacedStyleTop_ = false; + this.openAsModal_ = false; + + // Set a11y role. Browsers that support dialog implicitly know this already. + if (!dialog.hasAttribute('role')) { + dialog.setAttribute('role', 'dialog'); + } + + dialog.show = this.show.bind(this); + dialog.showModal = this.showModal.bind(this); + dialog.close = this.close.bind(this); + + if (!('returnValue' in dialog)) { + dialog.returnValue = ''; + } + + this.maybeHideModal = this.maybeHideModal.bind(this); + if ('MutationObserver' in window) { + // IE11+, most other browsers. + var mo = new MutationObserver(this.maybeHideModal); + mo.observe(dialog, { attributes: true, attributeFilter: ['open'] }); + } else { + dialog.addEventListener('DOMAttrModified', this.maybeHideModal); + } + // Note that the DOM is observed inside DialogManager while any dialog + // is being displayed as a modal, to catch modal removal from the DOM. + + Object.defineProperty(dialog, 'open', { + set: this.setOpen.bind(this), + get: dialog.hasAttribute.bind(dialog, 'open') + }); + + this.backdrop_ = document.createElement('div'); + this.backdrop_.className = 'backdrop'; + this.backdropClick_ = this.backdropClick_.bind(this); + } + + dialogPolyfillInfo.prototype = { + + get dialog() { + return this.dialog_; + }, + + /** + * Maybe remove this dialog from the modal top layer. This is called when + * a modal dialog may no longer be tenable, e.g., when the dialog is no + * longer open or is no longer part of the DOM. + */ + maybeHideModal: function() { + if (!this.openAsModal_) { return; } + if (this.dialog_.hasAttribute('open') && + document.body.contains(this.dialog_)) { return; } + + this.openAsModal_ = false; + this.dialog_.style.zIndex = ''; + + // This won't match the native exactly because if the user set + // top on a centered polyfill dialog, that top gets thrown away when the + // dialog is closed. Not sure it's possible to polyfill this perfectly. + if (this.replacedStyleTop_) { + this.dialog_.style.top = ''; + this.replacedStyleTop_ = false; + } + + // Optimistically clear the modal part of this . + this.backdrop_.removeEventListener('click', this.backdropClick_); + if (this.backdrop_.parentElement) { + this.backdrop_.parentElement.removeChild(this.backdrop_); + } + dialogPolyfill.dm.removeDialog(this); + }, + + /** + * @param {boolean} value whether to open or close this dialog + */ + setOpen: function(value) { + if (value) { + this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', ''); + } else { + this.dialog_.removeAttribute('open'); + this.maybeHideModal(); // nb. redundant with MutationObserver + } + }, + + /** + * Handles clicks on the fake .backdrop element, redirecting them as if + * they were on the dialog itself. + * + * @param {!Event} e to redirect + */ + backdropClick_: function(e) { + var redirectedEvent = document.createEvent('MouseEvents'); + redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window, + e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, + e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); + this.dialog_.dispatchEvent(redirectedEvent); + e.stopPropagation(); + }, + + /** + * Focuses on the first focusable element within the dialog. This will always blur the current + * focus, even if nothing within the dialog is found. + */ + focus_: function() { + // Find element with `autofocus` attribute, or fall back to the first form/tabindex control. + var target = this.dialog_.querySelector('[autofocus]:not([disabled])'); + if (!target) { + // Note that this is 'any focusable area'. This list is probably not exhaustive, but the + // alternative involves stepping through and trying to focus everything. + var opts = ['button', 'input', 'keygen', 'select', 'textarea']; + var query = opts.map(function(el) { + return el + ':not([disabled])'; + }); + // TODO(samthor): tabindex values that are not numeric are not focusable. + query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled + target = this.dialog_.querySelector(query.join(', ')); + } + safeBlur(document.activeElement); + target && target.focus(); + }, + + /** + * Sets the zIndex for the backdrop and dialog. + * + * @param {number} backdropZ + * @param {number} dialogZ + */ + updateZIndex: function(backdropZ, dialogZ) { + this.backdrop_.style.zIndex = backdropZ; + this.dialog_.style.zIndex = dialogZ; + }, + + /** + * Shows the dialog. If the dialog is already open, this does nothing. + */ + show: function() { + if (!this.dialog_.open) { + this.setOpen(true); + this.focus_(); + } + }, + + /** + * Show this dialog modally. + */ + showModal: function() { + if (this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.'); + } + if (!document.body.contains(this.dialog_)) { + throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.'); + } + if (!dialogPolyfill.dm.pushDialog(this)) { + throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.'); + } + this.show(); + this.openAsModal_ = true; + + // Optionally center vertically, relative to the current viewport. + if (dialogPolyfill.needsCentering(this.dialog_)) { + console.info('repositioning what'); + dialogPolyfill.reposition(this.dialog_); + this.replacedStyleTop_ = true; + } else { + console.info('NOT repositioning'); + this.replacedStyleTop_ = false; + } + + // Insert backdrop. + this.backdrop_.addEventListener('click', this.backdropClick_); + this.dialog_.parentNode.insertBefore(this.backdrop_, + this.dialog_.nextSibling); + + this.dialog_.addEventListener('DOMNodeRemoved', function(ev) { + console.info('dialog itself removed', ev); + }); + }, + + /** + * Closes this HTMLDialogElement. This is optional vs clearing the open + * attribute, however this fires a 'close' event. + * + * @param {string=} opt_returnValue to use as the returnValue + */ + close: function(opt_returnValue) { + if (!this.dialog_.hasAttribute('open')) { + throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.'); + } + this.setOpen(false); + + // Leave returnValue untouched in case it was set directly on the element + if (opt_returnValue !== undefined) { + this.dialog_.returnValue = opt_returnValue; + } + + // Triggering "close" event for any attached listeners on the . + var closeEvent = new supportCustomEvent('close', { + bubbles: false, + cancelable: false + }); + this.dialog_.dispatchEvent(closeEvent); + } + + }; + + var dialogPolyfill = {}; + + dialogPolyfill.reposition = function(element) { + var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; + var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2; + element.style.top = Math.max(scrollTop, topValue) + 'px'; + }; + + dialogPolyfill.isInlinePositionSetByStylesheet = function(element) { + for (var i = 0; i < document.styleSheets.length; ++i) { + var styleSheet = document.styleSheets[i]; + var cssRules = null; + // Some browsers throw on cssRules. + try { + cssRules = styleSheet.cssRules; + } catch (e) {} + if (!cssRules) { continue; } + for (var j = 0; j < cssRules.length; ++j) { + var rule = cssRules[j]; + var selectedNodes = null; + // Ignore errors on invalid selector texts. + try { + selectedNodes = document.querySelectorAll(rule.selectorText); + } catch(e) {} + if (!selectedNodes || !inNodeList(selectedNodes, element)) { + continue; + } + var cssTop = rule.style.getPropertyValue('top'); + var cssBottom = rule.style.getPropertyValue('bottom'); + if ((cssTop && cssTop != 'auto') || (cssBottom && cssBottom != 'auto')) { + return true; + } + } + } + return false; + }; + + dialogPolyfill.needsCentering = function(dialog) { + var computedStyle = window.getComputedStyle(dialog); + if (computedStyle.position != 'absolute') { + return false; + } + + // We must determine whether the top/bottom specified value is non-auto. In + // WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but + // Firefox returns the used value. So we do this crazy thing instead: check + // the inline style and then go through CSS rules. + if ((dialog.style.top != 'auto' && dialog.style.top != '') || + (dialog.style.bottom != 'auto' && dialog.style.bottom != '')) + return false; + return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog); + }; + + /** + * @param {!Element} element to force upgrade + */ + dialogPolyfill.forceRegisterDialog = function(element) { + if (element.showModal) { + console.warn('This browser already supports , the polyfill ' + + 'may not work correctly', element); + } + if (element.nodeName.toUpperCase() != 'DIALOG') { + throw new Error('Failed to register dialog: The element is not a dialog.'); + } + new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element)); + }; + + /** + * @param {!Element} element to upgrade, if necessary + */ + dialogPolyfill.registerDialog = function(element) { + if (!element.showModal) { + dialogPolyfill.forceRegisterDialog(element); + } + }; + + /** + * @constructor + */ + dialogPolyfill.DialogManager = function() { + /** @type {!Array} */ + this.pendingDialogStack = []; + + // The overlay is used to simulate how a modal dialog blocks the document. + // The blocking dialog is positioned on top of the overlay, and the rest of + // the dialogs on the pending dialog stack are positioned below it. In the + // actual implementation, the modal dialog stacking is controlled by the + // top layer, where z-index has no effect. + this.overlay = document.createElement('div'); + this.overlay.className = '_dialog_overlay'; + this.overlay.addEventListener('click', function(e) { + e.stopPropagation(); + }); + + this.handleKey_ = this.handleKey_.bind(this); + this.handleFocus_ = this.handleFocus_.bind(this); + this.handleRemove_ = this.handleRemove_.bind(this); + + this.zIndexLow_ = 100000; + this.zIndexHigh_ = 100000 + 150; + }; + + /** + * @return {Element} the top HTML dialog element, if any + */ + dialogPolyfill.DialogManager.prototype.topDialogElement = function() { + if (this.pendingDialogStack.length) { + var t = this.pendingDialogStack[this.pendingDialogStack.length - 1]; + return t.dialog; + } + return null; + }; + + /** + * Called on the first modal dialog being shown. Adds the overlay and related + * handlers. + */ + dialogPolyfill.DialogManager.prototype.blockDocument = function() { + document.body.appendChild(this.overlay); + document.body.addEventListener('focus', this.handleFocus_, true); + document.addEventListener('keydown', this.handleKey_); + document.addEventListener('DOMNodeRemoved', this.handleRemove_); + }; + + /** + * Called on the first modal dialog being removed, i.e., when no more modal + * dialogs are visible. + */ + dialogPolyfill.DialogManager.prototype.unblockDocument = function() { + document.body.removeChild(this.overlay); + document.body.removeEventListener('focus', this.handleFocus_, true); + document.removeEventListener('keydown', this.handleKey_); + document.removeEventListener('DOMNodeRemoved', this.handleRemove_); + }; + + dialogPolyfill.DialogManager.prototype.updateStacking = function() { + var zIndex = this.zIndexLow_; + + for (var i = 0; i < this.pendingDialogStack.length; i++) { + if (i == this.pendingDialogStack.length - 1) { + this.overlay.style.zIndex = zIndex++; + } + this.pendingDialogStack[i].updateZIndex(zIndex++, zIndex++); + } + }; + + dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) { + var candidate = findNearestDialog(/** @type {Element} */ (event.target)); + if (candidate != this.topDialogElement()) { + event.preventDefault(); + event.stopPropagation(); + safeBlur(/** @type {Element} */ (event.target)); + // TODO: Focus on the browser chrome (aka document) or the dialog itself + // depending on the tab direction. + return false; + } + }; + + dialogPolyfill.DialogManager.prototype.handleKey_ = function(event) { + if (event.keyCode == 27) { + event.preventDefault(); + event.stopPropagation(); + var cancelEvent = new supportCustomEvent('cancel', { + bubbles: false, + cancelable: true + }); + var dialog = this.topDialogElement(); + if (dialog.dispatchEvent(cancelEvent)) { + dialog.close(); + } + } + }; + + dialogPolyfill.DialogManager.prototype.handleRemove_ = function(event) { + if (event.target.nodeName.toUpperCase() != 'DIALOG') { return; } + + var dialog = /** @type {HTMLDialogElement} */ (event.target); + if (!dialog.open) { return; } + + console.info('dialog is removed', event); + + // Find a dialogPolyfillInfo which matches the removed . + this.pendingDialogStack.some(function(dpi) { + if (dpi.dialog == dialog) { + // This call will clear the dialogPolyfillInfo on this DialogManager + // as a side effect. + dpi.maybeHideModal(); + return true; + } + }); + }; + + /** + * @param {!dialogPolyfillInfo} dpi + * @return {boolean} whether the dialog was allowed + */ + dialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) { + var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1; + if (this.pendingDialogStack.length >= allowed) { + return false; + } + this.pendingDialogStack.push(dpi); + if (this.pendingDialogStack.length == 1) { + this.blockDocument(); + } + this.updateStacking(); + return true; + }; + + /** + * @param {!dialogPolyfillInfo} dpi + */ + dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) { + var index = this.pendingDialogStack.indexOf(dpi); + if (index == -1) { return; } + + this.pendingDialogStack.splice(index, 1); + this.updateStacking(); + if (this.pendingDialogStack.length == 0) { + this.unblockDocument(); + } + }; + + dialogPolyfill.dm = new dialogPolyfill.DialogManager(); + + /** + * Global form 'dialog' method handler. Closes a dialog correctly on submit + * and possibly sets its return value. + */ + document.addEventListener('submit', function(ev) { + var target = ev.target; + if (!target || !target.hasAttribute('method')) { return; } + if (target.getAttribute('method').toLowerCase() != 'dialog') { return; } + ev.preventDefault(); + + var dialog = findNearestDialog(/** @type {Element} */ (ev.target)); + if (!dialog) { return; } + + // FIXME: The original event doesn't contain the element used to submit the + // form (if any). Look in some possible places. + var returnValue; + var cands = [document.activeElement, ev.explicitOriginalTarget]; + var els = ['BUTTON', 'INPUT']; + cands.some(function(cand) { + if (cand && cand.form == ev.target && els.indexOf(cand.nodeName.toUpperCase()) != -1) { + returnValue = cand.value; + return true; + } + }); + dialog.close(returnValue); + }, true); + + dialogPolyfill['forceRegisterDialog'] = dialogPolyfill.forceRegisterDialog; + dialogPolyfill['registerDialog'] = dialogPolyfill.registerDialog; + + if (typeof define === 'function' && 'amd' in define) { + // AMD support + define(function() { return dialogPolyfill; }); + } else if (typeof module === 'object' && typeof module['exports'] === 'object') { + // CommonJS support + module['exports'] = dialogPolyfill; + } else { + // all others + window['dialogPolyfill'] = dialogPolyfill; + } +})(); \ No newline at end of file diff --git a/src/public/js/material.ext.js b/src/public/js/material.ext.js new file mode 100644 index 00000000..1167b6d1 --- /dev/null +++ b/src/public/js/material.ext.js @@ -0,0 +1,2 @@ +!function(){"use strict";var s=function(s){this.element_=s,this.init()};window.MaterialSelectfield=s,s.prototype.Constant_={},s.prototype.CssClasses_={LABEL:"mdl-selectfield__label",SELECT:"mdl-selectfield__select",IS_DIRTY:"is-dirty",IS_FOCUSED:"is-focused",IS_DISABLED:"is-disabled",IS_INVALID:"is-invalid",IS_UPGRADED:"is-upgraded"},s.prototype.onFocus_=function(s){this.element_.classList.add(this.CssClasses_.IS_FOCUSED)},s.prototype.onBlur_=function(s){this.element_.classList.remove(this.CssClasses_.IS_FOCUSED)},s.prototype.onReset_=function(s){this.updateClasses_()},s.prototype.updateClasses_=function(){this.checkDisabled(),this.checkValidity(),this.checkDirty()},s.prototype.checkDisabled=function(){this.select_.disabled?this.element_.classList.add(this.CssClasses_.IS_DISABLED):this.element_.classList.remove(this.CssClasses_.IS_DISABLED)},s.prototype.checkDisabled=s.prototype.checkDisabled,s.prototype.checkValidity=function(){this.select_.validity.valid?this.element_.classList.remove(this.CssClasses_.IS_INVALID):this.element_.classList.add(this.CssClasses_.IS_INVALID)},s.prototype.checkValidity=s.prototype.checkValidity,s.prototype.checkDirty=function(){this.select_.value&&this.select_.value.length>0?this.element_.classList.add(this.CssClasses_.IS_DIRTY):this.element_.classList.remove(this.CssClasses_.IS_DIRTY)},s.prototype.checkDirty=s.prototype.checkDirty,s.prototype.disable=function(){this.select_.disabled=!0,this.updateClasses_()},s.prototype.disable=s.prototype.disable,s.prototype.enable=function(){this.select_.disabled=!1,this.updateClasses_()},s.prototype.enable=s.prototype.enable,s.prototype.change=function(s){s&&(this.select_.value=s),this.updateClasses_()},s.prototype.change=s.prototype.change,s.prototype.init=function(){if(this.element_&&(this.label_=this.element_.querySelector("."+this.CssClasses_.LABEL),this.select_=this.element_.querySelector("."+this.CssClasses_.SELECT),this.select_)){this.boundUpdateClassesHandler=this.updateClasses_.bind(this),this.boundFocusHandler=this.onFocus_.bind(this),this.boundBlurHandler=this.onBlur_.bind(this),this.boundResetHandler=this.onReset_.bind(this),this.select_.addEventListener("change",this.boundUpdateClassesHandler),this.select_.addEventListener("focus",this.boundFocusHandler),this.select_.addEventListener("blur",this.boundBlurHandler),this.select_.addEventListener("reset",this.boundResetHandler);var s=this.element_.classList.contains(this.CssClasses_.IS_INVALID);this.updateClasses_(),this.element_.classList.add(this.CssClasses_.IS_UPGRADED),s&&this.element_.classList.add(this.CssClasses_.IS_INVALID)}},s.prototype.mdlDowngrade_=function(){this.select_.removeEventListener("change",this.boundUpdateClassesHandler),this.select_.removeEventListener("focus",this.boundFocusHandler),this.select_.removeEventListener("blur",this.boundBlurHandler),this.select_.removeEventListener("reset",this.boundResetHandler)},componentHandler.register({constructor:s,classAsString:"MaterialSelectfield",cssClass:"mdl-js-selectfield",widget:!0})}(); +//# sourceMappingURL=mdl-selectfield.min.js.map \ No newline at end of file diff --git a/src/public/js/material.js b/src/public/js/material.js new file mode 100644 index 00000000..0a86c3b4 --- /dev/null +++ b/src/public/js/material.js @@ -0,0 +1,3968 @@ +;(function() { +"use strict"; + +if (typeof window === 'undefined') return; + +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * A component handler interface using the revealing module design pattern. + * More details on this design pattern here: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @author Jason Mayes. + */ +/* exported componentHandler */ + +// Pre-defining the componentHandler interface, for closure documentation and +// static verification. +var componentHandler = { + /** + * Searches existing DOM for elements of our component type and upgrades them + * if they have not already been upgraded. + * + * @param {string=} optJsClass the programatic name of the element class we + * need to create a new instance of. + * @param {string=} optCssClass the name of the CSS class elements of this + * type will have. + */ + upgradeDom: function(optJsClass, optCssClass) {}, + /** + * Upgrades a specific element rather than all in the DOM. + * + * @param {!Element} element The element we wish to upgrade. + * @param {string=} optJsClass Optional name of the class we want to upgrade + * the element to. + */ + upgradeElement: function(element, optJsClass) {}, + /** + * Upgrades a specific list of elements rather than all in the DOM. + * + * @param {!Element|!Array|!NodeList|!HTMLCollection} elements + * The elements we wish to upgrade. + */ + upgradeElements: function(elements) {}, + /** + * Upgrades all registered components found in the current DOM. This is + * automatically called on window load. + */ + upgradeAllRegistered: function() {}, + /** + * Allows user to be alerted to any upgrades that are performed for a given + * component type + * + * @param {string} jsClass The class name of the MDL component we wish + * to hook into for any upgrades performed. + * @param {function(!HTMLElement)} callback The function to call upon an + * upgrade. This function should expect 1 parameter - the HTMLElement which + * got upgraded. + */ + registerUpgradedCallback: function(jsClass, callback) {}, + /** + * Registers a class for future use and attempts to upgrade existing DOM. + * + * @param {componentHandler.ComponentConfigPublic} config the registration configuration + */ + register: function(config) {}, + /** + * Downgrade either a given node, an array of nodes, or a NodeList. + * + * @param {!Node|!Array|!NodeList} nodes + */ + downgradeElements: function(nodes) {} +}; + +componentHandler = (function() { + 'use strict'; + + /** @type {!Array} */ + var registeredComponents_ = []; + + /** @type {!Array} */ + var createdComponents_ = []; + + var componentConfigProperty_ = 'mdlComponentConfigInternal_'; + + /** + * Searches registered components for a class we are interested in using. + * Optionally replaces a match with passed object if specified. + * + * @param {string} name The name of a class we want to use. + * @param {componentHandler.ComponentConfig=} optReplace Optional object to replace match with. + * @return {!Object|boolean} + * @private + */ + function findRegisteredClass_(name, optReplace) { + for (var i = 0; i < registeredComponents_.length; i++) { + if (registeredComponents_[i].className === name) { + if (typeof optReplace !== 'undefined') { + registeredComponents_[i] = optReplace; + } + return registeredComponents_[i]; + } + } + return false; + } + + /** + * Returns an array of the classNames of the upgraded classes on the element. + * + * @param {!Element} element The element to fetch data from. + * @return {!Array} + * @private + */ + function getUpgradedListOfElement_(element) { + var dataUpgraded = element.getAttribute('data-upgraded'); + // Use `['']` as default value to conform the `,name,name...` style. + return dataUpgraded === null ? [''] : dataUpgraded.split(','); + } + + /** + * Returns true if the given element has already been upgraded for the given + * class. + * + * @param {!Element} element The element we want to check. + * @param {string} jsClass The class to check for. + * @returns {boolean} + * @private + */ + function isElementUpgraded_(element, jsClass) { + var upgradedList = getUpgradedListOfElement_(element); + return upgradedList.indexOf(jsClass) !== -1; + } + + /** + * Searches existing DOM for elements of our component type and upgrades them + * if they have not already been upgraded. + * + * @param {string=} optJsClass the programatic name of the element class we + * need to create a new instance of. + * @param {string=} optCssClass the name of the CSS class elements of this + * type will have. + */ + function upgradeDomInternal(optJsClass, optCssClass) { + if (typeof optJsClass === 'undefined' && + typeof optCssClass === 'undefined') { + for (var i = 0; i < registeredComponents_.length; i++) { + upgradeDomInternal(registeredComponents_[i].className, + registeredComponents_[i].cssClass); + } + } else { + var jsClass = /** @type {string} */ (optJsClass); + if (typeof optCssClass === 'undefined') { + var registeredClass = findRegisteredClass_(jsClass); + if (registeredClass) { + optCssClass = registeredClass.cssClass; + } + } + + var elements = document.querySelectorAll('.' + optCssClass); + for (var n = 0; n < elements.length; n++) { + upgradeElementInternal(elements[n], jsClass); + } + } + } + + /** + * Upgrades a specific element rather than all in the DOM. + * + * @param {!Element} element The element we wish to upgrade. + * @param {string=} optJsClass Optional name of the class we want to upgrade + * the element to. + */ + function upgradeElementInternal(element, optJsClass) { + // Verify argument type. + if (!(typeof element === 'object' && element instanceof Element)) { + throw new Error('Invalid argument provided to upgrade MDL element.'); + } + var upgradedList = getUpgradedListOfElement_(element); + var classesToUpgrade = []; + // If jsClass is not provided scan the registered components to find the + // ones matching the element's CSS classList. + if (!optJsClass) { + var classList = element.classList; + registeredComponents_.forEach(function(component) { + // Match CSS & Not to be upgraded & Not upgraded. + if (classList.contains(component.cssClass) && + classesToUpgrade.indexOf(component) === -1 && + !isElementUpgraded_(element, component.className)) { + classesToUpgrade.push(component); + } + }); + } else if (!isElementUpgraded_(element, optJsClass)) { + classesToUpgrade.push(findRegisteredClass_(optJsClass)); + } + + // Upgrade the element for each classes. + for (var i = 0, n = classesToUpgrade.length, registeredClass; i < n; i++) { + registeredClass = classesToUpgrade[i]; + if (registeredClass) { + // Mark element as upgraded. + upgradedList.push(registeredClass.className); + element.setAttribute('data-upgraded', upgradedList.join(',')); + var instance = new registeredClass.classConstructor(element); + instance[componentConfigProperty_] = registeredClass; + createdComponents_.push(instance); + // Call any callbacks the user has registered with this component type. + for (var j = 0, m = registeredClass.callbacks.length; j < m; j++) { + registeredClass.callbacks[j](element); + } + + if (registeredClass.widget) { + // Assign per element instance for control over API + element[registeredClass.className] = instance; + } + } else { + throw new Error( + 'Unable to find a registered component for the given class.'); + } + + var ev; + if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { + ev = new CustomEvent('mdl-componentupgraded', { + bubbles: true, cancelable: false + }); + } else { + ev = document.createEvent('Events'); + ev.initEvent('mdl-componentupgraded', true, true); + } + element.dispatchEvent(ev); + } + } + + /** + * Upgrades a specific list of elements rather than all in the DOM. + * + * @param {!Element|!Array|!NodeList|!HTMLCollection} elements + * The elements we wish to upgrade. + */ + function upgradeElementsInternal(elements) { + if (!Array.isArray(elements)) { + if (elements instanceof Element) { + elements = [elements]; + } else { + elements = Array.prototype.slice.call(elements); + } + } + for (var i = 0, n = elements.length, element; i < n; i++) { + element = elements[i]; + if (element instanceof HTMLElement) { + upgradeElementInternal(element); + if (element.children.length > 0) { + upgradeElementsInternal(element.children); + } + } + } + } + + /** + * Registers a class for future use and attempts to upgrade existing DOM. + * + * @param {componentHandler.ComponentConfigPublic} config + */ + function registerInternal(config) { + // In order to support both Closure-compiled and uncompiled code accessing + // this method, we need to allow for both the dot and array syntax for + // property access. You'll therefore see the `foo.bar || foo['bar']` + // pattern repeated across this method. + var widgetMissing = (typeof config.widget === 'undefined' && + typeof config['widget'] === 'undefined'); + var widget = true; + + if (!widgetMissing) { + widget = config.widget || config['widget']; + } + + var newConfig = /** @type {componentHandler.ComponentConfig} */ ({ + classConstructor: config.constructor || config['constructor'], + className: config.classAsString || config['classAsString'], + cssClass: config.cssClass || config['cssClass'], + widget: widget, + callbacks: [] + }); + + registeredComponents_.forEach(function(item) { + if (item.cssClass === newConfig.cssClass) { + throw new Error('The provided cssClass has already been registered: ' + item.cssClass); + } + if (item.className === newConfig.className) { + throw new Error('The provided className has already been registered'); + } + }); + + if (config.constructor.prototype + .hasOwnProperty(componentConfigProperty_)) { + throw new Error( + 'MDL component classes must not have ' + componentConfigProperty_ + + ' defined as a property.'); + } + + var found = findRegisteredClass_(config.classAsString, newConfig); + + if (!found) { + registeredComponents_.push(newConfig); + } + } + + /** + * Allows user to be alerted to any upgrades that are performed for a given + * component type + * + * @param {string} jsClass The class name of the MDL component we wish + * to hook into for any upgrades performed. + * @param {function(!HTMLElement)} callback The function to call upon an + * upgrade. This function should expect 1 parameter - the HTMLElement which + * got upgraded. + */ + function registerUpgradedCallbackInternal(jsClass, callback) { + var regClass = findRegisteredClass_(jsClass); + if (regClass) { + regClass.callbacks.push(callback); + } + } + + /** + * Upgrades all registered components found in the current DOM. This is + * automatically called on window load. + */ + function upgradeAllRegisteredInternal() { + for (var n = 0; n < registeredComponents_.length; n++) { + upgradeDomInternal(registeredComponents_[n].className); + } + } + + /** + * Check the component for the downgrade method. + * Execute if found. + * Remove component from createdComponents list. + * + * @param {?componentHandler.Component} component + */ + function deconstructComponentInternal(component) { + if (component) { + var componentIndex = createdComponents_.indexOf(component); + createdComponents_.splice(componentIndex, 1); + + var upgrades = component.element_.getAttribute('data-upgraded').split(','); + var componentPlace = upgrades.indexOf(component[componentConfigProperty_].classAsString); + upgrades.splice(componentPlace, 1); + component.element_.setAttribute('data-upgraded', upgrades.join(',')); + + var ev; + if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { + ev = new CustomEvent('mdl-componentdowngraded', { + bubbles: true, cancelable: false + }); + } else { + ev = document.createEvent('Events'); + ev.initEvent('mdl-componentdowngraded', true, true); + } + component.element_.dispatchEvent(ev); + } + } + + /** + * Downgrade either a given node, an array of nodes, or a NodeList. + * + * @param {!Node|!Array|!NodeList} nodes + */ + function downgradeNodesInternal(nodes) { + /** + * Auxiliary function to downgrade a single node. + * @param {!Node} node the node to be downgraded + */ + var downgradeNode = function(node) { + createdComponents_.filter(function(item) { + return item.element_ === node; + }).forEach(deconstructComponentInternal); + }; + if (nodes instanceof Array || nodes instanceof NodeList) { + for (var n = 0; n < nodes.length; n++) { + downgradeNode(nodes[n]); + } + } else if (nodes instanceof Node) { + downgradeNode(nodes); + } else { + throw new Error('Invalid argument provided to downgrade MDL nodes.'); + } + } + + // Now return the functions that should be made public with their publicly + // facing names... + return { + upgradeDom: upgradeDomInternal, + upgradeElement: upgradeElementInternal, + upgradeElements: upgradeElementsInternal, + upgradeAllRegistered: upgradeAllRegisteredInternal, + registerUpgradedCallback: registerUpgradedCallbackInternal, + register: registerInternal, + downgradeElements: downgradeNodesInternal + }; +})(); + +/** + * Describes the type of a registered component type managed by + * componentHandler. Provided for benefit of the Closure compiler. + * + * @typedef {{ + * constructor: Function, + * classAsString: string, + * cssClass: string, + * widget: (string|boolean|undefined) + * }} + */ +componentHandler.ComponentConfigPublic; // jshint ignore:line + +/** + * Describes the type of a registered component type managed by + * componentHandler. Provided for benefit of the Closure compiler. + * + * @typedef {{ + * constructor: !Function, + * className: string, + * cssClass: string, + * widget: (string|boolean), + * callbacks: !Array + * }} + */ +componentHandler.ComponentConfig; // jshint ignore:line + +/** + * Created component (i.e., upgraded element) type as managed by + * componentHandler. Provided for benefit of the Closure compiler. + * + * @typedef {{ + * element_: !HTMLElement, + * className: string, + * classAsString: string, + * cssClass: string, + * widget: string + * }} + */ +componentHandler.Component; // jshint ignore:line + +// Export all symbols, for the benefit of Closure compiler. +// No effect on uncompiled code. +componentHandler['upgradeDom'] = componentHandler.upgradeDom; +componentHandler['upgradeElement'] = componentHandler.upgradeElement; +componentHandler['upgradeElements'] = componentHandler.upgradeElements; +componentHandler['upgradeAllRegistered'] = + componentHandler.upgradeAllRegistered; +componentHandler['registerUpgradedCallback'] = + componentHandler.registerUpgradedCallback; +componentHandler['register'] = componentHandler.register; +componentHandler['downgradeElements'] = componentHandler.downgradeElements; +window.componentHandler = componentHandler; +window['componentHandler'] = componentHandler; + +window.addEventListener('load', function() { + 'use strict'; + + /** + * Performs a "Cutting the mustard" test. If the browser supports the features + * tested, adds a mdl-js class to the element. It then upgrades all MDL + * components requiring JavaScript. + */ + if ('classList' in document.createElement('div') && + 'querySelector' in document && + 'addEventListener' in window && Array.prototype.forEach) { + document.documentElement.classList.add('mdl-js'); + } else { + /** + * Dummy function to avoid JS errors. + */ + componentHandler.upgradeElement = function() {}; + /** + * Dummy function to avoid JS errors. + */ + componentHandler.register = function() {}; + } +}); + +// Source: https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js +// Adapted from https://gist.github.com/paulirish/1579671 which derived from +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating +// requestAnimationFrame polyfill by Erik Möller. +// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon +// MIT license +if (!Date.now) { + /** + * Date.now polyfill. + * @return {number} the current Date + */ + Date.now = function () { + return new Date().getTime(); + }; + Date['now'] = Date.now; +} +var vendors = [ + 'webkit', + 'moz' +]; +for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { + var vp = vendors[i]; + window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; +} +if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { + var lastTime = 0; + /** + * requestAnimationFrame polyfill. + * @param {!Function} callback the callback function. + */ + window.requestAnimationFrame = function (callback) { + var now = Date.now(); + var nextTime = Math.max(lastTime + 16, now); + return setTimeout(function () { + callback(lastTime = nextTime); + }, nextTime - now); + }; + window.cancelAnimationFrame = clearTimeout; + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; +} +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Button MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialButton = function MaterialButton(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialButton'] = MaterialButton; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialButton.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialButton.prototype.CssClasses_ = { + RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_CONTAINER: 'mdl-button__ripple-container', + RIPPLE: 'mdl-ripple' +}; +/** + * Handle blur of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialButton.prototype.blurHandler_ = function (event) { + if (event) { + this.element_.blur(); + } +}; +// Public methods. +/** + * Disable button. + * + * @public + */ +MaterialButton.prototype.disable = function () { + this.element_.disabled = true; +}; +MaterialButton.prototype['disable'] = MaterialButton.prototype.disable; +/** + * Enable button. + * + * @public + */ +MaterialButton.prototype.enable = function () { + this.element_.disabled = false; +}; +MaterialButton.prototype['enable'] = MaterialButton.prototype.enable; +/** + * Initialize element. + */ +MaterialButton.prototype.init = function () { + if (this.element_) { + if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { + var rippleContainer = document.createElement('span'); + rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER); + this.rippleElement_ = document.createElement('span'); + this.rippleElement_.classList.add(this.CssClasses_.RIPPLE); + rippleContainer.appendChild(this.rippleElement_); + this.boundRippleBlurHandler = this.blurHandler_.bind(this); + this.rippleElement_.addEventListener('mouseup', this.boundRippleBlurHandler); + this.element_.appendChild(rippleContainer); + } + this.boundButtonBlurHandler = this.blurHandler_.bind(this); + this.element_.addEventListener('mouseup', this.boundButtonBlurHandler); + this.element_.addEventListener('mouseleave', this.boundButtonBlurHandler); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialButton, + classAsString: 'MaterialButton', + cssClass: 'mdl-js-button', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Checkbox MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialCheckbox = function MaterialCheckbox(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialCheckbox'] = MaterialCheckbox; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialCheckbox.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialCheckbox.prototype.CssClasses_ = { + INPUT: 'mdl-checkbox__input', + BOX_OUTLINE: 'mdl-checkbox__box-outline', + FOCUS_HELPER: 'mdl-checkbox__focus-helper', + TICK_OUTLINE: 'mdl-checkbox__tick-outline', + RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE_CONTAINER: 'mdl-checkbox__ripple-container', + RIPPLE_CENTER: 'mdl-ripple--center', + RIPPLE: 'mdl-ripple', + IS_FOCUSED: 'is-focused', + IS_DISABLED: 'is-disabled', + IS_CHECKED: 'is-checked', + IS_UPGRADED: 'is-upgraded' +}; +/** + * Handle change of state. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialCheckbox.prototype.onChange_ = function (event) { + this.updateClasses_(); +}; +/** + * Handle focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialCheckbox.prototype.onFocus_ = function (event) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle lost focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialCheckbox.prototype.onBlur_ = function (event) { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle mouseup. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialCheckbox.prototype.onMouseUp_ = function (event) { + this.blur_(); +}; +/** + * Handle class updates. + * + * @private + */ +MaterialCheckbox.prototype.updateClasses_ = function () { + this.checkDisabled(); + this.checkToggleState(); +}; +/** + * Add blur. + * + * @private + */ +MaterialCheckbox.prototype.blur_ = function () { + // TODO: figure out why there's a focus event being fired after our blur, + // so that we can avoid this hack. + window.setTimeout(function () { + this.inputElement_.blur(); + }.bind(this), this.Constant_.TINY_TIMEOUT); +}; +// Public methods. +/** + * Check the inputs toggle state and update display. + * + * @public + */ +MaterialCheckbox.prototype.checkToggleState = function () { + if (this.inputElement_.checked) { + this.element_.classList.add(this.CssClasses_.IS_CHECKED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_CHECKED); + } +}; +MaterialCheckbox.prototype['checkToggleState'] = MaterialCheckbox.prototype.checkToggleState; +/** + * Check the inputs disabled state and update display. + * + * @public + */ +MaterialCheckbox.prototype.checkDisabled = function () { + if (this.inputElement_.disabled) { + this.element_.classList.add(this.CssClasses_.IS_DISABLED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DISABLED); + } +}; +MaterialCheckbox.prototype['checkDisabled'] = MaterialCheckbox.prototype.checkDisabled; +/** + * Disable checkbox. + * + * @public + */ +MaterialCheckbox.prototype.disable = function () { + this.inputElement_.disabled = true; + this.updateClasses_(); +}; +MaterialCheckbox.prototype['disable'] = MaterialCheckbox.prototype.disable; +/** + * Enable checkbox. + * + * @public + */ +MaterialCheckbox.prototype.enable = function () { + this.inputElement_.disabled = false; + this.updateClasses_(); +}; +MaterialCheckbox.prototype['enable'] = MaterialCheckbox.prototype.enable; +/** + * Check checkbox. + * + * @public + */ +MaterialCheckbox.prototype.check = function () { + this.inputElement_.checked = true; + this.updateClasses_(); +}; +MaterialCheckbox.prototype['check'] = MaterialCheckbox.prototype.check; +/** + * Uncheck checkbox. + * + * @public + */ +MaterialCheckbox.prototype.uncheck = function () { + this.inputElement_.checked = false; + this.updateClasses_(); +}; +MaterialCheckbox.prototype['uncheck'] = MaterialCheckbox.prototype.uncheck; +/** + * Initialize element. + */ +MaterialCheckbox.prototype.init = function () { + if (this.element_) { + this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); + var boxOutline = document.createElement('span'); + boxOutline.classList.add(this.CssClasses_.BOX_OUTLINE); + var tickContainer = document.createElement('span'); + tickContainer.classList.add(this.CssClasses_.FOCUS_HELPER); + var tickOutline = document.createElement('span'); + tickOutline.classList.add(this.CssClasses_.TICK_OUTLINE); + boxOutline.appendChild(tickOutline); + this.element_.appendChild(tickContainer); + this.element_.appendChild(boxOutline); + if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + this.rippleContainerElement_ = document.createElement('span'); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); + this.boundRippleMouseUp = this.onMouseUp_.bind(this); + this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp); + var ripple = document.createElement('span'); + ripple.classList.add(this.CssClasses_.RIPPLE); + this.rippleContainerElement_.appendChild(ripple); + this.element_.appendChild(this.rippleContainerElement_); + } + this.boundInputOnChange = this.onChange_.bind(this); + this.boundInputOnFocus = this.onFocus_.bind(this); + this.boundInputOnBlur = this.onBlur_.bind(this); + this.boundElementMouseUp = this.onMouseUp_.bind(this); + this.inputElement_.addEventListener('change', this.boundInputOnChange); + this.inputElement_.addEventListener('focus', this.boundInputOnFocus); + this.inputElement_.addEventListener('blur', this.boundInputOnBlur); + this.element_.addEventListener('mouseup', this.boundElementMouseUp); + this.updateClasses_(); + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialCheckbox, + classAsString: 'MaterialCheckbox', + cssClass: 'mdl-js-checkbox', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for icon toggle MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialIconToggle = function MaterialIconToggle(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialIconToggle'] = MaterialIconToggle; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialIconToggle.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialIconToggle.prototype.CssClasses_ = { + INPUT: 'mdl-icon-toggle__input', + JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE_CONTAINER: 'mdl-icon-toggle__ripple-container', + RIPPLE_CENTER: 'mdl-ripple--center', + RIPPLE: 'mdl-ripple', + IS_FOCUSED: 'is-focused', + IS_DISABLED: 'is-disabled', + IS_CHECKED: 'is-checked' +}; +/** + * Handle change of state. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialIconToggle.prototype.onChange_ = function (event) { + this.updateClasses_(); +}; +/** + * Handle focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialIconToggle.prototype.onFocus_ = function (event) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle lost focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialIconToggle.prototype.onBlur_ = function (event) { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle mouseup. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialIconToggle.prototype.onMouseUp_ = function (event) { + this.blur_(); +}; +/** + * Handle class updates. + * + * @private + */ +MaterialIconToggle.prototype.updateClasses_ = function () { + this.checkDisabled(); + this.checkToggleState(); +}; +/** + * Add blur. + * + * @private + */ +MaterialIconToggle.prototype.blur_ = function () { + // TODO: figure out why there's a focus event being fired after our blur, + // so that we can avoid this hack. + window.setTimeout(function () { + this.inputElement_.blur(); + }.bind(this), this.Constant_.TINY_TIMEOUT); +}; +// Public methods. +/** + * Check the inputs toggle state and update display. + * + * @public + */ +MaterialIconToggle.prototype.checkToggleState = function () { + if (this.inputElement_.checked) { + this.element_.classList.add(this.CssClasses_.IS_CHECKED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_CHECKED); + } +}; +MaterialIconToggle.prototype['checkToggleState'] = MaterialIconToggle.prototype.checkToggleState; +/** + * Check the inputs disabled state and update display. + * + * @public + */ +MaterialIconToggle.prototype.checkDisabled = function () { + if (this.inputElement_.disabled) { + this.element_.classList.add(this.CssClasses_.IS_DISABLED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DISABLED); + } +}; +MaterialIconToggle.prototype['checkDisabled'] = MaterialIconToggle.prototype.checkDisabled; +/** + * Disable icon toggle. + * + * @public + */ +MaterialIconToggle.prototype.disable = function () { + this.inputElement_.disabled = true; + this.updateClasses_(); +}; +MaterialIconToggle.prototype['disable'] = MaterialIconToggle.prototype.disable; +/** + * Enable icon toggle. + * + * @public + */ +MaterialIconToggle.prototype.enable = function () { + this.inputElement_.disabled = false; + this.updateClasses_(); +}; +MaterialIconToggle.prototype['enable'] = MaterialIconToggle.prototype.enable; +/** + * Check icon toggle. + * + * @public + */ +MaterialIconToggle.prototype.check = function () { + this.inputElement_.checked = true; + this.updateClasses_(); +}; +MaterialIconToggle.prototype['check'] = MaterialIconToggle.prototype.check; +/** + * Uncheck icon toggle. + * + * @public + */ +MaterialIconToggle.prototype.uncheck = function () { + this.inputElement_.checked = false; + this.updateClasses_(); +}; +MaterialIconToggle.prototype['uncheck'] = MaterialIconToggle.prototype.uncheck; +/** + * Initialize element. + */ +MaterialIconToggle.prototype.init = function () { + if (this.element_) { + this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); + if (this.element_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + this.rippleContainerElement_ = document.createElement('span'); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); + this.rippleContainerElement_.classList.add(this.CssClasses_.JS_RIPPLE_EFFECT); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); + this.boundRippleMouseUp = this.onMouseUp_.bind(this); + this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp); + var ripple = document.createElement('span'); + ripple.classList.add(this.CssClasses_.RIPPLE); + this.rippleContainerElement_.appendChild(ripple); + this.element_.appendChild(this.rippleContainerElement_); + } + this.boundInputOnChange = this.onChange_.bind(this); + this.boundInputOnFocus = this.onFocus_.bind(this); + this.boundInputOnBlur = this.onBlur_.bind(this); + this.boundElementOnMouseUp = this.onMouseUp_.bind(this); + this.inputElement_.addEventListener('change', this.boundInputOnChange); + this.inputElement_.addEventListener('focus', this.boundInputOnFocus); + this.inputElement_.addEventListener('blur', this.boundInputOnBlur); + this.element_.addEventListener('mouseup', this.boundElementOnMouseUp); + this.updateClasses_(); + this.element_.classList.add('is-upgraded'); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialIconToggle, + classAsString: 'MaterialIconToggle', + cssClass: 'mdl-js-icon-toggle', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for dropdown MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialMenu = function MaterialMenu(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialMenu'] = MaterialMenu; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialMenu.prototype.Constant_ = { + // Total duration of the menu animation. + TRANSITION_DURATION_SECONDS: 0.3, + // The fraction of the total duration we want to use for menu item animations. + TRANSITION_DURATION_FRACTION: 0.8, + // How long the menu stays open after choosing an option (so the user can see + // the ripple). + CLOSE_TIMEOUT: 150 +}; +/** + * Keycodes, for code readability. + * + * @enum {number} + * @private + */ +MaterialMenu.prototype.Keycodes_ = { + ENTER: 13, + ESCAPE: 27, + SPACE: 32, + UP_ARROW: 38, + DOWN_ARROW: 40 +}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialMenu.prototype.CssClasses_ = { + CONTAINER: 'mdl-menu__container', + OUTLINE: 'mdl-menu__outline', + ITEM: 'mdl-menu__item', + ITEM_RIPPLE_CONTAINER: 'mdl-menu__item-ripple-container', + RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE: 'mdl-ripple', + // Statuses + IS_UPGRADED: 'is-upgraded', + IS_VISIBLE: 'is-visible', + IS_ANIMATING: 'is-animating', + // Alignment options + BOTTOM_LEFT: 'mdl-menu--bottom-left', + // This is the default. + BOTTOM_RIGHT: 'mdl-menu--bottom-right', + TOP_LEFT: 'mdl-menu--top-left', + TOP_RIGHT: 'mdl-menu--top-right', + UNALIGNED: 'mdl-menu--unaligned' +}; +/** + * Initialize element. + */ +MaterialMenu.prototype.init = function () { + if (this.element_) { + // Create container for the menu. + var container = document.createElement('div'); + container.classList.add(this.CssClasses_.CONTAINER); + this.element_.parentElement.insertBefore(container, this.element_); + this.element_.parentElement.removeChild(this.element_); + container.appendChild(this.element_); + this.container_ = container; + // Create outline for the menu (shadow and background). + var outline = document.createElement('div'); + outline.classList.add(this.CssClasses_.OUTLINE); + this.outline_ = outline; + container.insertBefore(outline, this.element_); + // Find the "for" element and bind events to it. + var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for'); + var forEl = null; + if (forElId) { + forEl = document.getElementById(forElId); + if (forEl) { + this.forElement_ = forEl; + forEl.addEventListener('click', this.handleForClick_.bind(this)); + forEl.addEventListener('keydown', this.handleForKeyboardEvent_.bind(this)); + } + } + var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); + this.boundItemKeydown_ = this.handleItemKeyboardEvent_.bind(this); + this.boundItemClick_ = this.handleItemClick_.bind(this); + for (var i = 0; i < items.length; i++) { + // Add a listener to each menu item. + items[i].addEventListener('click', this.boundItemClick_); + // Add a tab index to each menu item. + items[i].tabIndex = '-1'; + // Add a keyboard listener to each menu item. + items[i].addEventListener('keydown', this.boundItemKeydown_); + } + // Add ripple classes to each item, if the user has enabled ripples. + if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + for (i = 0; i < items.length; i++) { + var item = items[i]; + var rippleContainer = document.createElement('span'); + rippleContainer.classList.add(this.CssClasses_.ITEM_RIPPLE_CONTAINER); + var ripple = document.createElement('span'); + ripple.classList.add(this.CssClasses_.RIPPLE); + rippleContainer.appendChild(ripple); + item.appendChild(rippleContainer); + item.classList.add(this.CssClasses_.RIPPLE_EFFECT); + } + } + // Copy alignment classes to the container, so the outline can use them. + if (this.element_.classList.contains(this.CssClasses_.BOTTOM_LEFT)) { + this.outline_.classList.add(this.CssClasses_.BOTTOM_LEFT); + } + if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { + this.outline_.classList.add(this.CssClasses_.BOTTOM_RIGHT); + } + if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { + this.outline_.classList.add(this.CssClasses_.TOP_LEFT); + } + if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { + this.outline_.classList.add(this.CssClasses_.TOP_RIGHT); + } + if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { + this.outline_.classList.add(this.CssClasses_.UNALIGNED); + } + container.classList.add(this.CssClasses_.IS_UPGRADED); + } +}; +/** + * Handles a click on the "for" element, by positioning the menu and then + * toggling it. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialMenu.prototype.handleForClick_ = function (evt) { + if (this.element_ && this.forElement_) { + var rect = this.forElement_.getBoundingClientRect(); + var forRect = this.forElement_.parentElement.getBoundingClientRect(); + if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { + } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { + // Position below the "for" element, aligned to its right. + this.container_.style.right = forRect.right - rect.right + 'px'; + this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px'; + } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { + // Position above the "for" element, aligned to its left. + this.container_.style.left = this.forElement_.offsetLeft + 'px'; + this.container_.style.bottom = forRect.bottom - rect.top + 'px'; + } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { + // Position above the "for" element, aligned to its right. + this.container_.style.right = forRect.right - rect.right + 'px'; + this.container_.style.bottom = forRect.bottom - rect.top + 'px'; + } else { + // Default: position below the "for" element, aligned to its left. + this.container_.style.left = this.forElement_.offsetLeft + 'px'; + this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px'; + } + } + this.toggle(evt); +}; +/** + * Handles a keyboard event on the "for" element. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialMenu.prototype.handleForKeyboardEvent_ = function (evt) { + if (this.element_ && this.container_ && this.forElement_) { + var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])'); + if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { + if (evt.keyCode === this.Keycodes_.UP_ARROW) { + evt.preventDefault(); + items[items.length - 1].focus(); + } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) { + evt.preventDefault(); + items[0].focus(); + } + } + } +}; +/** + * Handles a keyboard event on an item. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialMenu.prototype.handleItemKeyboardEvent_ = function (evt) { + if (this.element_ && this.container_) { + var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])'); + if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { + var currentIndex = Array.prototype.slice.call(items).indexOf(evt.target); + if (evt.keyCode === this.Keycodes_.UP_ARROW) { + evt.preventDefault(); + if (currentIndex > 0) { + items[currentIndex - 1].focus(); + } else { + items[items.length - 1].focus(); + } + } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) { + evt.preventDefault(); + if (items.length > currentIndex + 1) { + items[currentIndex + 1].focus(); + } else { + items[0].focus(); + } + } else if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) { + evt.preventDefault(); + // Send mousedown and mouseup to trigger ripple. + var e = new MouseEvent('mousedown'); + evt.target.dispatchEvent(e); + e = new MouseEvent('mouseup'); + evt.target.dispatchEvent(e); + // Send click. + evt.target.click(); + } else if (evt.keyCode === this.Keycodes_.ESCAPE) { + evt.preventDefault(); + this.hide(); + } + } + } +}; +/** + * Handles a click event on an item. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialMenu.prototype.handleItemClick_ = function (evt) { + if (evt.target.hasAttribute('disabled')) { + evt.stopPropagation(); + } else { + // Wait some time before closing menu, so the user can see the ripple. + this.closing_ = true; + window.setTimeout(function (evt) { + this.hide(); + this.closing_ = false; + }.bind(this), this.Constant_.CLOSE_TIMEOUT); + } +}; +/** + * Calculates the initial clip (for opening the menu) or final clip (for closing + * it), and applies it. This allows us to animate from or to the correct point, + * that is, the point it's aligned to in the "for" element. + * + * @param {number} height Height of the clip rectangle + * @param {number} width Width of the clip rectangle + * @private + */ +MaterialMenu.prototype.applyClip_ = function (height, width) { + if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { + // Do not clip. + this.element_.style.clip = ''; + } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { + // Clip to the top right corner of the menu. + this.element_.style.clip = 'rect(0 ' + width + 'px ' + '0 ' + width + 'px)'; + } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { + // Clip to the bottom left corner of the menu. + this.element_.style.clip = 'rect(' + height + 'px 0 ' + height + 'px 0)'; + } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { + // Clip to the bottom right corner of the menu. + this.element_.style.clip = 'rect(' + height + 'px ' + width + 'px ' + height + 'px ' + width + 'px)'; + } else { + // Default: do not clip (same as clipping to the top left corner). + this.element_.style.clip = ''; + } +}; +/** + * Cleanup function to remove animation listeners. + * + * @param {Event} evt + * @private + */ +MaterialMenu.prototype.removeAnimationEndListener_ = function (evt) { + evt.target.classList.remove(MaterialMenu.prototype.CssClasses_.IS_ANIMATING); +}; +/** + * Adds an event listener to clean up after the animation ends. + * + * @private + */ +MaterialMenu.prototype.addAnimationEndListener_ = function () { + this.element_.addEventListener('transitionend', this.removeAnimationEndListener_); + this.element_.addEventListener('webkitTransitionEnd', this.removeAnimationEndListener_); +}; +/** + * Displays the menu. + * + * @public + */ +MaterialMenu.prototype.show = function (evt) { + if (this.element_ && this.container_ && this.outline_) { + // Measure the inner element. + var height = this.element_.getBoundingClientRect().height; + var width = this.element_.getBoundingClientRect().width; + // Apply the inner element's size to the container and outline. + this.container_.style.width = width + 'px'; + this.container_.style.height = height + 'px'; + this.outline_.style.width = width + 'px'; + this.outline_.style.height = height + 'px'; + var transitionDuration = this.Constant_.TRANSITION_DURATION_SECONDS * this.Constant_.TRANSITION_DURATION_FRACTION; + // Calculate transition delays for individual menu items, so that they fade + // in one at a time. + var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); + for (var i = 0; i < items.length; i++) { + var itemDelay = null; + if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT) || this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { + itemDelay = (height - items[i].offsetTop - items[i].offsetHeight) / height * transitionDuration + 's'; + } else { + itemDelay = items[i].offsetTop / height * transitionDuration + 's'; + } + items[i].style.transitionDelay = itemDelay; + } + // Apply the initial clip to the text before we start animating. + this.applyClip_(height, width); + // Wait for the next frame, turn on animation, and apply the final clip. + // Also make it visible. This triggers the transitions. + window.requestAnimationFrame(function () { + this.element_.classList.add(this.CssClasses_.IS_ANIMATING); + this.element_.style.clip = 'rect(0 ' + width + 'px ' + height + 'px 0)'; + this.container_.classList.add(this.CssClasses_.IS_VISIBLE); + }.bind(this)); + // Clean up after the animation is complete. + this.addAnimationEndListener_(); + // Add a click listener to the document, to close the menu. + var callback = function (e) { + // Check to see if the document is processing the same event that + // displayed the menu in the first place. If so, do nothing. + // Also check to see if the menu is in the process of closing itself, and + // do nothing in that case. + // Also check if the clicked element is a menu item + // if so, do nothing. + if (e !== evt && !this.closing_ && e.target.parentNode !== this.element_) { + document.removeEventListener('click', callback); + this.hide(); + } + }.bind(this); + document.addEventListener('click', callback); + } +}; +MaterialMenu.prototype['show'] = MaterialMenu.prototype.show; +/** + * Hides the menu. + * + * @public + */ +MaterialMenu.prototype.hide = function () { + if (this.element_ && this.container_ && this.outline_) { + var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); + // Remove all transition delays; menu items fade out concurrently. + for (var i = 0; i < items.length; i++) { + items[i].style.removeProperty('transition-delay'); + } + // Measure the inner element. + var rect = this.element_.getBoundingClientRect(); + var height = rect.height; + var width = rect.width; + // Turn on animation, and apply the final clip. Also make invisible. + // This triggers the transitions. + this.element_.classList.add(this.CssClasses_.IS_ANIMATING); + this.applyClip_(height, width); + this.container_.classList.remove(this.CssClasses_.IS_VISIBLE); + // Clean up after the animation is complete. + this.addAnimationEndListener_(); + } +}; +MaterialMenu.prototype['hide'] = MaterialMenu.prototype.hide; +/** + * Displays or hides the menu, depending on current state. + * + * @public + */ +MaterialMenu.prototype.toggle = function (evt) { + if (this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { + this.hide(); + } else { + this.show(evt); + } +}; +MaterialMenu.prototype['toggle'] = MaterialMenu.prototype.toggle; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialMenu, + classAsString: 'MaterialMenu', + cssClass: 'mdl-js-menu', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Progress MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialProgress = function MaterialProgress(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialProgress'] = MaterialProgress; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialProgress.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialProgress.prototype.CssClasses_ = { INDETERMINATE_CLASS: 'mdl-progress__indeterminate' }; +/** + * Set the current progress of the progressbar. + * + * @param {number} p Percentage of the progress (0-100) + * @public + */ +MaterialProgress.prototype.setProgress = function (p) { + if (this.element_.classList.contains(this.CssClasses_.INDETERMINATE_CLASS)) { + return; + } + this.progressbar_.style.width = p + '%'; +}; +MaterialProgress.prototype['setProgress'] = MaterialProgress.prototype.setProgress; +/** + * Set the current progress of the buffer. + * + * @param {number} p Percentage of the buffer (0-100) + * @public + */ +MaterialProgress.prototype.setBuffer = function (p) { + this.bufferbar_.style.width = p + '%'; + this.auxbar_.style.width = 100 - p + '%'; +}; +MaterialProgress.prototype['setBuffer'] = MaterialProgress.prototype.setBuffer; +/** + * Initialize element. + */ +MaterialProgress.prototype.init = function () { + if (this.element_) { + var el = document.createElement('div'); + el.className = 'progressbar bar bar1'; + this.element_.appendChild(el); + this.progressbar_ = el; + el = document.createElement('div'); + el.className = 'bufferbar bar bar2'; + this.element_.appendChild(el); + this.bufferbar_ = el; + el = document.createElement('div'); + el.className = 'auxbar bar bar3'; + this.element_.appendChild(el); + this.auxbar_ = el; + this.progressbar_.style.width = '0%'; + this.bufferbar_.style.width = '100%'; + this.auxbar_.style.width = '0%'; + this.element_.classList.add('is-upgraded'); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialProgress, + classAsString: 'MaterialProgress', + cssClass: 'mdl-js-progress', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Radio MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialRadio = function MaterialRadio(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialRadio'] = MaterialRadio; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialRadio.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialRadio.prototype.CssClasses_ = { + IS_FOCUSED: 'is-focused', + IS_DISABLED: 'is-disabled', + IS_CHECKED: 'is-checked', + IS_UPGRADED: 'is-upgraded', + JS_RADIO: 'mdl-js-radio', + RADIO_BTN: 'mdl-radio__button', + RADIO_OUTER_CIRCLE: 'mdl-radio__outer-circle', + RADIO_INNER_CIRCLE: 'mdl-radio__inner-circle', + RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE_CONTAINER: 'mdl-radio__ripple-container', + RIPPLE_CENTER: 'mdl-ripple--center', + RIPPLE: 'mdl-ripple' +}; +/** + * Handle change of state. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRadio.prototype.onChange_ = function (event) { + // Since other radio buttons don't get change events, we need to look for + // them to update their classes. + var radios = document.getElementsByClassName(this.CssClasses_.JS_RADIO); + for (var i = 0; i < radios.length; i++) { + var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN); + // Different name == different group, so no point updating those. + if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) { + radios[i]['MaterialRadio'].updateClasses_(); + } + } +}; +/** + * Handle focus. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRadio.prototype.onFocus_ = function (event) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle lost focus. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRadio.prototype.onBlur_ = function (event) { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle mouseup. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRadio.prototype.onMouseup_ = function (event) { + this.blur_(); +}; +/** + * Update classes. + * + * @private + */ +MaterialRadio.prototype.updateClasses_ = function () { + this.checkDisabled(); + this.checkToggleState(); +}; +/** + * Add blur. + * + * @private + */ +MaterialRadio.prototype.blur_ = function () { + // TODO: figure out why there's a focus event being fired after our blur, + // so that we can avoid this hack. + window.setTimeout(function () { + this.btnElement_.blur(); + }.bind(this), this.Constant_.TINY_TIMEOUT); +}; +// Public methods. +/** + * Check the components disabled state. + * + * @public + */ +MaterialRadio.prototype.checkDisabled = function () { + if (this.btnElement_.disabled) { + this.element_.classList.add(this.CssClasses_.IS_DISABLED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DISABLED); + } +}; +MaterialRadio.prototype['checkDisabled'] = MaterialRadio.prototype.checkDisabled; +/** + * Check the components toggled state. + * + * @public + */ +MaterialRadio.prototype.checkToggleState = function () { + if (this.btnElement_.checked) { + this.element_.classList.add(this.CssClasses_.IS_CHECKED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_CHECKED); + } +}; +MaterialRadio.prototype['checkToggleState'] = MaterialRadio.prototype.checkToggleState; +/** + * Disable radio. + * + * @public + */ +MaterialRadio.prototype.disable = function () { + this.btnElement_.disabled = true; + this.updateClasses_(); +}; +MaterialRadio.prototype['disable'] = MaterialRadio.prototype.disable; +/** + * Enable radio. + * + * @public + */ +MaterialRadio.prototype.enable = function () { + this.btnElement_.disabled = false; + this.updateClasses_(); +}; +MaterialRadio.prototype['enable'] = MaterialRadio.prototype.enable; +/** + * Check radio. + * + * @public + */ +MaterialRadio.prototype.check = function () { + this.btnElement_.checked = true; + this.onChange_(null); +}; +MaterialRadio.prototype['check'] = MaterialRadio.prototype.check; +/** + * Uncheck radio. + * + * @public + */ +MaterialRadio.prototype.uncheck = function () { + this.btnElement_.checked = false; + this.onChange_(null); +}; +MaterialRadio.prototype['uncheck'] = MaterialRadio.prototype.uncheck; +/** + * Initialize element. + */ +MaterialRadio.prototype.init = function () { + if (this.element_) { + this.btnElement_ = this.element_.querySelector('.' + this.CssClasses_.RADIO_BTN); + this.boundChangeHandler_ = this.onChange_.bind(this); + this.boundFocusHandler_ = this.onChange_.bind(this); + this.boundBlurHandler_ = this.onBlur_.bind(this); + this.boundMouseUpHandler_ = this.onMouseup_.bind(this); + var outerCircle = document.createElement('span'); + outerCircle.classList.add(this.CssClasses_.RADIO_OUTER_CIRCLE); + var innerCircle = document.createElement('span'); + innerCircle.classList.add(this.CssClasses_.RADIO_INNER_CIRCLE); + this.element_.appendChild(outerCircle); + this.element_.appendChild(innerCircle); + var rippleContainer; + if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + rippleContainer = document.createElement('span'); + rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER); + rippleContainer.classList.add(this.CssClasses_.RIPPLE_EFFECT); + rippleContainer.classList.add(this.CssClasses_.RIPPLE_CENTER); + rippleContainer.addEventListener('mouseup', this.boundMouseUpHandler_); + var ripple = document.createElement('span'); + ripple.classList.add(this.CssClasses_.RIPPLE); + rippleContainer.appendChild(ripple); + this.element_.appendChild(rippleContainer); + } + this.btnElement_.addEventListener('change', this.boundChangeHandler_); + this.btnElement_.addEventListener('focus', this.boundFocusHandler_); + this.btnElement_.addEventListener('blur', this.boundBlurHandler_); + this.element_.addEventListener('mouseup', this.boundMouseUpHandler_); + this.updateClasses_(); + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialRadio, + classAsString: 'MaterialRadio', + cssClass: 'mdl-js-radio', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Slider MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialSlider = function MaterialSlider(element) { + this.element_ = element; + // Browser feature detection. + this.isIE_ = window.navigator.msPointerEnabled; + // Initialize instance. + this.init(); +}; +window['MaterialSlider'] = MaterialSlider; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialSlider.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialSlider.prototype.CssClasses_ = { + IE_CONTAINER: 'mdl-slider__ie-container', + SLIDER_CONTAINER: 'mdl-slider__container', + BACKGROUND_FLEX: 'mdl-slider__background-flex', + BACKGROUND_LOWER: 'mdl-slider__background-lower', + BACKGROUND_UPPER: 'mdl-slider__background-upper', + IS_LOWEST_VALUE: 'is-lowest-value', + IS_UPGRADED: 'is-upgraded' +}; +/** + * Handle input on element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSlider.prototype.onInput_ = function (event) { + this.updateValueStyles_(); +}; +/** + * Handle change on element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSlider.prototype.onChange_ = function (event) { + this.updateValueStyles_(); +}; +/** + * Handle mouseup on element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSlider.prototype.onMouseUp_ = function (event) { + event.target.blur(); +}; +/** + * Handle mousedown on container element. + * This handler is purpose is to not require the use to click + * exactly on the 2px slider element, as FireFox seems to be very + * strict about this. + * + * @param {Event} event The event that fired. + * @private + * @suppress {missingProperties} + */ +MaterialSlider.prototype.onContainerMouseDown_ = function (event) { + // If this click is not on the parent element (but rather some child) + // ignore. It may still bubble up. + if (event.target !== this.element_.parentElement) { + return; + } + // Discard the original event and create a new event that + // is on the slider element. + event.preventDefault(); + var newEvent = new MouseEvent('mousedown', { + target: event.target, + buttons: event.buttons, + clientX: event.clientX, + clientY: this.element_.getBoundingClientRect().y + }); + this.element_.dispatchEvent(newEvent); +}; +/** + * Handle updating of values. + * + * @private + */ +MaterialSlider.prototype.updateValueStyles_ = function () { + // Calculate and apply percentages to div structure behind slider. + var fraction = (this.element_.value - this.element_.min) / (this.element_.max - this.element_.min); + if (fraction === 0) { + this.element_.classList.add(this.CssClasses_.IS_LOWEST_VALUE); + } else { + this.element_.classList.remove(this.CssClasses_.IS_LOWEST_VALUE); + } + if (!this.isIE_) { + this.backgroundLower_.style.flex = fraction; + this.backgroundLower_.style.webkitFlex = fraction; + this.backgroundUpper_.style.flex = 1 - fraction; + this.backgroundUpper_.style.webkitFlex = 1 - fraction; + } +}; +// Public methods. +/** + * Disable slider. + * + * @public + */ +MaterialSlider.prototype.disable = function () { + this.element_.disabled = true; +}; +MaterialSlider.prototype['disable'] = MaterialSlider.prototype.disable; +/** + * Enable slider. + * + * @public + */ +MaterialSlider.prototype.enable = function () { + this.element_.disabled = false; +}; +MaterialSlider.prototype['enable'] = MaterialSlider.prototype.enable; +/** + * Update slider value. + * + * @param {number} value The value to which to set the control (optional). + * @public + */ +MaterialSlider.prototype.change = function (value) { + if (typeof value !== 'undefined') { + this.element_.value = value; + } + this.updateValueStyles_(); +}; +MaterialSlider.prototype['change'] = MaterialSlider.prototype.change; +/** + * Initialize element. + */ +MaterialSlider.prototype.init = function () { + if (this.element_) { + if (this.isIE_) { + // Since we need to specify a very large height in IE due to + // implementation limitations, we add a parent here that trims it down to + // a reasonable size. + var containerIE = document.createElement('div'); + containerIE.classList.add(this.CssClasses_.IE_CONTAINER); + this.element_.parentElement.insertBefore(containerIE, this.element_); + this.element_.parentElement.removeChild(this.element_); + containerIE.appendChild(this.element_); + } else { + // For non-IE browsers, we need a div structure that sits behind the + // slider and allows us to style the left and right sides of it with + // different colors. + var container = document.createElement('div'); + container.classList.add(this.CssClasses_.SLIDER_CONTAINER); + this.element_.parentElement.insertBefore(container, this.element_); + this.element_.parentElement.removeChild(this.element_); + container.appendChild(this.element_); + var backgroundFlex = document.createElement('div'); + backgroundFlex.classList.add(this.CssClasses_.BACKGROUND_FLEX); + container.appendChild(backgroundFlex); + this.backgroundLower_ = document.createElement('div'); + this.backgroundLower_.classList.add(this.CssClasses_.BACKGROUND_LOWER); + backgroundFlex.appendChild(this.backgroundLower_); + this.backgroundUpper_ = document.createElement('div'); + this.backgroundUpper_.classList.add(this.CssClasses_.BACKGROUND_UPPER); + backgroundFlex.appendChild(this.backgroundUpper_); + } + this.boundInputHandler = this.onInput_.bind(this); + this.boundChangeHandler = this.onChange_.bind(this); + this.boundMouseUpHandler = this.onMouseUp_.bind(this); + this.boundContainerMouseDownHandler = this.onContainerMouseDown_.bind(this); + this.element_.addEventListener('input', this.boundInputHandler); + this.element_.addEventListener('change', this.boundChangeHandler); + this.element_.addEventListener('mouseup', this.boundMouseUpHandler); + this.element_.parentElement.addEventListener('mousedown', this.boundContainerMouseDownHandler); + this.updateValueStyles_(); + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialSlider, + classAsString: 'MaterialSlider', + cssClass: 'mdl-js-slider', + widget: true +}); +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Snackbar MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialSnackbar = function MaterialSnackbar(element) { + this.element_ = element; + this.textElement_ = this.element_.querySelector('.' + this.cssClasses_.MESSAGE); + this.actionElement_ = this.element_.querySelector('.' + this.cssClasses_.ACTION); + if (!this.textElement_) { + throw new Error('There must be a message element for a snackbar.'); + } + if (!this.actionElement_) { + throw new Error('There must be an action element for a snackbar.'); + } + this.active = false; + this.actionHandler_ = undefined; + this.message_ = undefined; + this.actionText_ = undefined; + this.queuedNotifications_ = []; + this.setActionHidden_(true); +}; +window['MaterialSnackbar'] = MaterialSnackbar; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialSnackbar.prototype.Constant_ = { + // The duration of the snackbar show/hide animation, in ms. + ANIMATION_LENGTH: 250 +}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialSnackbar.prototype.cssClasses_ = { + SNACKBAR: 'mdl-snackbar', + MESSAGE: 'mdl-snackbar__text', + ACTION: 'mdl-snackbar__action', + ACTIVE: 'mdl-snackbar--active' +}; +/** + * Display the snackbar. + * + * @private + */ +MaterialSnackbar.prototype.displaySnackbar_ = function () { + this.element_.setAttribute('aria-hidden', 'true'); + if (this.actionHandler_) { + this.actionElement_.textContent = this.actionText_; + this.actionElement_.addEventListener('click', this.actionHandler_); + this.setActionHidden_(false); + } + this.textElement_.textContent = this.message_; + this.element_.classList.add(this.cssClasses_.ACTIVE); + this.element_.setAttribute('aria-hidden', 'false'); + setTimeout(this.cleanup_.bind(this), this.timeout_); +}; +/** + * Show the snackbar. + * + * @param {Object} data The data for the notification. + * @public + */ +MaterialSnackbar.prototype.showSnackbar = function (data) { + if (data === undefined) { + throw new Error('Please provide a data object with at least a message to display.'); + } + if (data['message'] === undefined) { + throw new Error('Please provide a message to be displayed.'); + } + if (data['actionHandler'] && !data['actionText']) { + throw new Error('Please provide action text with the handler.'); + } + if (this.active) { + this.queuedNotifications_.push(data); + } else { + this.active = true; + this.message_ = data['message']; + if (data['timeout']) { + this.timeout_ = data['timeout']; + } else { + this.timeout_ = 2750; + } + if (data['actionHandler']) { + this.actionHandler_ = data['actionHandler']; + } + if (data['actionText']) { + this.actionText_ = data['actionText']; + } + this.displaySnackbar_(); + } +}; +MaterialSnackbar.prototype['showSnackbar'] = MaterialSnackbar.prototype.showSnackbar; +/** + * Check if the queue has items within it. + * If it does, display the next entry. + * + * @private + */ +MaterialSnackbar.prototype.checkQueue_ = function () { + if (this.queuedNotifications_.length > 0) { + this.showSnackbar(this.queuedNotifications_.shift()); + } +}; +/** + * Cleanup the snackbar event listeners and accessiblity attributes. + * + * @private + */ +MaterialSnackbar.prototype.cleanup_ = function () { + this.element_.classList.remove(this.cssClasses_.ACTIVE); + setTimeout(function () { + this.element_.setAttribute('aria-hidden', 'true'); + this.textElement_.textContent = ''; + if (!Boolean(this.actionElement_.getAttribute('aria-hidden'))) { + this.setActionHidden_(true); + this.actionElement_.textContent = ''; + this.actionElement_.removeEventListener('click', this.actionHandler_); + } + this.actionHandler_ = undefined; + this.message_ = undefined; + this.actionText_ = undefined; + this.active = false; + this.checkQueue_(); + }.bind(this), this.Constant_.ANIMATION_LENGTH); +}; +/** + * Set the action handler hidden state. + * + * @param {boolean} value + * @private + */ +MaterialSnackbar.prototype.setActionHidden_ = function (value) { + if (value) { + this.actionElement_.setAttribute('aria-hidden', 'true'); + } else { + this.actionElement_.removeAttribute('aria-hidden'); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialSnackbar, + classAsString: 'MaterialSnackbar', + cssClass: 'mdl-js-snackbar', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Spinner MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @param {HTMLElement} element The element that will be upgraded. + * @constructor + */ +var MaterialSpinner = function MaterialSpinner(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialSpinner'] = MaterialSpinner; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialSpinner.prototype.Constant_ = { MDL_SPINNER_LAYER_COUNT: 4 }; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialSpinner.prototype.CssClasses_ = { + MDL_SPINNER_LAYER: 'mdl-spinner__layer', + MDL_SPINNER_CIRCLE_CLIPPER: 'mdl-spinner__circle-clipper', + MDL_SPINNER_CIRCLE: 'mdl-spinner__circle', + MDL_SPINNER_GAP_PATCH: 'mdl-spinner__gap-patch', + MDL_SPINNER_LEFT: 'mdl-spinner__left', + MDL_SPINNER_RIGHT: 'mdl-spinner__right' +}; +/** + * Auxiliary method to create a spinner layer. + * + * @param {number} index Index of the layer to be created. + * @public + */ +MaterialSpinner.prototype.createLayer = function (index) { + var layer = document.createElement('div'); + layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER); + layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER + '-' + index); + var leftClipper = document.createElement('div'); + leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER); + leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_LEFT); + var gapPatch = document.createElement('div'); + gapPatch.classList.add(this.CssClasses_.MDL_SPINNER_GAP_PATCH); + var rightClipper = document.createElement('div'); + rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER); + rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_RIGHT); + var circleOwners = [ + leftClipper, + gapPatch, + rightClipper + ]; + for (var i = 0; i < circleOwners.length; i++) { + var circle = document.createElement('div'); + circle.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE); + circleOwners[i].appendChild(circle); + } + layer.appendChild(leftClipper); + layer.appendChild(gapPatch); + layer.appendChild(rightClipper); + this.element_.appendChild(layer); +}; +MaterialSpinner.prototype['createLayer'] = MaterialSpinner.prototype.createLayer; +/** + * Stops the spinner animation. + * Public method for users who need to stop the spinner for any reason. + * + * @public + */ +MaterialSpinner.prototype.stop = function () { + this.element_.classList.remove('is-active'); +}; +MaterialSpinner.prototype['stop'] = MaterialSpinner.prototype.stop; +/** + * Starts the spinner animation. + * Public method for users who need to manually start the spinner for any reason + * (instead of just adding the 'is-active' class to their markup). + * + * @public + */ +MaterialSpinner.prototype.start = function () { + this.element_.classList.add('is-active'); +}; +MaterialSpinner.prototype['start'] = MaterialSpinner.prototype.start; +/** + * Initialize element. + */ +MaterialSpinner.prototype.init = function () { + if (this.element_) { + for (var i = 1; i <= this.Constant_.MDL_SPINNER_LAYER_COUNT; i++) { + this.createLayer(i); + } + this.element_.classList.add('is-upgraded'); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialSpinner, + classAsString: 'MaterialSpinner', + cssClass: 'mdl-js-spinner', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Checkbox MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialSwitch = function MaterialSwitch(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialSwitch'] = MaterialSwitch; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialSwitch.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialSwitch.prototype.CssClasses_ = { + INPUT: 'mdl-switch__input', + TRACK: 'mdl-switch__track', + THUMB: 'mdl-switch__thumb', + FOCUS_HELPER: 'mdl-switch__focus-helper', + RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE_CONTAINER: 'mdl-switch__ripple-container', + RIPPLE_CENTER: 'mdl-ripple--center', + RIPPLE: 'mdl-ripple', + IS_FOCUSED: 'is-focused', + IS_DISABLED: 'is-disabled', + IS_CHECKED: 'is-checked' +}; +/** + * Handle change of state. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSwitch.prototype.onChange_ = function (event) { + this.updateClasses_(); +}; +/** + * Handle focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSwitch.prototype.onFocus_ = function (event) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle lost focus of element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSwitch.prototype.onBlur_ = function (event) { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle mouseup. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialSwitch.prototype.onMouseUp_ = function (event) { + this.blur_(); +}; +/** + * Handle class updates. + * + * @private + */ +MaterialSwitch.prototype.updateClasses_ = function () { + this.checkDisabled(); + this.checkToggleState(); +}; +/** + * Add blur. + * + * @private + */ +MaterialSwitch.prototype.blur_ = function () { + // TODO: figure out why there's a focus event being fired after our blur, + // so that we can avoid this hack. + window.setTimeout(function () { + this.inputElement_.blur(); + }.bind(this), this.Constant_.TINY_TIMEOUT); +}; +// Public methods. +/** + * Check the components disabled state. + * + * @public + */ +MaterialSwitch.prototype.checkDisabled = function () { + if (this.inputElement_.disabled) { + this.element_.classList.add(this.CssClasses_.IS_DISABLED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DISABLED); + } +}; +MaterialSwitch.prototype['checkDisabled'] = MaterialSwitch.prototype.checkDisabled; +/** + * Check the components toggled state. + * + * @public + */ +MaterialSwitch.prototype.checkToggleState = function () { + if (this.inputElement_.checked) { + this.element_.classList.add(this.CssClasses_.IS_CHECKED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_CHECKED); + } +}; +MaterialSwitch.prototype['checkToggleState'] = MaterialSwitch.prototype.checkToggleState; +/** + * Disable switch. + * + * @public + */ +MaterialSwitch.prototype.disable = function () { + this.inputElement_.disabled = true; + this.updateClasses_(); +}; +MaterialSwitch.prototype['disable'] = MaterialSwitch.prototype.disable; +/** + * Enable switch. + * + * @public + */ +MaterialSwitch.prototype.enable = function () { + this.inputElement_.disabled = false; + this.updateClasses_(); +}; +MaterialSwitch.prototype['enable'] = MaterialSwitch.prototype.enable; +/** + * Activate switch. + * + * @public + */ +MaterialSwitch.prototype.on = function () { + this.inputElement_.checked = true; + this.updateClasses_(); +}; +MaterialSwitch.prototype['on'] = MaterialSwitch.prototype.on; +/** + * Deactivate switch. + * + * @public + */ +MaterialSwitch.prototype.off = function () { + this.inputElement_.checked = false; + this.updateClasses_(); +}; +MaterialSwitch.prototype['off'] = MaterialSwitch.prototype.off; +/** + * Initialize element. + */ +MaterialSwitch.prototype.init = function () { + if (this.element_) { + this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); + var track = document.createElement('div'); + track.classList.add(this.CssClasses_.TRACK); + var thumb = document.createElement('div'); + thumb.classList.add(this.CssClasses_.THUMB); + var focusHelper = document.createElement('span'); + focusHelper.classList.add(this.CssClasses_.FOCUS_HELPER); + thumb.appendChild(focusHelper); + this.element_.appendChild(track); + this.element_.appendChild(thumb); + this.boundMouseUpHandler = this.onMouseUp_.bind(this); + if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + this.rippleContainerElement_ = document.createElement('span'); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT); + this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); + this.rippleContainerElement_.addEventListener('mouseup', this.boundMouseUpHandler); + var ripple = document.createElement('span'); + ripple.classList.add(this.CssClasses_.RIPPLE); + this.rippleContainerElement_.appendChild(ripple); + this.element_.appendChild(this.rippleContainerElement_); + } + this.boundChangeHandler = this.onChange_.bind(this); + this.boundFocusHandler = this.onFocus_.bind(this); + this.boundBlurHandler = this.onBlur_.bind(this); + this.inputElement_.addEventListener('change', this.boundChangeHandler); + this.inputElement_.addEventListener('focus', this.boundFocusHandler); + this.inputElement_.addEventListener('blur', this.boundBlurHandler); + this.element_.addEventListener('mouseup', this.boundMouseUpHandler); + this.updateClasses_(); + this.element_.classList.add('is-upgraded'); + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialSwitch, + classAsString: 'MaterialSwitch', + cssClass: 'mdl-js-switch', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Tabs MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {Element} element The element that will be upgraded. + */ +var MaterialTabs = function MaterialTabs(element) { + // Stores the HTML element. + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialTabs'] = MaterialTabs; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string} + * @private + */ +MaterialTabs.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialTabs.prototype.CssClasses_ = { + TAB_CLASS: 'mdl-tabs__tab', + PANEL_CLASS: 'mdl-tabs__panel', + ACTIVE_CLASS: 'is-active', + UPGRADED_CLASS: 'is-upgraded', + MDL_JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', + MDL_RIPPLE_CONTAINER: 'mdl-tabs__ripple-container', + MDL_RIPPLE: 'mdl-ripple', + MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events' +}; +/** + * Handle clicks to a tabs component + * + * @private + */ +MaterialTabs.prototype.initTabs_ = function () { + if (this.element_.classList.contains(this.CssClasses_.MDL_JS_RIPPLE_EFFECT)) { + this.element_.classList.add(this.CssClasses_.MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS); + } + // Select element tabs, document panels + this.tabs_ = this.element_.querySelectorAll('.' + this.CssClasses_.TAB_CLASS); + this.panels_ = this.element_.querySelectorAll('.' + this.CssClasses_.PANEL_CLASS); + // Create new tabs for each tab element + for (var i = 0; i < this.tabs_.length; i++) { + new MaterialTab(this.tabs_[i], this); + } + this.element_.classList.add(this.CssClasses_.UPGRADED_CLASS); +}; +/** + * Reset tab state, dropping active classes + * + * @private + */ +MaterialTabs.prototype.resetTabState_ = function () { + for (var k = 0; k < this.tabs_.length; k++) { + this.tabs_[k].classList.remove(this.CssClasses_.ACTIVE_CLASS); + } +}; +/** + * Reset panel state, droping active classes + * + * @private + */ +MaterialTabs.prototype.resetPanelState_ = function () { + for (var j = 0; j < this.panels_.length; j++) { + this.panels_[j].classList.remove(this.CssClasses_.ACTIVE_CLASS); + } +}; +/** + * Initialize element. + */ +MaterialTabs.prototype.init = function () { + if (this.element_) { + this.initTabs_(); + } +}; +/** + * Constructor for an individual tab. + * + * @constructor + * @param {Element} tab The HTML element for the tab. + * @param {MaterialTabs} ctx The MaterialTabs object that owns the tab. + */ +function MaterialTab(tab, ctx) { + if (tab) { + if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) { + var rippleContainer = document.createElement('span'); + rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER); + rippleContainer.classList.add(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT); + var ripple = document.createElement('span'); + ripple.classList.add(ctx.CssClasses_.MDL_RIPPLE); + rippleContainer.appendChild(ripple); + tab.appendChild(rippleContainer); + } + tab.addEventListener('click', function (e) { + e.preventDefault(); + ctx.resetTabState_(); + tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS); + }); + } +} +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialTabs, + classAsString: 'MaterialTabs', + cssClass: 'mdl-js-tabs' +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Textfield MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialTextfield = function MaterialTextfield(element) { + this.element_ = element; + this.maxRows = this.Constant_.NO_MAX_ROWS; + // Initialize instance. + this.init(); +}; +window['MaterialTextfield'] = MaterialTextfield; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialTextfield.prototype.Constant_ = { + NO_MAX_ROWS: -1, + MAX_ROWS_ATTRIBUTE: 'maxrows' +}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialTextfield.prototype.CssClasses_ = { + LABEL: 'mdl-textfield__label', + INPUT: 'mdl-textfield__input', + IS_DIRTY: 'is-dirty', + IS_FOCUSED: 'is-focused', + IS_DISABLED: 'is-disabled', + IS_INVALID: 'is-invalid', + IS_UPGRADED: 'is-upgraded', + HAS_PLACEHOLDER: 'has-placeholder' +}; +/** + * Handle input being entered. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialTextfield.prototype.onKeyDown_ = function (event) { + var currentRowCount = event.target.value.split('\n').length; + if (event.keyCode === 13) { + if (currentRowCount >= this.maxRows) { + event.preventDefault(); + } + } +}; +/** + * Handle focus. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialTextfield.prototype.onFocus_ = function (event) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle lost focus. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialTextfield.prototype.onBlur_ = function (event) { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); +}; +/** + * Handle reset event from out side. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialTextfield.prototype.onReset_ = function (event) { + this.updateClasses_(); +}; +/** + * Handle class updates. + * + * @private + */ +MaterialTextfield.prototype.updateClasses_ = function () { + this.checkDisabled(); + this.checkValidity(); + this.checkDirty(); + this.checkFocus(); +}; +// Public methods. +/** + * Check the disabled state and update field accordingly. + * + * @public + */ +MaterialTextfield.prototype.checkDisabled = function () { + if (this.input_.disabled) { + this.element_.classList.add(this.CssClasses_.IS_DISABLED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DISABLED); + } +}; +MaterialTextfield.prototype['checkDisabled'] = MaterialTextfield.prototype.checkDisabled; +/** + * Check the focus state and update field accordingly. + * + * @public + */ +MaterialTextfield.prototype.checkFocus = function () { + if (Boolean(this.element_.querySelector(':focus'))) { + this.element_.classList.add(this.CssClasses_.IS_FOCUSED); + } else { + this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); + } +}; +MaterialTextfield.prototype['checkFocus'] = MaterialTextfield.prototype.checkFocus; +/** + * Check the validity state and update field accordingly. + * + * @public + */ +MaterialTextfield.prototype.checkValidity = function () { + if (this.input_.validity) { + if (this.input_.validity.valid) { + this.element_.classList.remove(this.CssClasses_.IS_INVALID); + } else { + this.element_.classList.add(this.CssClasses_.IS_INVALID); + } + } +}; +MaterialTextfield.prototype['checkValidity'] = MaterialTextfield.prototype.checkValidity; +/** + * Check the dirty state and update field accordingly. + * + * @public + */ +MaterialTextfield.prototype.checkDirty = function () { + if (this.input_.value && this.input_.value.length > 0) { + this.element_.classList.add(this.CssClasses_.IS_DIRTY); + } else { + this.element_.classList.remove(this.CssClasses_.IS_DIRTY); + } +}; +MaterialTextfield.prototype['checkDirty'] = MaterialTextfield.prototype.checkDirty; +/** + * Disable text field. + * + * @public + */ +MaterialTextfield.prototype.disable = function () { + this.input_.disabled = true; + this.updateClasses_(); +}; +MaterialTextfield.prototype['disable'] = MaterialTextfield.prototype.disable; +/** + * Enable text field. + * + * @public + */ +MaterialTextfield.prototype.enable = function () { + this.input_.disabled = false; + this.updateClasses_(); +}; +MaterialTextfield.prototype['enable'] = MaterialTextfield.prototype.enable; +/** + * Update text field value. + * + * @param {string} value The value to which to set the control (optional). + * @public + */ +MaterialTextfield.prototype.change = function (value) { + this.input_.value = value || ''; + this.updateClasses_(); +}; +MaterialTextfield.prototype['change'] = MaterialTextfield.prototype.change; +/** + * Initialize element. + */ +MaterialTextfield.prototype.init = function () { + if (this.element_) { + this.label_ = this.element_.querySelector('.' + this.CssClasses_.LABEL); + this.input_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); + if (this.input_) { + if (this.input_.hasAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE)) { + this.maxRows = parseInt(this.input_.getAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE), 10); + if (isNaN(this.maxRows)) { + this.maxRows = this.Constant_.NO_MAX_ROWS; + } + } + if (this.input_.hasAttribute('placeholder')) { + this.element_.classList.add(this.CssClasses_.HAS_PLACEHOLDER); + } + this.boundUpdateClassesHandler = this.updateClasses_.bind(this); + this.boundFocusHandler = this.onFocus_.bind(this); + this.boundBlurHandler = this.onBlur_.bind(this); + this.boundResetHandler = this.onReset_.bind(this); + this.input_.addEventListener('input', this.boundUpdateClassesHandler); + this.input_.addEventListener('focus', this.boundFocusHandler); + this.input_.addEventListener('blur', this.boundBlurHandler); + this.input_.addEventListener('reset', this.boundResetHandler); + if (this.maxRows !== this.Constant_.NO_MAX_ROWS) { + // TODO: This should handle pasting multi line text. + // Currently doesn't. + this.boundKeyDownHandler = this.onKeyDown_.bind(this); + this.input_.addEventListener('keydown', this.boundKeyDownHandler); + } + var invalid = this.element_.classList.contains(this.CssClasses_.IS_INVALID); + this.updateClasses_(); + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + if (invalid) { + this.element_.classList.add(this.CssClasses_.IS_INVALID); + } + if (this.input_.hasAttribute('autofocus')) { + this.element_.focus(); + this.checkFocus(); + } + } + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialTextfield, + classAsString: 'MaterialTextfield', + cssClass: 'mdl-js-textfield', + widget: true +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Tooltip MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialTooltip = function MaterialTooltip(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialTooltip'] = MaterialTooltip; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialTooltip.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialTooltip.prototype.CssClasses_ = { + IS_ACTIVE: 'is-active', + BOTTOM: 'mdl-tooltip--bottom', + LEFT: 'mdl-tooltip--left', + RIGHT: 'mdl-tooltip--right', + TOP: 'mdl-tooltip--top' +}; +/** + * Handle mouseenter for tooltip. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialTooltip.prototype.handleMouseEnter_ = function (event) { + var props = event.target.getBoundingClientRect(); + var left = props.left + props.width / 2; + var top = props.top + props.height / 2; + var marginLeft = -1 * (this.element_.offsetWidth / 2); + var marginTop = -1 * (this.element_.offsetHeight / 2); + if (this.element_.classList.contains(this.CssClasses_.LEFT) || this.element_.classList.contains(this.CssClasses_.RIGHT)) { + left = props.width / 2; + if (top + marginTop < 0) { + this.element_.style.top = '0'; + this.element_.style.marginTop = '0'; + } else { + this.element_.style.top = top + 'px'; + this.element_.style.marginTop = marginTop + 'px'; + } + } else { + if (left + marginLeft < 0) { + this.element_.style.left = '0'; + this.element_.style.marginLeft = '0'; + } else { + this.element_.style.left = left + 'px'; + this.element_.style.marginLeft = marginLeft + 'px'; + } + } + if (this.element_.classList.contains(this.CssClasses_.TOP)) { + this.element_.style.top = props.top - this.element_.offsetHeight - 10 + 'px'; + } else if (this.element_.classList.contains(this.CssClasses_.RIGHT)) { + this.element_.style.left = props.left + props.width + 10 + 'px'; + } else if (this.element_.classList.contains(this.CssClasses_.LEFT)) { + this.element_.style.left = props.left - this.element_.offsetWidth - 10 + 'px'; + } else { + this.element_.style.top = props.top + props.height + 10 + 'px'; + } + this.element_.classList.add(this.CssClasses_.IS_ACTIVE); +}; +/** + * Hide tooltip on mouseleave or scroll + * + * @private + */ +MaterialTooltip.prototype.hideTooltip_ = function () { + this.element_.classList.remove(this.CssClasses_.IS_ACTIVE); +}; +/** + * Initialize element. + */ +MaterialTooltip.prototype.init = function () { + if (this.element_) { + var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for'); + if (forElId) { + this.forElement_ = document.getElementById(forElId); + } + if (this.forElement_) { + // It's left here because it prevents accidental text selection on Android + if (!this.forElement_.hasAttribute('tabindex')) { + this.forElement_.setAttribute('tabindex', '0'); + } + this.boundMouseEnterHandler = this.handleMouseEnter_.bind(this); + this.boundMouseLeaveAndScrollHandler = this.hideTooltip_.bind(this); + this.forElement_.addEventListener('mouseenter', this.boundMouseEnterHandler, false); + this.forElement_.addEventListener('touchend', this.boundMouseEnterHandler, false); + this.forElement_.addEventListener('mouseleave', this.boundMouseLeaveAndScrollHandler, false); + window.addEventListener('scroll', this.boundMouseLeaveAndScrollHandler, true); + window.addEventListener('touchstart', this.boundMouseLeaveAndScrollHandler); + } + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialTooltip, + classAsString: 'MaterialTooltip', + cssClass: 'mdl-tooltip' +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Layout MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialLayout = function MaterialLayout(element) { + this.element_ = element; + this.innerContainer_ = element.querySelector('.' + this.CssClasses_.INNER_CONTAINER); + // Initialize instance. + this.init(); +}; +window['MaterialLayout'] = MaterialLayout; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialLayout.prototype.Constant_ = { + MAX_WIDTH: '(max-width: 1024px)', + TAB_SCROLL_PIXELS: 100, + RESIZE_TIMEOUT: 100, + MENU_ICON: '', + CHEVRON_LEFT: 'chevron_left', + CHEVRON_RIGHT: 'chevron_right' +}; +/** + * Keycodes, for code readability. + * + * @enum {number} + * @private + */ +MaterialLayout.prototype.Keycodes_ = { + ENTER: 13, + ESCAPE: 27, + SPACE: 32 +}; +/** + * Modes. + * + * @enum {number} + * @private + */ +MaterialLayout.prototype.Mode_ = { + STANDARD: 0, + SEAMED: 1, + WATERFALL: 2, + SCROLL: 3 +}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialLayout.prototype.CssClasses_ = { + INNER_CONTAINER: 'mdl-layout__inner-container', + HEADER: 'mdl-layout__header', + DRAWER: 'mdl-layout__drawer', + CONTENT: 'mdl-layout__content', + DRAWER_BTN: 'mdl-layout__drawer-button', + ICON: 'material-icons', + JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', + RIPPLE_CONTAINER: 'mdl-layout__tab-ripple-container', + RIPPLE: 'mdl-ripple', + RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + HEADER_SEAMED: 'mdl-layout__header--seamed', + HEADER_WATERFALL: 'mdl-layout__header--waterfall', + HEADER_SCROLL: 'mdl-layout__header--scroll', + FIXED_HEADER: 'mdl-layout--fixed-header', + OBFUSCATOR: 'mdl-layout__obfuscator', + TAB_BAR: 'mdl-layout__tab-bar', + TAB_CONTAINER: 'mdl-layout__tab-bar-container', + TAB: 'mdl-layout__tab', + TAB_BAR_BUTTON: 'mdl-layout__tab-bar-button', + TAB_BAR_LEFT_BUTTON: 'mdl-layout__tab-bar-left-button', + TAB_BAR_RIGHT_BUTTON: 'mdl-layout__tab-bar-right-button', + PANEL: 'mdl-layout__tab-panel', + HAS_DRAWER: 'has-drawer', + HAS_TABS: 'has-tabs', + HAS_SCROLLING_HEADER: 'has-scrolling-header', + CASTING_SHADOW: 'is-casting-shadow', + IS_COMPACT: 'is-compact', + IS_SMALL_SCREEN: 'is-small-screen', + IS_DRAWER_OPEN: 'is-visible', + IS_ACTIVE: 'is-active', + IS_UPGRADED: 'is-upgraded', + IS_ANIMATING: 'is-animating', + ON_LARGE_SCREEN: 'mdl-layout--large-screen-only', + ON_SMALL_SCREEN: 'mdl-layout--small-screen-only' +}; +/** + * Handles scrolling on the content. + * + * @private + */ +MaterialLayout.prototype.contentScrollHandler_ = function () { + if (this.header_.classList.contains(this.CssClasses_.IS_ANIMATING)) { + return; + } + var headerVisible = !this.element_.classList.contains(this.CssClasses_.IS_SMALL_SCREEN) || this.element_.classList.contains(this.CssClasses_.FIXED_HEADER); + if (this.content_.scrollTop > 0 && !this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { + this.header_.classList.add(this.CssClasses_.CASTING_SHADOW); + this.header_.classList.add(this.CssClasses_.IS_COMPACT); + if (headerVisible) { + this.header_.classList.add(this.CssClasses_.IS_ANIMATING); + } + } else if (this.content_.scrollTop <= 0 && this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { + this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW); + this.header_.classList.remove(this.CssClasses_.IS_COMPACT); + if (headerVisible) { + this.header_.classList.add(this.CssClasses_.IS_ANIMATING); + } + } +}; +/** + * Handles a keyboard event on the drawer. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialLayout.prototype.keyboardEventHandler_ = function (evt) { + // Only react when the drawer is open. + if (evt.keyCode === this.Keycodes_.ESCAPE && this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) { + this.toggleDrawer(); + } +}; +/** + * Handles changes in screen size. + * + * @private + */ +MaterialLayout.prototype.screenSizeHandler_ = function () { + if (this.screenSizeMediaQuery_.matches) { + this.element_.classList.add(this.CssClasses_.IS_SMALL_SCREEN); + } else { + this.element_.classList.remove(this.CssClasses_.IS_SMALL_SCREEN); + // Collapse drawer (if any) when moving to a large screen size. + if (this.drawer_) { + this.drawer_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); + this.obfuscator_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); + } + } +}; +/** + * Handles events of drawer button. + * + * @param {Event} evt The event that fired. + * @private + */ +MaterialLayout.prototype.drawerToggleHandler_ = function (evt) { + if (evt && evt.type === 'keydown') { + if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) { + // prevent scrolling in drawer nav + evt.preventDefault(); + } else { + // prevent other keys + return; + } + } + this.toggleDrawer(); +}; +/** + * Handles (un)setting the `is-animating` class + * + * @private + */ +MaterialLayout.prototype.headerTransitionEndHandler_ = function () { + this.header_.classList.remove(this.CssClasses_.IS_ANIMATING); +}; +/** + * Handles expanding the header on click + * + * @private + */ +MaterialLayout.prototype.headerClickHandler_ = function () { + if (this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { + this.header_.classList.remove(this.CssClasses_.IS_COMPACT); + this.header_.classList.add(this.CssClasses_.IS_ANIMATING); + } +}; +/** + * Reset tab state, dropping active classes + * + * @private + */ +MaterialLayout.prototype.resetTabState_ = function (tabBar) { + for (var k = 0; k < tabBar.length; k++) { + tabBar[k].classList.remove(this.CssClasses_.IS_ACTIVE); + } +}; +/** + * Reset panel state, droping active classes + * + * @private + */ +MaterialLayout.prototype.resetPanelState_ = function (panels) { + for (var j = 0; j < panels.length; j++) { + panels[j].classList.remove(this.CssClasses_.IS_ACTIVE); + } +}; +/** + * Toggle drawer state + * + * @public + */ +MaterialLayout.prototype.toggleDrawer = function () { + var drawerButton = this.innerContainer_.querySelector('.' + this.CssClasses_.DRAWER_BTN); + this.drawer_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN); + this.obfuscator_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN); + // Set accessibility properties. + if (this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) { + this.drawer_.setAttribute('aria-hidden', 'false'); + drawerButton.setAttribute('aria-expanded', 'true'); + } else { + this.drawer_.setAttribute('aria-hidden', 'true'); + drawerButton.setAttribute('aria-expanded', 'false'); + } +}; +MaterialLayout.prototype['toggleDrawer'] = MaterialLayout.prototype.toggleDrawer; +/** + * Initialize element. + */ +MaterialLayout.prototype.init = function () { + if (this.element_) { + var focusedElement = this.element_.querySelector(':focus'); + if (focusedElement) { + focusedElement.focus(); + } + var directChildren = this.innerContainer_.childNodes; + var numChildren = directChildren.length; + for (var c = 0; c < numChildren; c++) { + var child = directChildren[c]; + if (child.classList && child.classList.contains(this.CssClasses_.HEADER)) { + this.header_ = child; + } + if (child.classList && child.classList.contains(this.CssClasses_.DRAWER)) { + this.drawer_ = child; + } + if (child.classList && child.classList.contains(this.CssClasses_.CONTENT)) { + this.content_ = child; + } + } + window.addEventListener('pageshow', function (e) { + if (e.persisted) { + // when page is loaded from back/forward cache + // trigger repaint to let layout scroll in safari + this.innerContainer_.style.overflowY = 'hidden'; + requestAnimationFrame(function () { + this.innerContainer_.style.overflowY = ''; + }.bind(this)); + } + }.bind(this), false); + if (this.header_) { + this.tabBar_ = this.header_.querySelector('.' + this.CssClasses_.TAB_BAR); + // Mik debug for crashing when HMR + if (this.tabBar_ && this.tabBar_.parentNode !== this.header_) { + this.tabBar_ = null; + } + } + var mode = this.Mode_.STANDARD; + if (this.header_) { + if (this.header_.classList.contains(this.CssClasses_.HEADER_SEAMED)) { + mode = this.Mode_.SEAMED; + } else if (this.header_.classList.contains(this.CssClasses_.HEADER_WATERFALL)) { + mode = this.Mode_.WATERFALL; + this.header_.addEventListener('transitionend', this.headerTransitionEndHandler_.bind(this)); + this.header_.addEventListener('click', this.headerClickHandler_.bind(this)); + } else if (this.header_.classList.contains(this.CssClasses_.HEADER_SCROLL)) { + mode = this.Mode_.SCROLL; + this.element_.classList.add(this.CssClasses_.HAS_SCROLLING_HEADER); + } + if (mode === this.Mode_.STANDARD) { + this.header_.classList.add(this.CssClasses_.CASTING_SHADOW); + if (this.tabBar_) { + this.tabBar_.classList.add(this.CssClasses_.CASTING_SHADOW); + } + } else if (mode === this.Mode_.SEAMED || mode === this.Mode_.SCROLL) { + this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW); + if (this.tabBar_) { + this.tabBar_.classList.remove(this.CssClasses_.CASTING_SHADOW); + } + } else if (mode === this.Mode_.WATERFALL) { + // Add and remove shadows depending on scroll position. + // Also add/remove auxiliary class for styling of the compact version of + // the header. + this.content_.addEventListener('scroll', this.contentScrollHandler_.bind(this)); + this.contentScrollHandler_(); + } + } + // Add drawer toggling button to our layout, if we have an openable drawer. + if (this.drawer_) { + var drawerButton = this.innerContainer_.querySelector('.' + this.CssClasses_.DRAWER_BTN); + if (!drawerButton) { + drawerButton = document.createElement('div'); + drawerButton.setAttribute('aria-expanded', 'false'); + drawerButton.setAttribute('role', 'button'); + drawerButton.setAttribute('tabindex', '0'); + drawerButton.classList.add(this.CssClasses_.DRAWER_BTN); + var drawerButtonIcon = document.createElement('i'); + drawerButtonIcon.classList.add(this.CssClasses_.ICON); + drawerButtonIcon.innerHTML = this.Constant_.MENU_ICON; + drawerButton.appendChild(drawerButtonIcon); + } + if (this.drawer_.classList.contains(this.CssClasses_.ON_LARGE_SCREEN)) { + //If drawer has ON_LARGE_SCREEN class then add it to the drawer toggle button as well. + drawerButton.classList.add(this.CssClasses_.ON_LARGE_SCREEN); + } else if (this.drawer_.classList.contains(this.CssClasses_.ON_SMALL_SCREEN)) { + //If drawer has ON_SMALL_SCREEN class then add it to the drawer toggle button as well. + drawerButton.classList.add(this.CssClasses_.ON_SMALL_SCREEN); + } + drawerButton.addEventListener('click', this.drawerToggleHandler_.bind(this)); + drawerButton.addEventListener('keydown', this.drawerToggleHandler_.bind(this)); + // Add a class if the layout has a drawer, for altering the left padding. + // Adds the HAS_DRAWER to the elements since this.header_ may or may + // not be present. + this.element_.classList.add(this.CssClasses_.HAS_DRAWER); + // If we have a fixed header, add the button to the header rather than + // the layout. + if (this.element_.classList.contains(this.CssClasses_.FIXED_HEADER)) { + this.header_.insertBefore(drawerButton, this.header_.firstChild); + } else { + this.innerContainer_.insertBefore(drawerButton, this.content_); + } + var obfuscator = document.createElement('div'); + obfuscator.classList.add(this.CssClasses_.OBFUSCATOR); + this.innerContainer_.appendChild(obfuscator); + obfuscator.addEventListener('click', this.drawerToggleHandler_.bind(this)); + this.obfuscator_ = obfuscator; + this.drawer_.addEventListener('keydown', this.keyboardEventHandler_.bind(this)); + this.drawer_.setAttribute('aria-hidden', 'true'); + } + // Keep an eye on screen size, and add/remove auxiliary class for styling + // of small screens. + this.screenSizeMediaQuery_ = window.matchMedia(this.Constant_.MAX_WIDTH); + this.screenSizeMediaQuery_.addListener(this.screenSizeHandler_.bind(this)); + this.screenSizeHandler_(); + // Initialize tabs, if any. + if (this.header_ && this.tabBar_) { + this.element_.classList.add(this.CssClasses_.HAS_TABS); + var tabContainer = document.createElement('div'); + tabContainer.classList.add(this.CssClasses_.TAB_CONTAINER); + this.header_.insertBefore(tabContainer, this.tabBar_); + this.header_.removeChild(this.tabBar_); + var leftButton = document.createElement('div'); + leftButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON); + leftButton.classList.add(this.CssClasses_.TAB_BAR_LEFT_BUTTON); + var leftButtonIcon = document.createElement('i'); + leftButtonIcon.classList.add(this.CssClasses_.ICON); + leftButtonIcon.textContent = this.Constant_.CHEVRON_LEFT; + leftButton.appendChild(leftButtonIcon); + leftButton.addEventListener('click', function () { + this.tabBar_.scrollLeft -= this.Constant_.TAB_SCROLL_PIXELS; + }.bind(this)); + var rightButton = document.createElement('div'); + rightButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON); + rightButton.classList.add(this.CssClasses_.TAB_BAR_RIGHT_BUTTON); + var rightButtonIcon = document.createElement('i'); + rightButtonIcon.classList.add(this.CssClasses_.ICON); + rightButtonIcon.textContent = this.Constant_.CHEVRON_RIGHT; + rightButton.appendChild(rightButtonIcon); + rightButton.addEventListener('click', function () { + this.tabBar_.scrollLeft += this.Constant_.TAB_SCROLL_PIXELS; + }.bind(this)); + tabContainer.appendChild(leftButton); + tabContainer.appendChild(this.tabBar_); + tabContainer.appendChild(rightButton); + // Add and remove tab buttons depending on scroll position and total + // window size. + var tabUpdateHandler = function () { + if (this.tabBar_.scrollLeft > 0) { + leftButton.classList.add(this.CssClasses_.IS_ACTIVE); + } else { + leftButton.classList.remove(this.CssClasses_.IS_ACTIVE); + } + if (this.tabBar_.scrollLeft < this.tabBar_.scrollWidth - this.tabBar_.offsetWidth) { + rightButton.classList.add(this.CssClasses_.IS_ACTIVE); + } else { + rightButton.classList.remove(this.CssClasses_.IS_ACTIVE); + } + }.bind(this); + this.tabBar_.addEventListener('scroll', tabUpdateHandler); + tabUpdateHandler(); + // Update tabs when the window resizes. + var windowResizeHandler = function () { + // Use timeouts to make sure it doesn't happen too often. + if (this.resizeTimeoutId_) { + clearTimeout(this.resizeTimeoutId_); + } + this.resizeTimeoutId_ = setTimeout(function () { + tabUpdateHandler(); + this.resizeTimeoutId_ = null; + }.bind(this), this.Constant_.RESIZE_TIMEOUT); + }.bind(this); + window.addEventListener('resize', windowResizeHandler); + if (this.tabBar_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) { + this.tabBar_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); + } + // Select element tabs, document panels + var tabs = this.tabBar_.querySelectorAll('.' + this.CssClasses_.TAB); + var panels = this.content_.querySelectorAll('.' + this.CssClasses_.PANEL); + // Create new tabs for each tab element + for (var i = 0; i < tabs.length; i++) { + new MaterialLayoutTab(tabs[i], tabs, panels, this); + } + } + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + } +}; +/** + * Constructor for an individual tab. + * + * @constructor + * @param {HTMLElement} tab The HTML element for the tab. + * @param {!Array} tabs Array with HTML elements for all tabs. + * @param {!Array} panels Array with HTML elements for all panels. + * @param {MaterialLayout} layout The MaterialLayout object that owns the tab. + */ +function MaterialLayoutTab(tab, tabs, panels, layout) { + /** + * Auxiliary method to programmatically select a tab in the UI. + */ + function selectTab() { + layout.resetTabState_(tabs); + tab.classList.add(layout.CssClasses_.IS_ACTIVE); + } + if (layout.tabBar_.classList.contains(layout.CssClasses_.JS_RIPPLE_EFFECT)) { + var rippleContainer = document.createElement('span'); + rippleContainer.classList.add(layout.CssClasses_.RIPPLE_CONTAINER); + rippleContainer.classList.add(layout.CssClasses_.JS_RIPPLE_EFFECT); + var ripple = document.createElement('span'); + ripple.classList.add(layout.CssClasses_.RIPPLE); + rippleContainer.appendChild(ripple); + tab.appendChild(rippleContainer); + } + tab.addEventListener('click', function (e) { + e.preventDefault(); + selectTab(); + }); + tab.show = selectTab; +} +window['MaterialLayoutTab'] = MaterialLayoutTab; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialLayout, + classAsString: 'MaterialLayout', + cssClass: 'mdl-js-layout' +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Data Table Card MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {Element} element The element that will be upgraded. + */ +var MaterialDataTable = function MaterialDataTable(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialDataTable'] = MaterialDataTable; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialDataTable.prototype.Constant_ = {}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialDataTable.prototype.CssClasses_ = { + DATA_TABLE: 'mdl-data-table', + SELECTABLE: 'mdl-data-table--selectable', + SELECT_ELEMENT: 'mdl-data-table__select', + IS_SELECTED: 'is-selected', + IS_UPGRADED: 'is-upgraded' +}; +/** + * Generates and returns a function that toggles the selection state of a + * single row (or multiple rows). + * + * @param {Element} checkbox Checkbox that toggles the selection state. + * @param {Element} row Row to toggle when checkbox changes. + * @param {(Array|NodeList)=} opt_rows Rows to toggle when checkbox changes. + * @private + */ +MaterialDataTable.prototype.selectRow_ = function (checkbox, row, opt_rows) { + if (row) { + return function () { + if (checkbox.checked) { + row.classList.add(this.CssClasses_.IS_SELECTED); + } else { + row.classList.remove(this.CssClasses_.IS_SELECTED); + } + }.bind(this); + } + if (opt_rows) { + return function () { + var i; + var el; + if (checkbox.checked) { + for (i = 0; i < opt_rows.length; i++) { + el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); + el['MaterialCheckbox'].check(); + opt_rows[i].classList.add(this.CssClasses_.IS_SELECTED); + } + } else { + for (i = 0; i < opt_rows.length; i++) { + el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); + el['MaterialCheckbox'].uncheck(); + opt_rows[i].classList.remove(this.CssClasses_.IS_SELECTED); + } + } + }.bind(this); + } +}; +/** + * Creates a checkbox for a single or or multiple rows and hooks up the + * event handling. + * + * @param {Element} row Row to toggle when checkbox changes. + * @param {(Array|NodeList)=} opt_rows Rows to toggle when checkbox changes. + * @private + */ +MaterialDataTable.prototype.createCheckbox_ = function (row, opt_rows) { + var label = document.createElement('label'); + var labelClasses = [ + 'mdl-checkbox', + 'mdl-js-checkbox', + 'mdl-js-ripple-effect', + this.CssClasses_.SELECT_ELEMENT + ]; + label.className = labelClasses.join(' '); + var checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('mdl-checkbox__input'); + if (row) { + checkbox.checked = row.classList.contains(this.CssClasses_.IS_SELECTED); + checkbox.addEventListener('change', this.selectRow_(checkbox, row)); + } else if (opt_rows) { + checkbox.addEventListener('change', this.selectRow_(checkbox, null, opt_rows)); + } + label.appendChild(checkbox); + componentHandler.upgradeElement(label, 'MaterialCheckbox'); + return label; +}; +/** + * Initialize element. + */ +MaterialDataTable.prototype.init = function () { + if (this.element_) { + var firstHeader = this.element_.querySelector('th'); + var bodyRows = Array.prototype.slice.call(this.element_.querySelectorAll('tbody tr')); + var footRows = Array.prototype.slice.call(this.element_.querySelectorAll('tfoot tr')); + var rows = bodyRows.concat(footRows); + if (this.element_.classList.contains(this.CssClasses_.SELECTABLE)) { + var th = document.createElement('th'); + var headerCheckbox = this.createCheckbox_(null, rows); + th.appendChild(headerCheckbox); + firstHeader.parentElement.insertBefore(th, firstHeader); + for (var i = 0; i < rows.length; i++) { + var firstCell = rows[i].querySelector('td'); + if (firstCell) { + var td = document.createElement('td'); + if (rows[i].parentNode.nodeName.toUpperCase() === 'TBODY') { + var rowCheckbox = this.createCheckbox_(rows[i]); + td.appendChild(rowCheckbox); + } + rows[i].insertBefore(td, firstCell); + } + } + this.element_.classList.add(this.CssClasses_.IS_UPGRADED); + } + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialDataTable, + classAsString: 'MaterialDataTable', + cssClass: 'mdl-js-data-table' +}); +/** + * @license + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * Class constructor for Ripple MDL component. + * Implements MDL component design pattern defined at: + * https://github.com/jasonmayes/mdl-component-design-pattern + * + * @constructor + * @param {HTMLElement} element The element that will be upgraded. + */ +var MaterialRipple = function MaterialRipple(element) { + this.element_ = element; + // Initialize instance. + this.init(); +}; +window['MaterialRipple'] = MaterialRipple; +/** + * Store constants in one place so they can be updated easily. + * + * @enum {string | number} + * @private + */ +MaterialRipple.prototype.Constant_ = { + INITIAL_SCALE: 'scale(0.0001, 0.0001)', + INITIAL_SIZE: '1px', + INITIAL_OPACITY: '0.4', + FINAL_OPACITY: '0', + FINAL_SCALE: '' +}; +/** + * Store strings for class names defined by this component that are used in + * JavaScript. This allows us to simply change it in one place should we + * decide to modify at a later date. + * + * @enum {string} + * @private + */ +MaterialRipple.prototype.CssClasses_ = { + RIPPLE_CENTER: 'mdl-ripple--center', + RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', + RIPPLE: 'mdl-ripple', + IS_ANIMATING: 'is-animating', + IS_VISIBLE: 'is-visible' +}; +/** + * Handle mouse / finger down on element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRipple.prototype.downHandler_ = function (event) { + if (!this.rippleElement_.style.width && !this.rippleElement_.style.height) { + var rect = this.element_.getBoundingClientRect(); + this.boundHeight = rect.height; + this.boundWidth = rect.width; + this.rippleSize_ = Math.sqrt(rect.width * rect.width + rect.height * rect.height) * 2 + 2; + this.rippleElement_.style.width = this.rippleSize_ + 'px'; + this.rippleElement_.style.height = this.rippleSize_ + 'px'; + } + this.rippleElement_.classList.add(this.CssClasses_.IS_VISIBLE); + if (event.type === 'mousedown' && this.ignoringMouseDown_) { + this.ignoringMouseDown_ = false; + } else { + if (event.type === 'touchstart') { + this.ignoringMouseDown_ = true; + } + var frameCount = this.getFrameCount(); + if (frameCount > 0) { + return; + } + this.setFrameCount(1); + var bound = event.currentTarget.getBoundingClientRect(); + var x; + var y; + // Check if we are handling a keyboard click. + if (event.clientX === 0 && event.clientY === 0) { + x = Math.round(bound.width / 2); + y = Math.round(bound.height / 2); + } else { + var clientX = event.clientX ? event.clientX : event.touches[0].clientX; + var clientY = event.clientY ? event.clientY : event.touches[0].clientY; + x = Math.round(clientX - bound.left); + y = Math.round(clientY - bound.top); + } + this.setRippleXY(x, y); + this.setRippleStyles(true); + window.requestAnimationFrame(this.animFrameHandler.bind(this)); + } +}; +/** + * Handle mouse / finger up on element. + * + * @param {Event} event The event that fired. + * @private + */ +MaterialRipple.prototype.upHandler_ = function (event) { + // Don't fire for the artificial "mouseup" generated by a double-click. + if (event && event.detail !== 2) { + // Allow a repaint to occur before removing this class, so the animation + // shows for tap events, which seem to trigger a mouseup too soon after + // mousedown. + window.setTimeout(function () { + this.rippleElement_.classList.remove(this.CssClasses_.IS_VISIBLE); + }.bind(this), 0); + } +}; +/** + * Initialize element. + */ +MaterialRipple.prototype.init = function () { + if (this.element_) { + var recentering = this.element_.classList.contains(this.CssClasses_.RIPPLE_CENTER); + if (!this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT_IGNORE_EVENTS)) { + this.rippleElement_ = this.element_.querySelector('.' + this.CssClasses_.RIPPLE); + this.frameCount_ = 0; + this.rippleSize_ = 0; + this.x_ = 0; + this.y_ = 0; + // Touch start produces a compat mouse down event, which would cause a + // second ripples. To avoid that, we use this property to ignore the first + // mouse down after a touch start. + this.ignoringMouseDown_ = false; + this.boundDownHandler = this.downHandler_.bind(this); + this.element_.addEventListener('mousedown', this.boundDownHandler); + this.element_.addEventListener('touchstart', this.boundDownHandler); + this.boundUpHandler = this.upHandler_.bind(this); + this.element_.addEventListener('mouseup', this.boundUpHandler); + this.element_.addEventListener('mouseleave', this.boundUpHandler); + this.element_.addEventListener('touchend', this.boundUpHandler); + this.element_.addEventListener('blur', this.boundUpHandler); + /** + * Getter for frameCount_. + * @return {number} the frame count. + */ + this.getFrameCount = function () { + return this.frameCount_; + }; + /** + * Setter for frameCount_. + * @param {number} fC the frame count. + */ + this.setFrameCount = function (fC) { + this.frameCount_ = fC; + }; + /** + * Getter for rippleElement_. + * @return {Element} the ripple element. + */ + this.getRippleElement = function () { + return this.rippleElement_; + }; + /** + * Sets the ripple X and Y coordinates. + * @param {number} newX the new X coordinate + * @param {number} newY the new Y coordinate + */ + this.setRippleXY = function (newX, newY) { + this.x_ = newX; + this.y_ = newY; + }; + /** + * Sets the ripple styles. + * @param {boolean} start whether or not this is the start frame. + */ + this.setRippleStyles = function (start) { + if (this.rippleElement_ !== null) { + var transformString; + var scale; + var size; + var offset = 'translate(' + this.x_ + 'px, ' + this.y_ + 'px)'; + if (start) { + scale = this.Constant_.INITIAL_SCALE; + size = this.Constant_.INITIAL_SIZE; + } else { + scale = this.Constant_.FINAL_SCALE; + size = this.rippleSize_ + 'px'; + if (recentering) { + offset = 'translate(' + this.boundWidth / 2 + 'px, ' + this.boundHeight / 2 + 'px)'; + } + } + transformString = 'translate(-50%, -50%) ' + offset + scale; + this.rippleElement_.style.webkitTransform = transformString; + this.rippleElement_.style.msTransform = transformString; + this.rippleElement_.style.transform = transformString; + if (start) { + this.rippleElement_.classList.remove(this.CssClasses_.IS_ANIMATING); + } else { + this.rippleElement_.classList.add(this.CssClasses_.IS_ANIMATING); + } + } + }; + /** + * Handles an animation frame. + */ + this.animFrameHandler = function () { + if (this.frameCount_-- > 0) { + window.requestAnimationFrame(this.animFrameHandler.bind(this)); + } else { + this.setRippleStyles(false); + } + }; + } + } +}; +// The component registers itself. It can assume componentHandler is available +// in the global scope. +componentHandler.register({ + constructor: MaterialRipple, + classAsString: 'MaterialRipple', + cssClass: 'mdl-js-ripple-effect', + widget: false +}); +}()); \ No newline at end of file diff --git a/src/server/index.js b/src/server/index.js new file mode 100644 index 00000000..f05233ec --- /dev/null +++ b/src/server/index.js @@ -0,0 +1,10 @@ +import Express from "express"; +import path from "path"; + +const app = Express(); +const directory = "/public/"; +app.use(Express.static(path.join(__dirname, directory))); +const PORT = process.env.PORT || 3000; +app.get("*", (request, response) => { response.sendFile(path.resolve(__dirname, "public", "index.html")); }); + +app.listen(PORT); diff --git a/src/shared/actions/api.js b/src/shared/actions/api.js new file mode 100644 index 00000000..167dfa39 --- /dev/null +++ b/src/shared/actions/api.js @@ -0,0 +1,92 @@ +import { + API_ADMIN, API_CREATEBOT, API_SAVEBOT, API_IMPORT, API_PUBLISH, + API_GETINTENTS, API_SENDINTENT, API_DELETEINTENT, API_MOVEINTENT, + API_SETADMINPARAMETERS, + API_GETMIDDLEWARES, API_SETMIDDLEWARE, API_DELETEMIDDLEWARE, + API_SB_GETMESSAGES, API_SB_SENDMESSAGE, API_SB_GETCONTEXT, API_SB_RESET, + FETCH_REQUEST, SUBSCRIBE, UNSUBSCRIBE, +} from "./constants"; + +export function apiAdminRequest() { + return { type: API_ADMIN + FETCH_REQUEST }; +} + +export function apiSetAdminParametersRequest(params) { + return { type: API_SETADMINPARAMETERS + FETCH_REQUEST, params }; +} + +export function apiCreateBot(botParams) { + return { type: API_CREATEBOT + FETCH_REQUEST, botParams }; +} + +export function apiSaveBotRequest(botParams) { + return { type: API_SAVEBOT + FETCH_REQUEST, botParams }; +} + +export function apiImportRequest(botId, data, options) { + return { + type: API_IMPORT + FETCH_REQUEST, botId, data, options, + }; +} + +export function apiPublishRequest(botId, channels, to = null, from = null) { + return { + type: API_PUBLISH + FETCH_REQUEST, botId, channels, to, from, + }; +} + +export function apiGetIntentsRequest(botId) { + return { type: API_GETINTENTS + FETCH_REQUEST, botId }; +} + +export function apiSendIntentRequest(botId, intent) { + return { type: API_SENDINTENT + FETCH_REQUEST, botId, intent }; +} + +export function apiDeleteIntentRequest(botId, intent) { + return { type: API_DELETEINTENT + FETCH_REQUEST, botId, intent }; +} + +export function apiMoveIntentRequest(botId, intentId, from, to) { + return { + type: API_MOVEINTENT + FETCH_REQUEST, botId, intentId, from, to, + }; +} + +export function apiGetSandboxMessagesRequest(botId) { + return { type: API_SB_GETMESSAGES + FETCH_REQUEST, botId }; +} + +export function apiSubscribeSandboxMessages(botId) { + return { type: API_SB_GETMESSAGES + SUBSCRIBE, botId }; +} + +export function apiUnsubscribeSandboxMessages(botId) { + return { type: API_SB_GETMESSAGES + UNSUBSCRIBE, botId }; +} + +export function apiSendSandboxMessageRequest(botId, conversationId, message) { + return { + type: API_SB_SENDMESSAGE + FETCH_REQUEST, botId, conversationId, message, + }; +} + +export function apiGetSandboxContextRequest(botId) { + return { type: API_SB_GETCONTEXT + FETCH_REQUEST, botId }; +} + +export function apiSandboxResetRequest(botId) { + return { type: API_SB_RESET + FETCH_REQUEST, botId }; +} + +export function apiGetMiddlewaresRequest(botId, middlewareType = null) { + return { type: API_GETMIDDLEWARES + FETCH_REQUEST, botId, middlewareType }; +} + +export function apiSetMiddlewareRequest(botId, middleware) { + return { type: API_SETMIDDLEWARE + FETCH_REQUEST, botId, middleware }; +} + +export function apiDeleteMiddlewareRequest(botId, middlewareId) { + return { type: API_DELETEMIDDLEWARE + FETCH_REQUEST, botId, middlewareId }; +} diff --git a/src/shared/actions/app.js b/src/shared/actions/app.js new file mode 100644 index 00000000..3af98390 --- /dev/null +++ b/src/shared/actions/app.js @@ -0,0 +1,30 @@ +import { + APP_SETTITLE, APP_SELECTINTENT, APP_UPDATEPUBLISHER, + APP_UPDATEINTENT, APP_SETINTENTACTION, APP_DELETEINTENTACTION, +} from "./constants"; + +export function appSelectIntent(selectedBotId, selectedIntentIndex) { + return { type: APP_SELECTINTENT, selectedBotId, selectedIntentIndex }; +} + +export function appSetTitle(titleName) { + return { type: APP_SETTITLE, titleName }; +} + +export function appUpdatePublisher(selectedBotId, publisher) { + return { type: APP_UPDATEPUBLISHER, selectedBotId, publisher }; +} + +export function appUpdateIntent(selectedBotId, intent) { + return { type: APP_UPDATEINTENT, selectedBotId, intent }; +} + +export function appSetIntentAction(actionContainer, actionType, actionValue, selectedAction) { + return { + type: APP_SETINTENTACTION, actionContainer, actionType, actionValue, selectedAction, + }; +} + +export function appDeleteIntentAction(actionContainer, selectedAction) { + return { type: APP_DELETEINTENTACTION, actionContainer, selectedAction }; +} diff --git a/src/shared/actions/authenticate.js b/src/shared/actions/authenticate.js new file mode 100644 index 00000000..7e903ca3 --- /dev/null +++ b/src/shared/actions/authenticate.js @@ -0,0 +1,15 @@ +export const AUTHENTICATE_START = "AUTHENTICATE_START"; +export const AUTHENTICATE_COMPLETE = "AUTHENTICATE_COMPLETE"; +export const AUTHENTICATE_ERROR = "AUTHENTICATE_ERROR"; + +export function authenticateStart() { + return { type: AUTHENTICATE_START }; +} + +export function authenticateComplete(user) { + return { type: AUTHENTICATE_COMPLETE, user }; +} + +export function authenticateError(errors) { + return { type: AUTHENTICATE_ERROR, errors }; +} diff --git a/src/shared/actions/constants.js b/src/shared/actions/constants.js new file mode 100644 index 00000000..4edf20df --- /dev/null +++ b/src/shared/actions/constants.js @@ -0,0 +1,59 @@ +export const AUTH_INIT_SETTINGS = "AUTH_INIT_SETTINGS"; + +// un/subscribing actions suffix +export const SUBSCRIBE = "_SUBSCRIBE"; +export const UNSUBSCRIBE = "_UNSUBSCRIBE"; + +// Fetching actions suffix +export const FETCH_REQUEST = "_REQUEST"; +export const FETCH_SUCCESS = "_SUCCESS"; +export const FETCH_FAILURE = "_FAILURE"; + +// Sign In constants +export const AUTH_SIGNIN = "AUTH_SIGNIN"; + +// Sign Out constants +export const AUTH_SIGNOUT = "AUTH_SIGNOUT"; + +// API User constants +export const API_USERPROFILE = "API_USERPROFILE"; +export const API_SAVEUSERPROFILE = "API_SAVEUSERPROFILE"; + +// API admin constants +export const API_ADMIN = "API_ADMIN"; +export const API_SETADMINPARAMETERS = "API_SETADMINPARAMETERS"; + +export const API_CREATEBOT = "API_CREATEBOT"; +export const API_SAVEBOT = "API_SAVEBOT"; +export const API_IMPORT = "API_IMPORT"; +export const API_PUBLISH = "API_PUBLISH"; + +export const API_GETINTENTS = "API_GETINTENTS"; +export const API_SENDINTENT = "API_SENDINTENT"; +export const API_DELETEINTENT = "API_DELETEINTENT"; +export const API_MOVEINTENT = "API_MOVEINTENT"; + +// API middlewares constants +export const API_GETMIDDLEWARES = "API_GETMIDDLEWARES"; +export const API_SETMIDDLEWARE = "API_SETMIDDLEWARE"; +export const API_DELETEMIDDLEWARE = "API_DELETEMIDDLEWARE"; + +// API webhooks constants +/* +export const API_GETWEBHOOKS = "API_GETWEBHOOKS"; +export const API_SETWEBHOOK = "API_SETWEBHOOK"; +export const API_DELETEWEBHOOK = "API_DELETEWEBHOOK"; */ + +// API sandbox constants +export const API_SB_GETMESSAGES = "API_SB_GETMESSAGES"; +export const API_SB_SENDMESSAGE = "API_SB_SENDMESSAGE"; +export const API_SB_GETCONTEXT = "API_SB_GETCONTEXT"; +export const API_SB_RESET = "API_SB_RESET"; + +// App logic constants +export const APP_SETTITLE = "APP_SETTITLE"; +export const APP_UPDATEPUBLISHER = "APP_UPDATEPUBLISHER"; +export const APP_SELECTINTENT = "APP_SELECTINTENT"; +export const APP_UPDATEINTENT = "APP_UPDATEINTENT"; +export const APP_SETINTENTACTION = "APP_SETINTENTACTION"; +export const APP_DELETEINTENTACTION = "APP_DELETEINTENTACTION"; diff --git a/src/shared/actions/initialize.js b/src/shared/actions/initialize.js new file mode 100644 index 00000000..2455dbf3 --- /dev/null +++ b/src/shared/actions/initialize.js @@ -0,0 +1,10 @@ +import { AUTH_INIT_SETTINGS } from "./constants"; + +export function initAuthSettings(config) { + return { type: AUTH_INIT_SETTINGS, config }; +} + +export function resetSettings(config) { + // TODO + return { type: AUTH_INIT_SETTINGS, config }; +} diff --git a/src/shared/actions/signIn.js b/src/shared/actions/signIn.js new file mode 100644 index 00000000..642d13c4 --- /dev/null +++ b/src/shared/actions/signIn.js @@ -0,0 +1,18 @@ +/** + * OAuth SignIn Action + */ +import { AUTH_SIGNIN, FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE } from "./constants"; + +export function signIn({ provider, username, password }) { + return { + type: AUTH_SIGNIN + FETCH_REQUEST, provider, username, password, + }; +} + +export function signInComplete({ user, provider }) { + return { type: AUTH_SIGNIN + FETCH_SUCCESS, user, provider }; +} + +export function signInError({ provider, error }) { + return { type: AUTH_SIGNIN + FETCH_FAILURE, provider, error }; +} diff --git a/src/shared/actions/signOut.js b/src/shared/actions/signOut.js new file mode 100644 index 00000000..d5b2da0c --- /dev/null +++ b/src/shared/actions/signOut.js @@ -0,0 +1,14 @@ + +import { AUTH_SIGNOUT, FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE } from "./constants"; + +export function signOutComplete({ provider }) { + return { type: AUTH_SIGNOUT + FETCH_SUCCESS, provider }; +} + +export function signOutError({ provider, error }) { + return { type: AUTH_SIGNOUT + FETCH_FAILURE, provider, error }; +} + +export function signOut({ provider }) { + return { type: AUTH_SIGNOUT + FETCH_REQUEST, provider }; +} diff --git a/src/shared/actions/user.js b/src/shared/actions/user.js new file mode 100644 index 00000000..4cbd6d4b --- /dev/null +++ b/src/shared/actions/user.js @@ -0,0 +1,12 @@ +import { + API_USERPROFILE, + FETCH_REQUEST, +} from "./constants"; + +export function apiUserProfileRequest() { + return { type: API_USERPROFILE + FETCH_REQUEST }; +} + +export function apiSaveUserProfileRequest() { + return { type: API_USERPROFILE + FETCH_REQUEST }; +} diff --git a/src/shared/components/IconExButton.jsx b/src/shared/components/IconExButton.jsx new file mode 100644 index 00000000..ae01f822 --- /dev/null +++ b/src/shared/components/IconExButton.jsx @@ -0,0 +1,22 @@ +import React from "react"; +import PropTypes from "prop-types"; + +const IconExButton = ({ name }) => { + if (name === "robot") { + return ( +
+ + + +
); + } else if (name === "opla") { + return (
opla
); + } + return ({name}); +}; + +IconExButton.propTypes = { + name: PropTypes.string.isRequired, +}; + +export default IconExButton; diff --git a/src/shared/components/actionEditor.jsx b/src/shared/components/actionEditor.jsx new file mode 100644 index 00000000..3f598985 --- /dev/null +++ b/src/shared/components/actionEditor.jsx @@ -0,0 +1,373 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { IconButton, Tooltip } from "react-mdl"; +import { ContentEditable } from "zoapp-ui"; +import ActionsTools from "../utils/actionsTools"; + +class ActionEditor extends Component { + static buildFromHtml(children) { + // WIP convert back html to action syntax + let actionText = ""; + // TODO append empty text span if first element is not a text + children.forEach((child, index) => { + const text = child.textContent; + const type = child.getAttribute("data"); + const t = text; // .trim(); + if (type === "any") { + actionText += "*"; + } else if (type === "output_var") { + // TODO check if t is empty and delete child + actionText += `{{${t}}}`; + } else if (type === "variable") { + // TODO check if t is empty and delete child + actionText += `<<${t}>>`; + } else if (type === "br") { + actionText += "
"; + } else if (type === "button") { + actionText += ``; + } else if (type === "text") { + if (index > 0 || t.length > 0) { + actionText += text; + } + } + }); + return actionText; // .trim(); + } + + static renderAction(items) { + const styleAny = "color: black; background-color: #fcea20;"; + const styleOut = "color: white; background-color: #23b4bb;"; + const styleVar = "color: white; background-color: #552682;"; + const styleHtml = "color: white; background-color: #aaa;"; + const styleText = "height: 32px; display: inline-block; margin: 2px 0px; padding: 0px 4px;"; + let html = ""; + let lastIsText = false; + let i = 1; + if (items.length < 1 || (items[0] && items[0].type !== "text")) { + html += ` `; + lastIsText = true; + i += 1; + } + items.forEach((item, index) => { + html += `any`; + lastIsText = false; + } else if (item.type === "output_var") { + // TODO add button to delete chip + html += `data="${item.type}" class="mdl-chip" style="${styleOut}" contentEditable=true>${item.text}`; + lastIsText = false; + } else if (item.type === "variable") { + // TODO add button to delete chip + html += `data="${item.type}" class="mdl-chip" style="${styleVar}" contentEditable=true>${item.text}`; + lastIsText = false; + } else if (item.type === "br") { + // TODO add button to delete chip + html += `data="${item.type}" class="mdl-chip" style="${styleHtml}" contentEditable=false>keyboard_return
`; + lastIsText = false; + } else if (item.type === "button") { + // TODO add button to delete chip + html += `data="${item.type}" class="mdl-chip" style="${styleHtml}" contentEditable=true>${item.text}`; + lastIsText = false; + } else { + html += `data="text" style="${styleText}" contentEditable=true>${item.text}`; + lastIsText = true; + } + i += 1; + }); + if (!lastIsText) { + html += ` `; + } + return html; + } + + static build(items) { + // WIP convert back html to action syntax + let actionText = ""; + // TODO append empty text span if first element is not a text + items.forEach((child, index) => { + const { text, type } = child; + const t = text; // .trim(); + if (type === "any") { + actionText += "*"; + } else if (type === "output_var") { + // TODO check if t is empty and delete child + actionText += `{{${t}}}`; + } else if (type === "variable") { + // TODO check if t is empty and delete child + actionText += `<<${t}>>`; + } else if (type === "br") { + actionText += "
"; + } else if (type === "button") { + actionText += ``; + } else if (type === "text") { + if (index > 0 || t.length > 0) { + actionText += text; + } + } + }); + return actionText; // .trim(); + } + + constructor(props) { + super(props); + const toolbox = { + text: true, + any: false, + entity: false, + code: false, + linebreak: false, + button: false, + trash: true, + }; + const { content } = this.props; + const items = ActionsTools.parse(content); + const selectedItem = items.length - 1; + const caretPosition = 0; + this.state = { + toolbox, content, items, selectedItem, caretPosition, + }; + } + + onFocusIn = (element, caretPosition) => { + const type = element.getAttribute("data"); + const key = element.getAttribute("key"); + console.log("onFocusIn", element.tabIndex, key, type, caretPosition); + if (type === "any") { + this.anySelect(); + } else if (type === "variable") { + this.codeSelect(); + } else if (type === "output_var") { + this.entitySelect(); + } else if (type === "br") { + this.lineBreakSelect(); + } else if (type === "button") { + this.buttonSelect(); + } else { + this.textSelect(); + } + const selectedItem = parseInt(key, 10); + if (this.state.selectedItem !== selectedItem) { + this.setState(() => ({ selectedItem })); + } + } + + onTextSelected() { + this.textSelect(); + this.insertItem(this.state.selectedItem + 1, { type: "text", text: "text" }); + } + + onAnySelected() { + this.anySelect(); + this.insertItem(this.state.selectedItem + 1, { type: "any", text: "" }); + } + + onEntitySelected() { + this.entitySelect(); + this.insertItem(this.state.selectedItem + 1, { type: "output_var", text: "entityname" }); + } + + onCodeSelected() { + this.codeSelect(); + this.insertItem(this.state.selectedItem + 1, { type: "variable", text: "entityname=value" }); + } + + onLineBreakSelected() { + this.lineBreakSelect(); + this.insertItem(this.state.selectedItem + 1, { type: "br", text: "" }); + } + + onButtonSelected() { + this.buttonSelect(); + this.insertItem(this.state.selectedItem + 1, { type: "button", text: "value" }); + } + + onTrashSelected() { + this.deleteItem(this.state.selectedItem); + } + + getContent() { + return this.state.content; + } + + insertItem(position, item) { + const { items } = this.state; + if (position < items.length) { + items.splice(position, 0, item); + } else { + items.push(item); + } + const selectedItem = position; + const content = ActionEditor.build(items); + this.setState(() => ({ content, items, selectedItem })); + } + + deleteItem(position) { + const { items } = this.state; + if (position < items.length) { + delete items[position]; + let selectedItem = position - 1; + if (selectedItem < 0) { + selectedItem = 0; + } + const content = ActionEditor.build(items); + this.setState(() => ({ content, items, selectedItem })); + } + } + + handleChange = (text, element) => { + const content = ActionEditor.buildFromHtml([...element.children]); + this.props.onChange(content); + const items = ActionsTools.parse(content); + this.setState(() => ({ content, items })); + } + + textSelect() { + const toolbox = { + text: true, + any: false, + entity: false, + code: false, + linebreak: false, + button: false, + trash: true, + }; + this.setState(() => ({ toolbox })); + } + + anySelect() { + const toolbox = { + text: false, + any: true, + entity: false, + code: false, + linebreak: false, + button: false, + trash: false, + }; + this.setState(() => ({ toolbox })); + } + + entitySelect() { + const toolbox = { + text: false, + any: false, + entity: true, + code: false, + linebreak: false, + button: false, + trash: false, + }; + this.setState(() => ({ toolbox })); + } + + codeSelect() { + const toolbox = { + text: false, + any: false, + entity: false, + code: true, + linebreak: false, + button: false, + trash: false, + }; + this.setState(() => ({ toolbox })); + } + + lineBreakSelect() { + const toolbox = { + text: false, + any: false, + entity: false, + code: false, + linebreak: true, + button: false, + trash: false, + }; + this.setState(() => ({ toolbox })); + } + + buttonSelect() { + const toolbox = { + text: false, + any: false, + entity: false, + code: false, + linebreak: false, + button: true, + trash: false, + }; + this.setState(() => ({ toolbox })); + } + + render() { + const content = ActionEditor.renderAction(this.state.items, this.state.selectedItem); + const style = { + overflow: "hidden", fontSize: "16px", letterSpacing: "0.04em", lineHeight: "1", color: "#757575", margin: "16px", + }; + const styleToolbox = { + width: "100%", backgroundColor: "#eee", marginBottom: "16px", display: "table", + }; + const styleToolbar = { borderRight: "1px solid #ddd", display: "table-cell" }; + const { toolbox } = this.state; + let extra = ""; + if (!this.props.isInput) { + extra = ( + + + { this.onCodeSelected(e); }} name="code" /> + + + { this.onLineBreakSelected(e); }} name="keyboard_return" /> + + + { this.onButtonSelected(e); }} name="insert_link" /> + + ); + } + return ( +
+
+
+ + { this.onTextSelected(e); }} name="text_fields" /> + + + { this.onAnySelected(e); }} name="all_out" /> + + + { this.onEntitySelected(e); }} name="assignment" /> + + {extra} +
+
+ + { this.onTrashSelected(e); }} name="delete" /> + +
+
+ +
); + } +} + +ActionEditor.defaultProps = { + content: "", + onChange: () => { }, + isInput: false, +}; + +ActionEditor.propTypes = { + content: PropTypes.string, + onChange: PropTypes.func, + isInput: PropTypes.bool, +}; + +export default ActionEditor; diff --git a/src/shared/components/actionsList.jsx b/src/shared/components/actionsList.jsx new file mode 100644 index 00000000..2f11f828 --- /dev/null +++ b/src/shared/components/actionsList.jsx @@ -0,0 +1,177 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { List, ListItem, ListItemContent, ListItemAction, IconButton, Chip } from "react-mdl"; +import { ExpansionPanel } from "zoapp-ui"; +/* import { DragDropContext } from "react-dnd"; +import HTML5Backend from "react-dnd-html5-backend"; +import ListDragItem from "./listDragItem"; */ +import ActionsTools from "../utils/actionsTools"; + +// @DragDropContext(HTML5Backend) +class ActionsList extends Component { + static renderActions(actionText) { + const actions = ActionsTools.parse(actionText); + const styleText = { + lineHeight: "32px", + height: "32px", + display: "inline-block", + margin: "2px 0", + padding: "0 4px", + }; + const styleVar = { + color: "white", + backgroundColor: "#552682", + }; + const styleOut = { + color: "white", + backgroundColor: "#23b4bb", + }; + const styleAny = { + color: "black", + backgroundColor: "#fcea20", + }; + const styleHtml = { + color: "white", + backgroundColor: "#aaa", + }; + return ( + {actions.map((actionItem, index) => { + const id = `al_${index}`; + if (actionItem.type === "any") { + return (any); + } else if (actionItem.type === "output_var") { + return ({actionItem.text}); + } else if (actionItem.type === "variable") { + return ({actionItem.text}); + } else if (actionItem.type === "br") { + return (); + } else if (actionItem.type === "button") { + return ({actionItem.text}); + } + return ({actionItem.text}); + })} + ); + } + + render() { + const { + name, actions, onSelect, onDrop, + } = this.props; + let content; + // let addDisabled; + let type = null; + if (name === "output" && ((!actions) || actions.length === 0 || actions[0].type === "condition")) { + type = "condition"; + } + const icon = name === "input" ? "format_quote" : "chat_bubble_outline"; + const style = { padding: "0px 16px" }; + const addText = name === "input" ? "Add an input sentence" : "Add an output response"; + const color = (!actions) || actions.length === 0 ? "rgb(213, 0, 0)" : "rgb(221, 221, 221)"; + const addContent = ( { e.preventDefault(); if (onSelect) { onSelect({ name, type, state: "add" }); } }}> + + {addText} + ); + if (actions && actions.length > 0) { + if (actions[0].type === "condition") { + const { children } = actions[0]; + type = "condition"; + // WIP display condition list + content = ( + { + children.map((action, index) => { + const text = ActionsList.renderActions(action.text); + let condition = action.name && action.name.length > 0 ? `${action.name} = ` : ""; + if (condition.length > 0) { + condition += `${action.value && action.value.length > 0 ? action.value : "undefined"} ?`; + } + if (condition.length === 0) { + condition = "default"; + } + const key = `cd_${index}`; + return ( + { + e.preventDefault(); if (onSelect) { + onSelect({ + name, type: "condition", state: "select", index, + }); + } + }} + > + {condition} + + { + e.preventDefault(); if (onSelect) { + onSelect({ + name, type: "condition", state: "delete", index, + }); + } + }} + /> + + + ); + }) + }{addContent} + ); + } else { + content = ( + { + actions.map((action, index) => { + const text = ActionsList.renderActions(action); + const key = `cd_${index}`; + return ( + { e.preventDefault(); if (onSelect) { onSelect({ name, state: "select", index }); } }} + > + {text} + + { e.preventDefault(); if (onSelect) { onSelect({ name, state: "delete", index }); } }} + /> + + + ); + }) + }{addContent} + ); + } + // addDisabled = false; + } else { + content = ({addContent}); + // addDisabled = true; + } + return ( + + {content} + + ); + } +} + +ActionsList.defaultProps = { + actions: [], + onSelect: null, + onDrop: null, +}; + +ActionsList.propTypes = { + name: PropTypes.string.isRequired, + actions: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({})])), + onSelect: PropTypes.func, + onDrop: PropTypes.func, +}; + +export default ActionsList; diff --git a/src/shared/components/donutChart.jsx b/src/shared/components/donutChart.jsx new file mode 100644 index 00000000..38bfc26d --- /dev/null +++ b/src/shared/components/donutChart.jsx @@ -0,0 +1,99 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Doughnut } from "react-chartjs-2"; + +const data = [{ + labels: [ + "Web", + "Facebook", + "Slack", + ], + datasets: [{ + data: [300, 50, 100], + backgroundColor: [ + "#FF6384", + "#36A2EB", + "#FFCE56", + ], + hoverBackgroundColor: [ + "#FF6384", + "#36A2EB", + "#FFCE56", + ], + }], +}, +{ + labels: [ + "Fr", + "Us", + ], + datasets: [{ + data: [50, 150], + backgroundColor: [ + "#FF6384", + "#36A2EB", + ], + hoverBackgroundColor: [ + "#FF6384", + "#36A2EB", + ], + }], +}, +{ + labels: [ + "French", + ], + datasets: [{ + data: [300], + backgroundColor: [ + "#FFCE56", + ], + hoverBackgroundColor: [ + "#FFCE56", + ], + }], +}, +{ + labels: [ + "18-24", + ], + datasets: [{ + data: [100], + backgroundColor: [ + "#FF6384", + ], + hoverBackgroundColor: [ + "#FF6384", + ], + }], +}, +]; + +const options = { + legend: { + display: false, + }, +}; + +const infoStyle = { + textAlign: "center", + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "20px 0", + lineHeight: "1.1", +}; + +const DonutChart = ({ title, dataset }) => ( +
+ +
{title}
+
+); + +DonutChart.propTypes = { + title: PropTypes.string.isRequired, + dataset: PropTypes.number.isRequired, +}; + +export default DonutChart; diff --git a/src/shared/components/fileInput.jsx b/src/shared/components/fileInput.jsx new file mode 100644 index 00000000..b1c251c2 --- /dev/null +++ b/src/shared/components/fileInput.jsx @@ -0,0 +1,35 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; + +export default class FileInput extends Component { + handleFileChange = (selectorFiles) => { + const file = selectorFiles[0]; + console.log("handleFileChange file=", file); + const reader = new FileReader(); + reader.onload = (e) => { + const data = e.target.result; + if (this.props.onLoad) { + this.props.onLoad(data, file.type); + } + }; + reader.readAsText(file); + } + + render() { + const { accept } = this.props; + return ( +
+ cloud_upload + this.handleFileChange(e.target.files)} /> +
); + } +} +FileInput.defaultProps = { + onLoad: null, + accept: null, +}; + +FileInput.propTypes = { + onLoad: PropTypes.func, + accept: PropTypes.string, +}; diff --git a/src/shared/components/headerIcon.jsx b/src/shared/components/headerIcon.jsx new file mode 100644 index 00000000..9d588285 --- /dev/null +++ b/src/shared/components/headerIcon.jsx @@ -0,0 +1,27 @@ +import React from "react"; +import PropTypes from "prop-types"; + +const HeaderIcon = ({ name }) => { + if (name === "robot") { + return ( +
+ + + +
); + } else if (name === "opla") { + return ( +
+ + + +
); + } + return ({name}); +}; + +HeaderIcon.propTypes = { + name: PropTypes.string.isRequired, +}; + +export default HeaderIcon; diff --git a/src/shared/components/intentDetail.jsx b/src/shared/components/intentDetail.jsx new file mode 100644 index 00000000..e280fbd5 --- /dev/null +++ b/src/shared/components/intentDetail.jsx @@ -0,0 +1,124 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { List, ListItem, ListItemContent, ListItemAction, Textfield, Button } from "react-mdl"; +import { ExpansionPanel, DialogManager } from "zoapp-ui"; +import ActionsList from "../components/actionsList"; +import ActionEditor from "../components/actionEditor"; + +const IntentDetail = ({ intent, onSelect }) => { + const { name, input, output } = intent; + const topic = intent.topic && intent.topic.length > 0 ? intent.topic : "*"; + return ( +
+
+ +
+ +
+ + + + Topic + + + + + + Previous + + + + + + +
+
+ ); +}; + +IntentDetail.propTypes = { + intent: PropTypes.shape({}).isRequired, + onSelect: PropTypes.func.isRequired, +}; + +export default IntentDetail; + +export const displayActionEditor = ( + title, + type, + action, + actionDef, + parameters, + setInput, + onEditAction, + onChange, + isInput, +) => { + let condition = ""; + let text = parameters; + let content = null; + if (actionDef === "Topic" || actionDef === "Previous") { + content = ( +
+ setInput(input)} + /> +
); + } else { + if (type === "condition") { + text = parameters.text ? parameters.text : ""; + const name = parameters.name ? parameters.name : ""; + const value = parameters.value ? parameters.value : ""; + condition = ( +
+ setInput(input, "fieldParamName")} + /> +
=
+ setInput(input, "fieldParamValue")} + /> +
); + } + content = ( +
{condition} + setInput(input)} + /> +
); + } + + + DialogManager.open({ + title, content, actions: [action, "Cancel"], actionsDef: [actionDef, "Cancel"], onAction: onEditAction, width: "720px", + }); +}; diff --git a/src/shared/components/listComponent.jsx b/src/shared/components/listComponent.jsx new file mode 100644 index 00000000..5bcb5114 --- /dev/null +++ b/src/shared/components/listComponent.jsx @@ -0,0 +1,59 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { List, ListItem, ListItemContent, Icon } from "react-mdl"; + +const ListComponent = ({ + items, selectedItem, onSelect, className, style, +}) => ( + + {items.map((item, index) => { + let icon = null; + let content = item.name; + if (item.icon) { + let { color } = item; + if (!color) { + color = "gray"; + } + const st = { + backgroundColor: color, + padding: "8px", + }; + if (item.icon.endsWith(".svg")) { + icon = ( +
+ {item.name} +
); + } else if (item.icon.endsWith(".png")) { + icon = ( +
+ {item.name} +
); + } else { + icon =
; + } + content = {content}; + } + let cn = "selectableListItem"; + if (selectedItem === index) { + cn = "selectedListItem"; + } + return ( + { e.preventDefault(); onSelect(index); }} + className={cn} + >{content} + ); + })} +
+); + +ListComponent.propTypes = { + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + selectedItem: PropTypes.number.isRequired, + onSelect: PropTypes.func.isRequired, + className: PropTypes.string.isRequired, + style: PropTypes.objectOf(PropTypes.string).isRequired, +}; + +export default ListComponent; diff --git a/src/shared/components/listDragComponent.jsx b/src/shared/components/listDragComponent.jsx new file mode 100644 index 00000000..456ac150 --- /dev/null +++ b/src/shared/components/listDragComponent.jsx @@ -0,0 +1,64 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { List } from "react-mdl"; +import { DragDropContext } from "react-dnd"; +import HTML5Backend from "react-dnd-html5-backend"; +import ListDragItem from "./listDragItem"; + +@DragDropContext(HTML5Backend) +class ListDragComponent extends Component { + render() { + const { + items, selectedItem, onSelect, onMove, onDrop, className, + } = this.props; + return ( + + {items.map((item, index) => { + if (selectedItem === index) { + return ( + { e.preventDefault(); onSelect(index); }} + className="selectedListItem" + >{item.name} + ); + } + return ( + { e.preventDefault(); onSelect(index); }} + className="selectableListItem" + >{item.name} + ); + })} + + ); + } +} + +ListDragComponent.defaultProps = { + className: null, + onMove: null, + onDrop: null, +}; + +ListDragComponent.propTypes = { + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + selectedItem: PropTypes.number.isRequired, + onSelect: PropTypes.func.isRequired, + className: PropTypes.string, + onMove: PropTypes.func, + onDrop: PropTypes.func, +}; + +export default ListDragComponent; diff --git a/src/shared/components/listDragItem.jsx b/src/shared/components/listDragItem.jsx new file mode 100644 index 00000000..5937b701 --- /dev/null +++ b/src/shared/components/listDragItem.jsx @@ -0,0 +1,141 @@ +import React, { Component, Children, cloneElement } from "react"; +import PropTypes from "prop-types"; +import { DragSource, DropTarget } from "react-dnd"; +import { ListItemContent } from "react-mdl"; + +const itemSource = { + beginDrag(props) { + return { + id: props.id, + index: props.index, + }; + }, +}; + +const itemTarget = { + drop(props, monitor) { + const dragIndex = monitor.getItem().index; + const dropIndex = props.index; + console.log("WIP", `ListDragItem.drop ${dragIndex} / ${dropIndex}`); + if (dragIndex !== dropIndex && props.onDrop) { + props.onDrop(dragIndex, dropIndex); + } + }, + hover(props, monitor, component) { + const item = monitor.getItem(); + const dragIndex = item.index; + const hoverIndex = props.index; + + // Don't replace items with themselves + if (dragIndex === hoverIndex || (!component) || (!component.ref)) { + return; + } + + // Determine rectangle on screen + const hoverBoundingRect = component.ref.getBoundingClientRect(); + + // Get vertical middle + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + + // Determine mouse position + const clientOffset = monitor.getClientOffset(); + + // Get pixels to the top + const hoverClientY = clientOffset.y - hoverBoundingRect.top; + + // Only perform the move when the mouse has crossed half of the items height + // When dragging downwards, only move when the cursor is below 50% + // When dragging upwards, only move when the cursor is above 50% + + // Dragging downwards + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + + // Dragging upwards + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + + // Time to actually perform the action + if (props.onMove) { + if (props.onMove(dragIndex, hoverIndex)) { + // Note: we're mutating the monitor item here! + // Generally it's better to avoid mutations, + // but it's good here for the sake of performance + // to avoid expensive index searches. + item.index = hoverIndex; + } + } + }, +}; + +@DropTarget("item", itemTarget, connect => ({ + connectDropTarget: connect.dropTarget(), +})) +@DragSource("item", itemSource, (connect, monitor) => ({ + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging(), +})) +export default class ListDragItem extends Component { + static defaultProps = { + children: null, + className: null, + twoLine: false, + threeLine: false, + onMove: null, + onDrop: null, + }; + + static propTypes = { + children: PropTypes.node, + className: PropTypes.string, + twoLine: PropTypes.bool, + threeLine: PropTypes.bool, + connectDragSource: PropTypes.func.isRequired, + connectDropTarget: PropTypes.func.isRequired, + index: PropTypes.number.isRequired, + isDragging: PropTypes.bool.isRequired, + id: PropTypes.string.isRequired, + onMove: PropTypes.func, + onDrop: PropTypes.func, + }; + + render() { + const { + connectDragSource, connectDropTarget, className, twoLine, threeLine, ...otherProps + } = this.props; + delete otherProps.index; + delete otherProps.onMove; + delete otherProps.onDrop; + delete otherProps.isDragging; + + /* const opacity = isDragging ? 0 : 1; */ + + let classes = "mdl-list__item"; + if (twoLine && !threeLine) { + classes += " mdl-list__item--two-line"; + } else if (!twoLine && threeLine) { + classes += " mdl-list__item--two-line"; + } + if (className) { + classes += ` ${className}`; + } + + const children = Children.map(otherProps.children, (child) => { + if (typeof child === "string") { + return {child}; + } + if (child.type === ListItemContent) { + return cloneElement(child, { + useBodyClass: !!threeLine, + }); + } + return child; + }); + return connectDragSource(connectDropTarget(( +
  • { this.ref = r; }}> + {children} +
  • ))); + } +} diff --git a/src/shared/components/loading.jsx b/src/shared/components/loading.jsx new file mode 100644 index 00000000..2948408d --- /dev/null +++ b/src/shared/components/loading.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import { Card, CardTitle, CardText, CardActions } from "react-mdl"; + +const Loading = () => ( + + Processing + + Please wait ... + + + ); + +Loading.propTypes = { +}; + +export default Loading; diff --git a/src/shared/components/messagingsList.jsx b/src/shared/components/messagingsList.jsx new file mode 100644 index 00000000..e8931dfb --- /dev/null +++ b/src/shared/components/messagingsList.jsx @@ -0,0 +1,84 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { List, ListItem, ListItemContent, ListItemAction, Icon, Switch } from "react-mdl"; + +const MessagingsList = (props) => { + const { + name, items, onSelect, + } = props; + + return ( +
    +
    +

    {name}

    +
    + { + items.map((item, index) => { + let icon = null; + if (item.icon) { + let { color } = item; + if (!item.enabled) { + color = "#ddd"; + } else if (!color) { + color = "gray"; + } + const style = { + backgroundColor: color, + color: "white", + padding: "8px", + }; + if (item.icon.endsWith(".svg")) { + icon = ( +
    + {item.name} +
    ); + } else { + icon =
    ; + } + } + const key = `li_${index}`; + return ( + { + console.log("e.target", e.target.className); + if (onSelect && (e.target.className.indexOf("mdl-switch") < 0)) { + e.preventDefault(); onSelect({ + name, state: "select", index, item, + }); + } + }} + > + {item.name} + + + { + e.preventDefault(); if (onSelect) { + onSelect({ + name, state: "enable", index, item, + }); + } + }} + /> + + + ); + }) + } +
    +
    + ); +}; + + +MessagingsList.propTypes = { + name: PropTypes.string.isRequired, + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + onSelect: PropTypes.func.isRequired, +}; + +export default MessagingsList; diff --git a/src/shared/components/messengerBox.jsx b/src/shared/components/messengerBox.jsx new file mode 100644 index 00000000..1df3fcb9 --- /dev/null +++ b/src/shared/components/messengerBox.jsx @@ -0,0 +1,175 @@ +import React, { Component } from "react"; +import { Textfield, IconButton, Button } from "react-mdl"; +import PropTypes from "prop-types"; + +class MessengerBox extends Component { + static createMessage(message) { + return { __html: message.body }; + } + + componentWillUpdate() { + const node = this.messengerContent; + this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight; + } + + componentDidUpdate() { + if (this.shouldScrollBottom) { + const node = this.messengerContent; + node.scrollTop = node.scrollHeight; + } + } + + render() { + const { + messages, users, onSendMessage, welcome, inputValue = "", + } = this.props; + let sorted = null; + if (messages && Array.isArray(messages)) { + sorted = [...messages]; + sorted = sorted.sort((msg1, msg2) => { + if (msg1.timestamp < msg2.timestamp) { + return -1; + } + if (msg1.timestamp === msg2.timestamp) { + return 0; + } + return 1; + }); + } else { + sorted = []; + } + if (welcome) { + sorted.splice(0, 0, { id: "welcome", body: welcome, welcome: true }); + } + let chatInput = inputValue; + return ( +
    +
    +
    { this.messengerContent = div; }} + className="messenger-content messenger-content-test bounceOutRight bounceInRight" + > + {sorted.map((message, index) => { + if (message.error) { + const inputText = message.input.text; + let buttons = ( +
    + +
    ); + if (this.props.isSelectedIntent) { + buttons = ( +
    + + +
    ); + } + return ( +
    +
    + Oh snap ! + I can"t associate an intent with previous input. +
    + {buttons} +
    ); + } else if (message.welcome) { + const key = `wl_${index}`; + return ( +
    { }} + onClick={(e) => { e.preventDefault(); this.props.onAction("welcomeMessage", message.body); }} + >{message.body} +
    ); + } + const from = message.from.toLowerCase(); + const user = users[from]; + // console.log("from=", from, user); + let dest = "you"; + let icon = "default"; + if (user) { + ({ dest, icon } = user); + } + // previous = message; + /* eslint-disable react/no-danger */ + return ( +
    +
    +
    +
    + ); + /* eslint-enable react/no-danger */ + })} +
    +
    +
    + { e.preventDefault(); }} name="add" /> + { e.preventDefault(); }} name="mic" /> + { chatInput = input; }} + onKeyUp={(e) => { + if (e.key === "Enter") { + if (onSendMessage && onSendMessage(chatInput.inputRef.value)) { + chatInput.inputRef.value = ""; + } + e.preventDefault(); + } + }} + /> + { + e.preventDefault(); + if (onSendMessage && onSendMessage(chatInput.inputRef.value)) { + chatInput.inputRef.value = ""; + } + }} + name="send" + /> +
    +
    + ); + } +} + +MessengerBox.defaultProps = { + onAction: null, + inputValue: null, + welcome: "", + isSelectedIntent: false, +}; + +MessengerBox.propTypes = { + messages: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + onSendMessage: PropTypes.func.isRequired, + onAction: PropTypes.func, + users: PropTypes.shape({}).isRequired, + inputValue: PropTypes.string, + welcome: PropTypes.string, + isSelectedIntent: PropTypes.bool, +}; + +export default MessengerBox; diff --git a/src/shared/components/providerEditor.jsx b/src/shared/components/providerEditor.jsx new file mode 100644 index 00000000..cabc5bc1 --- /dev/null +++ b/src/shared/components/providerEditor.jsx @@ -0,0 +1,29 @@ +import { DialogManager } from "zoapp-ui"; + +const displayProviderEditor = ( + title, + action, + actionDef, + parameters, + setInput, + onEditAction, + content, + className, +) => { + const actions = []; + if (action) { + actions.push(action); + actions.push("Cancel"); + } + + const actionsDef = []; + if (actionDef) { + actionsDef.push(actionDef); + actionsDef.push("Cancel"); + } + DialogManager.open({ + title, content, actions, actionsDef, onAction: onEditAction, className, + }); +}; + +export default displayProviderEditor; diff --git a/src/shared/components/serviceEditor.jsx b/src/shared/components/serviceEditor.jsx new file mode 100644 index 00000000..adc7f0e0 --- /dev/null +++ b/src/shared/components/serviceEditor.jsx @@ -0,0 +1,59 @@ +import React from "react"; +import { Textfield } from "react-mdl"; +import { DialogManager } from "zoapp-ui"; + +const displayWebServiceEditor = ( + title, + action, + actionDef, + parameters, + setInput, + onEditAction, + className, +) => { + const name = parameters.name ? parameters.name : ""; + const url = parameters.url ? parameters.url : ""; + const classes = parameters.classes ? parameters.classes : ""; + const secret = parameters.secret ? parameters.secret : ""; + const content = ( +
    + setInput(input, "name")} + /> + setInput(input, "url")} + /> + setInput(input, "secret")} + /> + setInput(input, "classes")} + /> +
    ); + + DialogManager.open({ + title, content, actions: [action, "Cancel"], actionsDef: [actionDef, "Cancel"], onAction: onEditAction, className, + }); +}; + +export default displayWebServiceEditor; diff --git a/src/shared/components/servicesList.jsx b/src/shared/components/servicesList.jsx new file mode 100644 index 00000000..31239dff --- /dev/null +++ b/src/shared/components/servicesList.jsx @@ -0,0 +1,71 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { List, ListItem, ListItemContent, ListItemAction, Button, IconButton } from "react-mdl"; + +const ServicesList = ({ + name, + items, + onSelect, + addDisabled, +}) => ( +
    +
    + +

    {name}

    +
    + { + items.map((item, index) => { + const icon = item.status === "start" ? "play_circle_filled" : "play_circle_outline"; + const color = item.status === "start" ? "service_start" : "service_stop"; + const key = `sl_${index}`; + return ( + { + e.preventDefault(); if (onSelect) { + onSelect({ + name, state: "select", index, item, + }); + } + }} + > + {item.name} + + { + e.preventDefault(); + if (onSelect) { + onSelect({ name, state: "delete", index }); + } + }} + /> + + + ); + }) + } + +
    +); + +ServicesList.defaultProps = { + addDisabled: false, +}; + +ServicesList.propTypes = { + name: PropTypes.string.isRequired, + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + onSelect: PropTypes.func.isRequired, + addDisabled: PropTypes.bool, +}; + +export default ServicesList; diff --git a/src/shared/components/subToolbar.jsx b/src/shared/components/subToolbar.jsx new file mode 100644 index 00000000..c9444143 --- /dev/null +++ b/src/shared/components/subToolbar.jsx @@ -0,0 +1,94 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { IconButton, Menu, MenuItem } from "react-mdl"; +import HeaderIcon from "./headerIcon"; + +const SubToolbar = ({ + titleIcon, + titleName, + icons, + menu, +}) => { + const menuRender = () => { + if (menu) { + const id = `${titleName}-menu`; + const align = menu.align ? menu.align : "left"; + const { items } = menu; + return ( +
    + + + {items.map((m, index) => { + const key = `m_${index}`; + if (m.disabled) { + return ({m.name}); + } + return ( + { e.preventDefault(); if (m.onSelect) m.onSelect(m.name); }} + > + {m.name} + ); + })} + +
    ); + } + return (
    ); + }; + + const iconsRender = () => { + if (icons) { + return ( +
    + {icons.map((icon, index) => { + const key = `m_${index}`; + return ( + { + e.preventDefault(); if (icon.onClick) icon.onClick(); + }} + /> + ); + })} +
    ); + } + return (
    ); + }; + let headerIcon = null; + let style = {}; + if (titleIcon) { + headerIcon = ; + } else { + style = { marginLeft: "16px" }; + } + return ( +
    + {headerIcon} +
    {titleName}
    +
    + {iconsRender()} + {menuRender()} +
    +
    + ); +}; +SubToolbar.defaultProps = { + titleIcon: null, + icons: null, + menu: null, +}; + +SubToolbar.propTypes = { + titleName: PropTypes.oneOfType([ + PropTypes.string, PropTypes.element]).isRequired, + titleIcon: PropTypes.string, + icons: PropTypes.arrayOf(PropTypes.shape({})), + menu: PropTypes.shape({ + items: PropTypes.arrayOf(PropTypes.shape({})), + }), +}; + +export default SubToolbar; diff --git a/src/shared/components/tableComponent.jsx b/src/shared/components/tableComponent.jsx new file mode 100644 index 00000000..20a21874 --- /dev/null +++ b/src/shared/components/tableComponent.jsx @@ -0,0 +1,117 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Icon } from "react-mdl"; + +const TableComponent = ({ + title, headers, items, selectedItem, onSelect, className, style, +}) => { + const s = style || {}; + if (!s.width) { + s.width = "100%"; + } + s.borderSpacing = "0"; + return ( +
    +
    {title} + + + + {headers.map((h, index) => { + const st = { + textAlign: "left", + paddingLeft: "24px", + }; + const key = `h_${index}`; + return ( + ); + })} + + + + {items.map((item, index) => { + let icon = ""; + if (item.icon) { + let { color } = item; + if (!color) { + color = "transparent"; + } + const stl = { + backgroundColor: color, + padding: "8px", + }; + if (item.icon.endsWith(".svg")) { + icon = ( +
    + {item.name} +
    ); + } else if (item.icon.endsWith(".png")) { + icon = ( +
    + {item.name} +
    ); + } else { + icon =
    ; + } + } + const { values } = item; + let cn = "selectableListItem"; + if (selectedItem === index) { + cn = "selectedListItem"; + } + const st = { + textAlign: "left", + paddingLeft: "24px", + height: "48px", + borderTop: "1px solid rgba(0, 0, 0, 0.12)", + }; + return ( + { e.preventDefault(); onSelect(index); }} + className={cn} + style={{ color: "rgba(0, 0, 0, 0.87)", fontSize: "13px" }} + > + {values.map((value, i) => { + const k = `c_${i}`; + return (); + })} + ); + })} + +
    {h}
    {icon} + {value}
    +
    +
    +
    + ); +}; + +TableComponent.defaultProps = { + className: null, + style: null, +}; + +TableComponent.propTypes = { + title: PropTypes.oneOfType([ + PropTypes.string, PropTypes.element]).isRequired, + className: PropTypes.string, + style: PropTypes.objectOf(PropTypes.string), + headers: PropTypes.arrayOf(PropTypes.string).isRequired, + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + selectedItem: PropTypes.number.isRequired, + onSelect: PropTypes.func.isRequired, +}; + +export default TableComponent; diff --git a/src/shared/components/templatesList.jsx b/src/shared/components/templatesList.jsx new file mode 100644 index 00000000..686f2f2b --- /dev/null +++ b/src/shared/components/templatesList.jsx @@ -0,0 +1,80 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Grid, Cell } from "react-mdl"; +import FileInput from "./fileInput"; + +const infoStyleC = { + fontSize: "16px", + fontWeight: "400", + color: "#666", + lineHeight: "1.1", + padding: "16px", + height: "87%", +}; + +const templateBoxStyle = { + height: "168px", + // backgroundColor: "white" +}; + +/* const templateSelectedBoxStyle = { + height: "168px", + backgroundColor: "#E0E0E0", +}; */ + +const anchorStyle = { + textDecoration: "none", + width: "100%", +}; + +const cellStyle = { + display: "table-row", + textAlign: "center", + width: "100%", +}; + +const TemplatesList = ({ + items, selectedItem, onSelect, onImport, acceptImport, +}) => ( + + {items.map((item, index) => { + let cn = "mdl-shadow--2dp selectableListItem"; + if (selectedItem === index) { + cn = "mdl-shadow--2dp selectedListItem"; + } + const i = `./images/robots/robot-${index}.svg`; + let b = {item.name}; + if (item.name === "Import") { + b =
    ; + } + return ( + +
    { }} + role="presentation" + style={anchorStyle} + onClick={() => { /* e.preventDefault(); */ onSelect(index); }} + > +
    {item.name}
    +
    {b}
    +
    +
    +
    ); + })} +
    +); + +TemplatesList.defaultProps = { + onImport: null, + acceptImport: null, +}; + +TemplatesList.propTypes = { + items: PropTypes.arrayOf(PropTypes.shape({})).isRequired, + selectedItem: PropTypes.number.isRequired, + onSelect: PropTypes.func.isRequired, + onImport: PropTypes.func, + acceptImport: PropTypes.string, +}; + +export default TemplatesList; diff --git a/src/shared/components/tunnelBox.jsx b/src/shared/components/tunnelBox.jsx new file mode 100644 index 00000000..296591cd --- /dev/null +++ b/src/shared/components/tunnelBox.jsx @@ -0,0 +1,108 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Textfield, Button } from "react-mdl"; +import { Selectfield } from "zoapp-ui"; + +class TunnelBox extends Component { + constructor(props) { + super(props); + this.state = { params: null, advanced: false }; + this.fields = {}; + } + + onChange = (name, value) => { + const params = this.state.params || { ...this.props.params }; + console.log("onChangeTunnel", name, value); + let { advanced } = this.state; + if (name === "provider") { + advanced = false; + if (value === "None") { + params.active = null; + } else { + params.active = { provider: value }; + } + } else if (params.active) { + params.active[name] = value; + } + // TODO check if params are the same than props + this.setState({ params, advanced }); + this.props.onChange(params); + } + + render() { + const params = this.state.params || this.props.params; + const none = "None"; + const items = [{ id: 0, name: none }]; + if (params.providers) { + params.providers.forEach((provider, index) => { + items.push({ id: (index + 1), name: provider.name }); + }); + } + const active = params.active || {}; + const value = active.provider; + let formDisplay = "none"; + let advanced = null; + const b = active.localhost || active.subdomain || active.host; + if (b || (value && this.state.advanced)) { + formDisplay = "block"; + } else if (value) { + advanced = ( + ); + } + return ( +
    +
    + { this.onChange("provider", e.target.value); }} + floatingLabel + ref={(input) => { this.fields.provider = input; }} + value={value} + style={{ width: "400px" }} + > + {items.map(item => ())} + +
    + {advanced} +
    +
    { this.onChange("subdomain", e.target.value); }} + label="Subdomain" + floatingLabel + style={{ width: "400px" }} + value={active.subdomain} + ref={(input) => { this.fields.subdomain = input; }} + /> +
    +
    { this.onChange("host", e.target.value); }} + label="Host" + floatingLabel + style={{ width: "400px" }} + value={active.host} + ref={(input) => { this.fields.host = input; }} + /> +
    +
    { this.onChange("localhost", e.target.value); }} + label="Localhost" + floatingLabel + style={{ width: "400px" }} + value={active.localhost} + ref={(input) => { this.fields.localhost = input; }} + /> +
    +
    +
    ); + } +} + +TunnelBox.propTypes = { + onChange: PropTypes.func.isRequired, + params: PropTypes.objectOf(PropTypes.shape({})).isRequired, +}; + +export default TunnelBox; diff --git a/src/shared/components/usersChart.jsx b/src/shared/components/usersChart.jsx new file mode 100644 index 00000000..61fe16ed --- /dev/null +++ b/src/shared/components/usersChart.jsx @@ -0,0 +1,74 @@ +import React from "react"; +import { Line } from "react-chartjs-2"; + +const data = { + labels: ["02/28", "03/01", "03/02", "03/03", "03/04", "03/05", "03/06"], + datasets: [ + { + label: "Monthly Users", + fill: false, + lineTension: 0.1, + backgroundColor: "rgba(75,192,192,0.4)", + borderColor: "rgba(75,192,192,1)", + borderCapStyle: "butt", + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: "miter", + pointBorderColor: "rgba(75,192,192,1)", + pointBackgroundColor: "#fff", + pointBorderWidth: 1, + pointHoverRadius: 5, + pointHoverBackgroundColor: "rgba(75,192,192,1)", + pointHoverBorderColor: "rgba(220,220,220,1)", + pointHoverBorderWidth: 2, + pointRadius: 1, + pointHitRadius: 10, + pointStyle: "circle", + data: [20, 30, 40, 44, 50, 55, 56], + }, + ], +}; + +const options = { + maintainAspectRatio: false, + scales: { + xAxes: [{ + gridLines: { + lineWidth: 0, + color: "rgba(0,0,0,0)", + drawBorder: false, + zeroLineWidth: 0, + zeroLineColor: "rgba(0,0,0,0)", + }, + }], + }, + legend: { + display: true, + position: "right", + labels: { + fontColor: "#666", + }, + }, +}; + +const styles = { + graphContainer: { + padding: "16px", + }, +}; + +const infoStyle = { + fontSize: "24px", + fontWeight: "300", + color: "#666", + paddingBottom: "20px", +}; + +const UsersCharts = () => ( +
    +
    Active users
    + +
    +); + +export default UsersCharts; diff --git a/src/shared/config.js b/src/shared/config.js new file mode 100644 index 00000000..04f980e3 --- /dev/null +++ b/src/shared/config.js @@ -0,0 +1,41 @@ +import config from "../../config/default.json"; + +export const application = { +}; + +const { backend } = config; + +let { host, port, path } = backend.auth; +if (!host) { + ({ host } = backend.api); +} +if (!port) { + ({ port } = backend.api); +} +// TODO remove url from config +let p = port ? `:${port}` : ""; +let url = `${host}${p}/${path}`; + +const authConfig = { + clientId: backend.auth.clientId, + clientSecret: backend.auth.clientSecret, + url, + host, + port, + path, + secure: backend.secure, +}; + +({ host, port, path } = backend.api); +// TODO remove url from config +p = port ? `:${port}` : ""; +url = `${host}${p}/${path}`; +const apiConfig = { + url, + host, + port, + path, + secure: backend.secure, +}; + +export { authConfig, apiConfig }; diff --git a/src/shared/containers/adminManager.jsx b/src/shared/containers/adminManager.jsx new file mode 100644 index 00000000..a3a40bb5 --- /dev/null +++ b/src/shared/containers/adminManager.jsx @@ -0,0 +1,354 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Grid, Cell, Button, IconButton, Content, Textfield, Tooltip } from "react-mdl"; +import { DialogManager, Selectfield } from "zoapp-ui"; +import { connect } from "react-redux"; +import { appSetTitle } from "../actions/app"; +import { apiSetAdminParametersRequest } from "../actions/api"; +import TableComponent from "../components/tableComponent"; +import Loading from "../components/loading"; +import SignInForm from "./signInForm"; +import ServicesContainer from "./servicesContainer"; +import PluginsManager from "../utils/pluginsManager"; +import TunnelBox from "../components/tunnelBox"; + + +const infoStyleD = { + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "24px", + lineHeight: "1.1", +}; + +class AdminManager extends Component { + static onActionTunnel(dialog, action) { + console.log("onActionTunnel", dialog, action); + DialogManager.close(); + } + + constructor(props) { + super(props); + const pluginsManager = new PluginsManager(); + this.state = { + pluginsManager, + botParams: null, + tunnelParams: null, + backendParams: null, + emailServerParams: null, + }; + } + + componentWillMount() { + this.updateParams(); + } + + componentWillUpdate() { + this.updateParams(); + } + + onChangeTunnel = (tunnelParams) => { + this.setState({ tunnelParams }); + } + + onSaveBackend() { + if (this.state.tunnelParams) { + // WIP save tunnel parameters + const tunnel = this.state.tunnelParams.active || "None"; + this.setState({ tunnelParams: null }); + this.props.apiSetAdminParametersRequest({ tunnel }); + } + } + + updateParams() { + this.props.appSetTitle("Admin"); + } + + displayTunnelDialog() { + const { params } = this.props.admin; + const backend = this.state.backendParams || params.backend || { }; + const tunnelParams = this.state.tunnelParams || backend.tunnel || { }; + const content = ; + DialogManager.open({ + title: "Tunnel settings", content, width: "520px", onAction: AdminManager.onActionTunnel, + }); + } + + render() { + let { isLoading } = this.props; + if ((!isLoading) && (!this.props.admin) && this.props.isSignedIn) { + isLoading = true; + } + if (!this.props.isSignedIn) { + return (); + } else if (isLoading || this.props.admin == null) { + return (); + } + const active = this.props.activeTab; + let content = ""; + if (active === 0) { + const saveDisabled = !this.state.botParams; + content = ( + + +
    +
    +
    +
    +
    +
    + {}} + label="Assistant name" + floatingLabel + style={{ width: "400px" }} + value={this.props.bot.name} + /> +
    +
    {}} + label="Describe how your assistant is wonderfull !" + rows={3} + value={this.props.bot.description} + style={{ width: "400px" }} + /> +
    +
    + { this.selectFieldLanguage = input; }} + value={this.props.bot.language} + > + + + +
    +
    + { this.selectFieldTimezone = input; }} + > + + + +
    +
    +
    +
    + + ); + } else if (active === 1) { + content = ( + + + ); + } else if (active === 2) { + const items = []; + const status = "you"; + const { user, profile } = this.props; + // const spanStyle = { width: "160px" }; + const values = []; + values.push(profile.username); + values.push(profile.email); + values.push(user.attributes.scope); + values.push(status); + items.push({ id: 1, values, icon: `../images/${profile.avatar}.png` }); + const headers = ["", "username", "email", "role", "status"]; + const title = ( +
    You could give an access to your collaborators here. + +
    ); + content = ( + + +
    + { }} + /> +
    +
    +
    ); + } else if (active === 3) { + const { params } = this.props.admin; + const emailServer = this.state.emailParams || params.emailServer || { }; + const backend = this.state.backendParams || params.backend || { }; + // const tunnelParams = this.state.tunnelParams || backend.tunnel || {}; + const hasTunnelParams = !!this.state.tunnelParams; + const saveBackendDisabled = !(this.state.backendParams || this.state.tunnelParams); + const saveEmailDisabled = !this.state.emailServerParams; + content = ( + + +
    Backend configuration + +
    +
    +
    + {}} + label="Public Api url" + floatingLabel + style={{ width: "400px" }} + value={backend.publicUrl} + /> + + { e.preventDefault(); this.displayTunnelDialog(); }} /> + +
    +
    {}} + label="Api url" + floatingLabel + disabled + style={{ width: "400px" }} + value={backend.apiUrl} + /> +
    +
    {}} + label="Auth url" + floatingLabel + disabled + style={{ width: "400px" }} + value={backend.authUrl} + /> +
    +
    {}} + label="AppId" + floatingLabel + disabled + style={{ width: "400px" }} + value={backend.clientId} + /> +
    +
    {}} + label="Secret" + floatingLabel + disabled + style={{ width: "400px" }} + value={backend.clientSecret} + /> +
    +
    +
    + + +
    Email server configuration
    +
    +
    {}} + label="Server address" + floatingLabel + style={{ width: "400px" }} + value={emailServer.url} + /> +
    +
    + {}} + label="Username" + floatingLabel + autoComplete="new-password" + style={{ width: "400px" }} + value={emailServer.username} + /> +
    +
    + {}} + label="Password" + floatingLabel + autoComplete="new-password" + type="password" + style={{ width: "400px" }} + value={emailServer.password} + /> +
    +
    +
    + + +
    Delete this assistant + +
    +
    + + ); + } + return ( + +
    + {content} +
    +
    + ); + } +} + +AdminManager.defaultProps = { + admin: null, + isLoading: false, + isSignedIn: false, + bot: null, + user: null, + profile: {}, + activeTab: 0, +}; + +AdminManager.propTypes = { + admin: PropTypes.shape({ params: PropTypes.shape({}).isRequired }), + isLoading: PropTypes.bool, + isSignedIn: PropTypes.bool, + bot: PropTypes.shape({ + name: PropTypes.string.isRequired, + description: PropTypes.string, + language: PropTypes.string, + }), + user: PropTypes.shape({}), + activeTab: PropTypes.number, + appSetTitle: PropTypes.func.isRequired, + apiSetAdminParametersRequest: PropTypes.func.isRequired, + profile: PropTypes.shape({}), +}; + +AdminManager.contextTypes = { + activeTab: PropTypes.number, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + const selectedBotId = state.app ? state.app.selectedBotId : null; + const { user } = state; + const profile = user ? user.profile : null; + // TODO get selectedBot from selectBotId + const bot = selectedBotId ? admin.bots[0] : null; + return { + admin, isLoading, isSignedIn, selectedBotId, bot, user, profile, + }; +}; + +const mapDispatchToProps = dispatch => ({ + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, + apiSetAdminParametersRequest: (params) => { + dispatch(apiSetAdminParametersRequest(params)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(AdminManager); diff --git a/src/shared/containers/app.jsx b/src/shared/containers/app.jsx new file mode 100644 index 00000000..bbe15fcc --- /dev/null +++ b/src/shared/containers/app.jsx @@ -0,0 +1,226 @@ +import React from "react"; +import { Layout, Header, Drawer, Navigation, IconButton, Menu, MenuItem, HeaderTabs, Tab } from "react-mdl"; +import PropTypes from "prop-types"; +import { Link, Route, Switch, withRouter } from "react-router-dom"; +import { connect } from "react-redux"; + +import Home from "OplaContainers/home"; +import ReportsManager from "OplaContainers/reportsManager"; +import ConversationsManager from "OplaContainers/conversationsManager"; +import CampaignsManager from "OplaContainers/campaignsManager"; +import BotManager from "OplaContainers/botManager"; +import AdminManager from "OplaContainers/adminManager"; +import CreateAssistant from "OplaContainers/createAssistant"; +import DemoManager from "OplaContainers/demoManager"; +import BuilderBox from "OplaContainers/builderBox"; +import UserBox from "./userBox"; +import { initAuthSettings } from "../actions/initialize"; +import { apiAdminRequest } from "../actions/api"; + +class App extends React.Component { + static closeDrawer() { + const d = document.querySelector(".mdl-layout"); + d.MaterialLayout.toggleDrawer(); + } + + constructor(props) { + super(props); + this.state = { needUpdate: true, activeTab: 0 }; + } + + componentDidMount() { + this.props.initAuthSettings(); + this.updateAdmin(); + } + + componentWillUpdate() { + const items = document.getElementsByClassName("mdl_closedrawer"); + for (let i = 0; i < items.length; i += 1) { + items[i].removeEventListener("click", App.closeDrawer); + } + } + + componentDidUpdate() { + this.updateAdmin(); + const items = document.getElementsByClassName("mdl_closedrawer"); + for (let i = 0; i < items.length; i += 1) { + items[i].addEventListener("click", App.closeDrawer); + } + } + + handleTimeoutError() { + this.todo = {}; + } + + updateAdmin() { + if (!this.props.isSignedIn) { + if (!this.state.needUpdate) { + this.setState({ needUpdate: true }); + } + return; + } + if (this.state.needUpdate) { + this.setState({ needUpdate: false }); + this.props.apiAdminRequest(); + } + } + + /** + * WIP : toggleDrawer : https://codepen.io/surma/pen/EKjNON?editors=1010 + */ + render() { + let { isLoading } = this.props; + if ((!isLoading) && (!this.props.admin) && this.props.isSignedIn) { + isLoading = true; + } + let botName = "opla.ai"; + if (this.props.bot && this.props.isSignedIn) { + botName = this.props.bot.name; + } + let titleName = " / Your open chatbot builder"; + const avatarClass = "opla-icon"; + let style = {}; + const items = []; + let toolbox = ""; + let navbox = ""; + if (this.props.isSignedIn) { + if (this.props.titleName === "Builder") { + style = { padding: "32px 80px 0px 0px" }; + navbox = ( + this.setState({ activeTab: tabId })} + > + Intents + Entities + Flows + ); + style = { paddingRight: "20%" }; + toolbox = (); + style = { width: "30%", textAlign: "right" }; + } else if (this.props.titleName === "Admin") { + style = { padding: "32px 80px 0px 0px", width: "620px" }; + navbox = ( + this.setState({ activeTab: tabId })} + > + General + Extensions + Users + Advanced + ); + style = { width: "30%", textAlign: "right" }; + } + titleName = ` / ${this.props.titleName}`; + let className = "mdl_closedrawer"; + className += this.props.titleName === "Dashboard" ? " mdl-navigation__selectedlink" : ""; + items.push({ + id: "1", to: "/", icon: "dashboard", name: "Dashboard", className, + }); + className = "mdl_closedrawer"; + className += this.props.titleName === "Builder" ? " mdl-navigation__selectedlink" : ""; + items.push({ + id: "2", to: "/builder", icon: "build", name: "Builder", className, + }); + className = "mdl_closedrawer"; + className += this.props.titleName === "Admin" ? " mdl-navigation__selectedlink" : ""; + items.push({ + id: "3", to: "/admin", icon: "settings", name: "Admin", className, + }); + } else { + items.push({ + id: "4", to: "/", name: "Home", icon: "home", className: "mdl_closedrawer", + }); + } + items.push({ + id: "5", to: "/", name: "Help", icon: "help", className: "mdl_closedrawer", + }); + + return ( +
    + +
    {botName}{titleName}}> + + {navbox} + {toolbox} + + +
    + {botName}}> + + Properties + Change Assistant + + + {items.map(item => ({item.icon}{item.name}))} + + + + + + + } /> + } /> + + + + +
    +
    + ); + } +} + +App.defaultProps = { + error: null, + admin: null, + bot: null, +}; + +App.propTypes = { + store: PropTypes.shape({}).isRequired, + isSignedIn: PropTypes.bool.isRequired, + titleName: PropTypes.string.isRequired, + isLoading: PropTypes.bool.isRequired, + error: PropTypes.shape({}), + admin: PropTypes.shape({}), + bot: PropTypes.shape({ name: PropTypes.string }), + initAuthSettings: PropTypes.func.isRequired, + apiAdminRequest: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const bot = admin ? admin.bots[0] : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = (state.app && state.app.loading) || + (state.auth && state.auth.loading) || (state.user && state.user.loading); + const titleName = state.app ? state.app.titleName : ""; + let error = null; + if (state.app && state.app.error) { + ({ error } = state.app); + } else if (state.auth && state.auth.error) { + ({ error } = state.auth); + } else if ((!error) && state.user && state.user.error) { + ({ error } = state.user); + } + return { + admin, bot, isLoading, isSignedIn, titleName, error, + }; +}; + +const mapDispatchToProps = dispatch => ({ + initAuthSettings: () => { + dispatch(initAuthSettings()); + }, + apiAdminRequest: () => { + dispatch(apiAdminRequest()); + }, +}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App)); diff --git a/src/shared/containers/botManager.jsx b/src/shared/containers/botManager.jsx new file mode 100644 index 00000000..28d56cf3 --- /dev/null +++ b/src/shared/containers/botManager.jsx @@ -0,0 +1,298 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Grid, Cell, Button, Content } from "react-mdl"; +import { DialogManager } from "zoapp-ui"; +import { apiGetIntentsRequest, apiSendIntentRequest, apiSaveBotRequest, apiImportRequest } from "../actions/api"; +import { appUpdateIntent, appSetTitle } from "../actions/app"; +import Loading from "../components/loading"; +import SignInForm from "./signInForm"; +import ExplorerContainer from "./explorerContainer"; +import IntentContainer from "./intentContainer"; +import SandboxContainer from "./sandboxContainer"; +import IODialog from "./ioDialog"; +import FileManager from "../utils/fileManager"; + +const infoStyleD = { + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "16px", + lineHeight: "1.1", + textAlign: "left", +}; + +class BotManager extends Component { + constructor(props) { + super(props); + this.state = { needUpdate: true }; + } + + componentWillMount() { + this.props.appSetTitle("Builder"); + this.updateIntents(); + } + + componentDidUpdate() { + this.props.appSetTitle("Builder"); + this.updateIntents(); + } + + onAddIntent = (dialog, action) => { + if (action === "Create") { + const intentName = dialog.getFieldValue(); + if (intentName === "") { + dialog.invalidateField(); + return false; + } + const data = dialog.getData(); + const intent = { ...data, name: intentName }; + this.props.apiSendIntentRequest(this.props.selectedBotId, intent); + } + return true; + } + + onImportData = (data, options) => { + console.log("BotManager.onUpload=", options.filetype); + if (options.filetype === "application/json" || options.filetype === "text/csv") { + // WIP detect format + console.log("BotManager.onUpload=", data); + this.props.apiImportRequest(this.props.selectedBotId, data, options); + } + } + + onDownloadData = () => { + const { name } = this.props.bot; + const data = { name, intents: this.props.intents }; + const json = JSON.stringify(data); + FileManager.download(json, `${name}.json`, "application/json,.csv", () => { console.log("ExplorerContainer.onDownload=", name); }); + } + + onEditWelcome = (dialog, action) => { + if (action === "Save") { + const welcome = dialog.getFieldValue(); + if (welcome === "") { + dialog.invalidateField(); + return false; + } + const bot = { ...this.props.bot, welcome }; + this.props.apiSaveBotRequest(bot); + } + return true; + } + + handleAddIntent = (defaultValue = "", data = {}) => { + const content = { + defaultValue, pattern: ".+", name: "Intent name", error: "Wrong name", + }; + DialogManager.open({ + title: "Add new intent", content, actions: ["Create", "Cancel"], onAction: this.onAddIntent, data, + }); + } + + handleExportImport = (importOnly = false) => { + const dialog = (); + DialogManager.open({ dialog }); + } + + handlePlaygroundAction = (action, defaultValue = "", data = {}) => { + if (action === "welcomeMessage") { + const content = { + defaultValue, pattern: ".+", name: "Welcome message", error: "Wrong message", + }; + DialogManager.open({ + title: "Edit Bot", content, actions: ["Save", "Cancel"], onAction: this.onEditWelcome, data, + }); + } else if (action === "createIntent") { + const intent = { input: [defaultValue] }; + this.handleAddIntent(defaultValue, intent); + } else if (action === "addInput") { + const intent = { ...this.props.selectedIntent }; + if (!intent.input) { + intent.input = []; + } + // TODO check if sentence already exists in input + intent.input.push(defaultValue); + this.props.appUpdateIntent(this.props.selectedBotId, intent); + } + console.log("botManager.handlePlaygroundAction", action); + } + + updateIntents() { + if (!this.props.isSignedIn) { + if (!this.state.needUpdate) { + this.setState({ needUpdate: true }); + } + return; + } + if (this.props.selectedBotId && this.state.needUpdate) { + this.setState({ needUpdate: false }); + this.props.apiGetIntentsRequest(this.props.selectedBotId); + } + } + + render() { + let { isLoading } = this.props; + if ((!isLoading) && (!this.props.intents) && this.props.isSignedIn) { + isLoading = true; + } + if (!this.props.isSignedIn) { + return (); + } else if (this.props.intents == null) { + return (); + } + let panel1 = null; + let panel2 = null; + if (this.props.intents.length > 0) { + panel1 = ( + + + ); + panel2 = ( + + + ); + } else { + panel1 = ( + +
    +
    +
    +

    Get Started

    +

    + This assistant has no data. You need to fill it with intents + to reply to inputs from end-users.
    + To do so you could create an intent. Or you could use + the playground to help you to create them.
    +

    +
    + For example: + send "Hello" using Playground's textfield at the bottom + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + An assistant has a list of intents.
    An intent + is an expected behaviour from the end-user.
    + Assistant's NLP (Natural Language Processing) + engine will use that list to match intent's input + with end-user's input. + If a match is found assistant responds using selected intent's output. +
    +
    +
    ); + panel2 = ""; + } + return ( + + + {panel1} + {panel2} + + + + + + ); + } +} + +BotManager.defaultProps = { + bot: null, + intents: null, + selectedIntent: null, + selectedBotId: null, + store: null, +}; + +BotManager.propTypes = { + isLoading: PropTypes.bool.isRequired, + isSignedIn: PropTypes.bool.isRequired, + selectedBotId: PropTypes.string, + bot: PropTypes.shape({ + name: PropTypes.string.isRequired, + description: PropTypes.string, + language: PropTypes.string, + }), + intents: PropTypes.arrayOf(PropTypes.shape({})), + selectedIntent: PropTypes.shape({}), + store: PropTypes.shape({}), + appSetTitle: PropTypes.func.isRequired, + apiGetIntentsRequest: PropTypes.func.isRequired, + apiSendIntentRequest: PropTypes.func.isRequired, + apiSaveBotRequest: PropTypes.func.isRequired, + apiImportRequest: PropTypes.func.isRequired, + appUpdateIntent: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + let { selectedIntent } = state.app; + const selectedBotId = state.app ? state.app.selectedBotId : null; + // TODO get selectedBot from selectBotId + const bot = selectedBotId ? admin.bots[0] : null; + const intents = state.app.intents ? state.app.intents : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.app ? state.app.loading : false; + const selectedIntentIndex = state.app ? state.app.selectedIntentIndex : 0; + if (!selectedIntent) { + selectedIntent = state.app.intents ? state.app.intents[selectedIntentIndex] : null; + } + return { + selectedBotId, bot, intents, isLoading, isSignedIn, selectedIntent, + }; +}; + +const mapDispatchToProps = dispatch => ({ + apiGetIntentsRequest: (botId) => { + dispatch(apiGetIntentsRequest(botId)); + }, + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, + apiSendIntentRequest: (botId, intent) => { + dispatch(apiSendIntentRequest(botId, intent)); + }, + apiSaveBotRequest: (bot) => { + dispatch(apiSaveBotRequest(bot)); + }, + apiImportRequest: (botId, data, options) => { + dispatch(apiImportRequest(botId, data, options)); + }, + appUpdateIntent: (botId, intent) => { + dispatch(appUpdateIntent(botId, intent)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(BotManager); diff --git a/src/shared/containers/builderBox.jsx b/src/shared/containers/builderBox.jsx new file mode 100644 index 00000000..7d841882 --- /dev/null +++ b/src/shared/containers/builderBox.jsx @@ -0,0 +1,62 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button } from "react-mdl"; +import { DialogManager } from "zoapp-ui"; +import { connect } from "react-redux"; +import PublishDialog from "./publishDialog"; + +class BuilderBox extends Component { + constructor(props) { + super(props); + this.state = { }; + } + + onAction = (action) => { + console.log("TODO Publish"); + if (action === "Publish") { + return false; + } + return true; + } + + handleOpenPublishDialog = () => { + const dialog = ; + DialogManager.open({ dialog }); + } + + render() { + if (this.props.isSignedIn) { + const style = { paddingRight: "20%" }; + return ( +
    + +
    ); + } + return (
    ); + } +} + +BuilderBox.defaultProps = { + isSignedIn: false, + store: null, +}; + +BuilderBox.propTypes = { + isSignedIn: PropTypes.bool, + store: PropTypes.shape({}), +}; + +const mapStateToProps = (state) => { + const selectedBotId = state.app ? state.app.selectedBotId : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.app.loading; + return { selectedBotId, isSignedIn, isLoading }; +}; + +export default connect(mapStateToProps)(BuilderBox); diff --git a/src/shared/containers/campaignsManager.jsx b/src/shared/containers/campaignsManager.jsx new file mode 100644 index 00000000..fb499054 --- /dev/null +++ b/src/shared/containers/campaignsManager.jsx @@ -0,0 +1,41 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Content } from "react-mdl"; +import { connect } from "react-redux"; +import { appSetTitle } from "../actions/app"; + + +class CampaignsManager extends Component { + componentWillMount() { + this.props.appSetTitle("Campaigns"); + } + + render() { + return ( + +
    +
    Campaigns : TODO
    +
    +
    + ); + } +} + +CampaignsManager.propTypes = { + appSetTitle: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + return { admin, isLoading, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(CampaignsManager); diff --git a/src/shared/containers/conversationsManager.jsx b/src/shared/containers/conversationsManager.jsx new file mode 100644 index 00000000..32d13658 --- /dev/null +++ b/src/shared/containers/conversationsManager.jsx @@ -0,0 +1,40 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Content } from "react-mdl"; +import { connect } from "react-redux"; +import { appSetTitle } from "../actions/app"; + +class ConversationsManager extends Component { + componentWillMount() { + this.props.appSetTitle("Users"); + } + + render() { + return ( + +
    +
    Users : TODO
    +
    +
    + ); + } +} + +ConversationsManager.propTypes = { + appSetTitle: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + return { admin, isLoading, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ConversationsManager); diff --git a/src/shared/containers/createAssistant.jsx b/src/shared/containers/createAssistant.jsx new file mode 100644 index 00000000..e3d7225e --- /dev/null +++ b/src/shared/containers/createAssistant.jsx @@ -0,0 +1,257 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Content, Button, Textfield } from "react-mdl"; +import { DialogManager, Selectfield } from "zoapp-ui"; +import { connect } from "react-redux"; +import { withRouter } from "react-router"; +import TemplatesList from "../components/templatesList"; +import ProcessingDialog from "./processingDialog"; +import { apiCreateBot } from "../actions/api"; +import { appSetTitle } from "../actions/app"; + +const formStyle = { + paddingLeft: "16px", +}; + +const advancedStyle = { + marginLeft: "16px", + color: "rgba(0, 0, 0, 0.54)", +}; + +const boxStyle = { + margin: "16px", +}; + +const headerStyle = { + padding: "16px", +}; + +const h4 = { + marginTop: "0px", + marginBottom: "16px", + fontSize: "16px", + color: "rgba(0, 0, 0, 0.87)", +}; +const secText = { + color: "rgba(0, 0, 0, 0.54)", +}; +/* const hintText = { + color: "rgba(0, 0, 0, 0.38)", +}; */ + +// TODO get templates from API +const templates = [ + { id: 1, name: "Empty" }, + { id: 2, name: "HelloWorld" }, + { id: 3, name: "Test1" }, + { id: 4, name: "Import" }, +]; + +class CreateAssistant extends Component { + constructor(props) { + super(props); + this.state = { selectedTemplate: 0, template: null, loading: false }; + } + + componentWillMount() { + this.props.appSetTitle("Create your virtual assistant"); + } + + componentDidUpdate() { + if (this.state.loading && this.props.isLoading === false) { + this.handleCloseCreateDialog(); + } + } + + onImportTemplate = (data) => { + // TODO check if json + const json = JSON.parse(data); + console.log("onImportTemplate json=", json); + this.onSelectTemplate(3, json); + } + + onSelectTemplate = (selected, data) => { + let template = data; + if (!template) { + template = templates[selected]; + } + this.setState({ selectedTemplate: selected, template }); + } + + handleCloseCreateDialog = () => { + this.setState({ loading: false }); + DialogManager.close(); + if (!this.props.error) { + this.props.history.push("/builder"); + } + } + + handleCreate = () => { + // Check textfields before processing + const name = this.nameField.inputRef.value; + const email = this.emailField.inputRef.value; + const username = this.usernameField.inputRef.value; + const password = this.passwordField.inputRef.value; + const language = this.selectField.inputRef.value || "en"; + if (this.state.loading === false && name !== "" && email !== "" && username !== "" && password !== "") { + const { template } = this.state; + const botParams = { + name, email, username, password, template, language, + }; + this.setState({ loading: true }); + const dialog = ; + DialogManager.open({ dialog }); + this.props.createBot(botParams); + } else { + // TODO display errors in dialogs + } + } + + handleLanguageChange = () => { + const language = this.selectField.inputRef.value; + console.log("handleCreate language=", language); + } + + render() { + const selected = this.state.selectedTemplate; + // TODO json only for instance + const acceptImport = "application/json"; + return ( + +
    +
    +

    Opla !

    +
    + Welcome to our five minutes installation process! Just fill in + the informations below and you will get the most powerfull + and extendable bot platform in the world. +
    +
    +
    +
    +
    +

    Templates

    +
    + Choose a prebuild asssistant, import one or select an empty model. +
    +
    + +
    +
    Want more ? +
    + In a near future we will release our BotStore to find + the perfect bot from our community. +
    +
    +
    +
    +
    +
    +

    Informations needed

    +
    + Please provide the following information. + Don't worry. You can always change them later. +
    +
    +
    +
    { this.nameField = input; }} + /> +
    +
    { this.usernameField = input; }} + /> +
    +
    { this.passwordField = input; }} + /> +
    +
    { this.emailField = input; }} + /> +
    +
    + { this.selectField = input; }} + > + + + +
    +
    +
    +
    + + +
    +
    + ); + } +} + +CreateAssistant.defaultProps = { + error: null, +}; + +CreateAssistant.propTypes = { + isLoading: PropTypes.bool.isRequired, + error: PropTypes.objectOf(), + createBot: PropTypes.func.isRequired, + appSetTitle: PropTypes.func.isRequired, + history: PropTypes.shape({ length: PropTypes.number, push: PropTypes.func }).isRequired, +}; + +const mapStateToProps = (state) => { + const { admin, error } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.app.loading; + return { + admin, isLoading, isSignedIn, error, + }; +}; + +const mapDispatchToProps = dispatch => ({ + createBot: (botParams) => { + dispatch(apiCreateBot(botParams)); + }, + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, +}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CreateAssistant)); diff --git a/src/shared/containers/dashboard.jsx b/src/shared/containers/dashboard.jsx new file mode 100644 index 00000000..020f27fd --- /dev/null +++ b/src/shared/containers/dashboard.jsx @@ -0,0 +1,138 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Content, Grid, Cell, Button } from "react-mdl"; +import Loading from "../components/loading"; +/* import UsersChart from "../components/usersChart"; */ +import DonutChart from "../components/donutChart"; +import { appSetTitle } from "../actions/app"; + +class Dashboard extends Component { + componentWillMount() { + this.props.appSetTitle("Dashboard"); + } + + render() { + const infoStyle = { + textAlign: "center", + fontSize: "28px", + fontWeight: "400", + color: "#888", + padding: "16px 0", + lineHeight: "1.1", + }; + const infoStyleB = { + textAlign: "center", + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "60px 0", + lineHeight: "1.1", + }; + const infoStyleC = { + fontSize: "16px", + fontWeight: "400", + color: "green", + padding: "60px 0", + lineHeight: "1.1", + }; + const infoStyleD = { + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "16px", + lineHeight: "1.1", + }; + + const { isLoading } = this.props; + if (!this.props.isSignedIn) { + return (
    You need to sign in...
    ); + } else if (isLoading || this.props.admin == null) { + return (); + } + const { admin } = this.props; + const usersCount = admin.users != null ? admin.users.count : 0; + const conversationsCount = admin.conversations != null ? admin.conversations.count : 0; + const messagesCount = admin.messages != null ? admin.messages.count : 0; + return ( + + + +
    Last 7 days | Filter: All + + + +
    + +
    + + + +
    + {usersCount}
    + users / +4% +
    +
    + +
    + {conversationsCount}
    + errors / +8% +
    +
    + +
    + {messagesCount}
    + messages / +11% +
    +
    +
    +
    + + + + + + + + + + + + + + + + +
    +
    + ); + } +} + +Dashboard.defaultProps = { + admin: null, + isLoading: false, + isSignedIn: false, +}; + +Dashboard.propTypes = { + admin: PropTypes.shape({ params: PropTypes.shape({}).isRequired }), + isLoading: PropTypes.bool, + isSignedIn: PropTypes.bool, + appSetTitle: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + return { admin, isLoading, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); diff --git a/src/shared/containers/demoManager.jsx b/src/shared/containers/demoManager.jsx new file mode 100644 index 00000000..dad68dcd --- /dev/null +++ b/src/shared/containers/demoManager.jsx @@ -0,0 +1,75 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Content } from "react-mdl"; +import { apiGetIntentsRequest, apiSendIntentRequest } from "../actions/api"; +import SignInForm from "./signInForm"; +import SandboxContainer from "./sandboxContainer"; +import { appSetTitle } from "../actions/app"; + + +class DemoManager extends Component { + constructor(props) { + super(props); + this.state = { }; + } + + componentWillMount() { + this.props.appSetTitle("Demo"); + } + + componentDidUpdate() { + } + + render() { + let { isLoading } = this.props; + if ((!isLoading) && (!this.props.intents) && this.props.isSignedIn) { + isLoading = true; + } + if (!this.props.isSignedIn) { + return (); + } + return ( + + + + ); + } +} + +DemoManager.defaultProps = { + intents: null, +}; + +DemoManager.propTypes = { + isLoading: PropTypes.bool.isRequired, + isSignedIn: PropTypes.bool.isRequired, + intents: PropTypes.arrayOf(PropTypes.shape({})), + appSetTitle: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const selectedBotId = state.app ? state.app.selectedBotId : null; + const bot = selectedBotId ? admin.bots[selectedBotId] : null; + const intents = state.app.intents ? state.app.intents : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.app ? state.app.loading : false; + return { + selectedBotId, bot, intents, isLoading, isSignedIn, + }; +}; + +const mapDispatchToProps = dispatch => ({ + apiGetIntentsRequest: (botId) => { + dispatch(apiGetIntentsRequest(botId)); + }, + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, + apiSendIntentRequest: (botId, intent) => { + dispatch(apiSendIntentRequest(botId, intent)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(DemoManager); diff --git a/src/shared/containers/devTools.jsx b/src/shared/containers/devTools.jsx new file mode 100644 index 00000000..d2f8676c --- /dev/null +++ b/src/shared/containers/devTools.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import { createDevTools } from "redux-devtools"; +import LogMonitor from "redux-devtools-log-monitor"; +import DockMonitor from "redux-devtools-dock-monitor"; + +// createDevTools takes a monitor and produces a DevTools component +const DevTools = createDevTools(( + + + )); + +export default DevTools; diff --git a/src/shared/containers/explorerContainer.jsx b/src/shared/containers/explorerContainer.jsx new file mode 100644 index 00000000..1facab5e --- /dev/null +++ b/src/shared/containers/explorerContainer.jsx @@ -0,0 +1,193 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { DialogManager } from "zoapp-ui"; +import ListDragComponent from "../components/listDragComponent"; +import SubToolbar from "../components/subToolbar"; +import { apiGetIntentsRequest, apiSendIntentRequest, apiDeleteIntentRequest, apiMoveIntentRequest } from "../actions/api"; +import { appSelectIntent } from "../actions/app"; + +class ExplorerContainer extends Component { + onDropIntent = (dragIndex, dropIndex) => { + console.log("TODO", `ExplorerContainer.onDropIntent ${dragIndex} / ${dropIndex}`); + const intent = this.props.intents[dragIndex]; + const intentId = intent.id; + this.props.apiMoveIntentRequest(this.props.selectedBotId, intentId, dragIndex, dropIndex); + } + + onSelectIntent = (selected) => { + this.props.appSelectIntent(this.props.selectedBotId, selected); + } + + onAddIntent = (dialog, action) => { + if (action === "Create") { + const intentName = dialog.getFieldValue(); + console.log("WIP", `ExplorerContainer.onAddIntent :${intentName}`); + if (intentName === "") { + dialog.invalidateField(); + return false; + } + const intent = { name: intentName }; + this.props.apiSendIntentRequest(this.props.selectedBotId, intent); + } + return true; + } + + onRenameIntent = (dialog, action) => { + if (action === "Rename") { + const intentName = dialog.getFieldValue(); + console.log("WIP", `ExplorerContainer.onRenameIntent :${intentName}`); + if (intentName === "") { + dialog.invalidateField(); + return false; + } + const selected = this.props.selectedIntentIndex; + const it = this.props.intents[selected]; + const intent = { ...it, name: intentName }; + this.props.apiSendIntentRequest(this.props.selectedBotId, intent); + } + return true; + } + + onDeleteIntent = (dialog, action) => { + if (action === "Delete") { + const selected = this.props.selectedIntentIndex; + const intent = this.props.intents[selected]; + console.log("WIP", `ExplorerContainer.onDeleteIntent :${intent.name}`); + this.props.apiDeleteIntentRequest(this.props.selectedBotId, intent); + } + return true; + } + + handleAddIntent = () => { + console.log("WIP", "ExplorerContainer.handleAddIntent"); + const content = { + defaultValue: "", pattern: ".+", name: "Intent name", error: "Wrong name", + }; + DialogManager.open({ + title: "Add new intent", content, actions: ["Create", "Cancel"], onAction: this.onAddIntent, + }); + } + + handleRename = () => { + console.log("TODO", "ExplorerContainer.handleRename"); + const selected = this.props.selectedIntentIndex; + const intent = this.props.intents[selected]; + const content = { + defaultValue: intent.name, pattern: ".+", name: "Intent name", error: "Wrong name", + }; + DialogManager.open({ + title: "Rename intent", content, actions: ["Rename", "Cancel"], onAction: this.onRenameIntent, + }); + } + + handleSynchronize = () => { + console.log("WIP", "ExplorerContainer.handleSynchronize"); + this.props.apiGetIntentsRequest(this.props.selectedBotId); + } + + handleDelete = () => { + console.log("WIP", "ExplorerContainer.handleDelete"); + const selected = this.props.selectedIntentIndex; + const intent = this.props.intents[selected]; + DialogManager.open({ + title: "Intent", content: `${intent.name} Do you want to delete it ?`, actions: ["Delete", "Cancel"], onAction: this.onDeleteIntent, + }); + } + + /* handleExportImport = () => { + const dialog = ; + DialogManager.open({ dialog }); + } */ + + render() { + const selected = this.props.selectedIntentIndex; + const name = "Intents"; + const items = []; + if (this.props.intents) { + this.props.intents.forEach((intent) => { + const { id } = intent; + const style = intent.notSaved ? { + marginRight: "4px", width: "8px", height: "8px", marginBottom: "2px", + } : { display: "none", marginRight: "2px" }; + const marginLeft = intent.notSaved ? "-14px" : "0px"; + const n = {intent.name}; + items.push({ id, name: n }); + }); + } + return ( +
    + { this.props.handleExportImport(); }) }], + }} + /> +
    + +
    +
    ); + } +} + +ExplorerContainer.defaultProps = { + intents: [], + selectedIntentIndex: 0, + selectedBotId: null, +}; + +ExplorerContainer.propTypes = { + selectedBotId: PropTypes.string, + intents: PropTypes.arrayOf(PropTypes.shape({})), + selectedIntentIndex: PropTypes.number, + apiGetIntentsRequest: PropTypes.func.isRequired, + apiSendIntentRequest: PropTypes.func.isRequired, + apiDeleteIntentRequest: PropTypes.func.isRequired, + apiMoveIntentRequest: PropTypes.func.isRequired, + appSelectIntent: PropTypes.func.isRequired, + handleExportImport: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const selectedIntentIndex = state.app ? state.app.selectedIntentIndex : 0; + const selectedBotId = state.app ? state.app.selectedBotId : null; + const intents = state.app.intents ? state.app.intents : null; + const { admin } = state.app; + const bot = admin ? admin.bots[0] : null; + return { + intents, selectedIntentIndex, selectedBotId, bot, + }; +}; + +const mapDispatchToProps = dispatch => ({ + apiGetIntentsRequest: (botId) => { + dispatch(apiGetIntentsRequest(botId)); + }, + apiSendIntentRequest: (botId, intent) => { + dispatch(apiSendIntentRequest(botId, intent)); + }, + apiDeleteIntentRequest: (botId, intentId) => { + dispatch(apiDeleteIntentRequest(botId, intentId)); + }, + apiMoveIntentRequest: (botId, intentId, from, to) => { + dispatch(apiMoveIntentRequest(botId, intentId, from, to)); + }, + appSelectIntent: (botId, intentIndex) => { + dispatch(appSelectIntent(botId, intentIndex)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ExplorerContainer); diff --git a/src/shared/containers/home.jsx b/src/shared/containers/home.jsx new file mode 100644 index 00000000..79f8e72a --- /dev/null +++ b/src/shared/containers/home.jsx @@ -0,0 +1,51 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Card, CardTitle, CardText, CardActions, Button, Content } from "react-mdl"; +import { connect } from "react-redux"; +import Dashboard from "./dashboard"; + +const Home = ({ isSignedIn }) => { + if (isSignedIn) { + return (); + } + return ( + +
    + + +

    Create your own virtual assistant +

    +
    + + It is easy and fast. In less than 5 min, your bot will be ready! + + + + +
    +
    +
    + ); +}; + +Home.propTypes = { + isSignedIn: PropTypes.bool.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + return { admin, isLoading, isSignedIn }; +}; + + +export default connect(mapStateToProps)(Home); diff --git a/src/shared/containers/intentContainer.jsx b/src/shared/containers/intentContainer.jsx new file mode 100644 index 00000000..6a82686e --- /dev/null +++ b/src/shared/containers/intentContainer.jsx @@ -0,0 +1,222 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { DialogManager } from "zoapp-ui"; +import IntentDetail, { displayActionEditor } from "../components/intentDetail"; +import SubToolbar from "../components/subToolbar"; +import { apiSendIntentRequest } from "../actions/api"; +import { appSetIntentAction, appDeleteIntentAction, appUpdateIntent } from "../actions/app"; + +class IntentContainer extends Component { + onChangeAction = (actionText) => { + console.log("IntentContainer.onChangeAction =", actionText); + } + + onEditAction = (dialog, editAction) => { + if (editAction === "Change" || editAction === "Add") { + const text = this.actionField.getContent().trim(); + let actionValue = null; + const intent = this.props.selectedIntent; + let { actionType } = this; + if (this.actionType === "condition") { + let name = this.paramNameField.inputRef.value.trim(); + if (!name || name.length === 0) { + name = null; + } + let value = this.paramValueField.inputRef.value.trim(); + if (!value || value.length === 0) { + value = null; + } + if (name === null && ((!intent.output) || intent.output.length === 0)) { + actionValue = text; + actionType = null; + } else if (name && text.length > 0) { + const type = "item"; + actionValue = { + name, value, text, type, + }; + } + } else { + actionValue = text; + } + console.log("WIP", `IntentContainer.onEditAction :${actionValue} / ${this.selectedAction}`); + if ((!actionValue) || actionValue === "") { + return false; + } + this.props.appSetIntentAction( + this.actionContainer, + actionType, actionValue, this.selectedAction, + ); + } else if (editAction === "Delete") { + console.log("WIP", `IntentContainer.onDeleteAction :${this.selectedAction}`); + this.props.appDeleteIntentAction(this.actionContainer, this.selectedAction); + } else if (editAction === "Topic") { + console.log("WIP", "IntentContainer.onTopic "); + const topic = this.actionField.inputRef.value.trim(); + const { selectedIntent } = this.props; + const currentTopic = selectedIntent.topic ? selectedIntent.topic : ""; + if (topic !== currentTopic) { + const intent = { ...selectedIntent, topic }; + this.props.appUpdateIntent(this.props.selectedBotId, intent); + } + } else if (editAction === "Previous") { + console.log("TODO", "IntentContainer.onPrevious "); + } + this.selectedAction = undefined; + this.actionContainer = undefined; + this.actionType = undefined; + return true; + } + + handleSaveIntent = () => { + console.log("WIP", "IntentContainer.handleSaveIntent"); + // DialogManager.open({ title: "TODO", content: "IntentContainer.handleSaveIntent" }); + if (this.props.selectedIntent) { + const intent = { ...this.props.selectedIntent }; + if (intent.notSaved) { + delete intent.notSaved; + this.props.apiSendIntentRequest(this.props.selectedBotId, intent); + } else { + console.log("WIP", "IntentContainer.handleSaveIntent : intent already saved"); + } + } + } + + handleActions = ({ + name, type, state, index, + }) => { + if (this.actionContainer) { + return; + } + this.actionContainer = name; + this.actionType = type; + this.selectedAction = index; + const intent = this.props.selectedIntent; + let title = name; + let parameters; + let action; + let actionDef; + let editor = true; + if (state === "select" && index >= 0) { + if (type === "condition") { + const condition = intent[name][0]; + parameters = condition.children[index]; + } else { + parameters = intent[name][index]; + } + title = `Edit ${title} item`; + action = "Change"; + } else if (state === "add") { + if (type === "condition") { + parameters = { name: "", value: "", text: "" }; + } else { + parameters = ""; + } + title = `Add ${title} item`; + action = "Add"; + } else if (state === "delete") { + editor = false; + title = `Remove ${title} item`; + action = "Delete"; + } else if (state === "topic") { + title = "Set topic name"; + action = "Set"; + actionDef = "Topic"; + parameters = intent.topic ? intent.topic : "*"; + } else if (state === "previous") { + title = "Set previous intent"; + action = "Set"; + actionDef = "Previous"; + } else if (state === "addCondition") { + title = `Add ${title} item`; + action = "Add"; + } + if (!actionDef) { + actionDef = action; + } + if (editor) { + const isInput = name === "input"; + displayActionEditor(title, type, action, actionDef, parameters, (input, ref = null) => { + if (ref === "fieldParamName") { + this.paramNameField = input; + } else if (ref === "fieldParamValue") { + this.paramValueField = input; + } else { this.actionField = input; } + }, this.onEditAction, this.onChangeAction, isInput); + } else { + DialogManager.open({ + title: "Action", content: "Do you want to delete it ?", actions: ["Delete", "Cancel"], onAction: this.onEditAction, + }); + } + } + + render() { + const intent = this.props.selectedIntent; + let name = ""; + if (intent) { + const style = intent.notSaved ? {} : { display: "none" }; + name = {intent.name}; + return ( +
    + + +
    + ); + } + return ( +
    + +
    You need to create an Intent
    +
    + ); + } +} + +IntentContainer.defaultProps = { + selectedIntent: null, + selectedBotId: null, +}; + +IntentContainer.propTypes = { + selectedBotId: PropTypes.string, + selectedIntent: PropTypes.shape({}), + apiSendIntentRequest: PropTypes.func.isRequired, + appDeleteIntentAction: PropTypes.func.isRequired, + appSetIntentAction: PropTypes.func.isRequired, + appUpdateIntent: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const selectedIntentIndex = state.app ? state.app.selectedIntentIndex : 0; + let { selectedIntent } = state.app; + if (!selectedIntent) { + selectedIntent = state.app.intents ? state.app.intents[selectedIntentIndex] : null; + } + const selectedBotId = state.app ? state.app.selectedBotId : null; + return { selectedIntent, selectedBotId }; +}; + +const mapDispatchToProps = dispatch => ({ + apiSendIntentRequest: (botId, intent) => { + dispatch(apiSendIntentRequest(botId, intent)); + }, + appUpdateIntent: (botId, intent) => { + dispatch(appUpdateIntent(botId, intent)); + }, + appSetIntentAction: (actionContainer, actionType, actionValue, selectedAction) => { + dispatch(appSetIntentAction(actionContainer, actionType, actionValue, selectedAction)); + }, + appDeleteIntentAction: (actionContainer, selectedAction) => { + dispatch(appDeleteIntentAction(actionContainer, selectedAction)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(IntentContainer); diff --git a/src/shared/containers/ioDialog.jsx b/src/shared/containers/ioDialog.jsx new file mode 100644 index 00000000..f22da65e --- /dev/null +++ b/src/shared/containers/ioDialog.jsx @@ -0,0 +1,189 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Checkbox, Button, DialogTitle, DialogContent, DialogActions, Tabs, Tab } from "react-mdl"; +import { DialogManager, DialogBox } from "zoapp-ui"; +import FileManager from "../utils/fileManager"; + +class IODialog extends Component { + constructor(props) { + super(props); + const { open } = props; + this.state = { + openDialog: open, + id: props.id, + activeTab: 0, + data: null, + filetype: null, + deletePrevious: false, + }; + } + + componentWillReceiveProps(props) { + if (this.props.open !== props.open) { + this.setState({ openDialog: props.open }); + } + } + + /* static importCSV(data) { + const lines = data.split(/\r\n|\n/); + const headers = lines.shift().split(","); + const items = []; + lines.forEach((line) => { + let open = true; + let buf = ""; + let i = 0; + const item = {}; + for (const ch of line) { + if (open && ch === ",") { + const name = headers[i]; + if (buf.length > 0) { + item[name] = buf; + buf = ""; + } + i += 1; + } else if (ch === "\"") { + open = !open; + } else { + buf += ch; + } + } + items.push(item); + }); + return items; + } */ + + onUpload = (selectorFiles) => { + FileManager.upload(selectorFiles, (data, filetype) => { + console.log("IODialog.onUpload=", filetype); + /* if (filetype === ".csv" || filetype === "text/csv") { + const csv = this.importCSV(data); + console.log("imported csv", csv); + } */ + this.setState({ data, filetype }); + }); + }; + + handleImport = () => { + if (this.state.data) { + const { deletePrevious } = this.state; + const options = { filetype: this.state.filetype, deletePrevious }; + this.props.onImport(this.state.data, options); + this.handleCloseDialog(); + } + }; + + handleOpenDialog = () => { + this.setState({ + openDialog: true, + }); + } + + handleCloseDialog = () => { + this.setState({ openDialog: false }); + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } else { + setTimeout(() => { DialogManager.close(); }, 300); + } + }; + + render() { + if (this.props.importOnly) { + return ( + + + Import Intents + + +
    + +
    +
    + + + + +
    + ); + } + const p1 = this.state.activeTab === 0 ? "block" : "none"; + const p2 = this.state.activeTab === 1 ? "block" : "none"; + let dialogActions = null; + if (this.state.activeTab === 0) { + dialogActions = ( + + + ); + } else { + dialogActions = ( + + + + ); + } + return ( + + + this.setState({ activeTab: tabId })} + ripple + > + Export + Import + + + +
    + +
    +
    + { this.setState({ deletePrevious: !!e.target.value }); }} + /> + +
    +
    + {dialogActions} +
    + ); + } +} + +IODialog.defaultProps = { + open: true, + id: null, + onClosed: null, + importOnly: false, +}; + +IODialog.propTypes = { + open: PropTypes.bool, + id: PropTypes.string, + importOnly: PropTypes.bool, + accept: PropTypes.string.isRequired, + onClosed: PropTypes.func, + onDownload: PropTypes.func.isRequired, + onImport: PropTypes.func.isRequired, +}; + +export default IODialog; diff --git a/src/shared/containers/processingDialog.jsx b/src/shared/containers/processingDialog.jsx new file mode 100644 index 00000000..8fdfcaf9 --- /dev/null +++ b/src/shared/containers/processingDialog.jsx @@ -0,0 +1,61 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { DialogTitle, DialogContent, DialogActions } from "react-mdl"; +import { DialogBox } from "zoapp-ui"; + +export default class ProcessingDialog extends Component { + constructor(props) { + super(props); + const { open } = props; + this.state = { openDialog: open, id: props.id }; + } + + componentWillReceiveProps(props) { + if (this.props.open !== props.open) { + this.setState({ openDialog: props.open }); + } + } + + handleOpenDialog = () => { + this.setState({ + openDialog: true, + }); + } + + handleCloseDialog = () => { + this.setState({ + openDialog: false, + }); + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } + } + + render() { + return ( + + Processing + + Please wait ... + + + + ); + } +} + +ProcessingDialog.defaultProps = { + open: true, + id: null, + onClosed: null, +}; + +ProcessingDialog.propTypes = { + open: PropTypes.bool, + id: PropTypes.string, + onClosed: PropTypes.func, +}; diff --git a/src/shared/containers/publishDialog.jsx b/src/shared/containers/publishDialog.jsx new file mode 100644 index 00000000..00cb830f --- /dev/null +++ b/src/shared/containers/publishDialog.jsx @@ -0,0 +1,275 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, DialogTitle, DialogContent, DialogActions } from "react-mdl"; +import { connect } from "react-redux"; +import { DialogManager, DialogBox } from "zoapp-ui"; +import PluginsManager from "../utils/pluginsManager"; +import MessagingsList from "../components/messagingsList"; +import ServiceDialog from "./serviceDialog"; +import { + apiGetMiddlewaresRequest, + /* apiSetMiddlewareRequest, apiDeleteMiddlewareRequest, */ + apiPublishRequest, +} from "../actions/api"; +import { appUpdatePublisher } from "../actions/app"; + +class PublishDialog extends Component { + constructor(props) { + super(props); + const openDialog = props.open; + this.state = { openDialog, isLoading: true }; + } + + componentDidMount() { + this.updateMiddlewares(true); + } + + componentDidUpdate() { + this.updateMiddlewares(); + /* DialogManager.forceUpdate(); */ + } + + onSelect = ({ + name, state, index, item, + }) => { + console.log("WIP onSelected", name, state, index); + const { service, instance } = item; + if (state === "enable") { + let status; + const n = service.getName(); + let publisher = this.props.publishers[n]; + if (publisher) { + ({ status } = publisher); + } else { + publisher = { name: n }; + ({ status } = service); + } + publisher.status = status === "start" ? null : "start"; + console.log("status ", publisher.status, status); + // this.setState({ servicesEnabled }); + this.props.appUpdatePublisher(this.props.selectedBotId, publisher); + } else { + const sdialog = ( + ); + setTimeout(() => DialogManager.open({ dialog: sdialog }), 100); + } + } + + onAction = (action) => { + console.log("WIP onAction=", action); + // TODO check if services are available + let ready = false; + const { publishers } = this.props; + const keys = Object.keys(publishers); + if (keys && keys.length > 0) { + keys.forEach((k) => { + const pub = publishers[k]; + if (pub.status === "start") { + ready = true; + } + }); + } + if (ready) { + this.props.apiPublishRequest(this.props.selectedBotId, publishers); + // TODO display published dialog with links to service's messenger + setTimeout(() => { + DialogManager.close(); + DialogManager.open({ + title: "Published", + content: "Published to:", + actions: ["Ok"], + onAction: this.handleCloseDialog, + }); + }, 100); + } else { + setTimeout(() => { + DialogManager.open({ + title: "Error", + content: "You need at least one service started !", + actions: ["Ok"], + onAction: this.handleCloseDialog, + }); + }, 100); + } + } + + handleCloseDialog = () => { + setTimeout(() => { DialogManager.close(); }, 100); + } + + updateMiddlewares(needUpdate = false) { + if (needUpdate) { + this.setState({ isLoading: true }); + // Call getMiddlewares + this.props.apiGetMiddlewaresRequest( + this.props.selectedBotId, + "MessengerConnector", + ); + } else if (this.state.isLoading && (!this.props.isLoading)) { + this.setState({ isLoading: false }); + } + } + + renderDialog = () => { + let content = null; + if (this.state.isLoading) { + content =
    Loading
    ; + } else { + const actives = []; + const pluginsManager = new PluginsManager(); + const services = pluginsManager.getPlugins({ type: "MessengerConnector", activated: true }); + const servicesEnabled = this.props.publishers; + if (this.props.middlewares && this.props.middlewares.length > 0) { + const { middlewares } = this.props; + middlewares.forEach((instance) => { + const service = pluginsManager.getPlugin(instance.name); + let status; + if (servicesEnabled[instance.name]) { + ({ status } = servicesEnabled[instance.name]); + } else { + ({ status } = instance); + } + const enabled = status === "start"; + actives.push({ + name: service.getTitle(), + icon: service.getIcon(), + color: service.getColor(), + service, + instance, + enabled, + status: instance.status, + }); + }); + } + const items = []; + services.forEach((service) => { + // TODO check if the item is already pushed + let active = null; + let i = 0; + for (; i < actives.length; i += 1) { + if (actives[i].service.getName() === service.getName()) { + active = actives[i]; + break; + } + } + if (active) { + items.push(active); + actives.splice(i, 1); + } else { + let status; + if (servicesEnabled[service.getName()]) { + ({ status } = servicesEnabled[service.getName()]); + } else { + status = "closed"; + } + const enabled = status === "start"; + items.push({ + name: service.getTitle(), + icon: service.getIcon(), + color: service.getColor(), + service, + enabled, + status, + }); + } + }); + actives.forEach((active) => { + items.push(active); + }); + content = ( +
    + +
    ); + } + + return content; + } + + render() { + const title = "Publish"; + const content = this.renderDialog(); + const style = { width: "550px" }; + return ( + + {title} + {content} + + + + + + ); + } +} + +PublishDialog.defaultProps = { + open: true, + middlewares: null, + selectedBotId: null, + isLoading: false, + publishers: null, + store: null, +}; + +PublishDialog.propTypes = { + open: PropTypes.bool, + middlewares: PropTypes.arrayOf(PropTypes.shape({})), + selectedBotId: PropTypes.string, + isLoading: PropTypes.bool, + publishers: PropTypes.objectOf(PropTypes.shape({})), + store: PropTypes.shape({}), + appUpdatePublisher: PropTypes.func.isRequired, + apiGetMiddlewaresRequest: PropTypes.func.isRequired, + apiPublishRequest: PropTypes.func.isRequired, + /* apiSetMiddlewareRequest: PropTypes.func.isRequired, + apiDeleteMiddlewareRequest: PropTypes.func.isRequired, */ +}; + +const mapStateToProps = (state) => { + const middlewares = state.app ? state.app.middlewares : null; + const selectedBotId = state.app ? state.app.selectedBotId : null; + // const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.app.loading; + const publishers = state.app.publishers || { }; + return { + middlewares, selectedBotId, isLoading, publishers, + }; +}; + +const mapDispatchToProps = dispatch => ({ + appUpdatePublisher: (botId, publisher) => { + dispatch(appUpdatePublisher(botId, publisher)); + }, + apiPublishRequest: (botId, publishers) => { + dispatch(apiPublishRequest(botId, publishers)); + }, + apiGetMiddlewaresRequest: (botId, type) => { + dispatch(apiGetMiddlewaresRequest(botId, type)); + }, + /* apiSetMiddlewareRequest: (botId, middleware) => { + dispatch(apiSetMiddlewareRequest(botId, middleware)); + }, + apiDeleteMiddlewareRequest: (botId, middleware) => { + dispatch(apiDeleteMiddlewareRequest(botId, middleware)); + }, */ +}); + +export default connect(mapStateToProps, mapDispatchToProps)(PublishDialog); diff --git a/src/shared/containers/reportsManager.jsx b/src/shared/containers/reportsManager.jsx new file mode 100644 index 00000000..66ab69d0 --- /dev/null +++ b/src/shared/containers/reportsManager.jsx @@ -0,0 +1,136 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Content, Grid, Cell, Button } from "react-mdl"; +import Loading from "../components/loading"; +import UsersChart from "../components/usersChart"; +import DonutChart from "../components/donutChart"; +import { appSetTitle } from "../actions/app"; + +class ReportsManager extends Component { + componentWillMount() { + this.props.appSetTitle("Reports"); + } + + render() { + const infoStyle = { + textAlign: "center", + fontSize: "28px", + fontWeight: "400", + color: "#888", + padding: "16px 0", + lineHeight: "1.1", + }; + const infoStyleB = { + textAlign: "center", + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "60px 0", + lineHeight: "1.1", + }; + const infoStyleC = { + fontSize: "16px", + fontWeight: "400", + color: "green", + padding: "60px 0", + lineHeight: "1.1", + }; + const infoStyleD = { + fontSize: "16px", + fontWeight: "400", + color: "#666", + padding: "16px", + lineHeight: "1.1", + }; + + const { isLoading } = this.props; + if (!this.props.isSignedIn) { + return (
    You need to sign in...
    ); + } else if (isLoading || this.props.admin == null) { + return (); + } + const { admin } = this.props; + const usersCount = admin.users != null ? admin.users.count : 0; + const conversationsCount = admin.conversations != null ? admin.conversations.count : 0; + const messagesCount = admin.messages != null ? admin.messages.count : 0; + return ( + + + +
    Last 7 days | Filter: All
    +
    + + + + + + +
    + {usersCount}
    + users / +4% +
    +
    + +
    + {conversationsCount}
    + websites / +8% +
    +
    + +
    + {messagesCount}
    + messages / +11% +
    +
    +
    +
    + + + + + + + + + + + + + + + + +
    +
    + ); + } +} + +ReportsManager.defaultProps = { + admin: null, + isLoading: false, + isSignedIn: false, +}; + +ReportsManager.propTypes = { + admin: PropTypes.shape({ params: PropTypes.shape({}).isRequired }), + isLoading: PropTypes.bool, + isSignedIn: PropTypes.bool, + appSetTitle: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const { admin } = state.app; + const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; + return { admin, isLoading, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + appSetTitle: (titleName) => { + dispatch(appSetTitle(titleName)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ReportsManager); diff --git a/src/shared/containers/sandboxContainer.jsx b/src/shared/containers/sandboxContainer.jsx new file mode 100644 index 00000000..9df1c5b5 --- /dev/null +++ b/src/shared/containers/sandboxContainer.jsx @@ -0,0 +1,232 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { DialogManager } from "zoapp-ui"; +import MessengerBox from "../components/messengerBox"; +import SubToolbar from "../components/subToolbar"; +import { + apiGetSandboxMessagesRequest, apiSubscribeSandboxMessages, + apiUnsubscribeSandboxMessages, apiSendSandboxMessageRequest, + apiGetSandboxContextRequest, apiSandboxResetRequest, +} from "../actions/api"; + + +class SandboxContainer extends Component { + constructor(props) { + super(props); + this.state = { needToSubscribe: true }; + } + + componentDidMount() { + this.subscribeSandboxMessages(); + } + + componentDidUpdate() { + this.subscribeSandboxMessages(); + } + + componentWillUnmount() { + console.log("UnsubscribeSandboxMessages"); + this.props.apiUnsubscribeSandboxMessages(this.props.selectedBotId); + } + + onReset = (dialog, action) => { + if (action === "Reset") { + console.log("WIP", "SandboxContainer.onReset"); + this.props.apiSandboxResetRequest(this.props.selectedBotId); + } + return true; + } + + subscribeSandboxMessages() { + if (this.props.selectedBot && this.state.needToSubscribe) { + this.setState({ needToSubscribe: false }); + console.log("SubscribeSandboxMessages"); + this.props.apiSubscribeSandboxMessages(this.props.selectedBotId); + } + } + + handleMenu = (action) => { + console.log("sandboxContainer.handleMenu", action); + DialogManager.open({ title: "TODO", content: "SandboxContainer.handleMenu" }); + } + + handleReset = () => { + DialogManager.open({ + title: "Sandbox", + content: "Do you want to reset conversation and context ?", + actions: ["Reset", "Cancel"], + onAction: this.onReset, + }); + } + + handleSend = (messageBody) => { + console.log("WIP", "SandboxContainer.handleSend"); + // DialogManager.open({ title:"TODO", content:"SandboxContainer.handleSend" + message}); + const body = messageBody.trim(); + if (this.props.conversation && body.length > 0) { + const message = { message: body, timestamp: Date.now() }; + this.props.apiSendSandboxMessageRequest( + this.props.selectedBotId, + this.props.conversation.id, message, + ); + return true; + } + console.log("Error", "SandboxContainer.handleSend", this.props.conversation, body.length); + return false; + } + + handleDemo = () => { + + } + + handleShare = () => { + + } + + handleSettings = () => { + + } + + handleAction = (action, defaultValue, data) => { + console.log("sandboxContainer.handleAction", action); + this.props.onAction(action, defaultValue, data); + } + + renderMessenger(messages, users) { + // TODO get welcome from bot + const welcome = this.props.selectedBot.welcome || "Welcome fellow user! Here you could test your assistant, before you publish it."; + return (); + } + + render() { + const name = "Playground"; + let messages = null; + if (this.props.conversation) { + ({ messages } = this.props.conversation); + } else { + messages = []; + } + const users = {}; + if (this.props.userProfile) { + const userName = (this.props.userProfile.username).toLowerCase(); + users[userName] = { + id: this.props.selectedBot.id, name: userName, dest: "you", icon: this.props.userProfile.avatar, + }; + } else { + users.anonymous = { + id: "1", name: "anonymous", dest: "you", icon: "default", + }; + } + if (this.props.selectedBot) { + const bot = this.props.selectedBot; + const botName = (`bot_${bot.name}_${bot.id}`).toLowerCase(); + users[botName] = { + id: this.props.selectedBot.id, name: botName, dest: "from", icon: botName, + }; + if (botName !== "opla") { + users.opla = users[botName]; + } + } else { + users.bot = { + id: "2", name: "bot", dest: "from", icon: "bot", + }; + } + return ( +
    + + {this.renderMessenger(messages, users)} +
    ); + } +} + +SandboxContainer.defaultProps = { + conversation: null, + selectedBotId: PropTypes.string, + selectedBot: PropTypes.shape({}), + userProfile: PropTypes.shape({}), + isSelectedIntent: PropTypes.bool, +}; + +SandboxContainer.propTypes = { + conversation: PropTypes.shape({ id: PropTypes.string }), + selectedBotId: PropTypes.string, + selectedBot: PropTypes.shape({ id: PropTypes.string, welcome: PropTypes.string }), + userProfile: PropTypes.shape({ username: PropTypes.string, avatar: PropTypes.string }), + isSelectedIntent: PropTypes.bool, + onAction: PropTypes.func.isRequired, + apiSubscribeSandboxMessages: PropTypes.func.isRequired, + apiUnsubscribeSandboxMessages: PropTypes.func.isRequired, + apiSendSandboxMessageRequest: PropTypes.func.isRequired, + apiSandboxResetRequest: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const sandbox = state.app ? state.app.sandbox : null; + const selectedBotId = state.app ? state.app.selectedBotId : null; + // TODO get Bot associated with selectedBotId + const selectedBot = selectedBotId ? state.app.admin.bots[0] : null; + const userProfile = state.user ? state.user.profile : null; + let conversation = null; + /* const isSignedIn = state.user ? state.user.isSignedIn : false; + const isLoading = state.loading; */ + const isSelectedIntent = !!(state.app.intents && + state.app.intents.length > 0 && Number.isInteger(state.app.selectedIntentIndex)); + + if (sandbox && sandbox.conversations) { + conversation = sandbox.conversations.length > 0 ? sandbox.conversations[0] : { messages: [] }; + } + return { + sandbox, + conversation, + selectedBotId, + selectedBot, + userProfile, + isSelectedIntent, + }; +}; + +const mapDispatchToProps = dispatch => ({ + apiGetSandboxMessagesRequest: (botId) => { + dispatch(apiGetSandboxMessagesRequest(botId)); + }, + apiSubscribeSandboxMessages: (botId) => { + dispatch(apiSubscribeSandboxMessages(botId)); + }, + apiUnsubscribeSandboxMessages: (botId) => { + dispatch(apiUnsubscribeSandboxMessages(botId)); + }, + apiSendSandboxMessageRequest: (botId, conversationId, message) => { + dispatch(apiSendSandboxMessageRequest(botId, conversationId, message)); + }, + apiGetSandboxContextRequest: (botId) => { + dispatch(apiGetSandboxContextRequest(botId)); + }, + apiSandboxResetRequest: (botId) => { + dispatch(apiSandboxResetRequest(botId)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SandboxContainer); diff --git a/src/shared/containers/serviceDialog.jsx b/src/shared/containers/serviceDialog.jsx new file mode 100644 index 00000000..39b1982a --- /dev/null +++ b/src/shared/containers/serviceDialog.jsx @@ -0,0 +1,138 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, DialogTitle, DialogContent, DialogActions } from "react-mdl"; +import { connect } from "react-redux"; +import { DialogManager, DialogBox } from "zoapp-ui"; +import { apiSetMiddlewareRequest } from "../actions/api"; +import PluginsManager from "../utils/pluginsManager"; +/* eslint-enable no-unused-vars */ + +class ServiceDialog extends Component { + constructor(props) { + super(props); + const { open, instance } = props; + this.state = { openDialog: open, instance }; + } + + componentDidMount() { + this.updateMiddleware(); + } + + componentWillReceiveProps(props) { + if (this.props.open !== props.open) { + this.setState({ openDialog: props.open }); + } + if (this.props.lastMiddleware) { + const instance = this.props.lastMiddleware; + this.setState({ instance }); + } + } + + onAction = (action) => { + const { service } = this.props; + const { instance } = this.state; + const title = service.name; + if (action === "save" && this.props.onAction) { + this.props.onAction(title, service, instance); + } + } + + handleOpenDialog = () => { + this.setState({ + openDialog: true, + }); + } + + handleCloseDialog = () => { + this.setState({ + openDialog: false, + }); + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } else { + setTimeout(() => { DialogManager.close(); }, 300); + } + } + + updateMiddleware() { + const origin = this.props.selectedBotId; + const { service } = this.props; + if (origin && service) { + const name = service.getName(); + const pluginsManager = new PluginsManager(); + const instance = pluginsManager.instanciate(name, origin); + this.props.apiSetMiddlewareRequest(origin, instance); + } + } + + render() { + const { service } = this.props; + const { instance } = this.state; + const title = service.getTitle(); + let content = null; + if (instance) { + content = service.renderSettings(instance, this.onAction, this.props.publicUrl); + } else { + content =
    Loading
    ; + } + const style = { width: "550px" }; + return ( + + {title} + {content} + + + + + + ); + } +} + +ServiceDialog.defaultProps = { + open: true, + instance: null, + service: null, + selectedBotId: null, + lastMiddleware: null, + publicUrl: null, + onClosed: null, + onAction: null, +}; + +ServiceDialog.propTypes = { + open: PropTypes.bool, + instance: PropTypes.shape({}), + service: PropTypes.shape({}), + selectedBotId: PropTypes.string, + lastMiddleware: PropTypes.shape({}), + publicUrl: PropTypes.string, + onClosed: PropTypes.func, + onAction: PropTypes.func, + apiSetMiddlewareRequest: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => { + const lastMiddleware = state.app ? state.app.lastMiddleware : null; + const selectedBotId = state.app ? state.app.selectedBotId : null; + const publicUrl = state.app ? state.app.admin.publicUrl : null; + return { + lastMiddleware, selectedBotId, publicUrl, + }; +}; + +const mapDispatchToProps = dispatch => ({ + apiSetMiddlewareRequest: (botId, middleware) => { + dispatch(apiSetMiddlewareRequest(botId, middleware)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ServiceDialog); diff --git a/src/shared/containers/servicesContainer.jsx b/src/shared/containers/servicesContainer.jsx new file mode 100644 index 00000000..62dbb4e2 --- /dev/null +++ b/src/shared/containers/servicesContainer.jsx @@ -0,0 +1,406 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Cell } from "react-mdl"; +import { DialogManager } from "zoapp-ui"; +import List from "../components/listComponent"; +import ServicesList from "../components/servicesList"; +import displayWebServiceEditor from "../components/serviceEditor"; +import displayProviderEditor from "../components/providerEditor"; +import { apiGetMiddlewaresRequest, apiSetMiddlewareRequest, apiDeleteMiddlewareRequest } from "../actions/api"; + +const divCellStyle = { + width: "100%", +}; + +class ServicesContainer extends Component { + constructor(props) { + super(props); + this.state = { needUpdate: true }; + } + + componentDidMount() { + this.updateServices(); + } + + componentDidUpdate() { + this.updateServices(); + } + + onEditAction = (dialog, editAction) => { + const { name, index } = this.currentSelected; + + if (editAction === "Change" || editAction === "Add") { + // WIP + const params = {}; + Object.keys(this.paramFields).forEach((inputName) => { + const value = this.paramFields[inputName].inputRef.value.trim(); + if (value && value.length > 0) { + params[inputName] = value; + } + }, this); + if (name === "Web services") { + if (editAction === "Change") { + const webservices = this.getMiddlewares("WebService"); + const wh = webservices[index]; + params.id = wh.id; + params.status = wh.status; + } + const botId = this.props.selectedBotId; + params.origin = botId; + if (params.classes) { + params.classes = params.classes.split(","); + } + if (!params.path) { + params.path = "/"; + } + if (!params.status) { + params.status = "start"; + } + params.remote = true; + params.type = "WebService"; + this.props.apiSetMiddlewareRequest(botId, params); + this.setState({ needUpdate: true }); + } + } else if (editAction === "Delete") { + // WIP + if (name === "Web services") { + const webservices = this.getMiddlewares("WebService"); + const wh = webservices[index]; + const botId = this.props.selectedBotId; + this.props.apiDeleteMiddlewareRequest(botId, wh.id); + this.setState({ needUpdate: true }); + } + } + console.log("TODO", `ServicesContainer.onEditAction : ${editAction}`); + + this.currentSelected = null; + this.paramFields = null; + return true; + } + + onSelect = (selected) => { + // WIP + if (this.currentSelected) { + return; + } + const { + name, state, index, item, + } = selected; + + let title = name; + let parameters = {}; + let action = null; + let actionDef; + let editor = null; + let services = null; + let content = null; + let couldDelete = true; + let className = null; + this.currentSelected = { ...selected }; + console.log("test"); + if (name === "Web services") { + services = this.getMiddlewares("WebService"); + editor = displayProviderEditor; + couldDelete = false; + console.log("ws"); + if ((state === "select" || state === "create")) { + if (item.provider) { + className = "mdl-dialog-extended"; + title = item.name; + content = item.provider.renderSettings(); + action = "next"; + } else { + console.log("demo"); + editor = displayWebServiceEditor; + if (state === "create") { + title = `Add ${title} entry`; + action = "Add"; + } + } + } else if (state === "add") { + className = "mdl-dialog-list"; + title = "Add a WebService"; + const items = this.getWebServices(true); + items.push({ + id: items.length + 1, name: "Add plugin", icon: "add", color: "gray", + }); + const that = this; + content = ( +
    { + const it = items[i]; + const n = it.name; + console.log("WIP select Web services =", n); + setTimeout(() => { + DialogManager.closeCurrentDialog(); + that.onSelect({ + name: "Web services", index: i, item: it, state: "create", + }); + }, 50); + }} + /> +
    ); + } + } else if (name === "AI/NLU providers") { + // WIP + title = null; + editor = displayProviderEditor; + couldDelete = false; + if ((state === "select" || state === "create") && item.provider) { + className = "mdl-dialog-extended"; + title = item.name; + content = item.provider.renderSettings(); + action = "next"; + } else if (state === "add") { + className = "mdl-dialog-list"; + title = "Add an AI/NLU provider"; + const items = this.getAIProviders(true); + items.push({ + id: items.length + 1, name: "Add plugin", icon: "add", color: "gray", + }); + const that = this; + content = ( +
    { + const it = items[i]; + const n = it.name; + console.log("WIP select AI/NLU providers =", n); + setTimeout(() => { + DialogManager.closeCurrentDialog(); + that.onSelect({ + name: "AI/NLU providers", index: i, item: it, state: "create", + }); + }, 50); + }} + /> +
    ); + } else { + this.currentSelected = null; + } + } else if (name === "Messaging platforms") { + // WIP + title = null; + editor = displayProviderEditor; + couldDelete = false; + if ((state === "select" || state === "create") && item.provider) { + className = "mdl-dialog-extended"; + title = item.name; + content = item.provider.renderSettings(); + action = "next"; + } else if (state === "add") { + className = "mdl-dialog-list"; + title = "Add a messaging platform"; + const items = this.getMessagingProviders(true); + items.push({ + id: items.length + 1, name: "Add plugin", icon: "add", color: "gray", + }); + const that = this; + content = ( +
    { + const it = items[i]; + const n = it.name; + console.log("WIP select messaging platform =", n); + setTimeout(() => { + DialogManager.closeCurrentDialog(); + that.onSelect({ + name: "Messaging platforms", index: i, item: it, state: "create", + }); + }, 50); + }} + /> +
    ); + } else { + this.currentSelected = null; + } + } else { + this.currentSelected = null; + } + + if (this.currentSelected) { + if (state === "add" && state === "create" && (!className)) { + if (title) { + title = `Add ${title} entry`; + action = "Add"; + } + } else if (state === "select" && (!className)) { + if (services) { + parameters = services[index]; + title = `Edit ${title} entry`; + } + if (!action) { + action = "Change"; + } + } else if (state === "delete") { + editor = null; + title = `Remove ${title} entry`; + action = "Delete"; + } + if (!actionDef) { + actionDef = action; + } + if (editor) { + this.paramFields = {}; + editor(title, action, actionDef, parameters, (input, ref) => { + if (this.paramFields) { + this.paramFields[ref] = input; + } + }, this.onEditAction, content, className); + } else if (state === "delete" && couldDelete) { + DialogManager.open({ + title, + content: "Do you want to delete it ?", + actions: ["Delete", "Cancel"], + onAction: this.onEditAction, + className, + }); + } + console.log("WIP WebServicesContainer.onSelect", selected); + } + } + + getWebServices(all = false) { + const providers = this.props.pluginsManager.getPlugins({ type: "WebServices" }); + const services = []; + services.push({ + id: 1, name: "JSON WebService", icon: "images/robot2.svg", color: "green", + }); + let id = 2; + providers.forEach((p) => { + if (all || p.isActive()) { + services.push({ + id, name: p.getTitle(), icon: p.getIcon(), color: p.getColor(), provider: p, + }); + } + id += 1; + }); + return services; + } + + getMessagingProviders(all = false) { + const providers = this.props.pluginsManager.getPlugins({ type: "MessengerConnector" }); + const messagings = []; + let id = 1; + providers.forEach((p) => { + if (all || p.isActive()) { + messagings.push({ + id, name: p.getTitle(), icon: p.getIcon(), color: p.getColor(), provider: p, + }); + } + id += 1; + }); + return messagings; + } + + getAIProviders(all = false) { + const providers = this.props.pluginsManager.getPlugins({ type: "AIProvider" }); + const ais = []; + let id = 1; + providers.forEach((p) => { + if (all || p.isActive()) { + ais.push({ + id, name: p.getTitle(), icon: p.getIcon(), status: "start", provider: p, + }); + } + id += 1; + }); + return ais; + } + + getMiddlewares(type) { + const list = []; + if (this.props.middlewares) { + // TODO + this.props.middlewares.forEach((m) => { + if (m.type === type) { + list.push({ ...m }); + } + }); + } + return list; + } + + updateServices() { + if (!this.props.isSignedIn) { + if (!this.state.needUpdate) { + this.setState({ needUpdate: true }); + } + return; + } + if (this.props.selectedBotId && this.state.needUpdate) { + this.setState({ needUpdate: false }); + this.props.apiGetMiddlewaresRequest(this.props.selectedBotId); + } + } + + render() { + const webservices = this.getMiddlewares("WebService"); + // WIP : need to get from backend which provider is activated/running + const messagings = this.getMiddlewares("MessengerConnector"); // this.getMessagingProviders(); + const ais = this.getMiddlewares("AIProvider"); // this.getAIProviders(); + + return ( +
    + + + + + + + + + +
    + ); + } +} + +ServicesContainer.defaultProps = { + isSignedIn: true, + selectedBotId: null, + middlewares: null, +}; + +ServicesContainer.propTypes = { + isSignedIn: PropTypes.bool, + selectedBotId: PropTypes.string, + middlewares: PropTypes.arrayOf(PropTypes.shape({})), + apiGetMiddlewaresRequest: PropTypes.func.isRequired, + apiSetMiddlewareRequest: PropTypes.func.isRequired, + apiDeleteMiddlewareRequest: PropTypes.func.isRequired, + pluginsManager: PropTypes.shape({ getPlugins: PropTypes.func }).isRequired, +}; + +const mapStateToProps = (state) => { + const middlewares = state.app ? state.app.middlewares : null; + const selectedBotId = state.app ? state.app.selectedBotId : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + return { middlewares, selectedBotId, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + apiGetMiddlewaresRequest: (botId) => { + dispatch(apiGetMiddlewaresRequest(botId)); + }, + apiSetMiddlewareRequest: (botId, middleware) => { + dispatch(apiSetMiddlewareRequest(botId, middleware)); + }, + apiDeleteMiddlewareRequest: (botId, middleware) => { + dispatch(apiDeleteMiddlewareRequest(botId, middleware.id)); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ServicesContainer); diff --git a/src/shared/containers/signInDialog.jsx b/src/shared/containers/signInDialog.jsx new file mode 100644 index 00000000..5d46a339 --- /dev/null +++ b/src/shared/containers/signInDialog.jsx @@ -0,0 +1,99 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, DialogTitle, DialogContent, DialogActions, Textfield } from "react-mdl"; +import { connect } from "react-redux"; +import { DialogBox } from "zoapp-ui"; +import { signIn } from "../actions/signIn"; + +class SignInDialog extends Component { + constructor(props) { + super(props); + const { open } = props; + this.state = { openDialog: open, id: props.id }; + } + + componentWillReceiveProps(props) { + if (this.props.open !== props.open) { + this.setState({ openDialog: props.open }); + } + } + + handleOpenDialog = () => { + this.setState({ + openDialog: true, + }); + } + + handleCloseDialog = () => { + this.setState({ + openDialog: false, + }); + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } + } + + handleSignIn = () => { + const username = this.usernameField.inputRef.value; + const password = this.passwordField.inputRef.value; + if (username !== "" && password !== "") { + const { provider, dispatch } = this.props; + dispatch(signIn({ provider, username, password })); + this.handleCloseDialog(); + } + } + + render() { + return ( + + Your credentials + +
    + { this.usernameField = input; }} + /> + { this.passwordField = input; }} + /> + +
    + + + + +
    + ); + } +} + +SignInDialog.defaultProps = { + open: true, + id: null, + onClosed: null, + provider: null, +}; + +SignInDialog.propTypes = { + open: PropTypes.bool, + id: PropTypes.string, + onClosed: PropTypes.func, + provider: PropTypes.string, + dispatch: PropTypes.func.isRequired, +}; + +export default connect()(SignInDialog); diff --git a/src/shared/containers/signInForm.jsx b/src/shared/containers/signInForm.jsx new file mode 100644 index 00000000..c70455ef --- /dev/null +++ b/src/shared/containers/signInForm.jsx @@ -0,0 +1,68 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, Card, CardTitle, CardText, CardActions, Textfield } from "react-mdl"; +import { connect } from "react-redux"; +import { signIn } from "../actions/signIn"; + +class SignInForm extends Component { + handleCloseDialog = () => { + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } + } + + handleSignIn = () => { + const username = this.usernameField.inputRef.value; + const password = this.passwordField.inputRef.value; + if (username !== "" && password !== "") { + const { provider, dispatch } = this.props; + dispatch(signIn({ provider, username, password })); + this.handleCloseDialog(); + } + } + + render() { + return ( + + Your credentials + +
    + { this.usernameField = input; }} + />
    + { this.passwordField = input; }} + /> + +
    + + + +
    + ); + } +} + +SignInForm.propTypes = { + onClosed: PropTypes.func, + provider: PropTypes.string, + dispatch: PropTypes.func.isRequired, +}; + +SignInForm.defaultProps = { + onClosed: null, + provider: null, +}; + +export default connect()(SignInForm); diff --git a/src/shared/containers/signOutDialog.jsx b/src/shared/containers/signOutDialog.jsx new file mode 100644 index 00000000..77b59400 --- /dev/null +++ b/src/shared/containers/signOutDialog.jsx @@ -0,0 +1,77 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, DialogTitle, DialogContent, DialogActions } from "react-mdl"; +import { connect } from "react-redux"; +import { DialogBox } from "zoapp-ui"; +import { signOut } from "../actions/signOut"; + +class SignOutDialog extends Component { + constructor(props) { + super(props); + const { open } = props; + this.state = { openDialog: open, id: props.id }; + } + + componentWillReceiveProps(props) { + if (this.props.open !== props.open) { + this.setState({ openDialog: props.open }); + } + } + + handleOpenDialog = () => { + this.setState({ + openDialog: true, + }); + } + + handleCloseDialog = () => { + this.setState({ + openDialog: false, + }); + if (this.props.onClosed instanceof Function) { + this.props.onClosed(); + } + } + + handleSignOut = () => { + const { provider, dispatch } = this.props; + dispatch(signOut({ provider })); + this.handleCloseDialog(); + } + + render() { + return ( + + Sign out + +
    Are you ok ?
    +
    + + + + +
    + ); + } +} + +SignOutDialog.defaultProps = { + open: true, + id: null, + onClosed: null, + provider: null, +}; + +SignOutDialog.propTypes = { + open: PropTypes.bool, + id: PropTypes.string, + onClosed: PropTypes.func, + provider: PropTypes.string, + dispatch: PropTypes.func.isRequired, +}; + +export default connect()(SignOutDialog); diff --git a/src/shared/containers/userBox.jsx b/src/shared/containers/userBox.jsx new file mode 100644 index 00000000..accbf1a2 --- /dev/null +++ b/src/shared/containers/userBox.jsx @@ -0,0 +1,92 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import { Button, IconButton, Menu, MenuItem } from "react-mdl"; +import { connect } from "react-redux"; +import { DialogManager } from "zoapp-ui"; +import { apiUserProfileRequest } from "../actions/user"; +import SignInDialog from "./signInDialog"; +import SignOutDialog from "./signOutDialog"; + +class UserBox extends Component { + componentDidUpdate() { + if ((!this.props.profile) && this.props.isSignedIn) { + this.props.apiUserProfileRequest(); + } + } + + handleOpenSignInDialog = () => { + const dialog = ; + setTimeout(() => { DialogManager.open({ dialog }); }, 100); + } + + handleOpenSignOutDialog = () => { + const dialog = (); + setTimeout(() => { DialogManager.open({ dialog }); }, 100); + } + + handleCloseDialog = () => { + setTimeout(() => { DialogManager.close(); }, 100); + } + + render() { + if (this.props.isSignedIn) { + const username = this.props.profile ? this.props.profile.username : ""; + const avatarClass = this.props.profile ? `${this.props.profile.avatar}-icon` : ""; + let avatar = this.props.profile ? this.props.profile.avatar : null; + if ((!avatar) || avatar === "default") { + avatar = "account_circle"; + } + return ( +
    {username} + + + Profile + Settings + { e.preventDefault(); this.handleOpenSignOutDialog(); }}> + Sign out + + +
    ); + } + return ( +
    + + + + Recover password + Sign up + Help + +
    ); + } +} + +UserBox.propTypes = { + store: PropTypes.shape({}).isRequired, + profile: PropTypes.shape({ username: PropTypes.string, avatar: PropTypes.string }), + isSignedIn: PropTypes.bool, + apiUserProfileRequest: PropTypes.func.isRequired, + style: PropTypes.objectOf(PropTypes.string), +}; + +UserBox.defaultProps = { profile: null, isSignedIn: false, style: null }; + +const mapStateToProps = (state) => { + const profile = state.user ? state.user.profile : null; + const isSignedIn = state.user ? state.user.isSignedIn : false; + return { profile, isSignedIn }; +}; + +const mapDispatchToProps = dispatch => ({ + apiUserProfileRequest: () => { + dispatch(apiUserProfileRequest()); + }, +}); + +export default connect(mapStateToProps, mapDispatchToProps)(UserBox); diff --git a/src/shared/reducers/app.js b/src/shared/reducers/app.js new file mode 100644 index 00000000..d0f93e34 --- /dev/null +++ b/src/shared/reducers/app.js @@ -0,0 +1,538 @@ +import { createReducer } from "./"; +import { + APP_SETTITLE, APP_UPDATEPUBLISHER, + APP_SELECTINTENT, APP_UPDATEINTENT, APP_SETINTENTACTION, APP_DELETEINTENTACTION, + API_ADMIN, API_CREATEBOT, API_SAVEBOT, API_IMPORT, API_PUBLISH, + API_GETINTENTS, API_SENDINTENT, API_DELETEINTENT, API_MOVEINTENT, + API_SETADMINPARAMETERS, + API_GETMIDDLEWARES, API_SETMIDDLEWARE, API_DELETEMIDDLEWARE, + API_SB_GETMESSAGES, API_SB_SENDMESSAGE, API_SB_GETCONTEXT, API_SB_RESET, + AUTH_SIGNOUT, + FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE, +} from "../actions/constants"; + +const initialState = { + loading: false, + admin: null, + intents: null, + selectedBotId: null, + selectedIntentIndex: 0, + sandbox: null, + loadingMessages: false, + titleName: "", + error: null, +}; + +export default createReducer(initialState, { + [API_ADMIN + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_ADMIN + FETCH_SUCCESS]: (state, { admin }) => { + let { selectedBotId } = state; + if (selectedBotId == null && admin.bots && admin.bots.length > 0) { + selectedBotId = admin.bots[0].id; + } + return { + ...state, loading: false, error: null, admin: { ...admin }, selectedBotId, + }; + }, + [API_ADMIN + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_SETADMINPARAMETERS + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_SETADMINPARAMETERS + FETCH_SUCCESS]: (state, { params }) => { + const admin = { ...state.admin }; + admin.params = { ...params }; + return { + ...state, loading: false, error: null, admin, + }; + }, + [API_SETADMINPARAMETERS + FETCH_FAILURE]: (state, { error }) => ({ + ...state, + loading: false, + error, + }), + + [API_GETMIDDLEWARES + FETCH_REQUEST]: state => ({ + ...state, + loading: true, + error: null, + lastMiddleware: null, + }), + [API_GETMIDDLEWARES + FETCH_SUCCESS]: (state, { middlewares }) => ({ + ...state, + loading: false, + error: null, + middlewares: [...middlewares], + }), + [API_GETMIDDLEWARES + FETCH_FAILURE]: (state, { error }) => ({ + ...state, + loading: false, + error, + }), + + [API_SETMIDDLEWARE + FETCH_REQUEST]: state => ({ + ...state, + loading: true, + error: null, + lastMiddleware: null, + }), + [API_SETMIDDLEWARE + FETCH_SUCCESS]: (state, { middleware }) => { + const middlewares = []; + let v = true; + state.middlewares.forEach((m) => { + if (m.id === middleware.id) { + middlewares.push({ ...middleware }); + v = false; + } else { + middlewares.push(m); + } + }); + if (v) { + middlewares.push({ ...middleware }); + } + return { + ...state, + loading: false, + error: null, + middlewares, + lastMiddleware: { ...middleware }, + }; + }, + [API_SETMIDDLEWARE + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_DELETEMIDDLEWARE + FETCH_REQUEST]: state => ({ + ...state, + loading: true, + error: null, + lastMiddleware: null, + }), + [API_DELETEMIDDLEWARE + FETCH_SUCCESS]: (state, { middlewareId }) => { + const middlewares = []; + state.middlewares.forEach((m) => { + if (m.id !== middlewareId) { + middlewares.push(m); + } + }); + return { + ...state, loading: false, error: null, middlewares, + }; + }, + [API_DELETEMIDDLEWARE + FETCH_FAILURE]: (state, { error }) => ({ + ...state, + loading: false, + error, + }), + [API_CREATEBOT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_CREATEBOT + FETCH_SUCCESS]: (state, { bot }) => { + const { error } = bot; + let { selectedBotId } = state; + let admin = null; + if (state.admin != null) { + admin = { ...state.admin }; + } + if (error) { + // error = bot.error; + } else if (admin != null) { + selectedBotId = bot.id; + const bots = []; + if (admin.bots) { + admin.bots.forEach((b) => { + if (b.id === selectedBotId) { + bots.push({ ...bot }); + } else { + bots.push(b); + } + }); + } else { + bots.push({ ...bot }); + } + bots.push({ ...bot }); + admin.bots = bots; + } + return { + ...state, loading: false, error, admin, selectedBotId, + }; + }, + [API_CREATEBOT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_SAVEBOT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_SAVEBOT + FETCH_SUCCESS]: (state, { bot }) => { + const { error } = bot; + let admin = null; + if (state.admin != null) { + admin = { ...state.admin }; + } + if (error) { + // error = bot.error; + } else if (admin != null) { + const botId = bot.id; + const bots = []; + if (admin.bots) { + admin.bots.forEach((b) => { + if (b.id === botId) { + bots.push({ ...bot }); + } else { + bots.push({ ...b }); + } + }); + } else { + bots.push({ ...bot }); + } + admin.bots = bots; + } + return { + ...state, loading: false, error, admin, + }; + }, + [API_SAVEBOT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_IMPORT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_IMPORT + FETCH_SUCCESS]: (state, { result }) => { + let { intents, selectedIntentIndex, selectedIntent } = state; + if (result.intents) { + intents = [...result.intents]; + if (selectedIntentIndex >= intents.length) { + selectedIntentIndex = 0; + } + if (intents && ((!selectedIntent) || (!selectedIntent.notSaved))) { + selectedIntent = { ...(intents[selectedIntentIndex]) }; + } else if ((!selectedIntent) && (!selectedIntent.notSaved)) { + selectedIntent = null; + } else { + // TODO handle conflicts + } + } + return { + ...state, loading: false, error: null, intents, selectedIntentIndex, selectedIntent, + }; + }, + [API_IMPORT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_PUBLISH + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_PUBLISH + FETCH_SUCCESS]: (state, { result }) => { + let { intents, selectedIntentIndex, selectedIntent } = state; + if (result.intents) { + intents = [...result.intents]; + if (selectedIntentIndex >= intents.length) { + selectedIntentIndex = 0; + } + if (intents && ((!selectedIntent) || (!selectedIntent.notSaved))) { + selectedIntent = { ...(intents[selectedIntentIndex]) }; + } else if ((!selectedIntent) && (!selectedIntent.notSaved)) { + selectedIntent = null; + } else { + // TODO handle conflicts + } + } + return { + ...state, loading: false, error: null, intents, selectedIntentIndex, selectedIntent, + }; + }, + [API_PUBLISH + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_GETINTENTS + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_GETINTENTS + FETCH_SUCCESS]: (state, { intents }) => { + let { selectedIntent, selectedIntentIndex } = state; + if (selectedIntentIndex >= intents.length) { + selectedIntentIndex = 0; + } + if (intents && ((!selectedIntent) || (!selectedIntent.notSaved))) { + selectedIntent = { ...(intents[selectedIntentIndex]) }; + } else if ((!selectedIntent) && (!selectedIntent.notSaved)) { + selectedIntent = null; + } else { + // TODO handle conflicts + } + return { + ...state, + loading: false, + error: null, + intents: [...intents], + selectedIntentIndex, + selectedIntent, + }; + }, + [API_GETINTENTS + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_SENDINTENT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_SENDINTENT + FETCH_SUCCESS]: (state, { data }) => { + // WIP search for intent in intents and add replace it + let { intents, selectedIntent, selectedIntentIndex } = state; + let remoteIntents = null; + if (data.intents) { + if (Array.isArray(data.intents)) { + remoteIntents = data.intents; + } + } else { + remoteIntents = []; + remoteIntents.push(data); + } + if (remoteIntents) { + remoteIntents.forEach((intent) => { + let previousIntent = null; + let previousIntentIndex = -1; + for (let i = 0; i < intents.length; i += 1) { + const int = intents[i]; + if (!int.id) { + if (int.name === intent.name) { + int.id = intent.id; + previousIntent = { ...int }; + previousIntentIndex = i; + break; + } + } else if (int.id === intent.id) { + int.name = intent.name; + if (intent.input) { + int.input = [...intent.input]; + } else { + int.input = null; + } + if (intent.output) { + int.output = [...intent.output]; + } else { + int.output = null; + } + previousIntent = { ...int }; + previousIntentIndex = i; + break; + } + } + + if (previousIntent) { + intents = [...state.intents]; + if (previousIntent.notSaved) { + delete previousIntent.notSaved; + } + intents[previousIntentIndex] = previousIntent; + + + if (selectedIntent && selectedIntent.id === intent.id) { + // WIP Compare input & output arrays + selectedIntent = { ...intent }; + } + } else { + intents.push({ ...intent }); + selectedIntentIndex = intents.length - 1; + selectedIntent = { ...intent }; + } + }); + } + return { + ...state, loading: false, error: null, intents, selectedIntentIndex, selectedIntent, + }; + }, + [API_SENDINTENT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_DELETEINTENT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_DELETEINTENT + FETCH_SUCCESS]: (state, { intent }) => { + // WIP search for intentId in intents and remove it + const intents = [...state.intents]; + let { selectedIntent, selectedIntentIndex } = state; + for (let i = 0; i < intents.length; i += 1) { + if (intents[i].id === intent.id) { + intents.splice(i, 1); + if (selectedIntentIndex === i) { + selectedIntentIndex = i - 1; + if (selectedIntentIndex < 0) { + selectedIntentIndex = 0; + } + if (intents && selectedIntentIndex < intents.length) { + selectedIntent = { ...(intents[selectedIntentIndex]) }; + } else { + selectedIntent = null; + } + } + break; + } + } + return { + ...state, loading: false, error: null, intents, selectedIntentIndex, selectedIntent, + }; + }, + [API_DELETEINTENT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_MOVEINTENT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_MOVEINTENT + FETCH_SUCCESS]: (state, { response }) => { + // TODO move intent + const { toIndex, fromIndex } = response; + const intents = [...state.intents]; + intents.splice(toIndex, 0, intents.splice(fromIndex, 1)[0]); + const selectedIntentIndex = toIndex; + const selectedIntent = intents[toIndex]; + return { + ...state, loading: false, error: null, intents, selectedIntentIndex, selectedIntent, + }; + }, + [API_MOVEINTENT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + /* API Sandbox section */ + [API_SB_GETMESSAGES + FETCH_REQUEST]: state => ({ + ...state, + loadingMessages: true, + error: null, + }), + [API_SB_GETMESSAGES + FETCH_SUCCESS]: (state, { conversations }) => { + // WIP, TODO check if BotId is ok + let { sandbox } = state; + if (sandbox === null) { + sandbox = {}; + } + if (conversations) { + sandbox.conversations = [...conversations]; + } else { + sandbox.conversations = []; + } + return { + ...state, loadingMessages: false, error: null, sandbox, + }; + }, + [API_SB_GETMESSAGES + FETCH_FAILURE]: (state, { error }) => ({ + ...state, + loadingMessages: false, + error, + }), + + [API_SB_SENDMESSAGE + FETCH_REQUEST]: state => ({ + ...state, + loadingMessages: true, + error: null, + }), + [API_SB_SENDMESSAGE + FETCH_SUCCESS]: (state) => { + // TODO , { conversationId, message } + const { sandbox } = state; + // sandbox.conversations = [...conversations]; + return { + ...state, loadingMessages: false, error: null, sandbox, + }; + }, + [API_SB_SENDMESSAGE + FETCH_FAILURE]: (state, { error }) => ({ + ...state, + loadingMessages: false, + error, + }), + + [API_SB_GETCONTEXT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_SB_GETCONTEXT + FETCH_SUCCESS]: (state, { context }) => { + // TODO check if BotId is ok + const { sandbox } = state; + sandbox.context = [...context]; + return { + ...state, loading: false, error: null, sandbox, + }; + }, + [API_SB_GETCONTEXT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + [API_SB_RESET + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_SB_RESET + FETCH_SUCCESS]: (state) => { + // TODO check if BotId is ok + const sandbox = { conversations: [] }; + return { + ...state, loading: false, error: null, sandbox, + }; + }, + [API_SB_RESET + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), + + /* APP Section */ + [APP_SETTITLE]: (state, { titleName }) => ({ ...state, titleName }), + [APP_SELECTINTENT]: (state, { selectedBotId, selectedIntentIndex }) => { + let selectedIntent = null; + if (state.intents && selectedIntentIndex < state.intents.length) { + selectedIntent = { ...(state.intents[selectedIntentIndex]) }; + } + return { + ...state, selectedBotId, selectedIntentIndex, selectedIntent, + }; + }, + [APP_UPDATEPUBLISHER]: (state, { selectedBotId, publisher }) => { + const publishers = { ...state.publishers }; + if (state.selectedBotId === selectedBotId) { + const { name } = publisher; + publishers[name] = { ...publisher }; + } + return { ...state, publishers }; + }, + [APP_UPDATEINTENT]: (state, { selectedBotId, intent }) => { + const selectedIntentIndex = + state.selectedIntentIndex !== undefined ? state.selectedIntentIndex : 0; + const intents = [...state.intents]; + let selectedIntent = null; + if (intents.length > 0 && selectedIntentIndex < intents.length) { + selectedIntent = { ...intent }; + intents[selectedIntentIndex] = selectedIntent; + selectedIntent.notSaved = true; + } + return { + ...state, selectedBotId, intents, selectedIntentIndex, selectedIntent, + }; + }, + [APP_SETINTENTACTION]: (state, { + actionContainer, actionType, actionValue, selectedAction, + }) => { + const intents = [...state.intents]; + const selectedIntentIndex = + state.selectedIntentIndex !== undefined ? state.selectedIntentIndex : 0; + const intent = intents[selectedIntentIndex]; + if (!intent[actionContainer]) { + intent[actionContainer] = []; + } + const actions = intent[actionContainer]; + + if (selectedAction === undefined) { + if (actionType === "condition") { + // WIP handle Condition type + let condition; + if (actions.length === 0) { + condition = { type: actionType, children: [] }; + actions.push(condition); + } else { + [condition] = actions; + } + condition.children.push(actionValue); + } else { + actions.push(actionValue); + } + } else if (actionType === "condition") { + // WIP handle Condition type + const condition = actions[0]; + condition.children.splice(selectedAction, 1, actionValue); + } else { + actions.splice(selectedAction, 1, actionValue); + } + intent.notSaved = true; + return { + ...state, + loading: false, + error: null, + intents, + selectedIntentIndex, + selectedIntent: { ...intent }, + }; + }, + [APP_DELETEINTENTACTION]: (state, { actionContainer, selectedAction }) => { + const intents = [...state.intents]; + const selectedIntentIndex = + state.selectedIntentIndex !== undefined ? state.selectedIntentIndex : 0; + const intent = intents[selectedIntentIndex]; + const actions = intent[actionContainer]; + // WIP handle Condition type + if (actions && actions.length > 0) { + if (typeof actions[0] === "string") { + actions.splice(selectedAction, 1); + } else if (actions[0].type === "condition") { + const { children } = actions[0]; + children.splice(selectedAction, 1); + if (children.length === 0) { + actions.splice(0, 1); + } + } + intent.notSaved = true; + } + return { + ...state, + loading: false, + error: null, + intents, + selectedIntentIndex, + selectedIntent: { ...intent }, + }; + }, + [AUTH_SIGNOUT + FETCH_SUCCESS]: () => ({ ...initialState }), +}); diff --git a/src/shared/reducers/auth.js b/src/shared/reducers/auth.js new file mode 100644 index 00000000..a17cb9bc --- /dev/null +++ b/src/shared/reducers/auth.js @@ -0,0 +1,58 @@ +import { createReducer } from "./"; +import { AUTH_SIGNIN, FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE, AUTH_SIGNOUT } from "../actions/constants"; + +const initialState = { + loading: false, + error: null, + username: null, + password: null, + provider: null, +}; + +export default createReducer(initialState, { + [AUTH_SIGNIN + FETCH_REQUEST]: (state, { provider, username, password }) => { + let newState; + if (provider) { + newState = { ...state, [provider]: { loading: false, error: null } }; + } else { + newState = { ...state, loading: false, error: null }; + } + return { + ...newState, username, password, provider, + }; + }, + [AUTH_SIGNIN + FETCH_SUCCESS]: (state, { provider }) => { + if (provider) { + return { + provider: { + loading: false, + error: null, + }, + }; + } + return { + loading: false, + error: null, + }; + }, + [AUTH_SIGNIN + FETCH_FAILURE]: (state, { provider, error }) => { + if (provider) { + return { + [provider]: { + loading: false, + error, + }, + }; + } + return { + loading: false, + error, + }; + }, + [AUTH_SIGNOUT + FETCH_SUCCESS]: () => ({ ...initialState }), + [AUTH_SIGNOUT + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + + [AUTH_SIGNOUT + FETCH_SUCCESS]: () => ({ ...initialState }), + + [AUTH_SIGNOUT + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), +}); diff --git a/src/shared/reducers/index.js b/src/shared/reducers/index.js new file mode 100644 index 00000000..ee4d4e5a --- /dev/null +++ b/src/shared/reducers/index.js @@ -0,0 +1,40 @@ +import { combineReducers } from "redux"; + +import initialize from "./initialize"; +import auth from "./auth"; +import user from "./user"; +import app from "./app"; + +const reducer = combineReducers({ + initialize, + auth, + user, + app, +}); + +export default (state = {}, action) => reducer(state, action); + +/* +http://redux.js.org/docs/recipes/ReducingBoilerplate.html +Modified for ESlint and ES6 +*/ + +/* +Why this code isn't working ? +const createReducer = (initialState, handlers) => (state = initialState, action) => { + if (Object.prototype.hasOwnProperty.call(handlers, action.type)) { + return handlers[action.type](state, action); + } + return state; +}; +export { createReducer }; */ + + +export function createReducer(initialState, handlers) { + return (state = initialState, action) => { + if (Object.prototype.hasOwnProperty.call(handlers, action.type)) { + return handlers[action.type](state, action); + } + return state; + }; +} diff --git a/src/shared/reducers/initialize.js b/src/shared/reducers/initialize.js new file mode 100644 index 00000000..ded30738 --- /dev/null +++ b/src/shared/reducers/initialize.js @@ -0,0 +1,7 @@ +import { createReducer } from "./"; +import { AUTH_INIT_SETTINGS } from "../actions/constants"; + +const initialState = {}; +export default createReducer(initialState, { + [AUTH_INIT_SETTINGS]: (state, { config }) => ({ ...config }), +}); diff --git a/src/shared/reducers/user.js b/src/shared/reducers/user.js new file mode 100644 index 00000000..5ce9a890 --- /dev/null +++ b/src/shared/reducers/user.js @@ -0,0 +1,29 @@ +import { createReducer } from "./"; + +/* import { AUTHENTICATE_COMPLETE, AUTHENTICATE_ERROR } from "actions/authenticate"; */ +import { AUTH_SIGNIN, API_USERPROFILE, FETCH_SUCCESS, FETCH_REQUEST, FETCH_FAILURE, AUTH_SIGNOUT } from "../actions/constants"; + +const initialState = { + attributes: null, + isSignedIn: false, + loading: false, + error: null, +}; + +export default createReducer(initialState, { + [AUTH_SIGNIN + FETCH_SUCCESS]: (state, { attributes }) => ({ + attributes, + isSignedIn: true, + loading: false, + error: null, + }), + [AUTH_SIGNOUT + FETCH_SUCCESS]: () => ({ ...initialState }), + [API_USERPROFILE + FETCH_REQUEST]: state => ({ ...state, loading: true, error: null }), + [API_USERPROFILE + FETCH_SUCCESS]: (state, { profile }) => ({ + ...state, + loading: false, + error: null, + profile: { ...profile }, + }), + [API_USERPROFILE + FETCH_FAILURE]: (state, { error }) => ({ ...state, loading: false, error }), +}); diff --git a/src/shared/sagas/api.js b/src/shared/sagas/api.js new file mode 100644 index 00000000..06a7f435 --- /dev/null +++ b/src/shared/sagas/api.js @@ -0,0 +1,329 @@ +import { delay, eventChannel } from "redux-saga"; +import { put, race, call, take, fork } from "redux-saga/effects"; +import { + API_USERPROFILE, API_ADMIN, API_GETINTENTS, API_SENDINTENT, API_DELETEINTENT, API_MOVEINTENT, + API_SETADMINPARAMETERS, + API_GETMIDDLEWARES, API_SETMIDDLEWARE, API_DELETEMIDDLEWARE, + API_SB_GETMESSAGES, API_SB_SENDMESSAGE, API_SB_GETCONTEXT, API_SB_RESET, + API_CREATEBOT, API_SAVEBOT, API_IMPORT, API_PUBLISH, + SUBSCRIBE, UNSUBSCRIBE, + FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE, +} from "../actions/constants"; +import { webService, createSocketService } from "./services"; + +function* getSandboxMessages(action) { + const { botId } = action; + try { + const response = yield webService.get(`bots/${botId}/sandbox/messages`); + yield put({ type: `${API_SB_GETMESSAGES}${FETCH_SUCCESS}`, loading: false, conversations: response }); + } catch (error) { + yield put({ type: `${API_SB_GETMESSAGES}${FETCH_FAILURE}`, error }); + } +} + +let subscribedSandboxMessages = false; + +function* pollSandboxMessages(action) { + if (subscribedSandboxMessages) return; + subscribedSandboxMessages = true; + while (subscribedSandboxMessages) { + try { + yield call(getSandboxMessages, action); + // TODO put the delay value in a constant + yield call(delay, 10000); + } catch (error) { + return; + } + } +} + +function subscribe(socketClient, action) { + return eventChannel((emitter) => { + socketClient.on("connected", () => { + const { botId } = action; + console.log(`WebSocket connected: ${botId}`); + const payload = JSON.stringify({ event: "subscribe", channelId: botId }); + socketClient.send(payload); + }); + socketClient.on("newMessages", (data) => { + console.log(`WebSocket newMessages: ${data}`); + emitter({ type: `${API_SB_GETMESSAGES}${FETCH_SUCCESS}`, loading: false, conversations: data }); + }); + socketClient.on("error", (error) => { + // TODO: handle error + console.log(`WebSocket error: ${error}`); + }); + socketClient.on("close", () => { + // TODO: handle close + console.log("WebSocket close"); + }); + return () => { + console.log("WebSocket off"); + }; + }); +} + + +function* subscribeSandboxMessages(action) { + const socketClient = createSocketService("bots/sandbox/messages"); + if (socketClient) { + yield socketClient.start(); + const channel = yield call(subscribe, socketClient, action); + if (subscribedSandboxMessages) return; + subscribedSandboxMessages = true; + while (subscribedSandboxMessages) { + const a = yield take(channel); + yield put(a); + } + yield socketClient.send("unsubscribe"); + yield socketClient.close(); + + return; + } + pollSandboxMessages(action); +} + +const api = [ +/* User */ + [API_USERPROFILE + FETCH_REQUEST, + function* f() { + try { + const response = yield webService.get("me"); + yield put({ type: `${API_USERPROFILE}${FETCH_SUCCESS}`, loading: false, profile: response }); + } catch (error) { + yield put({ type: `${API_USERPROFILE}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Admin */ + [API_ADMIN + FETCH_REQUEST, + function* f() { + try { + const response = yield webService.get("admin"); + yield put({ type: `${API_ADMIN}${FETCH_SUCCESS}`, loading: false, admin: response }); + } catch (error) { + yield put({ type: `${API_ADMIN}${FETCH_FAILURE}`, error }); + } + }, + ], + [API_SETADMINPARAMETERS + FETCH_REQUEST, + function* f(action) { + try { + const { params } = action; + const response = yield webService.put("admin", params); + yield put({ type: `${API_SETADMINPARAMETERS}${FETCH_SUCCESS}`, loading: false, params: response }); + } catch (error) { + yield put({ type: `${API_SETADMINPARAMETERS}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Create bot */ + [API_CREATEBOT + FETCH_REQUEST, + function* f(action) { + const { botParams } = action; + try { + const response = yield webService.post("bots", botParams, false); + yield put({ type: `${API_CREATEBOT}${FETCH_SUCCESS}`, loading: false, bot: response }); + } catch (error) { + yield put({ type: `${API_CREATEBOT}${FETCH_FAILURE}`, error }); + } + }, + ], + [API_SAVEBOT + FETCH_REQUEST, + function* f(action) { + const { botParams } = action; + const botId = botParams.id; + try { + const response = yield webService.put(`bots/${botId}`, botParams, false); + yield put({ type: `${API_SAVEBOT}${FETCH_SUCCESS}`, loading: false, bot: response }); + } catch (error) { + yield put({ type: `${API_SAVEBOT}${FETCH_FAILURE}`, error }); + } + }, + ], + [API_IMPORT + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + const params = { data: action.data, options: action.options }; + try { + const response = yield webService.post(`bots/${botId}/import`, params, false); + yield put({ type: `${API_IMPORT}${FETCH_SUCCESS}`, loading: false, result: response }); + } catch (error) { + yield put({ type: `${API_IMPORT}${FETCH_FAILURE}`, error }); + } + }, + ], + [API_PUBLISH + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + const params = { from: action.from, to: action.to, channels: action.channels }; + try { + const response = yield webService.post(`bots/${botId}/publish`, params, false); + yield put({ type: `${API_PUBLISH}${FETCH_SUCCESS}`, loading: false, result: response }); + } catch (error) { + yield put({ type: `${API_PUBLISH}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Intents */ + [API_GETINTENTS + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + try { + const response = yield webService.get(`bots/${botId}/intents`); + yield put({ type: `${API_GETINTENTS}${FETCH_SUCCESS}`, loading: false, intents: response.intents }); + } catch (error) { + yield put({ type: `${API_GETINTENTS}${FETCH_FAILURE}`, error }); + } + }, + ], + + [API_SENDINTENT + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + const { intent } = action; + try { + let response; + if (intent.id) { + response = yield webService.put(`bots/${botId}/intents`, intent); + } else { + response = yield webService.post(`bots/${botId}/intents`, intent); + } + yield put({ type: `${API_SENDINTENT}${FETCH_SUCCESS}`, loading: false, data: response }); + } catch (error) { + yield put({ type: `${API_SENDINTENT}${FETCH_FAILURE}`, error }); + } + }, + ], + + [API_MOVEINTENT + FETCH_REQUEST, + function* f(action) { + const { + botId, intentId, from, to, + } = action; + const data = { + botId, intentId, from, to, + }; + try { + const response = yield webService.put(`bots/${botId}/intents/${intentId}/move`, data); + yield put({ type: `${API_MOVEINTENT}${FETCH_SUCCESS}`, loading: false, response }); + } catch (error) { + yield put({ type: `${API_MOVEINTENT}${FETCH_FAILURE}`, error }); + } + }, + ], + + [API_DELETEINTENT + FETCH_REQUEST, + function* f(action) { + const { botId, intent } = action; + try { + const response = yield webService.delete(`bots/${botId}/intents/${intent.id}`); + yield put({ type: `${API_DELETEINTENT}${FETCH_SUCCESS}`, loading: false, intent: response }); + } catch (error) { + yield put({ type: `${API_DELETEINTENT}${FETCH_FAILURE}`, error }); + } + }, + ], + + /* Sandbox */ + [API_SB_GETMESSAGES + SUBSCRIBE, + function* f(action) { + yield race([ + fork(subscribeSandboxMessages, action), + take(API_SB_GETMESSAGES + UNSUBSCRIBE), + ]); + }, + ], + [API_SB_GETMESSAGES + UNSUBSCRIBE, + function* f() { + yield subscribedSandboxMessages = false; + }, + ], + [API_SB_GETMESSAGES + FETCH_REQUEST, + getSandboxMessages, + ], + + [API_SB_SENDMESSAGE + FETCH_REQUEST, + function* f(action) { + const { botId, conversationId, message } = action; + try { + const response = yield webService.post(`bots/${botId}/sandbox/messages/${conversationId}`, message); + yield put({ + type: `${API_SB_SENDMESSAGE}${FETCH_SUCCESS}`, loading: false, conversationId, message: response, + }); + } catch (error) { + yield put({ type: `${API_SB_SENDMESSAGE}${FETCH_FAILURE}`, error }); + } + }, + ], + + [API_SB_GETCONTEXT + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + try { + const response = yield webService.get(`bots/${botId}/sandbox/context`); + yield put({ type: `${API_SB_GETCONTEXT}${FETCH_SUCCESS}`, loading: false, context: response }); + } catch (error) { + yield put({ type: `${API_SB_GETCONTEXT}${FETCH_FAILURE}`, error }); + } + }, + ], + + [API_SB_RESET + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + try { + const response = yield webService.delete(`bots/${botId}/sandbox`); + yield put({ type: `${API_SB_RESET}${FETCH_SUCCESS}`, loading: false, result: response }); + } catch (error) { + yield put({ type: `${API_SB_RESET}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Get middlewares */ + [API_GETMIDDLEWARES + FETCH_REQUEST, + function* f(action) { + const { botId } = action; + let url = `middlewares/${botId}`; + if (action.middlewareType) { + url += `?type=${action.middlewareType}`; + } + try { + const middlewares = yield webService.get(url); + yield put({ type: `${API_GETMIDDLEWARES}${FETCH_SUCCESS}`, loading: false, middlewares }); + } catch (error) { + yield put({ type: `${API_GETMIDDLEWARES}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Set middleware */ + [API_SETMIDDLEWARE + FETCH_REQUEST, + function* f(action) { + const { botId, middleware } = action; + try { + let response; + if (middleware.id) { + response = yield webService.put(`middlewares/${botId}`, middleware); + } else { + response = yield webService.post(`middlewares/${botId}`, middleware); + } + yield put({ type: `${API_SETMIDDLEWARE}${FETCH_SUCCESS}`, loading: false, middleware: response }); + } catch (error) { + yield put({ type: `${API_SETMIDDLEWARE}${FETCH_FAILURE}`, error }); + } + }, + ], + /* Delete middleware */ + [API_DELETEMIDDLEWARE + FETCH_REQUEST, + function* f(action) { + const { botId, middlewareId } = action; + try { + const response = yield webService.delete(`middlewares/${botId}/${middlewareId}`); + yield put({ type: `${API_DELETEMIDDLEWARE}${FETCH_SUCCESS}`, loading: false, middlewareId: response.id }); + } catch (error) { + yield put({ type: `${API_DELETEMIDDLEWARE}${FETCH_FAILURE}`, error }); + } + }, + ], +]; +export default api; diff --git a/src/shared/sagas/auth.js b/src/shared/sagas/auth.js new file mode 100644 index 00000000..0d173a3c --- /dev/null +++ b/src/shared/sagas/auth.js @@ -0,0 +1,64 @@ +import { put, take, race, call } from "redux-saga/effects"; +import { AuthService } from "zoapp-common"; +import { AUTH_INIT_SETTINGS, AUTH_SIGNIN, AUTH_SIGNOUT, FETCH_REQUEST, FETCH_SUCCESS, FETCH_FAILURE } from "../actions/constants"; +import { authService } from "./services"; + +function getAuthService(provider) { + let service = authService; + if (provider) { + service = new AuthService({ provider }); + } + return service; +} + +function* authenticate({ username, password, provider }) { + try { + const service = getAuthService(provider); + + const response = yield service.authenticateUser({ username, password }); + yield put({ type: `${AUTH_SIGNIN}${FETCH_SUCCESS}`, attributes: response, provider }); + } catch (error) { + yield put({ type: `${AUTH_SIGNIN}${FETCH_FAILURE}`, provider, error }); + } +} + +export function* authInit() { + const service = getAuthService(); + if (service.isAccessTokenValid()) { + const attributes = service.getAttributes(); + yield put({ type: `${AUTH_SIGNIN}${FETCH_SUCCESS}`, attributes }); + } +} + +export function* signOut(action) { + const { provider } = action; + try { + const service = getAuthService(provider); + yield service.resetAccess(); + yield put({ type: `${AUTH_SIGNOUT}${FETCH_SUCCESS}`, provider }); + } catch (error) { + yield put({ type: `${AUTH_SIGNOUT}${FETCH_FAILURE}`, provider, error: error.message }); + } +} + +export function* signIn(action) { + const { username, password, provider } = action; + const winner = yield race({ + auth: call(authenticate, { username, password, provider }), + signOut: take(AUTH_SIGNOUT), + }); + if (winner.auth) { + // yield put({ type: AUTH_SIGNIN, newAuthState: true }); + } else if (winner.signOut) { + // yield put({ type: AUTH_SIGNIN, newAuthState: false }); + yield call(signOut); + } +} + +const auth = [ + [AUTH_INIT_SETTINGS, authInit], + [AUTH_SIGNIN + FETCH_REQUEST, signIn], + [AUTH_SIGNOUT + FETCH_REQUEST, signOut], +]; + +export default auth; diff --git a/src/shared/sagas/index.js b/src/shared/sagas/index.js new file mode 100644 index 00000000..c219406f --- /dev/null +++ b/src/shared/sagas/index.js @@ -0,0 +1,16 @@ +import { takeEvery } from "redux-saga"; +import auth from "./auth"; +import api from "./api"; + +function takeAll(subRoot) { + const takeList = []; + subRoot.forEach((sub) => { + takeList.push(takeEvery(sub[0], sub[1])); + }); + return takeList; +} + +export default function* root() { + yield takeAll(auth); + yield takeAll(api); +} diff --git a/src/shared/sagas/services.js b/src/shared/sagas/services.js new file mode 100644 index 00000000..18b98c86 --- /dev/null +++ b/src/shared/sagas/services.js @@ -0,0 +1,12 @@ +import { WebService, AuthService, SocketService } from "zoapp-common"; +import { apiConfig, authConfig } from "../config"; + +export const authService = new AuthService(authConfig); + +export const webService = new WebService(apiConfig, authService); + +export function createSocketService(path) { + const url = webService.buildUrl(path, "ws"); + const socketService = new SocketService(url); + return socketService; +} diff --git a/src/shared/store.js b/src/shared/store.js new file mode 100644 index 00000000..4f49e9f0 --- /dev/null +++ b/src/shared/store.js @@ -0,0 +1,38 @@ +import { createStore, applyMiddleware, compose } from "redux"; +import createSagaMiddleware from "redux-saga"; +import reducers from "./reducers"; +import rootSaga from "./sagas"; + +/* global window */ +export default function configureStore(initialState = {}) { + const sagaMiddleware = createSagaMiddleware(); + /* eslint-disable no-underscore-dangle */ + const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; + const store = createStore( + reducers, initialState, + composeEnhancers(applyMiddleware(sagaMiddleware)), + ); + sagaMiddleware.run(rootSaga); + /* eslint-enable no-underscore-dangle */ + + /* global module */ + /* eslint-disable global-require */ + /* eslint-disable no-undef */ + if (module.hot) { + module.hot.accept("OplaLibs/reducers", () => { + console.log("HMR reducers"); + store.replaceReducer(require("./reducers").default); + }); + module.hot.accept("OplaLibs/sagas", () => { + console.log("HMR sagas TODO"); + // TODO reload Sagas + // @see https://gist.github.com/markerikson/dc6cee36b5b6f8d718f2e24a249e0491 + // SagaManager.cancelSagas(store); + // require("./sagas").default.startSagas(sagaMiddleware); + }); + } + /* eslint-enable no-undef */ + /* eslint-enable global-require */ + + return store; +} diff --git a/src/shared/utils/actionsTools.js b/src/shared/utils/actionsTools.js new file mode 100644 index 00000000..0a810d40 --- /dev/null +++ b/src/shared/utils/actionsTools.js @@ -0,0 +1,124 @@ +const ActionsTools = { + parse(actionText) { + const actions = []; + const chrs = Array.from(actionText); + let buf = ""; + for (let i = 0; i < chrs.length; i += 1) { + const c = chrs[i]; + if (c === "*") { + if (buf.length > 0) { + actions.push({ type: "text", text: buf }); + buf = ""; + } + actions.push({ type: "any", text: "*" }); + } else if (c === "{" && chrs[i + 1] === "{") { + if (buf.length > 0) { + actions.push({ type: "text", text: buf }); + buf = ""; + } + let j = i + 2; + for (; j < chrs.length; j += 1) { + if (chrs[j] === "}" && chrs[j + 1] === "}") { + break; + } else { + buf += chrs[j]; + } + } + i = j + 1; + // TODO syntax error checking + actions.push({ type: "output_var", text: buf }); + buf = ""; + } else if (c === "<" && chrs[i + 1] === "<") { + if (buf.length > 0) { + actions.push({ type: "text", text: buf }); + buf = ""; + } + let j = i + 2; + for (; j < chrs.length; j += 1) { + if (chrs[j] === ">" && chrs[j + 1] === ">") { + break; + } else { + buf += chrs[j]; + } + } + i = j + 1; + // TODO syntax error checking + actions.push({ type: "variable", text: buf }); + buf = ""; + } else if (c === "<") { + // HTML parsing, very simple doesn't accept inner tags + let j = i + 1; + let tagStart = false; + let tagEnd = false; + let tag = ""; + for (; j < chrs.length; j += 1) { + if (chrs[j] === ">") { + tagStart = true; + break; + } else if (chrs[j] === "/" && chrs[j + 1] === ">") { + tagStart = true; + tagEnd = true; + j += 1; + break; + } else { + tag += chrs[j]; + } + } + if (tagStart) { + if (buf.length > 0) { + actions.push({ type: "text", text: buf }); + buf = ""; + } + if (tag === "br") { + // Force tagEnd + tagEnd = true; + } + // Search TagEnd + let t = tag; + let l = j; + if (!tagEnd) { + let k = j + 1; + for (; k < chrs.length; k += 1) { + if (chrs[k] === "<" && chrs[k + 1] === "/") { + tagEnd = true; + break; + } else { + buf += chrs[k]; + } + } + if (tagEnd) { + l = k + 2; + t = ""; + for (; l < chrs.length; l += 1) { + if (chrs[l] === ">") { + break; + } else { + t += chrs[l]; + } + } + } + } + console.log("parse HTML", tag, t, buf, actionText.substring(l + 1)); + if (t === tag) { + i = l; + actions.push({ type: tag, text: buf }); + buf = ""; + } else { + console.log("actionTools.parse HTML Error"); + } + } else { + buf += c; + } + } else { + buf += c; + } + } + if (buf.length > 0) { + actions.push({ type: "text", text: buf }); + buf = ""; + } + return actions; + }, +}; + +export default ActionsTools; diff --git a/src/shared/utils/fileManager.js b/src/shared/utils/fileManager.js new file mode 100644 index 00000000..56ed17f9 --- /dev/null +++ b/src/shared/utils/fileManager.js @@ -0,0 +1,41 @@ +const FileManager = { + download(data, filename, filetype, callback = null) { + /* eslint-disable no-undef */ + const element = document.createElement("a"); + const file = new Blob([data], { type: filetype }); + element.href = URL.createObjectURL(file); + element.download = filename; + element.click(); + if (callback) { + callback(); + } + /* eslint-enable no-undef */ + }, + + upload(selectorFiles, callback) { + const file = selectorFiles[0]; + console.log("FileManager file=", file); + /* eslint-disable no-undef */ + const reader = new FileReader(); + reader.onload = (e) => { + const data = e.target.result; + if (callback) { + let { type } = file; + if (type !== "application/json" && type !== "text/csv") { + if (file.name.indexOf(".json") > 0) { + type = "application/json"; + } else if (file.name.indexOf(".csv") > 0) { + type = "text/csv"; + } else if (file.name.indexOf(".txt") > 0) { + type = "text/csv"; + } + } + callback(data, type); + } + }; + /* eslint-enable no-undef */ + reader.readAsText(file); + }, +}; + +export default FileManager; diff --git a/src/shared/utils/pluginsManager.js b/src/shared/utils/pluginsManager.js new file mode 100644 index 00000000..ba8b1e47 --- /dev/null +++ b/src/shared/utils/pluginsManager.js @@ -0,0 +1,56 @@ +import loadPlugin from "OplaPlugins"; + +export default class PluginsManager { + constructor(app = null) { + this.app = app; + this.plugins = {}; + this.load(); + } + + load() { + const that = this; + loadPlugin(this, (plugin) => { + that.startPlugin(plugin); + }); + } + + startPlugin(plugin) { + const name = plugin.getName(); + this.plugins[name] = plugin; + if (plugin.start) { + plugin.start(); + } + } + + getPlugin(name) { + return this.plugins[name]; + } + + instanciate(name, origin) { + const service = this.plugins[name]; + let instance = null; + if (service.instanciate) { + instance = service.instanciate(origin); + } else { + instance = {}; + instance.name = service.getName(); + instance.title = service.getTitle(); + instance.origin = origin; + instance.color = service.getColor(); + instance.icon = service.getIcon(); + instance.type = service.getType(); + } + instance.status = "disabled"; + return instance; + } + getPlugins({ type = null, activated = null }) { + const plugins = []; + Object.keys(this.plugins).forEach((pluginName) => { + const p = this.plugins[pluginName]; + if ((type === null || p.isType(type)) && (activated === null || p.isActive() === activated)) { + plugins.push(p); + } + }, this); + return plugins; + } +} diff --git a/webpack.common.js b/webpack.common.js new file mode 100644 index 00000000..9f31b5d9 --- /dev/null +++ b/webpack.common.js @@ -0,0 +1,75 @@ +const path = require("path"); +const webpack = require("webpack"); +const CopyWebpackPlugin = require("copy-webpack-plugin"); + +module.exports = { + context: path.resolve(__dirname, "./src/"), + entry: { + app: "./client/index.jsx" + }, + output: { + path: path.resolve(__dirname, "./dist/public/js"), + filename: "app.js", + publicPath: "/", + hotUpdateChunkFilename: "hot/hot-update.js", + hotUpdateMainFilename: "hot/hot-update.json" + }, + resolve: { + extensions: [".js", ".jsx"], + alias: { + OplaPlugins: path.resolve(__dirname, "./src/plugins/"), + OplaLibs: path.resolve(__dirname, "./src/shared/"), + OplaContainers: path.resolve(__dirname, "./src/shared/containers/"), + MdlExt: path.resolve(__dirname, "./src/shared/components/mdl/") + }, + modules: [path.join(__dirname, "src"), "node_modules"] + }, + module: { + rules: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + use: { + loader: "babel-loader", + options: { + presets: ["es2015", "react", "stage-1"], + plugins: [ + ["transform-runtime", { "polyfill": false }], + "transform-regenerator", + "react-hot-loader/babel", + "transform-decorators-legacy" + ], + env: { + start: { + presets: ["react-hmre"] + } + } + } + } + } + ] + }, + plugins: [ + new webpack.HotModuleReplacementPlugin(), + new webpack.DefinePlugin({ + '__REACT_DEVTOOLS_GLOBAL_HOOK__': '({ isDisabled: true })' + }), + new CopyWebpackPlugin([ + { + from: "./public", + to: path.resolve(__dirname, "./dist/public"), + force: true + }, + { + from: "./server", + to: path.resolve(__dirname, "./dist"), + force: true + }, + { + from: path.resolve(__dirname, "./package.json"), + to: path.resolve(__dirname, "./dist/package.json"), + force: true + } + ]) + ] +}; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..524e95db --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,3 @@ +module.exports = (env) => { + return require(`./webpack.${env}.js`); +}; diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 00000000..65758d89 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,40 @@ +const merge = require("webpack-merge"); +const commonConfig = require("./webpack.common.js"); +const path = require("path"); +const webpack = require("webpack"); +// const CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = merge(commonConfig, { + entry: [ + "react-hot-loader/patch", + "webpack-dev-server/client?http://localhost:8080", + "webpack/hot/only-dev-server", + "./client/index.jsx" + ], + devtool: "inline-source-map", + devServer: { + hot: true, + contentBase: path.resolve(__dirname, "./dist/public"), + port: 8080, + host: "localhost", + publicPath: "/", + historyApiFallback: true, + }, + module: { + rules: [ + { + test: /\.jsx?$/, + use: ["babel-loader",], + exclude: /node_modules/ + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader?modules",], + }, + ], + }, + plugins: [ + /*new webpack.HotModuleReplacementPlugin(),*/ + new webpack.NamedModulesPlugin(), + ] +}); diff --git a/webpack.prod.js b/webpack.prod.js new file mode 100644 index 00000000..b2d6ed41 --- /dev/null +++ b/webpack.prod.js @@ -0,0 +1,26 @@ +const merge = require('webpack-merge'); +const commonConfig = require('./webpack.common.js'); +const webpack = require('webpack'); + +module.exports = merge(commonConfig, { + plugins: [ + new webpack.LoaderOptionsPlugin({ + minimize: true, + debug: false + }), + new webpack.optimize.UglifyJsPlugin({ + beautify: false, + mangle: { + screw_ie8: true, + keep_fnames: true + }, + compress: { + screw_ie8: true + }, + comments: false + }), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }) + ] +}); \ No newline at end of file