From 96a36f272c46e28e66d3af8ab0bee2f4fce97b4e Mon Sep 17 00:00:00 2001 From: Jeffrey Carandang Date: Tue, 9 Jun 2020 21:19:32 +0800 Subject: [PATCH 1/4] Add Import/Export on theme editor popover --- src/components/theme-import-export/index.js | 54 +++++++++++++++++++++ src/components/theme-switcher/index.js | 46 ++++++++++++++++-- 2 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/components/theme-import-export/index.js diff --git a/src/components/theme-import-export/index.js b/src/components/theme-import-export/index.js new file mode 100644 index 0000000..0df1ad4 --- /dev/null +++ b/src/components/theme-import-export/index.js @@ -0,0 +1,54 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Fragment, Component } from '@wordpress/element'; +import { withDispatch } from '@wordpress/data'; +import { compose, withInstanceId } from '@wordpress/compose'; +import { + MenuGroup, + MenuItem, + BaseControl, + RangeControl, + SelectControl, + withSpokenMessages, +} from '@wordpress/components'; + +class ThemeImportExport extends Component { + constructor() { + super( ...arguments ); + + this.state = { + updatedSettings: {}, + }; + } + componentDidMount() { + this.setState( { updatedSettings: this.props.themeSettings } ); + } + render() { + const { + onToggle, + onClose, + themeSettings, + loadConfig, + isEditingTypography, + updateState, + } = this.props; + + return asdfasdf; + } +} + +export default compose( [ + withInstanceId, + withDispatch( ( dispatch ) => { + const { setThemeSettings } = dispatch( 'iceberg-settings' ); + + return { + updateThemeSettings( settings ) { + setThemeSettings( settings ); + }, + }; + } ), + withSpokenMessages, +] )( ThemeImportExport ); diff --git a/src/components/theme-switcher/index.js b/src/components/theme-switcher/index.js index 34f4a8c..6a404fe 100644 --- a/src/components/theme-switcher/index.js +++ b/src/components/theme-switcher/index.js @@ -9,6 +9,7 @@ import { map, merge, assign, get } from 'lodash'; import defaults from '../theme-editor/default'; import EditorThemes from '../theme-editor/editor-themes'; import ThemeEditor from '../theme-editor'; +import ThemeImportExport from '../theme-import-export'; import icons from '../icons'; import { assignVariables } from './variables'; import difference from './utils/difference'; @@ -47,6 +48,7 @@ class ThemeSwitcher extends Component { isEditorThemeLoaded: false, isEditingTheme: false, isEditingTypography: false, + isImportExport: false, }; } @@ -162,7 +164,10 @@ class ThemeSwitcher extends Component { } } - this.setState( { isEditingTypography: false } ); + this.setState( { + isEditingTypography: false, + isImportExport: false, + } ); updateThemeSettings( this.state.themeSettings ); }; @@ -269,7 +274,8 @@ class ThemeSwitcher extends Component { renderContent={ ( { onToggle } ) => ( { ! this.state.isEditingTheme && - ! this.state.isEditingTypography ? ( + ! this.state.isEditingTypography && + ! this.state.isImportExport ? ( { map( @@ -358,9 +364,30 @@ class ThemeSwitcher extends Component { ) } { icons.typography } + { + this.setState( { + isEditingTheme: false, + isEditingTypography: false, + isImportExport: true, + } ); + this.onEditTheme( + onToggle, + 'isImportExport' + ); + } } + > + { __( + 'Import / Export', + 'iceberg' + ) } + - ) : ( + ) : null } + { ! this.state.isEditingTheme && + ! this.state.isEditingTypography ? null : ( ) } + + { this.state.isImportExport && ( + { + this.setState( { + isEditingTheme: false, + isEditingTypography: false, + } ); + this.onExitEditTheme( onToggle ); + } } + /> + ) } ) } /> From 2bc023173867a1c8df083e486aef67cffd92aed2 Mon Sep 17 00:00:00 2001 From: Jeffrey Carandang Date: Tue, 9 Jun 2020 21:35:56 +0800 Subject: [PATCH 2/4] Add working export theme settings --- src/components/theme-import-export/file.js | 25 +++++++++ src/components/theme-import-export/index.js | 51 ++++++++++++++++--- src/components/theme-import-export/style.scss | 3 ++ src/style.scss | 1 + 4 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/components/theme-import-export/file.js create mode 100644 src/components/theme-import-export/style.scss diff --git a/src/components/theme-import-export/file.js b/src/components/theme-import-export/file.js new file mode 100644 index 0000000..915da5b --- /dev/null +++ b/src/components/theme-import-export/file.js @@ -0,0 +1,25 @@ +/** + * Downloads a file. + * + * @param {string} fileName File Name. + * @param {string} content File Content. + * @param {string} contentType File mime type. + */ +export function download( fileName, content, contentType ) { + const file = new window.Blob( [ content ], { type: contentType } ); + + // IE11 can't use the click to download technique + // we use a specific IE11 technique instead. + if ( window.navigator.msSaveOrOpenBlob ) { + window.navigator.msSaveOrOpenBlob( file, fileName ); + } else { + const a = document.createElement( 'a' ); + a.href = URL.createObjectURL( file ); + a.download = fileName; + + a.style.display = 'none'; + document.body.appendChild( a ); + a.click(); + document.body.removeChild( a ); + } +} diff --git a/src/components/theme-import-export/index.js b/src/components/theme-import-export/index.js index 0df1ad4..89c1b34 100644 --- a/src/components/theme-import-export/index.js +++ b/src/components/theme-import-export/index.js @@ -1,9 +1,14 @@ +/** + * Internal dependencies + */ +import { download } from './file'; + /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { Fragment, Component } from '@wordpress/element'; -import { withDispatch } from '@wordpress/data'; +import { withDispatch, withSelect } from '@wordpress/data'; import { compose, withInstanceId } from '@wordpress/compose'; import { MenuGroup, @@ -12,19 +17,26 @@ import { RangeControl, SelectControl, withSpokenMessages, + Button, } from '@wordpress/components'; class ThemeImportExport extends Component { constructor() { super( ...arguments ); - this.state = { - updatedSettings: {}, - }; + this.exportAsJSON = this.exportAsJSON.bind( this ); } - componentDidMount() { - this.setState( { updatedSettings: this.props.themeSettings } ); + + exportAsJSON() { + const { themeSettings } = this.props; + + //do export magic + const fileContent = JSON.stringify( themeSettings, null, 2 ); + + const fileName = 'iceberg-theme-settings.json'; + download( fileName, fileContent, 'application/json' ); } + render() { const { onToggle, @@ -35,12 +47,37 @@ class ThemeImportExport extends Component { updateState, } = this.props; - return asdfasdf; + return ( + +
+ + { __( 'Export theme settings', 'iceberg' ) } + + + + { __( 'Import', 'iceberg' ) } +
+
+ ); } } export default compose( [ withInstanceId, + withSelect( ( select ) => { + const { getThemeSettings } = select( 'iceberg-settings' ); + + return { + themeSettings: getThemeSettings(), + }; + } ), withDispatch( ( dispatch ) => { const { setThemeSettings } = dispatch( 'iceberg-settings' ); diff --git a/src/components/theme-import-export/style.scss b/src/components/theme-import-export/style.scss new file mode 100644 index 0000000..e5d5c7d --- /dev/null +++ b/src/components/theme-import-export/style.scss @@ -0,0 +1,3 @@ +.components-iceberg-theme-switcher__import-export{ + padding: 12px; +} \ No newline at end of file diff --git a/src/style.scss b/src/style.scss index 71ef3b7..4183768 100644 --- a/src/style.scss +++ b/src/style.scss @@ -16,6 +16,7 @@ @import "./components/document-info/style.scss"; @import "./components/settings/style.scss"; @import "./components/block-indicator/style.scss"; + @import "./components/theme-import-export/style.scss"; //Editor styling @import "./styles/ui/hidden.scss"; From 4a648b1c30ba73577789885b3d3ea80018c93922 Mon Sep 17 00:00:00 2001 From: Jeffrey Carandang Date: Tue, 9 Jun 2020 22:27:22 +0800 Subject: [PATCH 3/4] Add working import settings --- src/components/theme-import-export/file.js | 34 +++++++++ src/components/theme-import-export/index.js | 82 ++++++++++++++++++--- src/components/theme-switcher/index.js | 3 + 3 files changed, 107 insertions(+), 12 deletions(-) diff --git a/src/components/theme-import-export/file.js b/src/components/theme-import-export/file.js index 915da5b..f820e84 100644 --- a/src/components/theme-import-export/file.js +++ b/src/components/theme-import-export/file.js @@ -23,3 +23,37 @@ export function download( fileName, content, contentType ) { document.body.removeChild( a ); } } + +/** + * Reads the textual content of the given file. + * + * @param {File} file File. + * @return {Promise} Content of the file. + */ +export function readTextFile( file ) { + const reader = new window.FileReader(); + return new Promise( ( resolve ) => { + reader.onload = function() { + resolve( reader.result ); + }; + reader.readAsText( file ); + } ); +} + +/** + * Import a reusable block from a JSON file. + * + * @param {File} file File. + * @return {Promise} Promise returning the imported reusable block. + */ +export async function importThemeSettings( file ) { + const fileContent = await readTextFile( file ); + let parsedContent; + try { + parsedContent = JSON.parse( fileContent ); + } catch ( e ) { + throw new Error( 'Invalid JSON file' ); + } + + return parsedContent; +} diff --git a/src/components/theme-import-export/index.js b/src/components/theme-import-export/index.js index 89c1b34..652e5c1 100644 --- a/src/components/theme-import-export/index.js +++ b/src/components/theme-import-export/index.js @@ -1,7 +1,8 @@ /** * Internal dependencies */ -import { download } from './file'; +import { download, importThemeSettings } from './file'; +import icons from '../icons'; /** * WordPress dependencies @@ -11,11 +12,11 @@ import { Fragment, Component } from '@wordpress/element'; import { withDispatch, withSelect } from '@wordpress/data'; import { compose, withInstanceId } from '@wordpress/compose'; import { + BaseControl, MenuGroup, MenuItem, - BaseControl, - RangeControl, - SelectControl, + DropZoneProvider, + DropZone, withSpokenMessages, Button, } from '@wordpress/components'; @@ -25,6 +26,10 @@ class ThemeImportExport extends Component { super( ...arguments ); this.exportAsJSON = this.exportAsJSON.bind( this ); + this.onFilesUpload = this.onFilesUpload.bind( this ); + this.state = { + isImported: false, + }; } exportAsJSON() { @@ -37,15 +42,35 @@ class ThemeImportExport extends Component { download( fileName, fileContent, 'application/json' ); } + onFilesUpload( files ) { + const { updateThemeSettings, loadConfig, updateState } = this.props; + let file = files[ 0 ]; + + if ( files.target ) { + file = event.target.files[ 0 ]; + } + + if ( ! file ) { + return; + } + + importThemeSettings( file ) + .then( ( importedSettings ) => { + updateState( 'themeSettings', importedSettings ); + updateState( 'theme', importedSettings.theme ); + updateThemeSettings( importedSettings ); + this.setState( { isImported: true } ); + + // reload variables + loadConfig( importedSettings.theme, importedSettings ); + } ) + .catch( () => { + this.setState( { error: true } ); + } ); + } + render() { - const { - onToggle, - onClose, - themeSettings, - loadConfig, - isEditingTypography, - updateState, - } = this.props; + const { onToggle, onClose } = this.props; return ( @@ -63,7 +88,40 @@ class ThemeImportExport extends Component { { __( 'Import', 'iceberg' ) } + +
+ { __( + 'Drag and drop iceberg-theme-settings.json file in here.', + 'iceberg' + ) } + +
+
+ + { + onClose(); + onToggle(); + onToggle(); + + // focus manually to fix closing outside bug + document + .querySelector( + '.components-iceberg-theme-switcher__content .components-popover__content' + ) + .focus(); + } } + > + { __( 'Back to editor themes', 'iceberg' ) } + { icons.back } + +
); } diff --git a/src/components/theme-switcher/index.js b/src/components/theme-switcher/index.js index 6a404fe..c43be2d 100644 --- a/src/components/theme-switcher/index.js +++ b/src/components/theme-switcher/index.js @@ -413,11 +413,14 @@ class ThemeSwitcher extends Component { { this.state.isImportExport && ( { this.setState( { isEditingTheme: false, isEditingTypography: false, + isImportExport: false, } ); this.onExitEditTheme( onToggle ); } } From 969b245bdf3136eb7a11cec2412e54aaa6896864 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 9 Jun 2020 14:30:36 +0000 Subject: [PATCH 4/4] Fix code style issues with stylelint --- src/components/theme-import-export/style.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/theme-import-export/style.scss b/src/components/theme-import-export/style.scss index e5d5c7d..47334aa 100644 --- a/src/components/theme-import-export/style.scss +++ b/src/components/theme-import-export/style.scss @@ -1,3 +1,3 @@ -.components-iceberg-theme-switcher__import-export{ +.components-iceberg-theme-switcher__import-export { padding: 12px; -} \ No newline at end of file +}