diff --git a/admin/resolver_additions.php b/admin/resolver_additions.php index 8d8a6343..3da26fc2 100644 --- a/admin/resolver_additions.php +++ b/admin/resolver_additions.php @@ -95,7 +95,6 @@ public static function export_theme_data( $content, $extra_theme_data = null ) { $data['$schema'] = $schema; $theme_json = wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); return preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json ); - } public static function get_theme_file_contents() { @@ -128,7 +127,6 @@ public static function clean_cached_data() { // Does this clear the Gutenberg equivalent? static::$theme_json_file_cache = array(); } - } } diff --git a/includes/class-create-block-theme-api.php b/includes/class-create-block-theme-api.php index 0ed2e4a5..807f24d7 100644 --- a/includes/class-create-block-theme-api.php +++ b/includes/class-create-block-theme-api.php @@ -97,6 +97,37 @@ public function register_rest_routes() { }, ) ); + register_rest_route( + 'create-block-theme/v1', + '/get-theme-data', + array( + 'methods' => 'GET', + 'callback' => array( $this, 'rest_get_theme_data' ), + 'permission_callback' => function () { + return current_user_can( 'edit_theme_options' ); + }, + ), + ); + } + + function rest_get_theme_data( $request ) { + try { + $theme_data = MY_Theme_JSON_Resolver::get_theme_file_contents(); + return new WP_REST_Response( + array( + 'status' => 'SUCCESS', + 'message' => __( 'Theme data retrieved.', 'create-block-theme' ), + 'data' => $theme_data, + ), + ); + } catch ( Exception $error ) { + return new WP_REST_Response( + array( + 'status' => 'FAILURE', + 'message' => $error->getMessage(), + ) + ); + } } function rest_get_readme_data( $request ) { diff --git a/package-lock.json b/package-lock.json index 58534f20..86f37743 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.13.8", "license": "GPL-2.0-or-later", "dependencies": { + "@codemirror/lang-json": "^6.0.1", + "@uiw/react-codemirror": "^4.21.24", "@wordpress/icons": "^9.24.0", "lib-font": "^2.4.0" }, @@ -2256,6 +2258,102 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@codemirror/autocomplete": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.14.0.tgz", + "integrity": "sha512-Kx9BCSOLKmqNXEvmViuzsBQJ2VEa/wWwOATNpixOa+suttTV3rDnAUtAIt5ObAUFjXvZakWfFfF/EbxELnGLzQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz", + "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", + "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.5.0.tgz", + "integrity": "sha512-+5YyicIaaAZKU8K43IQi8TBy6mF6giGeWAH7N96Z5LC30Wm5JMjqxOYIE9mxwMG1NbhT2mA3l9hA4uuKUM3E5g==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz", + "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.25.1", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.25.1.tgz", + "integrity": "sha512-2LXLxsQnHDdfGzDvjzAwZh2ZviNJm7im6tGpa0IONIDnFd8RZ80D2SNi8PDi6YjKcMoMRK20v6OmKIdsrwsyoQ==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@csstools/selector-specificity": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", @@ -3013,6 +3111,37 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz", + "integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz", + "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -4773,6 +4902,57 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uiw/codemirror-extensions-basic-setup": { + "version": "4.21.24", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.21.24.tgz", + "integrity": "sha512-TJYKlPxNAVJNclW1EGumhC7I02jpdMgBon4jZvb5Aju9+tUzS44IwORxUx8BD8ZtH2UHmYS+04rE3kLk/BtnCQ==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/autocomplete": ">=6.0.0", + "@codemirror/commands": ">=6.0.0", + "@codemirror/language": ">=6.0.0", + "@codemirror/lint": ">=6.0.0", + "@codemirror/search": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/react-codemirror": { + "version": "4.21.24", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.21.24.tgz", + "integrity": "sha512-8zs5OuxbhikHocHBsVBMuW1vqlv4ccZAkt4rFwr7ebLP2Q6RwHsjpsR9GeGyAigAqonKRoeHugqF78UMrkaTgg==", + "dependencies": { + "@babel/runtime": "^7.18.6", + "@codemirror/commands": "^6.1.0", + "@codemirror/state": "^6.1.1", + "@codemirror/theme-one-dark": "^6.0.0", + "@uiw/codemirror-extensions-basic-setup": "4.21.24", + "codemirror": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.11.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/theme-one-dark": ">=6.0.0", + "@codemirror/view": ">=6.0.0", + "codemirror": ">=6.0.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -7183,6 +7363,20 @@ "node": ">= 0.12.0" } }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -7605,6 +7799,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/cross-fetch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", @@ -18515,6 +18714,11 @@ "node": ">=0.8.0" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -19697,6 +19901,11 @@ "node": ">= 0.8" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", diff --git a/package.json b/package.json index a2cdf238..0a4a2c84 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ }, "main": "build/index.js", "dependencies": { + "@codemirror/lang-json": "^6.0.1", + "@uiw/react-codemirror": "^4.21.24", "@wordpress/icons": "^9.24.0", "lib-font": "^2.4.0" }, diff --git a/src/editor-sidebar/json-editor-modal.js b/src/editor-sidebar/json-editor-modal.js new file mode 100644 index 00000000..1b568195 --- /dev/null +++ b/src/editor-sidebar/json-editor-modal.js @@ -0,0 +1,38 @@ +import { useState, useEffect } from '@wordpress/element'; +import { Modal } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import CodeMirror from '@uiw/react-codemirror'; +import { json } from '@codemirror/lang-json'; +import { fetchThemeJson } from '../resolvers'; + +const ThemeJsonEditorModal = ( { onRequestClose } ) => { + const [ themeData, setThemeData ] = useState( '' ); + const themeName = useSelect( ( select ) => + select( 'core' ).getCurrentTheme() + )?.name?.raw; + const fetchThemeData = async () => { + setThemeData( await fetchThemeJson() ); + }; + const handleSave = () => {}; + + useEffect( () => { + fetchThemeData(); + } ); + + return ( + + + + ); +}; + +export default ThemeJsonEditorModal; diff --git a/src/plugin-sidebar.js b/src/plugin-sidebar.js index 2898291c..20397f15 100644 --- a/src/plugin-sidebar.js +++ b/src/plugin-sidebar.js @@ -1,3 +1,4 @@ +import { useState } from '@wordpress/element'; import { registerPlugin } from '@wordpress/plugins'; import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/edit-site'; import { __, _x } from '@wordpress/i18n'; @@ -28,6 +29,8 @@ import { import { UpdateThemePanel } from './editor-sidebar/update-panel'; import { CreateThemePanel } from './editor-sidebar/create-panel'; +import ThemeJsonEditorModal from './editor-sidebar/json-editor-modal'; + import { tool, copy, @@ -38,6 +41,7 @@ import { } from '@wordpress/icons'; const CreateBlockThemePlugin = () => { + const [ isEditorOpen, setIsEditorOpen ] = useState( false ); const { createErrorNotice } = useDispatch( noticesStore ); const handleSaveClick = () => { @@ -97,6 +101,7 @@ const CreateBlockThemePlugin = () => { exportTheme(); }; + return ( <> { 'create-block-theme' ) } +
+ + + { __( + 'Open the theme.json file to inspect theme data.', + 'create-block-theme' + ) } + @@ -201,6 +222,11 @@ const CreateBlockThemePlugin = () => { + { isEditorOpen && ( + setIsEditorOpen( false ) } + /> + ) } ); }; diff --git a/src/resolvers.js b/src/resolvers.js new file mode 100644 index 00000000..41308384 --- /dev/null +++ b/src/resolvers.js @@ -0,0 +1,27 @@ +import apiFetch from '@wordpress/api-fetch'; + +export async function fetchThemeJson() { + const fetchOptions = { + path: '/create-block-theme/v1/get-theme-data', + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }; + + try { + const response = await apiFetch( fetchOptions ); + + if ( ! response?.data || 'SUCCESS' !== response?.status ) { + throw new Error( + `Failed to fetch theme data: ${ + response?.message || response?.status + }` + ); + } + + return JSON.stringify( response?.data, null, 2 ); + } catch ( e ) { + // @todo: handle error + } +}