@cu-mkp/editioncrafter 1.3.1-beta.1 → 1.3.1-beta.11
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.
- package/dist/editioncrafter.js +12865 -12751
- package/dist/es/src/EditionCrafter/action/DocumentActions.js +1 -0
- package/dist/es/src/EditionCrafter/action/rootReducer.js +9 -4
- package/dist/es/src/EditionCrafter/component/DiploMatic.js +17 -31
- package/dist/es/src/EditionCrafter/component/DocumentView.js +6 -48
- package/dist/es/src/EditionCrafter/component/ImageMetadata.js +32 -0
- package/dist/es/src/EditionCrafter/component/ImageView.js +6 -0
- package/dist/es/src/EditionCrafter/component/RouteListener.js +1 -1
- package/dist/es/src/EditionCrafter/context/TagFilter.jsx +6 -0
- package/dist/es/src/EditionCrafter/context/TagFilterContext.js +1 -0
- package/dist/es/src/EditionCrafter/saga/RouteListenerSaga.js +3 -4
- package/dist/es/src/EditionCrafter/scss/_imageMetadata.scss +20 -0
- package/dist/es/src/EditionCrafter/scss/editioncrafter.scss +1 -0
- package/dist/es/src/TagExplore/assets/InsertLeft.jsx +6 -3
- package/dist/es/src/TagExplore/assets/InsertRight.jsx +5 -3
- package/dist/es/src/TagExplore/components/DocumentDetail.jsx +40 -33
- package/dist/es/src/TagExplore/components/DocumentFilters.jsx +293 -0
- package/dist/es/src/TagExplore/components/SurfaceBrowser.jsx +108 -52
- package/dist/es/src/TagExplore/components/TagFilters.jsx +212 -56
- package/dist/es/src/TagExplore/index.jsx +6 -8
- package/dist/es/src/TagExplore/styles/base.css +12 -5
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Checkbox, FormControlLabel, FormGroup, Typography } from '@material-ui/core'
|
|
2
|
-
import
|
|
1
|
+
import { Accordion, AccordionDetails, AccordionSummary, Checkbox, FormControlLabel, FormGroup, Typography } from '@material-ui/core'
|
|
2
|
+
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
|
|
3
|
+
import { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
|
3
4
|
import { getObjs } from '../../common/lib/sql'
|
|
4
5
|
import TagFilterContext from '../../EditionCrafter/context/TagFilterContext'
|
|
5
6
|
|
|
@@ -9,6 +10,17 @@ function getData(db) {
|
|
|
9
10
|
*
|
|
10
11
|
FROM
|
|
11
12
|
taxonomies;
|
|
13
|
+
ORDER BY
|
|
14
|
+
name ASC;
|
|
15
|
+
`)
|
|
16
|
+
|
|
17
|
+
const categoriesStmt = db.prepare(`
|
|
18
|
+
SELECT
|
|
19
|
+
*
|
|
20
|
+
FROM
|
|
21
|
+
categories
|
|
22
|
+
ORDER BY
|
|
23
|
+
name ASC;
|
|
12
24
|
`)
|
|
13
25
|
|
|
14
26
|
const tagsStmt = db.prepare(`
|
|
@@ -16,90 +28,234 @@ function getData(db) {
|
|
|
16
28
|
tags.id AS id,
|
|
17
29
|
tags.name AS name,
|
|
18
30
|
tags.xml_id AS xml_id,
|
|
31
|
+
tags.parent_category_id AS parent_category_id,
|
|
19
32
|
taxonomies.name as taxonomy,
|
|
20
33
|
taxonomies.id as taxonomy_id
|
|
21
34
|
FROM
|
|
22
35
|
tags
|
|
23
36
|
LEFT JOIN taxonomies
|
|
24
37
|
ON tags.taxonomy_id = taxonomies.id
|
|
25
|
-
INNER JOIN taggings
|
|
26
|
-
ON taggings.tag_id = tags.id
|
|
27
|
-
INNER JOIN elements
|
|
28
|
-
ON elements.id = taggings.element_id
|
|
29
|
-
WHERE
|
|
30
|
-
elements.type = 'zone'
|
|
31
38
|
GROUP BY
|
|
32
|
-
tags.xml_id
|
|
39
|
+
tags.xml_id
|
|
40
|
+
ORDER BY
|
|
41
|
+
tags.name ASC`)
|
|
33
42
|
|
|
34
43
|
return {
|
|
35
44
|
tags: getObjs(tagsStmt),
|
|
45
|
+
categories: getObjs(categoriesStmt),
|
|
36
46
|
taxonomies: getObjs(taxonomiesStmt),
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
function CategoryFilter(props) {
|
|
51
|
+
const {
|
|
52
|
+
name,
|
|
53
|
+
categoryId,
|
|
54
|
+
tags,
|
|
55
|
+
categories,
|
|
56
|
+
toggleTag,
|
|
57
|
+
onToggleSelected,
|
|
58
|
+
isSurface,
|
|
59
|
+
filters,
|
|
60
|
+
} = props
|
|
61
|
+
|
|
62
|
+
const hasDescendentTags = useCallback((catId) => {
|
|
63
|
+
if (tags?.filter(tag => (tag.parent_category_id === catId))?.length) {
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const subs = categories?.filter(cat => (cat.parent_category_id === catId))
|
|
68
|
+
|
|
69
|
+
for (const sub of subs) {
|
|
70
|
+
if (hasDescendentTags(sub.id)) {
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return false
|
|
76
|
+
}, [tags, categories])
|
|
77
|
+
|
|
78
|
+
const countDescendentTags = useCallback((catId) => {
|
|
79
|
+
let count = tags?.filter(tag => (tag.parent_category_id === catId))?.length
|
|
80
|
+
|
|
81
|
+
const subs = categories?.filter(cat => (cat.parent_category_id === catId))
|
|
82
|
+
|
|
83
|
+
for (const sub of subs) {
|
|
84
|
+
count = count + countDescendentTags(sub.id)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return count
|
|
88
|
+
}, [tags, categories])
|
|
89
|
+
|
|
90
|
+
const categoryTags = useMemo(() => {
|
|
91
|
+
return tags?.filter(tag => (tag.parent_category_id === categoryId))
|
|
92
|
+
}, [tags, categoryId])
|
|
93
|
+
|
|
94
|
+
const subcategories = useMemo(() => {
|
|
95
|
+
return categories?.filter(cat => (cat.parent_category_id === categoryId))
|
|
96
|
+
}, [categories, categoryId])
|
|
97
|
+
|
|
98
|
+
return hasDescendentTags(categoryId) && (
|
|
99
|
+
<Accordion>
|
|
100
|
+
<AccordionSummary
|
|
101
|
+
expandIcon={<ExpandMoreIcon />}
|
|
102
|
+
aria-controls={`category-tags-${name}-content`}
|
|
103
|
+
id={`category-tags-${name}`}
|
|
104
|
+
className="accordion-summary"
|
|
105
|
+
>
|
|
106
|
+
<Typography>{name}</Typography>
|
|
107
|
+
<Typography>{countDescendentTags(categoryId) || ''}</Typography>
|
|
108
|
+
</AccordionSummary>
|
|
109
|
+
<AccordionDetails
|
|
110
|
+
className="accordion-detail"
|
|
111
|
+
>
|
|
112
|
+
{ !!categoryTags?.length && (
|
|
113
|
+
<ul>
|
|
114
|
+
{ categoryTags?.map(tag => (
|
|
115
|
+
<FormControlLabel
|
|
116
|
+
as="li"
|
|
117
|
+
control={(
|
|
118
|
+
<Checkbox
|
|
119
|
+
checked={filters.includes(tag.id)}
|
|
120
|
+
onChange={() => {
|
|
121
|
+
onToggleSelected(tag.id)
|
|
122
|
+
if (isSurface) {
|
|
123
|
+
toggleTag(tag.xml_id, 'left')
|
|
124
|
+
toggleTag(tag.xml_id, 'right')
|
|
125
|
+
}
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
)}
|
|
129
|
+
key={tag.id}
|
|
130
|
+
label={tag.name}
|
|
131
|
+
/>
|
|
132
|
+
))}
|
|
133
|
+
</ul>
|
|
134
|
+
)}
|
|
135
|
+
{
|
|
136
|
+
!!subcategories?.length && (
|
|
137
|
+
<>
|
|
138
|
+
{
|
|
139
|
+
subcategories.map(cat => (
|
|
140
|
+
<CategoryFilter
|
|
141
|
+
key={cat.id}
|
|
142
|
+
name={cat.name}
|
|
143
|
+
categoryId={cat.id}
|
|
144
|
+
tags={tags}
|
|
145
|
+
categories={categories}
|
|
146
|
+
toggleTag={toggleTag}
|
|
147
|
+
onToggleSelected={onToggleSelected}
|
|
148
|
+
isSurface={isSurface}
|
|
149
|
+
filters={filters}
|
|
150
|
+
/>
|
|
151
|
+
))
|
|
152
|
+
}
|
|
153
|
+
</>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
</AccordionDetails>
|
|
157
|
+
</Accordion>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
40
161
|
function TagFilters(props) {
|
|
41
|
-
const { onToggleSelected, filters } = props
|
|
162
|
+
const { onToggleSelected, filters, query } = props
|
|
42
163
|
const data = useMemo(() => getData(props.db), [props.db])
|
|
43
|
-
const [expanded, setExpanded] = useState(data.taxonomies?.map(() => (false)))
|
|
44
164
|
const [displayedTags, setDisplayedTags] = useState({})
|
|
45
165
|
|
|
46
166
|
const { toggleTag } = useContext(TagFilterContext)
|
|
47
167
|
|
|
48
168
|
useEffect(() => {
|
|
49
169
|
const tags = {}
|
|
170
|
+
const filteredTags = data.tags.filter(tag => (!query || !query.length || tag.name.toLowerCase().includes(query.toLowerCase())))
|
|
50
171
|
for (let i = 0; i < data.taxonomies.length; i++) {
|
|
51
172
|
const tax = data.taxonomies[i]
|
|
52
|
-
const tagList =
|
|
53
|
-
|
|
173
|
+
const tagList = filteredTags.filter(t => t.taxonomy_id === tax.id)
|
|
174
|
+
if (tagList?.length) {
|
|
175
|
+
tags[tax.id] = tagList
|
|
176
|
+
}
|
|
54
177
|
}
|
|
55
178
|
setDisplayedTags(tags)
|
|
56
|
-
}, [
|
|
179
|
+
}, [data, query])
|
|
57
180
|
|
|
58
181
|
return (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
182
|
+
<>
|
|
183
|
+
{
|
|
184
|
+
data?.tags?.length
|
|
185
|
+
? (
|
|
186
|
+
<div className="tag-list">
|
|
187
|
+
<FormGroup>
|
|
188
|
+
{ data.taxonomies.sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 0)).map((tax) => {
|
|
189
|
+
const tagList = displayedTags[tax.id]
|
|
190
|
+
const topLevelTags = tagList?.filter(tag => (!tag.parent_category_id))
|
|
191
|
+
return (
|
|
192
|
+
tagList?.length
|
|
193
|
+
? (
|
|
194
|
+
<Accordion>
|
|
195
|
+
<AccordionSummary
|
|
196
|
+
expandIcon={<ExpandMoreIcon />}
|
|
197
|
+
aria-controls={`tags-${tax.name}-content`}
|
|
198
|
+
id={`tags-${tax.name}`}
|
|
199
|
+
className="accordion-summary"
|
|
200
|
+
>
|
|
201
|
+
<Typography>{`${tax.name.slice(0, 1).toUpperCase()}${tax.name.slice(1)}`}</Typography>
|
|
202
|
+
<Typography>{tagList?.length || ''}</Typography>
|
|
203
|
+
</AccordionSummary>
|
|
204
|
+
<AccordionDetails
|
|
205
|
+
className="accordion-detail"
|
|
206
|
+
>
|
|
207
|
+
<div key={tax.id}>
|
|
208
|
+
{ !!topLevelTags?.length && (
|
|
209
|
+
<ul>
|
|
210
|
+
{ topLevelTags?.map(tag => (
|
|
211
|
+
<FormControlLabel
|
|
212
|
+
as="li"
|
|
213
|
+
control={(
|
|
214
|
+
<Checkbox
|
|
215
|
+
checked={filters.includes(tag.id)}
|
|
216
|
+
onChange={() => {
|
|
217
|
+
onToggleSelected(tag.id)
|
|
218
|
+
if (tax.is_surface) {
|
|
219
|
+
toggleTag(tag.xml_id, 'left')
|
|
220
|
+
toggleTag(tag.xml_id, 'right')
|
|
221
|
+
}
|
|
222
|
+
}}
|
|
223
|
+
/>
|
|
224
|
+
)}
|
|
225
|
+
key={tag.id}
|
|
226
|
+
label={tag.name}
|
|
227
|
+
/>
|
|
228
|
+
))}
|
|
229
|
+
</ul>
|
|
230
|
+
)}
|
|
231
|
+
{
|
|
232
|
+
data.categories?.filter(cat => (cat.taxonomy_id === tax.id && !cat.parent_category_id))?.map(cat => (
|
|
233
|
+
<CategoryFilter
|
|
234
|
+
key={cat.id}
|
|
235
|
+
name={cat.name}
|
|
236
|
+
categoryId={cat.id}
|
|
237
|
+
tags={tagList}
|
|
238
|
+
categories={data.categories}
|
|
239
|
+
toggleTag={toggleTag}
|
|
240
|
+
onToggleSelected={onToggleSelected}
|
|
241
|
+
isSurface={tax.is_surface}
|
|
242
|
+
filters={filters}
|
|
243
|
+
/>
|
|
244
|
+
))
|
|
245
|
+
}
|
|
246
|
+
</div>
|
|
247
|
+
</AccordionDetails>
|
|
248
|
+
</Accordion>
|
|
249
|
+
)
|
|
250
|
+
: null
|
|
251
|
+
)
|
|
252
|
+
})}
|
|
253
|
+
</FormGroup>
|
|
97
254
|
</div>
|
|
98
255
|
)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
</div>
|
|
256
|
+
: null
|
|
257
|
+
}
|
|
258
|
+
</>
|
|
103
259
|
)
|
|
104
260
|
}
|
|
105
261
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEffect,
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { HashRouter } from 'react-router-dom'
|
|
3
3
|
import initSqlJs from 'sql.js'
|
|
4
4
|
import sqlJsInfo from 'sql.js/package.json'
|
|
5
5
|
import Loading from '../common/components/Loading'
|
|
@@ -48,14 +48,14 @@ function getData(db) {
|
|
|
48
48
|
|
|
49
49
|
function generateECProps(props, db) {
|
|
50
50
|
const documents = getData(db)
|
|
51
|
-
const { documentName, baseURL, transcriptionTypes } = props
|
|
51
|
+
const { documentName, baseURL, transcriptionTypes, manifestPath = '/iiif/manifest.json' } = props
|
|
52
52
|
const documentInfo = {}
|
|
53
53
|
|
|
54
54
|
for (const document of documents) {
|
|
55
55
|
documentInfo[document.local_id] = {
|
|
56
56
|
documentName: document.name,
|
|
57
57
|
transcriptionTypes,
|
|
58
|
-
iiifManifest: `${baseURL}/${document.local_id}
|
|
58
|
+
iiifManifest: `${baseURL}/${document.local_id}${manifestPath}`,
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -71,8 +71,6 @@ function TagExplore(props) {
|
|
|
71
71
|
const [ecProps, setECProps] = useState(null)
|
|
72
72
|
const [filters, setFilters] = useState(initialFilters)
|
|
73
73
|
|
|
74
|
-
const Router = useMemo(() => props.serverNav ? BrowserRouter : HashRouter, [props.serverNav])
|
|
75
|
-
|
|
76
74
|
useEffect(() => {
|
|
77
75
|
const loadDb = async () => {
|
|
78
76
|
const db = await initDb(props.dbUrl)
|
|
@@ -98,12 +96,12 @@ function TagExplore(props) {
|
|
|
98
96
|
|
|
99
97
|
return (
|
|
100
98
|
<div className="tag-explore">
|
|
101
|
-
<
|
|
99
|
+
<HashRouter>
|
|
102
100
|
<TagFilterProvider>
|
|
103
101
|
<TagExploreSidebar db={db} />
|
|
104
102
|
<EditionCrafter {...ecProps} />
|
|
105
103
|
</TagFilterProvider>
|
|
106
|
-
</
|
|
104
|
+
</HashRouter>
|
|
107
105
|
</div>
|
|
108
106
|
)
|
|
109
107
|
}
|
|
@@ -26,13 +26,18 @@
|
|
|
26
26
|
overflow-y: auto;
|
|
27
27
|
position: absolute;
|
|
28
28
|
top: 48px;
|
|
29
|
-
left:
|
|
29
|
+
left: 400px;
|
|
30
30
|
background-color: #242629;
|
|
31
31
|
z-index: 10000;
|
|
32
32
|
padding: 12px 0 12px 12px;
|
|
33
|
-
width:
|
|
33
|
+
width: 490px;
|
|
34
34
|
height: 100%;
|
|
35
|
-
max-height:
|
|
35
|
+
max-height: calc(97dvh - 48px);
|
|
36
|
+
border-left: solid white 1px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tag-explore .tag-filters .tag-filters-search {
|
|
40
|
+
margin-bottom: 24px;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
.tag-explore .tag-filter-button {
|
|
@@ -153,8 +158,8 @@
|
|
|
153
158
|
position: absolute;
|
|
154
159
|
top: 0;
|
|
155
160
|
left: 48px;
|
|
156
|
-
height:
|
|
157
|
-
|
|
161
|
+
height: 97dvh;
|
|
162
|
+
width: 400px;
|
|
158
163
|
display: flex;
|
|
159
164
|
flex-direction: column;
|
|
160
165
|
background-color: #242629;
|
|
@@ -189,4 +194,6 @@
|
|
|
189
194
|
|
|
190
195
|
.tag-explore .accordion-detail {
|
|
191
196
|
background-color: #242629;
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
192
199
|
}
|