diff --git a/docs/API.md b/docs/API.md index a48cb8ea..74a9c723 100644 --- a/docs/API.md +++ b/docs/API.md @@ -21,6 +21,7 @@ with the following top-level properties: | `canChat` | bool | Optional | `true` | Whether the user can be offered chat or not. | | `layout` | string | Optional | `max-width-fixed-height` | The chat layout `max-width-fixed-height`\|`max-parent-size`\|`panel-fixed-size`\|`panel-max-parent-size` | | `nodeId` | string | Mandatory | `null` | The id of the HTMLNode where Happychat will be rendered. | +| `theme` | string | Optional | `calypso` | Color theme. Valid values are `calypso`, `woo`, and `woo` ### The entry prop diff --git a/docs/HACKING.md b/docs/HACKING.md index 33e518d6..b2e78648 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -46,11 +46,11 @@ Upon the iframe creation a spinner line is shown right away within the iframe -a We've transitioned to a codebase that supports themes by consolidating the colors used and using CSS Custom Properties. At the time of writing we support 3 themes, that may be found at `src/ui/css/themes`: -- `main`: follows the [WordPress.com guidelines](https://wordpress.com/design-handbook/colors/). It's the default theme. +- `calypso`: follows the [WordPress.com guidelines](https://wordpress.com/design-handbook/colors/). It's the default theme. - `jpop`: follows the Jetpack guidelines. - `woo`: follows the [WooCommerce guidelines](https://woocommerce.com/style-guide/#sg-palette). -All SCSS color variables are declared at `/home/andres/src/happychat-client/src/ui/css/shared/_colors.scss`. The themes are automatically selected depending on the the chat group the user is routed to. For example, the `woo` theme will be activated when group is `woo`, and `jpop` when group is `jpop`. +All SCSS color variables are declared at `/home/andres/src/happychat-client/src/ui/css/shared/_colors.scss`. The themes are selected based on the `theme` parameter sent, the default theme is `calypso` Note that CSS Custom Properties support is yet not [ubiquitous](https://caniuse.com/#feat=css-variables) -current offenders are IE11 and Opera Mini- so we use [postcss-custom-properties](https://github.com/postcss/postcss-custom-properties) processors to compile back for those browsers. diff --git a/package.json b/package.json index 4e6b0624..8ed8b2cf 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dev:standalone:js": "NODE_ENV=development webpack-dev-server --config webpack.standalone.config.js", "dev:standalone:css": "run-p dev:standalone:css:*", "dev:standalone:css:main": "node-sass src/form.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/happychat.css", + "dev:standalone:css:calypso": "node-sass src/ui/css/themes/_calypso.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/calypso.css", "dev:standalone:css:woo": "node-sass src/ui/css/themes/_woo.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/woo.css", "dev:standalone:css:jpop": "node-sass src/ui/css/themes/_jpop.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/jpop.css", @@ -29,6 +30,7 @@ "dev:npm:js": "NODE_ENV=development ./node_modules/babel-cli/bin/babel.js --watch src --out-dir targets/npm", "dev:npm:css": "run-p dev:npm:css:*", "dev:npm:css:main": "node-sass src/form.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/happychat.css", + "dev:npm:css:calypso": "node-sass src/ui/css/themes/_calypso.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/calypso.css", "dev:npm:css:woo": "node-sass src/ui/css/themes/_woo.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/woo.css", "dev:npm:css:jpop": "node-sass src/ui/css/themes/_jpop.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/jpop.css", "dev:npm:css:serve": "NODE_ENV=development webpack-dev-server --config webpack.npm.config.js", @@ -37,6 +39,7 @@ "dev:wordpress:js": "NODE_ENV=development webpack-dev-server --config webpack.wordpress.config.js", "dev:wordpress:css": "run-p dev:wordpress:css:*", "dev:wordpress:css:main": "node-sass src/form.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/happychat.css", + "dev:wordpress:css:calypso": "node-sass src/ui/css/themes/_calypso.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/calypso.css", "dev:wordpress:css:woo": "node-sass src/ui/css/themes/_woo.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/woo.css", "dev:wordpress:css:jpop": "node-sass src/ui/css/themes/_jpop.scss | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/jpop.css", @@ -45,6 +48,7 @@ "build:standalone:js": "NODE_ENV=production webpack -p --config webpack.standalone.config.js -p", "build:standalone:css": "run-p build:standalone:css:*", "build:standalone:css:main": "node-sass src/form.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/happychat.css", + "build:standalone:css:calypso": "node-sass src/ui/css/themes/_calypso.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/calypso.css", "build:standalone:css:woo": "node-sass src/ui/css/themes/_woo.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/woo.css", "build:standalone:css:jpop": "node-sass src/ui/css/themes/_jpop.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/standalone/jpop.css", @@ -52,6 +56,7 @@ "build:npm:js": "NODE_ENV=production ./node_modules/babel-cli/bin/babel.js src --out-dir targets/npm", "build:npm:css": "run-p build:npm:css:*", "build:npm:css:main": "node-sass src/form.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/happychat.css", + "build:npm:css:calypso": "node-sass src/ui/css/themes/_calypso.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/calypso.css", "build:npm:css:woo": "node-sass src/ui/css/themes/_woo.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/woo.css", "build:npm:css:jpop": "node-sass src/ui/css/themes/_jpop.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/npm/jpop.css", @@ -59,6 +64,7 @@ "build:wordpress:js": "NODE_ENV=production webpack -p --config webpack.wordpress.config.js", "build:wordpress:css": "run-p build:wordpress:css:*", "build:wordpress:css:main": "node-sass src/form.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/assets/happychat.css", + "build:wordpress:css:calypso": "node-sass src/ui/css/themes/_calypso.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/assets/calypso.css", "build:wordpress:css:woo": "node-sass src/ui/css/themes/_woo.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/assets/woo.css", "build:wordpress:css:jpop": "node-sass src/ui/css/themes/_jpop.scss --output-style compressed | postcss --config postcss.config.json -u autoprefixer -u postcss-custom-properties --no-map -o targets/wordpress/assets/jpop.css", "test": "jest -c jest.config.json" diff --git a/src/api.js b/src/api.js index 7870ebfa..a0c93629 100644 --- a/src/api.js +++ b/src/api.js @@ -15,7 +15,7 @@ import { renderError, } from './index'; import authenticator from 'src/lib/auth'; -import { LAYOUT_MAX_WIDTH_FIXED_HEIGHT } from './constants'; +import { LAYOUT_MAX_WIDTH_FIXED_HEIGHT, THEME_CALYPSO } from './constants'; const api = { /** @@ -35,6 +35,7 @@ const api = { * @param {String} layout Optional. The chat layout max-width-fixed-height | max-parent-size | panel-fixed-size | panel-max-parent-size * @param {string} nodeId Mandatory. HTML Node id where Happychat will be rendered. * @param {Object} user Optional. Customer information . + * @param {string} theme Optional. Selected color theme. */ open: ( { authentication, @@ -45,10 +46,11 @@ const api = { layout = LAYOUT_MAX_WIDTH_FIXED_HEIGHT, nodeId, user, + theme = THEME_CALYPSO, } ) => { authenticator.init( authentication ); - const targetNode = createTargetNode( { entryOptions, groups, layout, nodeId } ); + const targetNode = createTargetNode( { entryOptions, groups, layout, nodeId, theme } ); authenticator.login() .then( () => isEmpty( user ) ? authenticator.getUser() : Promise.resolve( user ) ) diff --git a/src/constants.js b/src/constants.js index fe82eea1..5d097abd 100644 --- a/src/constants.js +++ b/src/constants.js @@ -8,6 +8,11 @@ export const LAYOUT_MAX_PARENT_SIZE = 'max-parent-size'; export const LAYOUT_PANEL_FIXED_SIZE = 'panel-fixed-size'; export const LAYOUT_PANEL_MAX_PARENT_SIZE = 'panel-max-parent-size'; +// Themes +export const THEME_CALYPSO = 'calypso'; +export const THEME_WOO = 'woo'; +export const THEME_JPOP = 'jpop'; + // Entry export const ENTRY_CHAT = 'chat'; export const ENTRY_FORM = 'form'; diff --git a/src/form.scss b/src/form.scss index 82dfe033..6a7ba668 100644 --- a/src/form.scss +++ b/src/form.scss @@ -15,7 +15,6 @@ @import 'ui/css/shared/mixins/noticon'; @import 'ui/css/shared/animation'; @import 'ui/css/shared/classes'; -@import 'ui/css/themes/main'; // General styles @import 'ui/css/shared/vendor/noticon'; // .noticon diff --git a/src/index.js b/src/index.js index b2b5ab2a..59d53203 100644 --- a/src/index.js +++ b/src/index.js @@ -34,6 +34,7 @@ import { LAYOUT_MAX_PARENT_SIZE, LAYOUT_PANEL_FIXED_SIZE, LAYOUT_PANEL_MAX_PARENT_SIZE, + THEME_CALYPSO, } from 'src/constants'; const store = createStore( @@ -55,26 +56,26 @@ const dispatchAssetsFinishedDownloading = () => store.dispatch( setAssetsLoaded( * @returns {HTMLNode} Target node where Happychat can hook into. */ const createIframe = ( props, assetsLoadedHook = () => {} ) => { - const { entryOptions, groups, layout, nodeId } = props; + const { entryOptions, groups, layout, nodeId, theme } = props; const iframeElement = document.createElement( 'iframe' ); let iframeHeight = 0; let iframeWidth = 0; switch ( layout ) { case LAYOUT_MAX_WIDTH_FIXED_HEIGHT: - const primaryHasAnySecondary = options => - Array.isArray( options ) && find( options, opt => opt.secondaryOptions ); + const primaryHasAnySecondary = options => + Array.isArray( options ) && find( options, opt => opt.secondaryOptions ); - const isThereAnySecondaryOptions = options => - options && - ( options.secondaryOptions || primaryHasAnySecondary( entryOptions.primaryOptions ) ); + const isThereAnySecondaryOptions = options => + options && + ( options.secondaryOptions || primaryHasAnySecondary( entryOptions.primaryOptions ) ); - // Calculate height based on the number of components - // the iframe may need to render. + // Calculate height based on the number of components + // the iframe may need to render. iframeHeight = 480; - iframeHeight = iframeHeight + ( entryOptions && entryOptions.primaryOptions ? 110 : 0 ); - iframeHeight = iframeHeight + ( isThereAnySecondaryOptions( entryOptions ) ? 110 : 0 ); - iframeHeight = iframeHeight + ( entryOptions && entryOptions.itemList ? 70 : 0 ); + iframeHeight = iframeHeight + ( entryOptions && entryOptions.primaryOptions ? 110 : 0 ); + iframeHeight = iframeHeight + ( isThereAnySecondaryOptions( entryOptions ) ? 110 : 0 ); + iframeHeight = iframeHeight + ( entryOptions && entryOptions.itemList ? 70 : 0 ); iframeHeight = iframeHeight + 'em'; iframeWidth = '100%'; @@ -157,20 +158,17 @@ const createIframe = ( props, assetsLoadedHook = () => {} ) => { styleHC.setAttribute( 'type', 'text/css' ); styleHC.setAttribute( 'href', config( 'css_url' ) ); - // TODO: rework this to use skills and have local themes loaded const styleHCPromise = new Promise( resolve => ( styleHC.onload = () => resolve() ) ); const styleHCTheme = document.createElement( 'link' ); styleHCTheme.setAttribute( 'rel', 'stylesheet' ); styleHCTheme.setAttribute( 'type', 'text/css' ); let styleHCThemePromise = Promise.resolve(); - if ( groups && groups.length > 0 ) { - const groupName = groups[ 0 ]; - if ( groupName === 'woo' || groupName === 'jpop' ) { - styleHCTheme.setAttribute( 'href', 'https://widgets.wp.com/happychat/' + groupName + '.css' ); - styleHCThemePromise = new Promise( resolve => ( styleHCTheme.onload = () => resolve() ) ); - } - } + + // if we are not using the default theme load the requested one + // TODO: cleanup the css url to use base url + styleHCTheme.setAttribute( 'href', config( 'css_url' ).replace( 'happychat.css', theme + '.css' ) ); + styleHCThemePromise = new Promise( resolve => ( styleHCTheme.onload = () => resolve() ) ); Promise.all( [ styleNoticonPromise, styleHCPromise, styleHCThemePromise ] ).then( () => assetsLoadedHook() @@ -222,12 +220,14 @@ export const renderHappychat = ( username, display_name, avatar_URL, + language, localeSlug, }, groups = [ HAPPYCHAT_GROUP_WPCOM ], canChat = true, entry = ENTRY_FORM, entryOptions = {}, + layout, } ) => { const { fallbackTicket } = entryOptions; @@ -241,7 +241,8 @@ export const renderHappychat = ( } ) ); store.dispatch( setGroups( groups ) ); - store.dispatch( setLocale( localeSlug ) ); + // TODO: fix this - currentUser object differs from calypso to oauth. + store.dispatch( setLocale( language | localeSlug ) ); store.dispatch( setFallbackTicketOptions( fallbackTicket ) ); isAnyCanChatPropFalse( canChat, entryOptions ) @@ -250,7 +251,7 @@ export const renderHappychat = ( ReactDOM.render( - + , targetNode ); diff --git a/src/ui/css/_main.scss b/src/ui/css/_main.scss index 8bcddfc8..43f4ae96 100644 --- a/src/ui/css/_main.scss +++ b/src/ui/css/_main.scss @@ -10,6 +10,7 @@ body { font-size: 15px; line-height: 1.5; color: var(--neutral-dark); + background: var(--neutral-lighten-30); margin: 1; // separate from iframe, so children can style the borders } diff --git a/src/ui/css/themes/_main.scss b/src/ui/css/themes/_calypso.scss similarity index 92% rename from src/ui/css/themes/_main.scss rename to src/ui/css/themes/_calypso.scss index 65cbf88f..06bbe387 100644 --- a/src/ui/css/themes/_main.scss +++ b/src/ui/css/themes/_calypso.scss @@ -1,5 +1,8 @@ /** @format */ +@import '../shared/colors'; +@import '../shared/functions/tint-and-shade'; + :root { --selected: $blue-medium; --selected-darken-5: darken($blue-medium, 5%); diff --git a/targets/standalone/example.html b/targets/standalone/example.html index 14359197..b5ec702c 100644 --- a/targets/standalone/example.html +++ b/targets/standalone/example.html @@ -23,6 +23,7 @@ }, }, nodeId: 'support', + theme: 'jpop', groups: ['woo'], entryOptions: { primaryOptions: [