From 54fc472c6d098526c86e8a8e4d063e62b262d030 Mon Sep 17 00:00:00 2001 From: undemian Date: Tue, 3 Apr 2018 17:54:38 +0300 Subject: [PATCH 1/2] Add theme option --- docs/API.md | 1 + docs/HACKING.md | 4 ++-- src/api.js | 6 ++++-- src/constants.js | 5 +++++ src/index.js | 20 ++++++++++---------- targets/standalone/example.html | 1 + 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/API.md b/docs/API.md index 57f754e2..41df2c63 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 | `panel` | The chat layout fullscreen (100%), panel (floating) | | `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/src/api.js b/src/api.js index 8c93e82a..aa9a442e 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_PANEL } from './constants'; +import { LAYOUT_PANEL, THEME_CALYPSO } from './constants'; const api = { /** @@ -35,6 +35,7 @@ const api = { * @param {Array} layout Optional. Happychat layout (panel or fullscreen) default value is panel * @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_PANEL, 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 f91638ff..896a2069 100644 --- a/src/constants.js +++ b/src/constants.js @@ -6,6 +6,11 @@ export const AUTH_TYPE_WPCOM_PROXY_IFRAME = 'wpcom-proxy-iframe'; export const LAYOUT_FULLSCREEN = 'fullscreen'; export const LAYOUT_PANEL = 'panel'; +// 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/index.js b/src/index.js index eee7a127..8d27ba88 100644 --- a/src/index.js +++ b/src/index.js @@ -27,7 +27,7 @@ import { setAssetsLoaded } from 'src/state/ui/actions'; import { setCurrentUser, setGroups, setLocale, setEligibility } from 'src/state/user/actions'; import { setFallbackTicketOptions } from 'src/state/fallbackTicket/actions'; import config from 'src/config'; -import { ENTRY_FORM, LAYOUT_FULLSCREEN } from 'src/constants'; +import { ENTRY_FORM, LAYOUT_FULLSCREEN, THEME_CALYPSO } from 'src/constants'; const store = createStore( reducer, @@ -48,7 +48,7 @@ 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' ); const primaryHasAnySecondary = options => @@ -135,19 +135,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 ( theme !== THEME_CALYPSO ) { + // if we are not using the default theme load the requested one + styleHCTheme.setAttribute( 'href', 'https://widgets.wp.com/happychat/' + theme + '.css' ); + styleHCThemePromise = new Promise( resolve => ( styleHCTheme.onload = () => resolve() ) ); } Promise.all( [ styleNoticonPromise, styleHCPromise, styleHCThemePromise ] ).then( () => @@ -200,6 +198,7 @@ export const renderHappychat = ( username, display_name, avatar_URL, + language, localeSlug, }, groups = [ HAPPYCHAT_GROUP_WPCOM ], @@ -219,7 +218,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 ) 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: [ From 64404bda34c858165dca9a33124d4a6e250b95d7 Mon Sep 17 00:00:00 2001 From: undemian Date: Wed, 11 Apr 2018 00:39:57 +0300 Subject: [PATCH 2/2] Add calypso theme --- package.json | 6 ++++ src/form.scss | 1 - src/index.js | 32 +++++++++---------- src/ui/css/_main.scss | 1 + .../css/themes/{_main.scss => _calypso.scss} | 3 ++ 5 files changed, 26 insertions(+), 17 deletions(-) rename src/ui/css/themes/{_main.scss => _calypso.scss} (92%) 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/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 67064a37..59d53203 100644 --- a/src/index.js +++ b/src/index.js @@ -63,19 +63,19 @@ const createIframe = ( props, assetsLoadedHook = () => {} ) => { 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%'; @@ -165,11 +165,10 @@ const createIframe = ( props, assetsLoadedHook = () => {} ) => { styleHCTheme.setAttribute( 'type', 'text/css' ); let styleHCThemePromise = Promise.resolve(); - if ( theme !== THEME_CALYPSO ) { - // if we are not using the default theme load the requested one - styleHCTheme.setAttribute( 'href', 'https://widgets.wp.com/happychat/' + theme + '.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() @@ -228,6 +227,7 @@ export const renderHappychat = ( canChat = true, entry = ENTRY_FORM, entryOptions = {}, + layout, } ) => { const { fallbackTicket } = entryOptions; @@ -251,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%);