PluginProbe
Code Snippets / 4.0.0-beta.2
Code Snippets v4.0.0-beta.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / common / Toolbar.tsx

Toolbar.tsx in Code Snippets 4.0.0-beta.2, at js/components/common/Toolbar.tsx

239 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __, _x } from '@wordpress/i18n'
2 import classnames from 'classnames'
3 import React, { useMemo, useState } from 'react'
4 import { isLicensed, shouldShowUpsell } from '../../utils/screen'
5 import { buildUrl, fetchConstQueryParam } from '../../utils/urls'
6 import { SUBPAGES, SUBPAGE_ENTRIES, type SubpageName } from '../ManageMenu/subpages'
7 import { hasSeenDemo } from './demo/useDemoSeen'
8 import { AiAgentIcon } from './icons/AiAgentIcon'
9 import { BlueprintIcon } from './icons/BlueprintIcon'
10 import { CommunityIcon } from './icons/CommunityIcon'
11 import { LibraryIcon } from './icons/LibraryIcon'
12 import { SettingsIcon } from './icons/SettingsIcon'
13 import { SnippetsIcon } from './icons/SnippetsIcon'
14 import { UpsellDialog } from './UpsellDialog'
15 import type { SVGProps } from 'react'
16
17 const searchParams = new URLSearchParams(window.location.search)
18
19 const managePageSlug = window.CODE_SNIPPETS?.urls.manage
20 ? new URL(window.CODE_SNIPPETS.urls.manage).searchParams.get('page')
21 : null
22
23 // The manage screen resolves an absent or unrecognised `subpage` to the first subpage, so
24 // mirror that fallback here — comparing against the raw param would leave every lower-nav
25 // tab inactive on the default Snippets view, which is where the page opens.
26 const activeSubpage = searchParams.get('page') === managePageSlug
27 ? fetchConstQueryParam('subpage', SUBPAGES) ?? SUBPAGES[0]
28 : null
29
30 interface UpperNavItemProps {
31 name: string
32 url: string
33 label: string
34 }
35
36 const UpperNavItem = ({ name, url, label }: UpperNavItemProps) => {
37 const pageSlug = useMemo(() => new URL(url).searchParams.get('page'), [url])
38
39 const isActive = !searchParams.get('subpage') && searchParams.get('page') === pageSlug
40
41 return (
42 <li>
43 <a
44 href={url}
45 className={classnames(`${name}-link`, { 'active-link': isActive })}
46 {...!pageSlug && { target: '_blank', rel: 'noopener noreferrer' }}
47 >
48 {label}
49 </a>
50 </li>
51 )
52 }
53 const UpperNavItems = () =>
54 <>
55 {window.CODE_SNIPPETS?.urls.insights && (
56 <UpperNavItem
57 name="insights"
58 url={window.CODE_SNIPPETS.urls.insights}
59 label={__('Insights', 'code-snippets')}
60 />)}
61
62 {window.CODE_SNIPPETS?.urls.import && (
63 <UpperNavItem
64 name="import-snippets"
65 url={window.CODE_SNIPPETS.urls.import}
66 label={_x('Import', 'snippets', 'code-snippets')}
67 />)}
68
69 {window.CODE_SNIPPETS?.urls.welcome && (
70 <UpperNavItem
71 name="welcome"
72 url={window.CODE_SNIPPETS.urls.welcome}
73 label={__("What's New", 'code-snippets')}
74 />)}
75
76 <UpperNavItem
77 name="docs"
78 url="https://codesnippets.pro/docs"
79 label={__('Docs', 'code-snippets')}
80 />
81
82 <UpperNavItem
83 name="cloud"
84 url={window.CODE_SNIPPETS?.urls.cloud ?? 'https://codesnippets.cloud'}
85 label={__('Cloud Dashboard', 'code-snippets')}
86 />
87
88 </>
89
90 const MoreNav = () =>
91 <li className="toolbar-more-item">
92 <details className="toolbar-more-menu">
93 <summary>
94 {__('More', 'code-snippets')}
95 <span className="dashicons dashicons-arrow-down-alt2" aria-hidden="true"></span>
96 </summary>
97 <ul>
98 <UpperNavItems />
99 </ul>
100 </details>
101 </li>
102
103 const UpperNav: React.FC = () => {
104 const [isUpsellDialogOpen, setIsUpsellDialogOpen] = useState(false)
105
106 return (
107 <div className="code-snippets-toolbar-upper">
108 <div className="logo">
109 <img
110 src={`${window.CODE_SNIPPETS?.urls.plugin}/assets/icon.svg`}
111 alt={__('Code Snippets logo', 'code-snippets')}
112 aria-hidden="true"
113 />
114
115 <div>{__('Code Snippets', 'code-snippets')}</div>
116 </div>
117
118 <nav aria-label={__('Main links', 'code-snippets')}>
119 <ul>
120 <UpperNavItems />
121 <MoreNav />
122
123 {shouldShowUpsell() && (
124 <li className="toolbar-upgrade-item">
125 <a
126 className="button button-large button-secondary"
127 href="https://codesnippets.pro/pricing/"
128 target="_blank" rel="noopener noreferrer"
129 onClick={event => {
130 event.preventDefault()
131 setIsUpsellDialogOpen(true)
132 }}
133 >
134 {__('Upgrade to Pro', 'code-snippets')}
135 </a>
136 </li>)}
137 </ul>
138 </nav>
139
140 <UpsellDialog isOpen={isUpsellDialogOpen} setIsOpen={setIsUpsellDialogOpen} />
141 </div>
142 )
143 }
144
145 interface SubpageItemProps {
146 subpage: SubpageName
147 label: string
148 Icon: React.FC<SVGProps<SVGSVGElement>>
149 }
150
151 const SubpageItem: React.FC<SubpageItemProps> = ({ subpage, label, Icon }) => {
152 const { demo, isPro } = SUBPAGE_ENTRIES[subpage]
153 const isNew = 'announce' === demo && !hasSeenDemo(subpage)
154
155 return (
156 <li>
157 <a
158 href={buildUrl(window.CODE_SNIPPETS?.urls.manage, { subpage: subpage })}
159 className={classnames(`${subpage}-link`, { 'active-link': subpage === activeSubpage })}
160 >
161 <Icon aria-hidden="true" />
162 <span className="toolbar-nav-label">{label}</span>
163 {demo && (isNew
164 ? <span className="new-chip">{__('New', 'code-snippets')}</span>
165 : <span className="demo-chip">{__('Demo', 'code-snippets')}</span>)}
166 {isPro && !isLicensed() && <span className="pro-chip">{__('Pro', 'code-snippets')}</span>}
167 </a>
168 </li>
169 )
170 }
171
172 const SettingsItem = () =>
173 window.CODE_SNIPPETS?.urls.settings
174 ? <li>
175 <a
176 href={window.CODE_SNIPPETS.urls.settings}
177 className={classnames('settings-link', {
178 'active-link': 'snippets-settings' === searchParams.get('page')
179 })}
180 >
181 <SettingsIcon aria-hidden="true" />
182 <span className="toolbar-nav-label">{__('Settings', 'code-snippets')}</span>
183 </a>
184 </li>
185 : null
186
187 const LowerNav = () =>
188 <div className="code-snippets-toolbar-lower">
189 <nav aria-label={__('Main features', 'code-snippets')}>
190 <ul>
191 <SubpageItem
192 subpage="snippets"
193 label={__('Snippets', 'code-snippets')}
194 Icon={SnippetsIcon}
195 />
196
197 {isLicensed() && (
198 <SubpageItem
199 subpage="blueprints"
200 label={__('Blueprints', 'code-snippets')}
201 Icon={BlueprintIcon}
202 />)}
203
204 <SubpageItem
205 subpage="cloud-community"
206 label={__('Cloud Community', 'code-snippets')}
207 Icon={CommunityIcon}
208 />
209
210 <SubpageItem
211 subpage="cloud-library"
212 label={__('Cloud Library', 'code-snippets')}
213 Icon={LibraryIcon}
214 />
215
216 {!isLicensed() && (
217 <SubpageItem
218 subpage="blueprints"
219 label={__('Blueprints', 'code-snippets')}
220 Icon={BlueprintIcon}
221 />)}
222
223 <SubpageItem
224 subpage="ai-agent"
225 label={__('AI Agent', 'code-snippets')}
226 Icon={AiAgentIcon}
227 />
228
229 <SettingsItem />
230 </ul>
231 </nav>
232 </div>
233
234 export const Toolbar = () =>
235 <div className="code-snippets-toolbar">
236 <UpperNav />
237 <LowerNav />
238 </div>
239