Single.js (5776B)
1 import { ImportButton } from '../../components/ImportButton' 2 import { __ } from '@wordpress/i18n' 3 import classNames from 'classnames' 4 import { useUserStore } from '../../state/User' 5 import { ExternalLink } from '@wordpress/components' 6 import { 7 useEffect, useState, useCallback, 8 } from '@wordpress/element' 9 import { Templates as TemplatesApi } from '../../api/Templates' 10 import TaxonomyList from '../../components/TaxonomyList' 11 import { useIsMounted } from '../../hooks/helpers' 12 import { useTemplatesStore } from '../../state/Templates' 13 14 const relatedMap = new Map() 15 16 export default function Single({ template }) { 17 const { 18 tax_categories: categories, 19 required_plugins: requiredPlugins, 20 tax_style: styles, 21 tax_pattern_types: types, 22 } = template.fields 23 const apiKey = useUserStore(state => state.apiKey) 24 const [related, setRelated] = useState([]) 25 const [alternatives, setAlternatives] = useState([]) 26 const isMounted = useIsMounted() 27 const setActiveTemplate = useTemplatesStore(state => state.setActive) 28 29 const changeTemplate = (template) => { 30 setRelated([]) 31 setAlternatives([]) 32 requestAnimationFrame(() => setActiveTemplate(template)) 33 } 34 35 const fetchRelated = useCallback(async (queryType, wantedType) => { 36 const key = `${template.id}|${queryType}|${wantedType}` 37 if (relatedMap.has(key)) { 38 return relatedMap.get(key) 39 } 40 const results = await TemplatesApi.related( 41 template, queryType, wantedType, 42 ) 43 relatedMap.set(key, results) 44 return results 45 }, [template]) 46 47 useEffect(() => { TemplatesApi.single(template) }, [template]) 48 useEffect(() => { 49 fetchRelated('related', 'pattern').then((results) => { 50 isMounted.current && setRelated(results) 51 // fetchRelated('alternatives', template.fields.type).then((results) => { 52 // isMounted.current && setAlternatives(results) 53 // }) 54 }) 55 }, [template, fetchRelated, isMounted]) 56 57 return <div className="flex flex-col min-h-screen bg-white sm:min-h-0 items-start overflow-y-auto h-full sm:pr-8 lg:pl-px lg:-ml-px"> 58 <div className="lg:sticky top-0 bg-white flex flex-col lg:flex-row items-start justify-start lg:items-center lg:justify-between w-full max-w-screen-xl lg:border-b border-gray-300"> 59 <div className="text-left m-0 h-full px-6 sm:p-0"> 60 <h1 className="leading-tight text-left mb-2.5 mt-0 sm:text-3xl font-normal">{template.fields.display_title}</h1> 61 <ExternalLink href={template.fields.url}> 62 {__('Demo', 'extendify-sdk')} 63 </ExternalLink> 64 </div> 65 <div className={classNames({ 66 'inline-flex sm:top-auto right-0 m-6 sm:m-0 sm:my-6 space-x-3': true, 67 'top-16 mt-5': !apiKey.length, 68 'top-0': apiKey.length > 0, 69 })}> 70 <ImportButton template={template} /> 71 </div> 72 </div> 73 <div className="max-w-screen-xl sm:w-full sm:m-0 sm:mb-8 m-6 border lg:border-t-0 border-gray-300 m-46"> 74 <img 75 className="max-w-full w-full block" 76 src={template?.fields?.screenshot[0]?.thumbnails?.full?.url ?? template?.fields?.screenshot[0]?.url}/> 77 </div> 78 79 <div className="divide-y p-6 sm:p-0 mb-16"> 80 {related.length > 0 && <section className="mb-4"> 81 <h4 className="text-lg m-0 mb-4 text-left font-semibold">{__('Related', 'extendify-sdk')}</h4> 82 <div className="grid md:grid-cols-2 xl:grid-cols-4 gap-6"> 83 {related.map((template) => { 84 return <button key={template.id} 85 type="button" 86 className="min-h-60 border border-transparent hover:border-wp-theme-500 transition duration-150 p-0 m-0 cursor-pointer" 87 onClick={() => changeTemplate(template)}> 88 <img 89 className="max-w-full block p-0 m-0 object-cover" 90 src={template?.fields?.screenshot[0]?.thumbnails?.large?.url ?? template?.fields?.screenshot[0]?.url}/> 91 </button> 92 })} 93 </div> 94 </section>} 95 {alternatives.length > 0 && <section className="mb-4 pt-6"> 96 <h4 className="text-lg m-0 mb-4 text-left font-semibold">{__('Alternatives', 'extendify-sdk')}</h4> 97 <div className="grid md:grid-cols-2 xl:grid-cols-4 gap-6"> 98 {alternatives.map((template) => { 99 return <button key={template.id} 100 type="button" 101 className="min-h-60 border border-transparent hover:border-wp-theme-500 transition duration-150 p-0 m-0 cursor-pointer" 102 onClick={() => changeTemplate(template)}> 103 <img 104 className="max-w-full block p-0 m-0 object-cover" 105 src={template?.fields?.screenshot[0]?.thumbnails?.large?.url ?? template?.fields?.screenshot[0]?.url}/> 106 </button> 107 })} 108 </div> 109 </section>} 110 </div> 111 112 {/* Hides on desktop and is repeated in the single sidebar too */} 113 <div className="text-xs text-left p-6 w-full block sm:hidden divide-y"> 114 <TaxonomyList 115 categories={categories} 116 types={types} 117 requiredPlugins={requiredPlugins} 118 styles={styles}/> 119 </div> 120 </div> 121 }