@brilo/base-blocks 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/career/career-header/edit.d.ts +6 -0
  3. package/build/blocks/career/career-header/edit.d.ts.map +1 -0
  4. package/build/blocks/career/career-header/edit.js +11 -0
  5. package/build/blocks/career/career-header/factory.d.ts +5 -0
  6. package/build/blocks/career/career-header/factory.d.ts.map +1 -0
  7. package/build/blocks/career/career-header/factory.js +24 -0
  8. package/build/blocks/career/career-header/icon.d.ts +2 -0
  9. package/build/blocks/career/career-header/icon.d.ts.map +1 -0
  10. package/build/blocks/career/career-header/icon.js +2 -0
  11. package/build/blocks/career/career-header/index.d.ts +5 -0
  12. package/build/blocks/career/career-header/index.d.ts.map +1 -0
  13. package/build/blocks/career/career-header/index.js +4 -0
  14. package/build/blocks/career/career-header/types.d.ts +10 -0
  15. package/build/blocks/career/career-header/types.d.ts.map +1 -0
  16. package/build/blocks/career/career-header/types.js +1 -0
  17. package/build/blocks/career/job-position-group/JobPositionsSelectModal.d.ts +9 -0
  18. package/build/blocks/career/job-position-group/JobPositionsSelectModal.d.ts.map +1 -0
  19. package/build/blocks/career/job-position-group/JobPositionsSelectModal.js +123 -0
  20. package/build/blocks/career/job-position-group/constants.d.ts +10 -0
  21. package/build/blocks/career/job-position-group/constants.d.ts.map +1 -0
  22. package/build/blocks/career/job-position-group/constants.js +9 -0
  23. package/build/blocks/career/job-position-group/edit.d.ts +6 -0
  24. package/build/blocks/career/job-position-group/edit.d.ts.map +1 -0
  25. package/build/blocks/career/job-position-group/edit.js +17 -0
  26. package/build/blocks/career/job-position-group/factory.d.ts +5 -0
  27. package/build/blocks/career/job-position-group/factory.d.ts.map +1 -0
  28. package/build/blocks/career/job-position-group/factory.js +44 -0
  29. package/build/blocks/career/job-position-group/icon.d.ts +2 -0
  30. package/build/blocks/career/job-position-group/icon.d.ts.map +1 -0
  31. package/build/blocks/career/job-position-group/icon.js +2 -0
  32. package/build/blocks/career/job-position-group/index.d.ts +6 -0
  33. package/build/blocks/career/job-position-group/index.d.ts.map +1 -0
  34. package/build/blocks/career/job-position-group/index.js +5 -0
  35. package/build/blocks/career/job-position-group/types.d.ts +20 -0
  36. package/build/blocks/career/job-position-group/types.d.ts.map +1 -0
  37. package/build/blocks/career/job-position-group/types.js +1 -0
  38. package/build/blocks/document/documents-group/DocumentsSelectModal.d.ts +12 -0
  39. package/build/blocks/document/documents-group/DocumentsSelectModal.d.ts.map +1 -0
  40. package/build/blocks/document/documents-group/DocumentsSelectModal.js +153 -0
  41. package/build/blocks/document/documents-group/constants.d.ts +7 -0
  42. package/build/blocks/document/documents-group/constants.d.ts.map +1 -0
  43. package/build/blocks/document/documents-group/constants.js +5 -0
  44. package/build/blocks/document/documents-group/edit.d.ts +6 -0
  45. package/build/blocks/document/documents-group/edit.d.ts.map +1 -0
  46. package/build/blocks/document/documents-group/edit.js +27 -0
  47. package/build/blocks/document/documents-group/factory.d.ts +5 -0
  48. package/build/blocks/document/documents-group/factory.d.ts.map +1 -0
  49. package/build/blocks/document/documents-group/factory.js +50 -0
  50. package/build/blocks/document/documents-group/icon.d.ts +2 -0
  51. package/build/blocks/document/documents-group/icon.d.ts.map +1 -0
  52. package/build/blocks/document/documents-group/icon.js +2 -0
  53. package/build/blocks/document/documents-group/index.d.ts +6 -0
  54. package/build/blocks/document/documents-group/index.d.ts.map +1 -0
  55. package/build/blocks/document/documents-group/index.js +5 -0
  56. package/build/blocks/document/documents-group/types.d.ts +22 -0
  57. package/build/blocks/document/documents-group/types.d.ts.map +1 -0
  58. package/build/blocks/document/documents-group/types.js +1 -0
  59. package/build/blocks/layout/layout-aside/factory.d.ts.map +1 -1
  60. package/build/blocks/layout/layout-aside/icon.d.ts.map +1 -1
  61. package/build/blocks/layout/layout-content/factory.d.ts.map +1 -1
  62. package/build/blocks/layout/layout-content/icon.d.ts.map +1 -1
  63. package/build/blocks/layout/layout-content-w-aside/edit.d.ts.map +1 -1
  64. package/build/blocks/layout/layout-content-w-aside/edit.js +1 -1
  65. package/build/blocks/layout/layout-content-w-aside/factory.d.ts.map +1 -1
  66. package/build/blocks/layout/layout-content-w-aside/icon.d.ts.map +1 -1
  67. package/build/blocks/post/post-content/edit.d.ts +6 -0
  68. package/build/blocks/post/post-content/edit.d.ts.map +1 -0
  69. package/build/blocks/post/post-content/edit.js +9 -0
  70. package/build/blocks/post/post-content/factory.d.ts +5 -0
  71. package/build/blocks/post/post-content/factory.d.ts.map +1 -0
  72. package/build/blocks/post/post-content/factory.js +18 -0
  73. package/build/blocks/post/post-content/icon.d.ts +2 -0
  74. package/build/blocks/post/post-content/icon.d.ts.map +1 -0
  75. package/build/blocks/post/post-content/icon.js +2 -0
  76. package/build/blocks/post/post-content/index.d.ts +5 -0
  77. package/build/blocks/post/post-content/index.d.ts.map +1 -0
  78. package/build/blocks/post/post-content/index.js +4 -0
  79. package/build/blocks/post/post-content/types.d.ts +5 -0
  80. package/build/blocks/post/post-content/types.d.ts.map +1 -0
  81. package/build/blocks/post/post-content/types.js +1 -0
  82. package/build/blocks/sections/base-section/controls.d.ts.map +1 -1
  83. package/build/blocks/sections/base-section/controls.js +1 -1
  84. package/build/blocks/share/share/constants.d.ts +2 -0
  85. package/build/blocks/share/share/constants.d.ts.map +1 -0
  86. package/build/blocks/share/share/constants.js +1 -0
  87. package/build/blocks/share/share/edit.d.ts +6 -0
  88. package/build/blocks/share/share/edit.d.ts.map +1 -0
  89. package/build/blocks/share/share/edit.js +18 -0
  90. package/build/blocks/share/share/factory.d.ts +5 -0
  91. package/build/blocks/share/share/factory.d.ts.map +1 -0
  92. package/build/blocks/share/share/factory.js +26 -0
  93. package/build/blocks/share/share/icon.d.ts +2 -0
  94. package/build/blocks/share/share/icon.d.ts.map +1 -0
  95. package/build/blocks/share/share/icon.js +2 -0
  96. package/build/blocks/share/share/index.d.ts +5 -0
  97. package/build/blocks/share/share/index.d.ts.map +1 -0
  98. package/build/blocks/share/share/index.js +4 -0
  99. package/build/blocks/share/share/types.d.ts +11 -0
  100. package/build/blocks/share/share/types.d.ts.map +1 -0
  101. package/build/blocks/share/share/types.js +1 -0
  102. package/build/index.d.ts +10 -0
  103. package/build/index.d.ts.map +1 -1
  104. package/build/index.js +5 -0
  105. package/package.json +6 -1
  106. package/src/blocks/career/career-header/edit.tsx +61 -0
  107. package/src/blocks/career/career-header/factory.tsx +28 -0
  108. package/src/blocks/career/career-header/icon.tsx +8 -0
  109. package/src/blocks/career/career-header/index.ts +8 -0
  110. package/src/blocks/career/career-header/types.ts +11 -0
  111. package/src/blocks/career/job-position-group/JobPositionsSelectModal.tsx +238 -0
  112. package/src/blocks/career/job-position-group/constants.ts +11 -0
  113. package/src/blocks/career/job-position-group/edit.tsx +93 -0
  114. package/src/blocks/career/job-position-group/factory.tsx +56 -0
  115. package/src/blocks/career/job-position-group/icon.tsx +7 -0
  116. package/src/blocks/career/job-position-group/index.ts +15 -0
  117. package/src/blocks/career/job-position-group/types.ts +23 -0
  118. package/src/blocks/document/documents-group/DocumentsSelectModal.tsx +273 -0
  119. package/src/blocks/document/documents-group/constants.ts +7 -0
  120. package/src/blocks/document/documents-group/edit.tsx +96 -0
  121. package/src/blocks/document/documents-group/factory.tsx +59 -0
  122. package/src/blocks/document/documents-group/icon.tsx +9 -0
  123. package/src/blocks/document/documents-group/index.ts +15 -0
  124. package/src/blocks/document/documents-group/types.ts +25 -0
  125. package/src/blocks/layout/layout-aside/factory.tsx +1 -3
  126. package/src/blocks/layout/layout-aside/icon.tsx +1 -6
  127. package/src/blocks/layout/layout-content/editor.scss +1 -1
  128. package/src/blocks/layout/layout-content/factory.tsx +1 -3
  129. package/src/blocks/layout/layout-content/icon.tsx +1 -6
  130. package/src/blocks/layout/layout-content-w-aside/edit.tsx +5 -1
  131. package/src/blocks/layout/layout-content-w-aside/factory.tsx +1 -3
  132. package/src/blocks/layout/layout-content-w-aside/icon.tsx +1 -6
  133. package/src/blocks/post/post-content/edit.tsx +18 -0
  134. package/src/blocks/post/post-content/factory.tsx +22 -0
  135. package/src/blocks/post/post-content/icon.tsx +9 -0
  136. package/src/blocks/post/post-content/index.ts +8 -0
  137. package/src/blocks/post/post-content/types.ts +6 -0
  138. package/src/blocks/sections/base-section/controls.tsx +7 -1
  139. package/src/blocks/share/share/constants.ts +1 -0
  140. package/src/blocks/share/share/edit.tsx +57 -0
  141. package/src/blocks/share/share/factory.tsx +30 -0
  142. package/src/blocks/share/share/icon.tsx +9 -0
  143. package/src/blocks/share/share/index.ts +8 -0
  144. package/src/blocks/share/share/types.ts +12 -0
  145. package/src/index.ts +22 -0
@@ -0,0 +1,273 @@
1
+ import apiFetch from '@wordpress/api-fetch'
2
+ import {Button, Card, CardBody, __experimentalHStack as HStack, Modal, __experimentalVStack as VStack} from '@wordpress/components'
3
+ import {DataViews, type View} from '@wordpress/dataviews/wp'
4
+ import {__} from '@wordpress/i18n'
5
+ import {arrowDown, arrowUp, close, plusCircle} from '@wordpress/icons'
6
+ // biome-ignore lint/correctness/noUnusedImports: required in scope for classic JSX transform
7
+ import React, {useEffect, useMemo, useState} from 'react'
8
+ import type {SelectControlProps} from './types'
9
+
10
+ type DocumentRecord = {
11
+ id: number
12
+ title: {rendered: string}
13
+ date: string
14
+ document_alt_title?: string
15
+ document_url?: string
16
+ document_file_display?: string
17
+ document_category_names?: string
18
+ }
19
+
20
+ const DEFAULT_VIEW: View = {
21
+ type: 'table',
22
+ search: '',
23
+ filters: [],
24
+ page: 1,
25
+ perPage: 20,
26
+ sort: {field: 'title', direction: 'asc'},
27
+ fields: ['document_file_display', 'document_category_names', 'document_alt_title', 'document_url'],
28
+ titleField: 'title',
29
+ }
30
+
31
+ function useDocuments() {
32
+ const [documents, setDocuments] = useState<DocumentRecord[]>([])
33
+ const [isLoading, setIsLoading] = useState(true)
34
+
35
+ useEffect(() => {
36
+ setIsLoading(true)
37
+ apiFetch<DocumentRecord[]>({
38
+ path:
39
+ '/wp/v2/document?per_page=100&orderby=title&order=asc&' +
40
+ '_fields=id,title,date,document_alt_title,document_url,document_file_display,document_category_names',
41
+ })
42
+ .then((result) => setDocuments(result))
43
+ .catch(() => setDocuments([]))
44
+ .finally(() => setIsLoading(false))
45
+ }, [])
46
+
47
+ return {documents, isLoading}
48
+ }
49
+
50
+ function SelectedOrderList({
51
+ items,
52
+ onChange,
53
+ onRemove,
54
+ }: {
55
+ items: DocumentRecord[]
56
+ onChange: (ids: number[]) => void
57
+ onRemove: (id: number) => void
58
+ }) {
59
+ if (0 === items.length) {
60
+ return <p className="i-documents-select-modal__empty">{__('Nevybrány žádné dokumenty.', 'brilo-blocks')}</p>
61
+ }
62
+
63
+ const move = (index: number, direction: -1 | 1) => {
64
+ const target = index + direction
65
+
66
+ if (target < 0 || target >= items.length) {
67
+ return
68
+ }
69
+
70
+ const next = [...items]
71
+ ;[next[index], next[target]] = [next[target], next[index]]
72
+ onChange(next.map((item) => item.id))
73
+ }
74
+
75
+ return (
76
+ <VStack spacing={2}>
77
+ {items.map((item, index) => (
78
+ <Card size="small" className="i-documents-select-modal__item" key={item.id}>
79
+ <CardBody>
80
+ <HStack alignment="center">
81
+ <span
82
+ className="i-documents-select-modal__item-title"
83
+ style={{
84
+ flexGrow: 1,
85
+ minWidth: 0,
86
+ textAlign: 'left',
87
+ overflow: 'hidden',
88
+ textOverflow: 'ellipsis',
89
+ whiteSpace: 'nowrap',
90
+ }}
91
+ >
92
+ {item.title.rendered || __('(bez názvu)', 'brilo-blocks')}
93
+ </span>
94
+
95
+ <HStack expanded={false} spacing={1}>
96
+ <Button
97
+ size="small"
98
+ icon={arrowUp}
99
+ label={__('Posunout výš', 'brilo-blocks')}
100
+ onClick={() => move(index, -1)}
101
+ disabled={0 === index}
102
+ />
103
+ <Button
104
+ size="small"
105
+ icon={arrowDown}
106
+ label={__('Posunout níž', 'brilo-blocks')}
107
+ onClick={() => move(index, 1)}
108
+ disabled={index === items.length - 1}
109
+ />
110
+ <Button size="small" icon={close} isDestructive label={__('Odebrat', 'brilo-blocks')} onClick={() => onRemove(item.id)} />
111
+ </HStack>
112
+ </HStack>
113
+ </CardBody>
114
+ </Card>
115
+ ))}
116
+ </VStack>
117
+ )
118
+ }
119
+
120
+ /**
121
+ * Manual document picker built on the real @wordpress/dataviews package: a
122
+ * fill-size modal (table view, search, sort, checkbox selection) for
123
+ * browsing/selecting documents, plus an up/down-reorderable list of the
124
+ * current selection below (drag-and-drop conflicted with the block editor's
125
+ * own native block dragging — see git history). Local to this block — not a
126
+ * shared @brilo/gutenberg-toolkit component.
127
+ */
128
+ export function DocumentsSelectModal({selectedItems, onChange}: SelectControlProps) {
129
+ const {documents, isLoading} = useDocuments()
130
+ const [isOpen, setIsOpen] = useState(false)
131
+ const [view, setView] = useState<View>(DEFAULT_VIEW)
132
+
133
+ const selectedDocuments = useMemo(
134
+ () => selectedItems.map((id) => documents.find((doc) => doc.id === id)).filter((doc): doc is DocumentRecord => undefined !== doc),
135
+ [selectedItems, documents],
136
+ )
137
+
138
+ const fields = useMemo(
139
+ () => [
140
+ {
141
+ id: 'title',
142
+ label: __('Název', 'brilo-blocks'),
143
+ enableHiding: false,
144
+ enableSorting: true,
145
+ render: ({item}: {item: DocumentRecord}) => item.title.rendered || __('(bez názvu)', 'brilo-blocks'),
146
+ },
147
+ {
148
+ id: 'document_file_display',
149
+ label: __('Soubor', 'brilo-blocks'),
150
+ enableSorting: false,
151
+ render: ({item}: {item: DocumentRecord}) => item.document_file_display || '—',
152
+ },
153
+ {
154
+ id: 'document_category_names',
155
+ label: __('Kategorie', 'brilo-blocks'),
156
+ enableSorting: false,
157
+ render: ({item}: {item: DocumentRecord}) => item.document_category_names || '—',
158
+ },
159
+ {
160
+ id: 'document_alt_title',
161
+ label: __('Alternativní titulek', 'brilo-blocks'),
162
+ enableSorting: false,
163
+ render: ({item}: {item: DocumentRecord}) => item.document_alt_title || '—',
164
+ },
165
+ {
166
+ id: 'document_url',
167
+ label: __('Alternativní URL', 'brilo-blocks'),
168
+ enableSorting: false,
169
+ render: ({item}: {item: DocumentRecord}) => item.document_url || '—',
170
+ },
171
+ {
172
+ id: 'date',
173
+ label: __('Datum', 'brilo-blocks'),
174
+ enableSorting: true,
175
+ render: ({item}: {item: DocumentRecord}) => (item.date ? new Date(item.date).toLocaleDateString() : '—'),
176
+ },
177
+ ],
178
+ [],
179
+ )
180
+
181
+ const {data, paginationInfo} = useMemo(() => {
182
+ let filtered = documents
183
+
184
+ if (view.search) {
185
+ const needle = view.search.toLowerCase()
186
+ filtered = filtered.filter((doc) => doc.title.rendered.toLowerCase().includes(needle))
187
+ }
188
+
189
+ if (view.sort?.field) {
190
+ const {field, direction} = view.sort
191
+ const sorted = [...filtered]
192
+
193
+ sorted.sort((a, b) => {
194
+ const valueA = 'title' === field ? a.title.rendered : ((a as never)[field] ?? '')
195
+ const valueB = 'title' === field ? b.title.rendered : ((b as never)[field] ?? '')
196
+ const result = String(valueA).localeCompare(String(valueB))
197
+
198
+ return 'desc' === direction ? -result : result
199
+ })
200
+
201
+ filtered = sorted
202
+ }
203
+
204
+ const perPage = view.perPage ?? 20
205
+ const page = view.page ?? 1
206
+ const start = (page - 1) * perPage
207
+
208
+ return {
209
+ data: filtered.slice(start, start + perPage),
210
+ paginationInfo: {totalItems: filtered.length, totalPages: Math.ceil(filtered.length / perPage) || 1},
211
+ }
212
+ }, [documents, view])
213
+
214
+ const toggleSelected = (id: number) => {
215
+ onChange(selectedItems.includes(id) ? selectedItems.filter((itemId) => itemId !== id) : [...selectedItems, id])
216
+ }
217
+
218
+ return (
219
+ <VStack spacing={3} className="i-documents-select-modal">
220
+ <Button variant="secondary" icon={plusCircle} onClick={() => setIsOpen(true)}>
221
+ {__('Vybrat dokumenty', 'brilo-blocks')}
222
+ </Button>
223
+
224
+ <SelectedOrderList
225
+ items={selectedDocuments}
226
+ onChange={onChange}
227
+ onRemove={(id) => onChange(selectedItems.filter((itemId) => itemId !== id))}
228
+ />
229
+
230
+ {isOpen && (
231
+ <Modal title={__('Vybrat dokumenty', 'brilo-blocks')} onRequestClose={() => setIsOpen(false)} size="fill">
232
+ <VStack spacing={4} style={{height: '100%'}}>
233
+ <div style={{flexGrow: 1, minHeight: 0}}>
234
+ <DataViews<DocumentRecord>
235
+ data={data}
236
+ fields={fields}
237
+ view={view}
238
+ onChangeView={setView}
239
+ paginationInfo={paginationInfo}
240
+ isLoading={isLoading}
241
+ defaultLayouts={{table: {}}}
242
+ getItemId={(item) => String(item.id)}
243
+ selection={selectedItems.map(String)}
244
+ onChangeSelection={(ids) => onChange(ids.map(Number))}
245
+ actions={[
246
+ {
247
+ id: 'toggle',
248
+ label: (items) =>
249
+ items.length && selectedItems.includes(items[0].id) ? __('Odebrat', 'brilo-blocks') : __('Přidat', 'brilo-blocks'),
250
+ // supportsBulk is what makes DataViews render a checkbox per row —
251
+ // without it there's no way to select items other than this menu.
252
+ supportsBulk: true,
253
+ callback: (items) => {
254
+ items.forEach((item) => {
255
+ toggleSelected(item.id)
256
+ })
257
+ },
258
+ },
259
+ ]}
260
+ />
261
+ </div>
262
+
263
+ <HStack justify="flex-end">
264
+ <Button variant="primary" onClick={() => setIsOpen(false)}>
265
+ {__('Hotovo', 'brilo-blocks')}
266
+ </Button>
267
+ </HStack>
268
+ </VStack>
269
+ </Modal>
270
+ )}
271
+ </VStack>
272
+ )
273
+ }
@@ -0,0 +1,7 @@
1
+ import type {DocumentsGroupColumns, DocumentsGroupMode, DocumentsGroupListingStyle, DocumentsGroupSortBy} from './types'
2
+
3
+ export const DOCUMENTS_GROUP_MODE_DEFAULT: DocumentsGroupMode = 'manual'
4
+ export const DOCUMENTS_GROUP_LISTING_STYLE_DEFAULT: DocumentsGroupListingStyle = 'classic'
5
+ export const DOCUMENTS_GROUP_SORT_BY_DEFAULT: DocumentsGroupSortBy = 'manual-order'
6
+ export const DOCUMENTS_GROUP_COLUMNS_DEFAULT: DocumentsGroupColumns = 1
7
+ export const DOCUMENTS_GROUP_COLUMNS: DocumentsGroupColumns[] = [1, 2, 3, 4, 6]
@@ -0,0 +1,96 @@
1
+ import {InspectorControls, useBlockProps} from '@wordpress/block-editor'
2
+ import {
3
+ PanelBody,
4
+ __experimentalToggleGroupControl as ToggleGroupControl,
5
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
6
+ } from '@wordpress/components'
7
+ import {__} from '@wordpress/i18n'
8
+ import {DOCUMENTS_GROUP_COLUMNS} from './constants'
9
+ import type {DocumentsGroupAttributes, DocumentsGroupOptions} from './types'
10
+
11
+ export function createDocumentsGroupEdit(options: DocumentsGroupOptions) {
12
+ return function Edit({
13
+ attributes,
14
+ setAttributes,
15
+ }: {
16
+ attributes: DocumentsGroupAttributes
17
+ setAttributes: (a: Partial<DocumentsGroupAttributes>) => void
18
+ }) {
19
+ const {mode, listingStyle, sortBy, columns, selectedDocuments, selectedCategories} = attributes
20
+
21
+ const blockProps = useBlockProps({className: 'wp-block-section'})
22
+
23
+ return (
24
+ <>
25
+ <InspectorControls>
26
+ <PanelBody title={__('Nastavení výpisu', 'brilo-blocks')} initialOpen>
27
+ <ToggleGroupControl
28
+ label={__('Zdroj dokumentů', 'brilo-blocks')}
29
+ value={mode}
30
+ onChange={(value) => {
31
+ const nextMode = value as DocumentsGroupAttributes['mode']
32
+ setAttributes({
33
+ mode: nextMode,
34
+ sortBy: 'manual' === nextMode ? sortBy : sortBy === 'manual-order' ? 'menu_order' : sortBy,
35
+ })
36
+ }}
37
+ isBlock
38
+ >
39
+ <ToggleGroupControlOption value="manual" label={__('Ruční výběr', 'brilo-blocks')} />
40
+ <ToggleGroupControlOption value="category" label={__('Dle kategorie', 'brilo-blocks')} />
41
+ </ToggleGroupControl>
42
+
43
+ <ToggleGroupControl
44
+ label={__('Styl výpisu', 'brilo-blocks')}
45
+ value={listingStyle}
46
+ onChange={(value) => setAttributes({listingStyle: value as DocumentsGroupAttributes['listingStyle']})}
47
+ isBlock
48
+ >
49
+ <ToggleGroupControlOption value="classic" label={__('Klasický výpis', 'brilo-blocks')} />
50
+ <ToggleGroupControlOption value="group-by-category" label={__('Dle kategorií', 'brilo-blocks')} />
51
+ </ToggleGroupControl>
52
+
53
+ <ToggleGroupControl
54
+ label={__('Řazení', 'brilo-blocks')}
55
+ value={sortBy}
56
+ onChange={(value) => setAttributes({sortBy: value as DocumentsGroupAttributes['sortBy']})}
57
+ isBlock
58
+ >
59
+ <ToggleGroupControlOption value="menu_order" label={__('Pořadí', 'brilo-blocks')} />
60
+ <ToggleGroupControlOption value="date" label={__('Datum', 'brilo-blocks')} />
61
+ {'manual' === mode && <ToggleGroupControlOption value="manual-order" label={__('Dle výběru', 'brilo-blocks')} />}
62
+ </ToggleGroupControl>
63
+
64
+ <ToggleGroupControl
65
+ label={__('Počet sloupců', 'brilo-blocks')}
66
+ help={
67
+ 'group-by-category' === listingStyle ? __('Platí pro seznam dokumentů uvnitř každé kategorie.', 'brilo-blocks') : undefined
68
+ }
69
+ value={String(columns)}
70
+ onChange={(value) => setAttributes({columns: Number(value) as DocumentsGroupAttributes['columns']})}
71
+ isBlock
72
+ >
73
+ {DOCUMENTS_GROUP_COLUMNS.map((c) => (
74
+ <ToggleGroupControlOption key={c} value={String(c)} label={String(c)} />
75
+ ))}
76
+ </ToggleGroupControl>
77
+ </PanelBody>
78
+ </InspectorControls>
79
+
80
+ <div {...blockProps}>
81
+ {'category' === mode &&
82
+ options.renderCategoryControl?.({
83
+ selectedItems: selectedCategories,
84
+ onChange: (ids: number[]) => setAttributes({selectedCategories: ids}),
85
+ })}
86
+
87
+ {'manual' === mode &&
88
+ options.renderDocumentsControl?.({
89
+ selectedItems: selectedDocuments,
90
+ onChange: (ids: number[]) => setAttributes({selectedDocuments: ids}),
91
+ })}
92
+ </div>
93
+ </>
94
+ )
95
+ }
96
+ }
@@ -0,0 +1,59 @@
1
+ import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {__} from '@wordpress/i18n'
3
+ import {
4
+ DOCUMENTS_GROUP_COLUMNS_DEFAULT,
5
+ DOCUMENTS_GROUP_LISTING_STYLE_DEFAULT,
6
+ DOCUMENTS_GROUP_MODE_DEFAULT,
7
+ DOCUMENTS_GROUP_SORT_BY_DEFAULT,
8
+ } from './constants'
9
+ import {createDocumentsGroupEdit} from './edit'
10
+ import {icon as defaultIcon} from './icon'
11
+ import type {DocumentsGroupAttributes, DocumentsGroupOptions} from './types'
12
+
13
+ export type {DocumentsGroupAttributes, DocumentsGroupOptions}
14
+
15
+ export function createDocumentsGroupBlock(options: DocumentsGroupOptions): BlockConfiguration<DocumentsGroupAttributes> {
16
+ return {
17
+ name: options.name,
18
+ title: options.title ?? __('Dokumenty', 'brilo-blocks'),
19
+ description: options.description,
20
+ category: options.category ?? 'widgets',
21
+ ...(options.parent && {parent: options.parent}),
22
+ icon: options.icon ?? {src: defaultIcon},
23
+ supports: {html: false, customClassName: false},
24
+ attributes: {
25
+ mode: {
26
+ type: 'string',
27
+ default: DOCUMENTS_GROUP_MODE_DEFAULT,
28
+ enum: ['manual', 'category'],
29
+ },
30
+ listingStyle: {
31
+ type: 'string',
32
+ default: DOCUMENTS_GROUP_LISTING_STYLE_DEFAULT,
33
+ enum: ['classic', 'group-by-category'],
34
+ },
35
+ sortBy: {
36
+ type: 'string',
37
+ default: DOCUMENTS_GROUP_SORT_BY_DEFAULT,
38
+ enum: ['menu_order', 'date', 'manual-order'],
39
+ },
40
+ columns: {
41
+ type: 'number',
42
+ default: DOCUMENTS_GROUP_COLUMNS_DEFAULT,
43
+ enum: [1, 2, 3, 4, 6],
44
+ },
45
+ selectedDocuments: {
46
+ type: 'array',
47
+ default: [],
48
+ items: {type: 'number'},
49
+ },
50
+ selectedCategories: {
51
+ type: 'array',
52
+ default: [],
53
+ items: {type: 'number'},
54
+ },
55
+ },
56
+ edit: createDocumentsGroupEdit(options),
57
+ save: () => null,
58
+ } as unknown as BlockConfiguration<DocumentsGroupAttributes>
59
+ }
@@ -0,0 +1,9 @@
1
+ export const icon = (
2
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M4 1H12L16 5V19H4V1Z" stroke="black" fill="none" />
4
+ <path d="M12 1V5H16" stroke="black" fill="none" />
5
+ <line x1="6.5" y1="9" x2="13.5" y2="9" stroke="black" />
6
+ <line x1="6.5" y1="12" x2="13.5" y2="12" stroke="black" />
7
+ <line x1="6.5" y1="15" x2="11" y2="15" stroke="black" />
8
+ </svg>
9
+ )
@@ -0,0 +1,15 @@
1
+ export type {
2
+ DocumentsGroupAttributes,
3
+ DocumentsGroupOptions,
4
+ DocumentsGroupListingStyle,
5
+ DocumentsGroupMode,
6
+ DocumentsGroupSortBy,
7
+ } from './types'
8
+ export {createDocumentsGroupBlock} from './factory'
9
+ export {DocumentsSelectModal} from './DocumentsSelectModal'
10
+
11
+ import type {DocumentsGroupOptions} from './types'
12
+
13
+ export const documentsGroupDefaults: DocumentsGroupOptions = {
14
+ name: 'brilo/documents-group',
15
+ }
@@ -0,0 +1,25 @@
1
+ import type {BriloBlockType} from '~/types'
2
+
3
+ export type DocumentsGroupMode = 'manual' | 'category'
4
+ export type DocumentsGroupListingStyle = 'classic' | 'group-by-category'
5
+ export type DocumentsGroupSortBy = 'menu_order' | 'date' | 'manual-order'
6
+ export type DocumentsGroupColumns = 1 | 2 | 3 | 4 | 6
7
+
8
+ export interface DocumentsGroupAttributes extends Record<string, unknown> {
9
+ mode: DocumentsGroupMode
10
+ listingStyle: DocumentsGroupListingStyle
11
+ sortBy: DocumentsGroupSortBy
12
+ columns: DocumentsGroupColumns
13
+ selectedDocuments: number[]
14
+ selectedCategories: number[]
15
+ }
16
+
17
+ export interface SelectControlProps {
18
+ selectedItems: number[]
19
+ onChange: (ids: number[]) => void
20
+ }
21
+
22
+ export interface DocumentsGroupOptions extends BriloBlockType {
23
+ renderCategoryControl?: (props: SelectControlProps) => JSX.Element
24
+ renderDocumentsControl?: (props: SelectControlProps) => JSX.Element
25
+ }
@@ -6,9 +6,7 @@ import {createAsideEdit} from './edit'
6
6
  import {icon as defaultIcon} from './icon'
7
7
  import type {AsideAttributes, AsideOptions} from './types'
8
8
 
9
- export function createAsideBlock(
10
- options: AsideOptions,
11
- ): BlockConfiguration<AsideAttributes> {
9
+ export function createAsideBlock(options: AsideOptions): BlockConfiguration<AsideAttributes> {
12
10
  return {
13
11
  name: options.name,
14
12
  title: options.title ?? __('Postranní panel', 'brilo-blocks'),
@@ -2,11 +2,6 @@ import React from 'react'
2
2
 
3
3
  export const icon = (
4
4
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
5
- <path
6
- fillRule="evenodd"
7
- clipRule="evenodd"
8
- d="M8 4H20V20H8V4ZM10 6H18V18H10V6Z"
9
- fill="currentColor"
10
- />
5
+ <path fillRule="evenodd" clipRule="evenodd" d="M8 4H20V20H8V4ZM10 6H18V18H10V6Z" fill="currentColor" />
11
6
  </svg>
12
7
  )
@@ -6,4 +6,4 @@
6
6
  padding: 8px;
7
7
  min-height: 120px;
8
8
  }
9
- }
9
+ }
@@ -6,9 +6,7 @@ import {createContentEdit} from './edit'
6
6
  import {icon as defaultIcon} from './icon'
7
7
  import type {ContentAttributes, ContentOptions} from './types'
8
8
 
9
- export function createContentBlock(
10
- options: ContentOptions,
11
- ): BlockConfiguration<ContentAttributes> {
9
+ export function createContentBlock(options: ContentOptions): BlockConfiguration<ContentAttributes> {
12
10
  return {
13
11
  name: options.name,
14
12
  title: options.title ?? __('Obsah', 'brilo-blocks'),
@@ -2,11 +2,6 @@ import React from 'react'
2
2
 
3
3
  export const icon = (
4
4
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
5
- <path
6
- fillRule="evenodd"
7
- clipRule="evenodd"
8
- d="M4 4H16V20H4V4ZM6 6H14V18H6V6Z"
9
- fill="currentColor"
10
- />
5
+ <path fillRule="evenodd" clipRule="evenodd" d="M4 4H16V20H4V4ZM6 6H14V18H6V6Z" fill="currentColor" />
11
6
  </svg>
12
7
  )
@@ -1,5 +1,9 @@
1
1
  import {InspectorControls} from '@wordpress/block-editor'
2
- import {PanelBody, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption} from '@wordpress/components'
2
+ import {
3
+ PanelBody,
4
+ __experimentalToggleGroupControl as ToggleGroupControl,
5
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
6
+ } from '@wordpress/components'
3
7
  import {__} from '@wordpress/i18n'
4
8
  import React from 'react'
5
9
  import {useGroupBlock} from '~/hooks/useGroupBlock'
@@ -8,9 +8,7 @@ import {createContentWithAsideEdit} from './edit'
8
8
  import {icon as defaultIcon} from './icon'
9
9
  import type {ContentWithAsideAttributes, ContentWithAsideOptions} from './types'
10
10
 
11
- export function createContentWithAsideBlock<
12
- TAsideSizes extends OptionArray = typeof ASIDE_SIZES,
13
- >(
11
+ export function createContentWithAsideBlock<TAsideSizes extends OptionArray = typeof ASIDE_SIZES>(
14
12
  options: ContentWithAsideOptions<TAsideSizes>,
15
13
  ): BlockConfiguration<ContentWithAsideAttributes<TAsideSizes[number]['value']>> {
16
14
  const asideSizes = options.asideSizes ?? ASIDE_SIZES
@@ -2,11 +2,6 @@ import React from 'react'
2
2
 
3
3
  export const icon = (
4
4
  <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
5
- <path
6
- fillRule="evenodd"
7
- clipRule="evenodd"
8
- d="M4 4H20V20H4V4ZM6 6H13V18H6V6ZM15 6H18V18H15V6Z"
9
- fill="currentColor"
10
- />
5
+ <path fillRule="evenodd" clipRule="evenodd" d="M4 4H20V20H4V4ZM6 6H13V18H6V6ZM15 6H18V18H15V6Z" fill="currentColor" />
11
6
  </svg>
12
7
  )
@@ -0,0 +1,18 @@
1
+ import {useBlockProps} from '@wordpress/block-editor'
2
+ import {__} from '@wordpress/i18n'
3
+ import type {PostContentAttributes, PostContentOptions} from './types'
4
+
5
+ export function createPostContentEdit(_options: PostContentOptions) {
6
+ return function Edit(_props: {attributes: PostContentAttributes; setAttributes: (a: Partial<PostContentAttributes>) => void}) {
7
+ const blockProps = useBlockProps({className: 'wp-block-section'})
8
+
9
+ return (
10
+ <div {...blockProps}>
11
+ <div className="components-placeholder">
12
+ <div className="components-placeholder__label">{__('Obsah postu', 'brilo-blocks')}</div>
13
+ <div className="components-placeholder__instructions">{__('Zobrazí obsah aktuální postu.', 'brilo-blocks')}</div>
14
+ </div>
15
+ </div>
16
+ )
17
+ }
18
+ }
@@ -0,0 +1,22 @@
1
+ import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {__} from '@wordpress/i18n'
3
+ import {createPostContentEdit} from './edit'
4
+ import {icon as defaultIcon} from './icon'
5
+ import type {PostContentAttributes, PostContentOptions} from './types'
6
+
7
+ export type {PostContentAttributes, PostContentOptions}
8
+
9
+ export function createPostContentBlock(options: PostContentOptions): BlockConfiguration<PostContentAttributes> {
10
+ return {
11
+ name: options.name,
12
+ title: options.title ?? __('Content postu', 'brilo-blocks'),
13
+ description: options.description,
14
+ category: options.category ?? 'widgets',
15
+ ...(options.parent && {parent: options.parent}),
16
+ icon: options.icon ?? {src: defaultIcon},
17
+ supports: {html: false, customClassName: false},
18
+ attributes: {},
19
+ edit: createPostContentEdit(options),
20
+ save: () => null,
21
+ } as unknown as BlockConfiguration<PostContentAttributes>
22
+ }
@@ -0,0 +1,9 @@
1
+ export const icon = (
2
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="3" y="2" width="14" height="16" rx="1" stroke="black" fill="none" />
4
+ <line x1="6" y1="6" x2="14" y2="6" stroke="black" />
5
+ <line x1="6" y1="9" x2="14" y2="9" stroke="black" />
6
+ <line x1="6" y1="12" x2="14" y2="12" stroke="black" />
7
+ <line x1="6" y1="15" x2="10" y2="15" stroke="black" />
8
+ </svg>
9
+ )
@@ -0,0 +1,8 @@
1
+ export type {PostContentAttributes, PostContentOptions} from './types'
2
+ export {createPostContentBlock} from './factory'
3
+
4
+ import type {PostContentOptions} from './types'
5
+
6
+ export const postContentDefaults: PostContentOptions = {
7
+ name: 'brilo/post-content',
8
+ }
@@ -0,0 +1,6 @@
1
+ import type {BriloBlockType} from '~/types'
2
+
3
+ // biome-ignore lint/complexity/noBannedTypes: no block-specific attributes, matches BriloBlockType's generic constraint shape
4
+ export interface PostContentAttributes extends Record<string, unknown> {}
5
+
6
+ export type PostContentOptions = BriloBlockType