@wordpress/edit-site 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/build/components/add-new-template/add-custom-template-modal.js +185 -0
- package/build/components/add-new-template/add-custom-template-modal.js.map +1 -0
- package/build/components/add-new-template/new-template.js +79 -14
- package/build/components/add-new-template/new-template.js.map +1 -1
- package/build/components/add-new-template/utils.js +139 -0
- package/build/components/add-new-template/utils.js.map +1 -0
- package/build/components/global-styles/context-menu.js +6 -3
- package/build/components/global-styles/context-menu.js.map +1 -1
- package/build/components/global-styles/hooks.js +1 -1
- package/build/components/global-styles/hooks.js.map +1 -1
- package/build/components/global-styles/palette.js +2 -1
- package/build/components/global-styles/palette.js.map +1 -1
- package/build/components/global-styles/screen-block-list.js +4 -1
- package/build/components/global-styles/screen-block-list.js.map +1 -1
- package/build/components/global-styles/screen-button-color.js +80 -0
- package/build/components/global-styles/screen-button-color.js.map +1 -0
- package/build/components/global-styles/screen-colors.js +47 -7
- package/build/components/global-styles/screen-colors.js.map +1 -1
- package/build/components/global-styles/screen-root.js +4 -2
- package/build/components/global-styles/screen-root.js.map +1 -1
- package/build/components/global-styles/screen-typography-element.js +4 -0
- package/build/components/global-styles/screen-typography-element.js.map +1 -1
- package/build/components/global-styles/screen-typography.js +9 -1
- package/build/components/global-styles/screen-typography.js.map +1 -1
- package/build/components/global-styles/ui.js +11 -0
- package/build/components/global-styles/ui.js.map +1 -1
- package/build/components/global-styles/use-global-styles-output.js +40 -9
- package/build/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build/components/global-styles/utils.js +3 -1
- package/build/components/global-styles/utils.js.map +1 -1
- package/build/components/header/index.js +28 -10
- package/build/components/header/index.js.map +1 -1
- package/build/components/header/more-menu/site-export.js +4 -1
- package/build/components/header/more-menu/site-export.js.map +1 -1
- package/build/components/header/undo-redo/redo.js +13 -4
- package/build/components/header/undo-redo/redo.js.map +1 -1
- package/build/components/header/undo-redo/undo.js +13 -4
- package/build/components/header/undo-redo/undo.js.map +1 -1
- package/build/components/keyboard-shortcut-help-modal/config.js +17 -0
- package/build/components/keyboard-shortcut-help-modal/config.js.map +1 -1
- package/build/components/sidebar/template-card/index.js +19 -7
- package/build/components/sidebar/template-card/index.js.map +1 -1
- package/build/components/sidebar/template-card/template-actions.js +64 -0
- package/build/components/sidebar/template-card/template-actions.js.map +1 -0
- package/build-module/components/add-new-template/add-custom-template-modal.js +170 -0
- package/build-module/components/add-new-template/add-custom-template-modal.js.map +1 -0
- package/build-module/components/add-new-template/new-template.js +79 -17
- package/build-module/components/add-new-template/new-template.js.map +1 -1
- package/build-module/components/add-new-template/utils.js +119 -0
- package/build-module/components/add-new-template/utils.js.map +1 -0
- package/build-module/components/global-styles/context-menu.js +6 -3
- package/build-module/components/global-styles/context-menu.js.map +1 -1
- package/build-module/components/global-styles/hooks.js +1 -1
- package/build-module/components/global-styles/hooks.js.map +1 -1
- package/build-module/components/global-styles/palette.js +2 -1
- package/build-module/components/global-styles/palette.js.map +1 -1
- package/build-module/components/global-styles/screen-block-list.js +4 -1
- package/build-module/components/global-styles/screen-block-list.js.map +1 -1
- package/build-module/components/global-styles/screen-button-color.js +67 -0
- package/build-module/components/global-styles/screen-button-color.js.map +1 -0
- package/build-module/components/global-styles/screen-colors.js +48 -8
- package/build-module/components/global-styles/screen-colors.js.map +1 -1
- package/build-module/components/global-styles/screen-root.js +4 -2
- package/build-module/components/global-styles/screen-root.js.map +1 -1
- package/build-module/components/global-styles/screen-typography-element.js +4 -0
- package/build-module/components/global-styles/screen-typography-element.js.map +1 -1
- package/build-module/components/global-styles/screen-typography.js +10 -2
- package/build-module/components/global-styles/screen-typography.js.map +1 -1
- package/build-module/components/global-styles/ui.js +10 -0
- package/build-module/components/global-styles/ui.js.map +1 -1
- package/build-module/components/global-styles/use-global-styles-output.js +39 -9
- package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build-module/components/global-styles/utils.js +3 -1
- package/build-module/components/global-styles/utils.js.map +1 -1
- package/build-module/components/header/index.js +29 -11
- package/build-module/components/header/index.js.map +1 -1
- package/build-module/components/header/more-menu/site-export.js +4 -1
- package/build-module/components/header/more-menu/site-export.js.map +1 -1
- package/build-module/components/header/undo-redo/redo.js +9 -3
- package/build-module/components/header/undo-redo/redo.js.map +1 -1
- package/build-module/components/header/undo-redo/undo.js +9 -3
- package/build-module/components/header/undo-redo/undo.js.map +1 -1
- package/build-module/components/keyboard-shortcut-help-modal/config.js +17 -0
- package/build-module/components/keyboard-shortcut-help-modal/config.js.map +1 -1
- package/build-module/components/sidebar/template-card/index.js +18 -7
- package/build-module/components/sidebar/template-card/index.js.map +1 -1
- package/build-module/components/sidebar/template-card/template-actions.js +49 -0
- package/build-module/components/sidebar/template-card/template-actions.js.map +1 -0
- package/build-style/style-rtl.css +167 -16
- package/build-style/style.css +167 -16
- package/package.json +29 -29
- package/src/components/add-new-template/add-custom-template-modal.js +231 -0
- package/src/components/add-new-template/new-template.js +124 -47
- package/src/components/add-new-template/style.scss +116 -0
- package/src/components/add-new-template/utils.js +125 -0
- package/src/components/global-styles/context-menu.js +3 -0
- package/src/components/global-styles/hooks.js +1 -0
- package/src/components/global-styles/palette.js +4 -1
- package/src/components/global-styles/screen-block-list.js +10 -1
- package/src/components/global-styles/screen-button-color.js +102 -0
- package/src/components/global-styles/screen-colors.js +49 -4
- package/src/components/global-styles/screen-root.js +8 -2
- package/src/components/global-styles/screen-typography-element.js +4 -0
- package/src/components/global-styles/screen-typography.js +17 -2
- package/src/components/global-styles/style.scss +10 -0
- package/src/components/global-styles/test/use-global-styles-output.js +82 -16
- package/src/components/global-styles/ui.js +13 -0
- package/src/components/global-styles/use-global-styles-output.js +43 -4
- package/src/components/global-styles/utils.js +3 -0
- package/src/components/header/index.js +36 -10
- package/src/components/header/more-menu/site-export.js +3 -0
- package/src/components/header/style.scss +53 -5
- package/src/components/header/undo-redo/redo.js +6 -1
- package/src/components/header/undo-redo/undo.js +6 -1
- package/src/components/keyboard-shortcut-help-modal/config.js +12 -0
- package/src/components/sidebar/template-card/index.js +15 -6
- package/src/components/sidebar/template-card/style.scss +49 -35
- package/src/components/sidebar/template-card/template-actions.js +43 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/edit-site",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.0",
|
|
4
4
|
"description": "Edit Site Page module for WordPress.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -27,33 +27,33 @@
|
|
|
27
27
|
"react-native": "src/index",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@babel/runtime": "^7.16.0",
|
|
30
|
-
"@wordpress/a11y": "^3.
|
|
31
|
-
"@wordpress/api-fetch": "^6.
|
|
32
|
-
"@wordpress/block-editor": "^9.
|
|
33
|
-
"@wordpress/block-library": "^7.
|
|
34
|
-
"@wordpress/blocks": "^11.
|
|
35
|
-
"@wordpress/components": "^19.
|
|
36
|
-
"@wordpress/compose": "^5.
|
|
37
|
-
"@wordpress/core-data": "^4.
|
|
38
|
-
"@wordpress/data": "^6.
|
|
39
|
-
"@wordpress/deprecated": "^3.
|
|
40
|
-
"@wordpress/editor": "^12.
|
|
41
|
-
"@wordpress/element": "^4.
|
|
42
|
-
"@wordpress/hooks": "^3.
|
|
43
|
-
"@wordpress/html-entities": "^3.
|
|
44
|
-
"@wordpress/i18n": "^4.
|
|
45
|
-
"@wordpress/icons": "^9.
|
|
46
|
-
"@wordpress/interface": "^4.
|
|
47
|
-
"@wordpress/keyboard-shortcuts": "^3.
|
|
48
|
-
"@wordpress/keycodes": "^3.
|
|
49
|
-
"@wordpress/media-utils": "^4.
|
|
50
|
-
"@wordpress/notices": "^3.
|
|
51
|
-
"@wordpress/plugins": "^4.
|
|
52
|
-
"@wordpress/preferences": "^2.
|
|
53
|
-
"@wordpress/reusable-blocks": "^3.
|
|
54
|
-
"@wordpress/style-engine": "^0.
|
|
55
|
-
"@wordpress/url": "^3.
|
|
56
|
-
"@wordpress/viewport": "^4.
|
|
30
|
+
"@wordpress/a11y": "^3.12.0",
|
|
31
|
+
"@wordpress/api-fetch": "^6.9.0",
|
|
32
|
+
"@wordpress/block-editor": "^9.4.0",
|
|
33
|
+
"@wordpress/block-library": "^7.9.0",
|
|
34
|
+
"@wordpress/blocks": "^11.11.0",
|
|
35
|
+
"@wordpress/components": "^19.14.0",
|
|
36
|
+
"@wordpress/compose": "^5.10.0",
|
|
37
|
+
"@wordpress/core-data": "^4.10.0",
|
|
38
|
+
"@wordpress/data": "^6.12.0",
|
|
39
|
+
"@wordpress/deprecated": "^3.12.0",
|
|
40
|
+
"@wordpress/editor": "^12.11.0",
|
|
41
|
+
"@wordpress/element": "^4.10.0",
|
|
42
|
+
"@wordpress/hooks": "^3.12.0",
|
|
43
|
+
"@wordpress/html-entities": "^3.12.0",
|
|
44
|
+
"@wordpress/i18n": "^4.12.0",
|
|
45
|
+
"@wordpress/icons": "^9.3.0",
|
|
46
|
+
"@wordpress/interface": "^4.11.0",
|
|
47
|
+
"@wordpress/keyboard-shortcuts": "^3.10.0",
|
|
48
|
+
"@wordpress/keycodes": "^3.12.0",
|
|
49
|
+
"@wordpress/media-utils": "^4.3.0",
|
|
50
|
+
"@wordpress/notices": "^3.12.0",
|
|
51
|
+
"@wordpress/plugins": "^4.10.0",
|
|
52
|
+
"@wordpress/preferences": "^2.4.0",
|
|
53
|
+
"@wordpress/reusable-blocks": "^3.10.0",
|
|
54
|
+
"@wordpress/style-engine": "^0.11.0",
|
|
55
|
+
"@wordpress/url": "^3.13.0",
|
|
56
|
+
"@wordpress/viewport": "^4.10.0",
|
|
57
57
|
"classnames": "^2.3.1",
|
|
58
58
|
"downloadjs": "^1.4.7",
|
|
59
59
|
"history": "^5.1.0",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "a80eeb62ec7cb1418b9915c277e084a29d6665e3"
|
|
72
72
|
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useMemo, useEffect } from '@wordpress/element';
|
|
5
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
6
|
+
import {
|
|
7
|
+
Button,
|
|
8
|
+
Flex,
|
|
9
|
+
FlexItem,
|
|
10
|
+
Modal,
|
|
11
|
+
SearchControl,
|
|
12
|
+
TextHighlight,
|
|
13
|
+
__experimentalText as Text,
|
|
14
|
+
__experimentalHeading as Heading,
|
|
15
|
+
__unstableComposite as Composite,
|
|
16
|
+
__unstableUseCompositeState as useCompositeState,
|
|
17
|
+
__unstableCompositeItem as CompositeItem,
|
|
18
|
+
} from '@wordpress/components';
|
|
19
|
+
import { useDebounce } from '@wordpress/compose';
|
|
20
|
+
import { useEntityRecords } from '@wordpress/core-data';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Internal dependencies
|
|
24
|
+
*/
|
|
25
|
+
import { mapToIHasNameAndId } from './utils';
|
|
26
|
+
|
|
27
|
+
const EMPTY_ARRAY = [];
|
|
28
|
+
const BASE_QUERY = {
|
|
29
|
+
order: 'asc',
|
|
30
|
+
_fields: 'id,title,slug,link',
|
|
31
|
+
context: 'view',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function SuggestionListItem( {
|
|
35
|
+
suggestion,
|
|
36
|
+
search,
|
|
37
|
+
onSelect,
|
|
38
|
+
entityForSuggestions,
|
|
39
|
+
composite,
|
|
40
|
+
} ) {
|
|
41
|
+
const baseCssClass =
|
|
42
|
+
'edit-site-custom-template-modal__suggestions_list__list-item';
|
|
43
|
+
return (
|
|
44
|
+
<CompositeItem
|
|
45
|
+
role="option"
|
|
46
|
+
as={ Button }
|
|
47
|
+
{ ...composite }
|
|
48
|
+
className={ baseCssClass }
|
|
49
|
+
onClick={ () => {
|
|
50
|
+
const title = sprintf(
|
|
51
|
+
// translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type and %2$s is the name of the post, e.g. "Post: Hello, WordPress"
|
|
52
|
+
__( '%1$s: %2$s' ),
|
|
53
|
+
entityForSuggestions.labels.singular_name,
|
|
54
|
+
suggestion.name
|
|
55
|
+
);
|
|
56
|
+
onSelect( {
|
|
57
|
+
title,
|
|
58
|
+
description: sprintf(
|
|
59
|
+
// translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Post: Hello, WordPress"
|
|
60
|
+
__( 'Template for %1$s' ),
|
|
61
|
+
title
|
|
62
|
+
),
|
|
63
|
+
slug: `single-${ entityForSuggestions.slug }-${ suggestion.slug }`,
|
|
64
|
+
} );
|
|
65
|
+
} }
|
|
66
|
+
>
|
|
67
|
+
<span className={ `${ baseCssClass }__title` }>
|
|
68
|
+
<TextHighlight text={ suggestion.name } highlight={ search } />
|
|
69
|
+
</span>
|
|
70
|
+
{ suggestion.link && (
|
|
71
|
+
<span className={ `${ baseCssClass }__info` }>
|
|
72
|
+
{ suggestion.link }
|
|
73
|
+
</span>
|
|
74
|
+
) }
|
|
75
|
+
</CompositeItem>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function SuggestionList( { entityForSuggestions, onSelect } ) {
|
|
80
|
+
const composite = useCompositeState( { orientation: 'vertical' } );
|
|
81
|
+
const [ suggestions, setSuggestions ] = useState( EMPTY_ARRAY );
|
|
82
|
+
// We need to track two values, the search input's value(searchInputValue)
|
|
83
|
+
// and the one we want to debounce(search) and make REST API requests.
|
|
84
|
+
const [ searchInputValue, setSearchInputValue ] = useState( '' );
|
|
85
|
+
const [ search, setSearch ] = useState( '' );
|
|
86
|
+
const debouncedSearch = useDebounce( setSearch, 250 );
|
|
87
|
+
const query = {
|
|
88
|
+
...BASE_QUERY,
|
|
89
|
+
search,
|
|
90
|
+
orderby: search ? 'relevance' : 'modified',
|
|
91
|
+
exclude: entityForSuggestions.postsToExclude,
|
|
92
|
+
per_page: search ? 20 : 10,
|
|
93
|
+
};
|
|
94
|
+
const { records: searchResults, hasResolved: searchHasResolved } =
|
|
95
|
+
useEntityRecords(
|
|
96
|
+
entityForSuggestions.type,
|
|
97
|
+
entityForSuggestions.slug,
|
|
98
|
+
query
|
|
99
|
+
);
|
|
100
|
+
useEffect( () => {
|
|
101
|
+
if ( search !== searchInputValue ) {
|
|
102
|
+
debouncedSearch( searchInputValue );
|
|
103
|
+
}
|
|
104
|
+
}, [ search, searchInputValue ] );
|
|
105
|
+
const entitiesInfo = useMemo( () => {
|
|
106
|
+
if ( ! searchResults?.length ) return EMPTY_ARRAY;
|
|
107
|
+
return mapToIHasNameAndId( searchResults, 'title.rendered' );
|
|
108
|
+
}, [ searchResults ] );
|
|
109
|
+
// Update suggestions only when the query has resolved.
|
|
110
|
+
useEffect( () => {
|
|
111
|
+
if ( ! searchHasResolved ) return;
|
|
112
|
+
setSuggestions( entitiesInfo );
|
|
113
|
+
}, [ entitiesInfo, searchHasResolved ] );
|
|
114
|
+
return (
|
|
115
|
+
<>
|
|
116
|
+
<SearchControl
|
|
117
|
+
onChange={ setSearchInputValue }
|
|
118
|
+
value={ searchInputValue }
|
|
119
|
+
label={ entityForSuggestions.labels.search_items }
|
|
120
|
+
placeholder={ entityForSuggestions.labels.search_items }
|
|
121
|
+
/>
|
|
122
|
+
{ !! suggestions?.length && (
|
|
123
|
+
<Composite
|
|
124
|
+
{ ...composite }
|
|
125
|
+
role="listbox"
|
|
126
|
+
className="edit-site-custom-template-modal__suggestions_list"
|
|
127
|
+
>
|
|
128
|
+
{ suggestions.map( ( suggestion ) => (
|
|
129
|
+
<SuggestionListItem
|
|
130
|
+
key={ suggestion.slug }
|
|
131
|
+
suggestion={ suggestion }
|
|
132
|
+
search={ search }
|
|
133
|
+
onSelect={ onSelect }
|
|
134
|
+
entityForSuggestions={ entityForSuggestions }
|
|
135
|
+
composite={ composite }
|
|
136
|
+
/>
|
|
137
|
+
) ) }
|
|
138
|
+
</Composite>
|
|
139
|
+
) }
|
|
140
|
+
{ search && ! suggestions?.length && (
|
|
141
|
+
<p className="edit-site-custom-template-modal__no-results">
|
|
142
|
+
{ entityForSuggestions.labels.not_found }
|
|
143
|
+
</p>
|
|
144
|
+
) }
|
|
145
|
+
</>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function AddCustomTemplateModal( { onClose, onSelect, entityForSuggestions } ) {
|
|
150
|
+
const [ showSearchEntities, setShowSearchEntities ] = useState(
|
|
151
|
+
entityForSuggestions.hasGeneralTemplate
|
|
152
|
+
);
|
|
153
|
+
const baseCssClass = 'edit-site-custom-template-modal';
|
|
154
|
+
return (
|
|
155
|
+
<Modal
|
|
156
|
+
title={ sprintf(
|
|
157
|
+
// translators: %s: Name of the post type e.g: "Post".
|
|
158
|
+
__( 'Add template: %s' ),
|
|
159
|
+
entityForSuggestions.labels.singular_name
|
|
160
|
+
) }
|
|
161
|
+
className={ baseCssClass }
|
|
162
|
+
closeLabel={ __( 'Close' ) }
|
|
163
|
+
onRequestClose={ onClose }
|
|
164
|
+
>
|
|
165
|
+
{ ! showSearchEntities && (
|
|
166
|
+
<>
|
|
167
|
+
<p>
|
|
168
|
+
{ __(
|
|
169
|
+
'Select whether to create a single template for all items or a specific one.'
|
|
170
|
+
) }
|
|
171
|
+
</p>
|
|
172
|
+
<Flex
|
|
173
|
+
className={ `${ baseCssClass }__contents` }
|
|
174
|
+
gap="4"
|
|
175
|
+
align="initial"
|
|
176
|
+
>
|
|
177
|
+
<FlexItem
|
|
178
|
+
isBlock
|
|
179
|
+
onClick={ () => {
|
|
180
|
+
const { slug, title, description } =
|
|
181
|
+
entityForSuggestions.template;
|
|
182
|
+
onSelect( { slug, title, description } );
|
|
183
|
+
} }
|
|
184
|
+
>
|
|
185
|
+
<Heading level={ 5 }>
|
|
186
|
+
{ entityForSuggestions.labels.all_items }
|
|
187
|
+
</Heading>
|
|
188
|
+
<Text as="span">
|
|
189
|
+
{
|
|
190
|
+
// translators: The user is given the choice to set up a template for all items of a post type, or just a specific one.
|
|
191
|
+
__( 'For all items' )
|
|
192
|
+
}
|
|
193
|
+
</Text>
|
|
194
|
+
</FlexItem>
|
|
195
|
+
<FlexItem
|
|
196
|
+
isBlock
|
|
197
|
+
onClick={ () => {
|
|
198
|
+
setShowSearchEntities( true );
|
|
199
|
+
} }
|
|
200
|
+
>
|
|
201
|
+
<Heading level={ 5 }>
|
|
202
|
+
{ entityForSuggestions.labels.singular_name }
|
|
203
|
+
</Heading>
|
|
204
|
+
<Text as="span">
|
|
205
|
+
{
|
|
206
|
+
// translators: The user is given the choice to set up a template for all items of a post type, or just a specific one.
|
|
207
|
+
__( 'For a specific item' )
|
|
208
|
+
}
|
|
209
|
+
</Text>
|
|
210
|
+
</FlexItem>
|
|
211
|
+
</Flex>
|
|
212
|
+
</>
|
|
213
|
+
) }
|
|
214
|
+
{ showSearchEntities && (
|
|
215
|
+
<>
|
|
216
|
+
<p>
|
|
217
|
+
{ __(
|
|
218
|
+
'This template will be used only for the specific item chosen.'
|
|
219
|
+
) }
|
|
220
|
+
</p>
|
|
221
|
+
<SuggestionList
|
|
222
|
+
entityForSuggestions={ entityForSuggestions }
|
|
223
|
+
onSelect={ onSelect }
|
|
224
|
+
/>
|
|
225
|
+
</>
|
|
226
|
+
) }
|
|
227
|
+
</Modal>
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export default AddCustomTemplateModal;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { filter, includes
|
|
4
|
+
import { filter, includes } from 'lodash';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
MenuItem,
|
|
13
13
|
NavigableMenu,
|
|
14
14
|
} from '@wordpress/components';
|
|
15
|
+
import { useState } from '@wordpress/element';
|
|
15
16
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
16
17
|
import { store as coreStore } from '@wordpress/core-data';
|
|
17
18
|
import { store as editorStore } from '@wordpress/editor';
|
|
@@ -30,12 +31,14 @@ import {
|
|
|
30
31
|
search,
|
|
31
32
|
tag,
|
|
32
33
|
} from '@wordpress/icons';
|
|
33
|
-
import { __ } from '@wordpress/i18n';
|
|
34
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
34
35
|
import { store as noticesStore } from '@wordpress/notices';
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Internal dependencies
|
|
38
39
|
*/
|
|
40
|
+
import AddCustomTemplateModal from './add-custom-template-modal';
|
|
41
|
+
import { usePostTypes, usePostTypesEntitiesInfo } from './utils';
|
|
39
42
|
import { useHistory } from '../routes';
|
|
40
43
|
import { store as editSiteStore } from '../../store';
|
|
41
44
|
|
|
@@ -72,9 +75,13 @@ const TEMPLATE_ICONS = {
|
|
|
72
75
|
|
|
73
76
|
export default function NewTemplate( { postType } ) {
|
|
74
77
|
const history = useHistory();
|
|
75
|
-
const
|
|
78
|
+
const postTypes = usePostTypes();
|
|
79
|
+
const [ showCustomTemplateModal, setShowCustomTemplateModal ] =
|
|
80
|
+
useState( false );
|
|
81
|
+
const [ entityForSuggestions, setEntityForSuggestions ] = useState( {} );
|
|
82
|
+
const { existingTemplates, defaultTemplateTypes } = useSelect(
|
|
76
83
|
( select ) => ( {
|
|
77
|
-
|
|
84
|
+
existingTemplates: select( coreStore ).getEntityRecords(
|
|
78
85
|
'postType',
|
|
79
86
|
'wp_template',
|
|
80
87
|
{ per_page: -1 }
|
|
@@ -84,6 +91,7 @@ export default function NewTemplate( { postType } ) {
|
|
|
84
91
|
} ),
|
|
85
92
|
[]
|
|
86
93
|
);
|
|
94
|
+
const postTypesEntitiesInfo = usePostTypesEntitiesInfo( existingTemplates );
|
|
87
95
|
const { saveEntityRecord } = useDispatch( coreStore );
|
|
88
96
|
const { createErrorNotice } = useDispatch( noticesStore );
|
|
89
97
|
const { setTemplate } = useDispatch( editSiteStore );
|
|
@@ -91,7 +99,6 @@ export default function NewTemplate( { postType } ) {
|
|
|
91
99
|
async function createTemplate( template ) {
|
|
92
100
|
try {
|
|
93
101
|
const { title, description, slug } = template;
|
|
94
|
-
|
|
95
102
|
const newTemplate = await saveEntityRecord(
|
|
96
103
|
'postType',
|
|
97
104
|
'wp_template',
|
|
@@ -128,9 +135,9 @@ export default function NewTemplate( { postType } ) {
|
|
|
128
135
|
} );
|
|
129
136
|
}
|
|
130
137
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
const existingTemplateSlugs = ( existingTemplates || [] ).map(
|
|
139
|
+
( { slug } ) => slug
|
|
140
|
+
);
|
|
134
141
|
const missingTemplates = filter(
|
|
135
142
|
defaultTemplateTypes,
|
|
136
143
|
( template ) =>
|
|
@@ -138,54 +145,124 @@ export default function NewTemplate( { postType } ) {
|
|
|
138
145
|
! includes( existingTemplateSlugs, template.slug )
|
|
139
146
|
);
|
|
140
147
|
|
|
141
|
-
|
|
148
|
+
const extraTemplates = ( postTypes || [] ).reduce(
|
|
149
|
+
( accumulator, _postType ) => {
|
|
150
|
+
const { slug, labels, icon } = _postType;
|
|
151
|
+
const hasGeneralTemplate = existingTemplateSlugs?.includes(
|
|
152
|
+
`single-${ slug }`
|
|
153
|
+
);
|
|
154
|
+
const hasEntities = postTypesEntitiesInfo?.[ slug ]?.hasEntities;
|
|
155
|
+
const menuItem = {
|
|
156
|
+
slug: `single-${ slug }`,
|
|
157
|
+
title: sprintf(
|
|
158
|
+
// translators: %s: Name of the post type e.g: "Post".
|
|
159
|
+
__( 'Single item: %s' ),
|
|
160
|
+
labels.singular_name
|
|
161
|
+
),
|
|
162
|
+
description: sprintf(
|
|
163
|
+
// translators: %s: Name of the post type e.g: "Post".
|
|
164
|
+
__( 'Displays a single item: %s.' ),
|
|
165
|
+
labels.singular_name
|
|
166
|
+
),
|
|
167
|
+
// `icon` is the `menu_icon` property of a post type. We
|
|
168
|
+
// only handle `dashicons` for now, even if the `menu_icon`
|
|
169
|
+
// also supports urls and svg as values.
|
|
170
|
+
icon: icon?.startsWith( 'dashicons-' )
|
|
171
|
+
? icon.slice( 10 )
|
|
172
|
+
: null,
|
|
173
|
+
};
|
|
174
|
+
// We have a different template creation flow only if they have entities.
|
|
175
|
+
if ( hasEntities ) {
|
|
176
|
+
menuItem.onClick = ( template ) => {
|
|
177
|
+
setShowCustomTemplateModal( true );
|
|
178
|
+
setEntityForSuggestions( {
|
|
179
|
+
type: 'postType',
|
|
180
|
+
slug,
|
|
181
|
+
labels,
|
|
182
|
+
hasGeneralTemplate,
|
|
183
|
+
template,
|
|
184
|
+
postsToExclude:
|
|
185
|
+
postTypesEntitiesInfo[ slug ].existingPosts,
|
|
186
|
+
} );
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// We don't need to add the menu item if there are no
|
|
190
|
+
// entities and the general template exists.
|
|
191
|
+
if ( ! hasGeneralTemplate || hasEntities ) {
|
|
192
|
+
accumulator.push( menuItem );
|
|
193
|
+
}
|
|
194
|
+
return accumulator;
|
|
195
|
+
},
|
|
196
|
+
[]
|
|
197
|
+
);
|
|
198
|
+
if ( ! missingTemplates.length && ! extraTemplates.length ) {
|
|
142
199
|
return null;
|
|
143
200
|
}
|
|
144
|
-
|
|
145
201
|
// Update the sort order to match the DEFAULT_TEMPLATE_SLUGS order.
|
|
146
|
-
missingTemplates
|
|
202
|
+
missingTemplates?.sort( ( template1, template2 ) => {
|
|
147
203
|
return (
|
|
148
204
|
DEFAULT_TEMPLATE_SLUGS.indexOf( template1.slug ) -
|
|
149
205
|
DEFAULT_TEMPLATE_SLUGS.indexOf( template2.slug )
|
|
150
206
|
);
|
|
151
207
|
} );
|
|
152
|
-
|
|
208
|
+
// Append all extra templates at the end of the list for now.
|
|
209
|
+
missingTemplates.push( ...extraTemplates );
|
|
153
210
|
return (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
{
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
211
|
+
<>
|
|
212
|
+
<DropdownMenu
|
|
213
|
+
className="edit-site-new-template-dropdown"
|
|
214
|
+
icon={ null }
|
|
215
|
+
text={ postType.labels.add_new }
|
|
216
|
+
label={ postType.labels.add_new_item }
|
|
217
|
+
popoverProps={ {
|
|
218
|
+
noArrow: false,
|
|
219
|
+
} }
|
|
220
|
+
toggleProps={ {
|
|
221
|
+
variant: 'primary',
|
|
222
|
+
} }
|
|
223
|
+
>
|
|
224
|
+
{ () => (
|
|
225
|
+
<NavigableMenu className="edit-site-new-template-dropdown__popover">
|
|
226
|
+
<MenuGroup label={ postType.labels.add_new_item }>
|
|
227
|
+
{ missingTemplates.map( ( template ) => {
|
|
228
|
+
const {
|
|
229
|
+
title,
|
|
230
|
+
description,
|
|
231
|
+
slug,
|
|
232
|
+
onClick,
|
|
233
|
+
icon,
|
|
234
|
+
} = template;
|
|
235
|
+
return (
|
|
236
|
+
<MenuItem
|
|
237
|
+
icon={
|
|
238
|
+
icon ||
|
|
239
|
+
TEMPLATE_ICONS[ slug ] ||
|
|
240
|
+
post
|
|
241
|
+
}
|
|
242
|
+
iconPosition="left"
|
|
243
|
+
info={ description }
|
|
244
|
+
key={ slug }
|
|
245
|
+
onClick={ () =>
|
|
246
|
+
onClick
|
|
247
|
+
? onClick( template )
|
|
248
|
+
: createTemplate( template )
|
|
249
|
+
}
|
|
250
|
+
>
|
|
251
|
+
{ title }
|
|
252
|
+
</MenuItem>
|
|
253
|
+
);
|
|
254
|
+
} ) }
|
|
255
|
+
</MenuGroup>
|
|
256
|
+
</NavigableMenu>
|
|
257
|
+
) }
|
|
258
|
+
</DropdownMenu>
|
|
259
|
+
{ showCustomTemplateModal && (
|
|
260
|
+
<AddCustomTemplateModal
|
|
261
|
+
onClose={ () => setShowCustomTemplateModal( false ) }
|
|
262
|
+
onSelect={ createTemplate }
|
|
263
|
+
entityForSuggestions={ entityForSuggestions }
|
|
264
|
+
/>
|
|
188
265
|
) }
|
|
189
|
-
|
|
266
|
+
</>
|
|
190
267
|
);
|
|
191
268
|
}
|
|
@@ -9,3 +9,119 @@
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
.edit-site-custom-template-modal {
|
|
14
|
+
&__contents {
|
|
15
|
+
> div {
|
|
16
|
+
text-align: center;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
padding: $grid-unit-30;
|
|
19
|
+
border: 1px solid $gray-300;
|
|
20
|
+
border-radius: $radius-block-ui;
|
|
21
|
+
width: 256px;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
gap: $grid-unit;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
|
|
28
|
+
span {
|
|
29
|
+
color: $gray-700;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&:hover {
|
|
33
|
+
border-color: var(--wp-admin-theme-color);
|
|
34
|
+
|
|
35
|
+
h5 {
|
|
36
|
+
color: var(--wp-admin-theme-color);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&:focus {
|
|
41
|
+
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.components-search-control {
|
|
47
|
+
input[type="search"].components-search-control__input {
|
|
48
|
+
background: $white;
|
|
49
|
+
border: 1px solid $gray-300;
|
|
50
|
+
|
|
51
|
+
&:focus {
|
|
52
|
+
border-color: var(--wp-admin-theme-color);
|
|
53
|
+
box-shadow: 0 0 0 1px var(--wp-admin-theme-color);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@include break-medium() {
|
|
59
|
+
width: 456px;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.edit-site-custom-template-modal__suggestions_list {
|
|
64
|
+
margin-top: $grid-unit-20;
|
|
65
|
+
|
|
66
|
+
@include break-small() {
|
|
67
|
+
height: 232px;
|
|
68
|
+
overflow: scroll;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&__list-item {
|
|
72
|
+
display: block;
|
|
73
|
+
width: 100%;
|
|
74
|
+
text-align: left;
|
|
75
|
+
white-space: pre-wrap;
|
|
76
|
+
overflow-wrap: break-word;
|
|
77
|
+
height: auto;
|
|
78
|
+
|
|
79
|
+
mark {
|
|
80
|
+
font-weight: 700;
|
|
81
|
+
background: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&:hover {
|
|
85
|
+
background-color: $gray-100;
|
|
86
|
+
|
|
87
|
+
mark {
|
|
88
|
+
color: var(--wp-admin-theme-color);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&:focus {
|
|
93
|
+
background-color: $gray-100;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&:focus:not(:disabled) {
|
|
97
|
+
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color) inset;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&__title,
|
|
101
|
+
&__info {
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
text-overflow: ellipsis;
|
|
104
|
+
display: block;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&__title {
|
|
108
|
+
font-weight: 500;
|
|
109
|
+
margin-bottom: 0.2em;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&__info {
|
|
113
|
+
color: $gray-700;
|
|
114
|
+
font-size: 0.9em;
|
|
115
|
+
line-height: 1.3;
|
|
116
|
+
word-break: break-all;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.edit-site-custom-template-modal__no-results {
|
|
122
|
+
border: 1px solid $gray-400;
|
|
123
|
+
border-radius: $radius-block-ui;
|
|
124
|
+
padding: $grid-unit-20;
|
|
125
|
+
margin-bottom: 0;
|
|
126
|
+
margin-top: $grid-unit-20;
|
|
127
|
+
}
|