add-library.js
2 years ago
category-list.js
1 year ago
insert-pattern.js
2 years ago
library-cache.js
2 years ago
library-layout.js
1 year ago
library-provider.js
2 years ago
library-selector.js
1 year ago
manage-libraries.js
2 years ago
pattern-details-header.js
1 year ago
pattern-details.js
1 year ago
pattern-list.js
1 year ago
pattern-search.js
2 years ago
pattern.js
1 year ago
selected-patterns.js
1 year ago
library-layout.js
231 lines
| 1 | import { Button } from '@wordpress/components'; |
| 2 | import { close, arrowLeft } from '@wordpress/icons'; |
| 3 | import { __ } from '@wordpress/i18n'; |
| 4 | import { useState, useEffect, useRef } from '@wordpress/element'; |
| 5 | import { decodeEntities } from '@wordpress/html-entities'; |
| 6 | import { doAction } from '@wordpress/hooks'; |
| 7 | |
| 8 | import classnames from 'classnames'; |
| 9 | |
| 10 | import CategoryList from './category-list'; |
| 11 | import LibrarySelector from './library-selector'; |
| 12 | import { useLibrary } from './library-provider'; |
| 13 | import PatternList from './pattern-list'; |
| 14 | import PatternSearch from './pattern-search'; |
| 15 | import { SelectedPatterns } from './selected-patterns'; |
| 16 | import { PatternDetailsHeader } from './pattern-details-header'; |
| 17 | import LibraryCache from './library-cache'; |
| 18 | import ManageLibraries from './manage-libraries'; |
| 19 | import getIcon from '../../utils/get-icon'; |
| 20 | |
| 21 | const searchCache = {}; |
| 22 | |
| 23 | export default function LibraryLayout( { closeModal, readOnly } ) { |
| 24 | const { |
| 25 | activePatternId, |
| 26 | setActivePatternId, |
| 27 | patterns, |
| 28 | setScrollPosition, |
| 29 | scrollPosition, |
| 30 | activeCategory, |
| 31 | search, |
| 32 | setSearch, |
| 33 | isLocal, |
| 34 | activeLibrary, |
| 35 | selectedPatterns, |
| 36 | } = useLibrary(); |
| 37 | const [ bulkInsertEnabled, setBulkInsertEnabled ] = useState( false ); |
| 38 | const [ filteredPatterns, setFilteredPatterns ] = useState( patterns ); |
| 39 | const [ globalStyleCSS, setGlobalStyleCSS ] = useState( '' ); |
| 40 | const [ globalStyleData, setGlobalStyleData ] = useState( [] ); |
| 41 | const [ cacheIsClearing, setCacheIsClearing ] = useState( false ); |
| 42 | const activePattern = patterns.find( ( pattern ) => activePatternId === pattern.id ); |
| 43 | const patternContentRef = useRef(); |
| 44 | |
| 45 | function filterPatterns( value ) { |
| 46 | return patterns.filter( ( pattern ) => { |
| 47 | const viewingAll = activeCategory === ''; |
| 48 | const stringMatch = pattern.label.toLowerCase().includes( value.toLowerCase() ); |
| 49 | const categoryMatch = pattern.categories.includes( activeCategory ); |
| 50 | |
| 51 | return viewingAll ? stringMatch : stringMatch && categoryMatch; |
| 52 | } ); |
| 53 | } |
| 54 | |
| 55 | useEffect( () => { |
| 56 | if ( activeCategory === '' ) { |
| 57 | setFilteredPatterns( patterns ); |
| 58 | } else { |
| 59 | setFilteredPatterns( filterPatterns( search ) ); |
| 60 | } |
| 61 | |
| 62 | if ( patternContentRef.current ) { |
| 63 | patternContentRef.current.scrollTop = 0; |
| 64 | } |
| 65 | }, [ patterns, activeCategory ] ); |
| 66 | |
| 67 | function maybeGetCachedSearchResult( value ) { |
| 68 | const category = activeCategory === '' ? 'all' : activeCategory; |
| 69 | const library = activeLibrary?.id || ''; |
| 70 | |
| 71 | if ( ! searchCache[ library ] || ! searchCache[ library ][ category ] ) { |
| 72 | searchCache[ library ] = searchCache[ library ] || {}; |
| 73 | searchCache[ library ][ category ] = searchCache[ library ][ category ] || {}; |
| 74 | } |
| 75 | |
| 76 | // Check if the value exists in the cache |
| 77 | if ( ! searchCache[ library ][ category ][ value ] ) { |
| 78 | return false; |
| 79 | } |
| 80 | |
| 81 | return searchCache[ library ][ category ][ value ]; |
| 82 | } |
| 83 | |
| 84 | const contentStyles = {}; |
| 85 | |
| 86 | if ( activePatternId ) { |
| 87 | contentStyles.gridColumn = '1 / -1'; |
| 88 | } |
| 89 | |
| 90 | doAction( |
| 91 | 'generateblocks.patterns.patternsList', |
| 92 | { activeLibrary, setGlobalStyleCSS, setGlobalStyleData, isLocal, cacheIsClearing } |
| 93 | ); |
| 94 | |
| 95 | return ( |
| 96 | <div className="gb-pattern-library"> |
| 97 | <div className="gb-pattern-library__header"> |
| 98 | <div className="gb-pattern-library__header-title"> |
| 99 | { ! activePatternId |
| 100 | ? <h1>{ getIcon( 'generateblocks' ) } { __( 'Pattern Library', 'generateblocks' ) }</h1> |
| 101 | : <h1>{ decodeEntities( activePattern.label ) }</h1> |
| 102 | } |
| 103 | </div> |
| 104 | |
| 105 | <div className="gb-pattern-library__header-action"> |
| 106 | { ! activePatternId |
| 107 | ? <LibrarySelector readOnly={ readOnly } /> |
| 108 | : ( |
| 109 | <PatternDetailsHeader |
| 110 | pattern={ activePattern } |
| 111 | bulkInsertEnabled={ bulkInsertEnabled } |
| 112 | globalStyleData={ globalStyleData } |
| 113 | closeModal={ closeModal } |
| 114 | readOnly={ readOnly } |
| 115 | /> |
| 116 | ) |
| 117 | } |
| 118 | </div> |
| 119 | |
| 120 | <div className="gb-pattern-library__header-close"> |
| 121 | { ! activePatternId |
| 122 | ? ( |
| 123 | <> |
| 124 | { ! readOnly && ( |
| 125 | <> |
| 126 | <LibraryCache |
| 127 | setCacheIsClearing={ setCacheIsClearing } |
| 128 | cacheIsClearing={ cacheIsClearing } |
| 129 | /> |
| 130 | <ManageLibraries /> |
| 131 | </> |
| 132 | ) } |
| 133 | { typeof closeModal === 'function' && ( |
| 134 | <Button |
| 135 | variant="tertiary" |
| 136 | icon={ close } |
| 137 | label={ __( 'Close Pattern Library', 'generateblocks' ) } |
| 138 | showTooltip={ true } |
| 139 | onClick={ closeModal } |
| 140 | /> |
| 141 | ) } |
| 142 | </> |
| 143 | ) : ( |
| 144 | <Button |
| 145 | icon={ arrowLeft } |
| 146 | onClick={ () => { |
| 147 | setActivePatternId( '' ); |
| 148 | setScrollPosition( scrollPosition ); |
| 149 | } } |
| 150 | > |
| 151 | { __( 'Return to library' ) } |
| 152 | </Button> |
| 153 | ) |
| 154 | } |
| 155 | </div> |
| 156 | </div> |
| 157 | <div className="gb-pattern-library__sidebar"> |
| 158 | { ! activePatternId && |
| 159 | <> |
| 160 | <PatternSearch onChange={ ( value ) => { |
| 161 | setSearch( value ); |
| 162 | |
| 163 | const category = activeCategory === '' ? 'all' : activeCategory; |
| 164 | |
| 165 | // Check if result has been cached already |
| 166 | const cachedResult = maybeGetCachedSearchResult( value ); |
| 167 | |
| 168 | if ( cachedResult ) { |
| 169 | setFilteredPatterns( cachedResult ); |
| 170 | return; |
| 171 | } |
| 172 | |
| 173 | const newPatternList = filterPatterns( value ); |
| 174 | |
| 175 | const library = activeLibrary?.id; |
| 176 | |
| 177 | if ( library ) { |
| 178 | searchCache[ library ][ category ][ value ] = newPatternList; |
| 179 | } |
| 180 | |
| 181 | setFilteredPatterns( newPatternList ); |
| 182 | } } /> |
| 183 | |
| 184 | <CategoryList |
| 185 | bulkInsertEnabled={ bulkInsertEnabled } |
| 186 | selectedPatterns={ selectedPatterns } |
| 187 | /> |
| 188 | |
| 189 | { ! readOnly && ( |
| 190 | <> |
| 191 | { ! bulkInsertEnabled ? ( |
| 192 | <Button |
| 193 | variant="primary" |
| 194 | onClick={ () => setBulkInsertEnabled( true ) } |
| 195 | > |
| 196 | { __( 'Bulk Insert', 'generateblocks' ) } |
| 197 | </Button> |
| 198 | ) : ( |
| 199 | <SelectedPatterns |
| 200 | closeModal={ closeModal } |
| 201 | globalStyleData={ globalStyleData } |
| 202 | setBulkInsertEnabled={ setBulkInsertEnabled } |
| 203 | filteredPatterns={ filteredPatterns } |
| 204 | /> |
| 205 | ) } |
| 206 | </> |
| 207 | ) } |
| 208 | </> |
| 209 | } |
| 210 | </div> |
| 211 | <div |
| 212 | className={ classnames( { |
| 213 | 'gb-pattern-library__content': true, |
| 214 | 'gb-pattern-library__content--active': activePatternId, |
| 215 | } ) } |
| 216 | style={ contentStyles } |
| 217 | ref={ patternContentRef } |
| 218 | > |
| 219 | <PatternList |
| 220 | patterns={ filteredPatterns } |
| 221 | bulkInsertEnabled={ bulkInsertEnabled } |
| 222 | closeModal={ closeModal } |
| 223 | globalStyleCSS={ globalStyleCSS } |
| 224 | globalStyleData={ globalStyleData } |
| 225 | readOnly={ readOnly } |
| 226 | /> |
| 227 | </div> |
| 228 | </div> |
| 229 | ); |
| 230 | } |
| 231 |