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 / SnippetsCardGrid.tsx

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

140 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import classnames from 'classnames'
2 import React, { useMemo, useState } from 'react'
3 import { fetchQueryParam } from '../../../utils/urls'
4 import { TableNavigation } from '../../common/ListTable/TableNavigation'
5 import { ManageSnippetCard } from './ManageSnippetCard'
6 import type { ListTableAction, ListTableNavProps } from '../../common/ListTable'
7 import type { Snippet } from '../../../types/Snippet'
8 import type { Dispatch, ReactNode, SetStateAction } from 'react'
9
10 const PAGE_SEARCH_PARAM = 'paged'
11
12 interface CardGridProps {
13 snippets: Snippet[]
14 noItems: ReactNode
15 selected: Set<Snippet['id']>
16 setSelected: Dispatch<SetStateAction<Set<Snippet['id']>>>
17 }
18
19 const CardGrid: React.FC<CardGridProps> = ({ snippets, noItems, selected, setSelected }) =>
20 0 < snippets.length
21 ? <ul
22 className={classnames('code-snippets-cards', 'snippets-card-grid', {
23 'has-selection': snippets.some(snippet => selected.has(snippet.id))
24 })}
25 >
26 {snippets.map(snippet =>
27 <ManageSnippetCard
28 key={snippet.id}
29 snippet={snippet}
30 isSelected={selected.has(snippet.id)}
31 onSelectedChange={isSelected => {
32 setSelected(previous => {
33 const updated = new Set(previous)
34
35 if (isSelected) {
36 updated.add(snippet.id)
37 } else {
38 updated.delete(snippet.id)
39 }
40
41 return updated
42 })
43 }}
44 />)}
45 </ul>
46 : <p className="no-items">{noItems}</p>
47
48 const getVisibleSelection = (selected: Set<Snippet['id']>, visible: Snippet[]): Set<Snippet['id']> =>
49 new Set([...selected].filter(id => visible.some(snippet => snippet.id === id)))
50
51 interface PagedSnippetsParams {
52 snippets: Snippet[]
53 itemsPerPage: number | undefined
54 currentPage: number
55 }
56
57 interface PagedSnippets {
58 totalPages: number
59 safePage: number
60 visibleSnippets: Snippet[]
61 }
62
63 const usePagedSnippets = ({
64 snippets,
65 itemsPerPage,
66 currentPage
67 }: PagedSnippetsParams): PagedSnippets => {
68 const totalPages = itemsPerPage ? Math.ceil(snippets.length / itemsPerPage) : 0
69 const safePage = totalPages ? Math.min(currentPage, totalPages) : 1
70
71 const visibleSnippets = useMemo(
72 () => itemsPerPage
73 ? snippets.slice((safePage - 1) * itemsPerPage, safePage * itemsPerPage)
74 : snippets,
75 [snippets, itemsPerPage, safePage]
76 )
77
78 return { totalPages, safePage, visibleSnippets }
79 }
80
81 export interface SnippetsCardGridProps<A extends string>
82 extends Pick<ListTableNavProps<Snippet['id'], A>, 'extraTableNav' | 'endTableNav'> {
83 snippets: Snippet[]
84 actions: ListTableAction<A>[]
85 doAction: (action: A | undefined, selected: Set<Snippet['id']>) => Promise<void>
86 itemsPerPage?: number
87 noItems: ReactNode
88 beforeGrid?: ReactNode
89 }
90
91 export const SnippetsCardGrid = <A extends string>({
92 snippets,
93 actions,
94 doAction,
95 extraTableNav,
96 endTableNav,
97 itemsPerPage,
98 noItems,
99 beforeGrid
100 }: SnippetsCardGridProps<A>) => {
101 const [selected, setSelected] = useState(() => new Set<Snippet['id']>())
102 const [currentPage, setCurrentPage] = useState(
103 () => Number(fetchQueryParam(PAGE_SEARCH_PARAM)) || 1
104 )
105
106 const { totalPages, safePage, visibleSnippets } = usePagedSnippets({
107 snippets,
108 itemsPerPage,
109 currentPage
110 })
111
112 return (
113 <div className="snippets-card-grid-container">
114 <TableNavigation
115 totalItems={snippets.length}
116 totalPages={0 < totalPages ? totalPages : undefined}
117 currentPage={safePage}
118 setCurrentPage={setCurrentPage}
119 pageSearchParam={PAGE_SEARCH_PARAM}
120 selected={getVisibleSelection(selected, visibleSnippets)}
121 setSelected={setSelected}
122 selectAllKeys={visibleSnippets.map(snippet => snippet.id)}
123 actions={actions}
124 doAction={doAction}
125 extraTableNav={extraTableNav}
126 endTableNav={endTableNav}
127 >
128 {beforeGrid}
129
130 <CardGrid
131 snippets={visibleSnippets}
132 noItems={noItems}
133 selected={selected}
134 setSelected={setSelected}
135 />
136 </TableNavigation>
137 </div>
138 )
139 }
140