PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.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 / ManageMenu / SnippetsTable / SnippetsTable.tsx

SnippetsTable.tsx in Code Snippets 3.10.2, at js/components/ManageMenu/SnippetsTable/SnippetsTable.tsx

178 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __, sprintf } from '@wordpress/i18n'
2 import { createInterpolateElement } from '@wordpress/element'
3 import React, { useCallback, useMemo } from 'react'
4 import classnames from 'classnames'
5 import { useHorizontalScrollOverflow } from '../../../hooks/useHorizontalScrollOverflow'
6 import { WithRestAPIContext } from '../../../hooks/useRestAPI'
7 import { useSnippetView } from '../../../hooks/useSnippetView'
8 import { WithSnippetsAPIContext } from '../../../hooks/useSnippetsAPI'
9 import { WithSnippetsListContext, useSnippetsList } from '../../../hooks/useSnippetsList'
10 import { SNIPPET_TYPES } from '../../../types/Snippet'
11 import { isLicensed } from '../../../utils/screen'
12 import { SNIPPET_TYPE_LABELS, getSnippetAddNewUrl, getSnippetType, isProType } from '../../../utils/snippets/snippets'
13 import { buildUrl } from '../../../utils/urls'
14 import { Badge } from '../../common/Badge'
15 import { Notice } from '../../common/Notice'
16 import { ScreenMetaSlot } from '../../common/ScreenMetaSlot'
17 import { UpsellPage } from '../../common/UpsellDialog'
18 import { WithSnippetsTableFilters, useSnippetsFilters } from './WithSnippetsTableFilters'
19 import { WithFilteredSnippetsContext } from './WithFilteredSnippetsContext'
20 import { SnippetsListTable } from './SnippetsListTable'
21 import type { SnippetType } from '../../../types/Snippet'
22
23 interface SnippetTypeTabProps {
24 type?: SnippetType
25 count?: number
26 }
27
28 const SnippetTypeTab: React.FC<SnippetTypeTabProps> = ({ type, count }) => {
29 const { currentType, setCurrentType } = useSnippetsFilters()
30 const tabName = type ?? 'all'
31
32 const isActive = type === currentType
33 const isProLocked = type && isProType(type) && !isLicensed()
34
35 return (
36 <li>
37 <a
38 href={buildUrl(window.location.href, { type: tabName })}
39 className={classnames('snippet-type-link', `${tabName}-type-link`, {
40 'active-type': isActive,
41 'pro-locked-type': isProLocked && !isActive
42 })}
43 aria-current={isActive ? 'page' : undefined}
44 onClick={event => {
45 event.preventDefault()
46 setCurrentType(type)
47 }}
48 >
49 {type && <Badge name={type} />}
50 <span className={classnames(`${tabName}-label`, 'snippet-type-name')}>
51 {type
52 ? SNIPPET_TYPE_LABELS[type]
53 : <>
54 <span className="snippet-type-name-full">{__('All Snippets', 'code-snippets')}</span>
55 <span className="snippet-type-name-short">{__('All', 'code-snippets')}</span>
56 </>}
57 </span>
58 {count && !isProLocked && <span className="subnav-count">{count}</span>}
59 {isProLocked && <span className="pro-chip">{__('Pro', 'code-snippets')}</span>}
60 </a>
61 </li>
62 )
63 }
64
65 const SafeModeNotice = () =>
66 window.CODE_SNIPPETS_MANAGE?.isSafeModeActive
67 ? <Notice type="error">
68 <p>
69 <strong>{__('Warning:', 'code-snippets')}</strong>{'\n'}
70 {__('Safe mode is active and snippets will not execute!', 'code-snippets')}{'\n'}
71
72 {createInterpolateElement(
73 __('Remove the <code>CODE_SNIPPETS_SAFE_MODE</code> constant from <code>wp-config.php</code> file to turn off safe mode.', 'code-snippets'),
74 {
75 code: <code />
76 }
77 )}{'\n'}
78
79 <a href="https://codesnippets.pro/doc/safe-mode" target="_blank" rel="noreferrer">
80 {__('Read more', 'code-snippets')}
81 </a>
82 </p>
83 </Notice>
84 : null
85
86 // Counts render immediately from the values localized with the page, then
87 // switch to live values derived from the snippets list once it has loaded.
88 const useSnippetTypeCounts = () => {
89 const { snippetsList } = useSnippetsList()
90
91 const countedSnippets = useMemo(
92 () => snippetsList?.filter(snippet => !snippet.trashed),
93 [snippetsList]
94 )
95
96 const typeCounts = useMemo(
97 () => countedSnippets?.reduce((counts, snippet) => {
98 const type = getSnippetType(snippet)
99 return counts.set(type, (counts.get(type) ?? 0) + 1)
100 }, new Map<SnippetType, number>()),
101 [countedSnippets]
102 )
103
104 const localized = window.CODE_SNIPPETS_MANAGE?.typeCounts
105
106 const getCount = useCallback(
107 (type?: SnippetType) => countedSnippets
108 ? type ? typeCounts?.get(type) ?? 0 : countedSnippets.length
109 : localized?.[type ?? 'all'],
110 [countedSnippets, typeCounts, localized]
111 )
112
113 return { getCount }
114 }
115
116 const SnippetsTableInner = () => {
117 const { snippetView, setSnippetView } = useSnippetView()
118 const { currentType } = useSnippetsFilters()
119 const { getCount } = useSnippetTypeCounts()
120 const { atStart, atEnd, scrollRef } = useHorizontalScrollOverflow()
121
122 return (
123 <>
124 <div
125 className={classnames('snippet-type-nav-wrapper', {
126 'has-scroll-start': !atStart,
127 'has-scroll-end': !atEnd
128 })}
129 >
130 <nav
131 ref={scrollRef}
132 className="snippet-type-nav"
133 aria-label={__('Snippet types', 'code-snippets')}
134 >
135 <ul>
136 <SnippetTypeTab count={getCount()} />
137 {SNIPPET_TYPES.map(type => <SnippetTypeTab key={type} type={type} count={getCount(type)} />)}
138 </ul>
139 </nav>
140 </div>
141
142 <ScreenMetaSlot />
143
144 <div className="snippets-page-header">
145 <h1>{sprintf(
146 // translators: %s: label of the currently selected snippet type.
147 __('Local Snippets: %s', 'code-snippets'),
148 currentType ? SNIPPET_TYPE_LABELS[currentType] : __('All Snippets', 'code-snippets')
149 )}</h1>
150 <a href={getSnippetAddNewUrl(currentType)} className="button button-primary">
151 {__('Add Snippet', 'code-snippets')}
152 </a>
153 </div>
154
155 <hr className="wp-header-end" />
156
157 <SafeModeNotice />
158
159 {currentType && !isLicensed() && isProType(currentType)
160 ? <UpsellPage />
161 : <WithFilteredSnippetsContext>
162 <SnippetsListTable snippetView={snippetView} setSnippetView={setSnippetView} />
163 </WithFilteredSnippetsContext>}
164 </>
165 )
166 }
167
168 export const SnippetsTable: React.FC = () =>
169 <WithRestAPIContext>
170 <WithSnippetsAPIContext>
171 <WithSnippetsListContext>
172 <WithSnippetsTableFilters>
173 <SnippetsTableInner />
174 </WithSnippetsTableFilters>
175 </WithSnippetsListContext>
176 </WithSnippetsAPIContext>
177 </WithRestAPIContext>
178