@cu-mkp/editioncrafter 1.3.1-beta.1 → 1.3.1-beta.3
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 +12320 -12342
- 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/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/TagExplore/assets/InsertLeft.jsx +6 -3
- package/dist/es/src/TagExplore/assets/InsertRight.jsx +5 -3
- package/dist/es/src/TagExplore/components/DocumentDetail.jsx +26 -23
- package/dist/es/src/TagExplore/components/DocumentFilters.jsx +293 -0
- package/dist/es/src/TagExplore/components/SurfaceBrowser.jsx +101 -52
- package/dist/es/src/TagExplore/components/TagFilters.jsx +65 -52
- package/dist/es/src/TagExplore/index.jsx +4 -6
- package/dist/es/src/TagExplore/styles/base.css +10 -5
- package/package.json +1 -1
|
@@ -1,29 +1,43 @@
|
|
|
1
|
-
import { Box, Button,
|
|
2
|
-
import { red } from '@material-ui/core/colors'
|
|
1
|
+
import { Box, Button, Collapse, Divider, IconButton, Input, Typography } from '@material-ui/core'
|
|
3
2
|
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'
|
|
4
|
-
import GridOnIcon from '@material-ui/icons/GridOn'
|
|
5
|
-
import ListIcon from '@material-ui/icons/List'
|
|
6
3
|
import TuneIcon from '@material-ui/icons/Tune'
|
|
7
|
-
import { useEffect, useMemo, useState } from 'react'
|
|
4
|
+
import { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
|
8
5
|
|
|
9
6
|
import { useLocation, useNavigate } from 'react-router-dom'
|
|
10
7
|
import { getObjs } from '../../common/lib/sql'
|
|
11
8
|
import DocumentDetail from './DocumentDetail'
|
|
9
|
+
// import DocumentFilters from './DocumentFilters'
|
|
10
|
+
import TagFilterContext from '../../EditionCrafter/context/TagFilterContext'
|
|
12
11
|
import TagFilters from './TagFilters'
|
|
13
12
|
|
|
14
13
|
function getData(db) {
|
|
15
14
|
const docStmt = db.prepare(`
|
|
16
15
|
SELECT
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
d.id AS id,
|
|
17
|
+
d.name AS name,
|
|
18
|
+
d.local_id AS local_id,
|
|
19
|
+
json_group_array(document_taggings.tag) as tags
|
|
20
20
|
FROM
|
|
21
|
-
documents
|
|
21
|
+
documents d
|
|
22
|
+
LEFT JOIN document_taggings ON d.id = document_taggings.document
|
|
23
|
+
GROUP BY d.id, d.name, d.local_id
|
|
22
24
|
`)
|
|
23
|
-
|
|
24
25
|
return getObjs(docStmt)
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function getDocTags(db) {
|
|
29
|
+
const tagsStmt = db.prepare(`
|
|
30
|
+
SELECT
|
|
31
|
+
tags.id AS id
|
|
32
|
+
FROM
|
|
33
|
+
tags
|
|
34
|
+
LEFT JOIN taxonomies ON tags.taxonomy_id = taxonomies.id
|
|
35
|
+
WHERE
|
|
36
|
+
taxonomies.is_surface = 0 OR taxonomies.is_surface IS NULL
|
|
37
|
+
`)
|
|
38
|
+
return getObjs(tagsStmt)
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
function parseFolioID(folioID) {
|
|
28
42
|
if (!folioID) {
|
|
29
43
|
return null
|
|
@@ -50,27 +64,47 @@ function getSelection(path) {
|
|
|
50
64
|
function SurfaceBrowser(props) {
|
|
51
65
|
const { db, open, toggleOpen } = props
|
|
52
66
|
const documents = useMemo(() => getData(db), [db])
|
|
67
|
+
const docTags = useMemo(() => getDocTags(db)?.map(tag => (tag.id)), [db])
|
|
53
68
|
const [pageCount, setPageCount] = useState({})
|
|
54
69
|
const [totalPages, setTotalPages] = useState(0)
|
|
55
70
|
const [tags, setTags] = useState([])
|
|
56
71
|
const [showFilters, setShowFilters] = useState(false)
|
|
72
|
+
const [query, setQuery] = useState(undefined)
|
|
73
|
+
|
|
74
|
+
const filterDocs = useCallback((docs, tags) => {
|
|
75
|
+
return docs.filter((doc) => {
|
|
76
|
+
const docID = doc.id
|
|
77
|
+
for (const tag of tags) {
|
|
78
|
+
if (docTags.includes(tag) && !JSON.parse(doc.tags)?.includes(tag)) {
|
|
79
|
+
const newCount = pageCount
|
|
80
|
+
newCount[docID] = 0
|
|
81
|
+
setPageCount(newCount)
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true
|
|
86
|
+
})
|
|
87
|
+
}, [docTags, pageCount])
|
|
88
|
+
|
|
89
|
+
const filteredDocs = useMemo(() => (filterDocs(documents, tags)), [filterDocs, documents, tags])
|
|
57
90
|
|
|
58
91
|
const navigate = useNavigate()
|
|
59
92
|
const location = useLocation()
|
|
60
93
|
const selection = useMemo(() => getSelection(location.pathname), [location])
|
|
94
|
+
const { clearTags } = useContext(TagFilterContext)
|
|
61
95
|
|
|
62
|
-
const navigateToSelection = (nextSelection) => {
|
|
96
|
+
const navigateToSelection = useCallback((nextSelection) => {
|
|
63
97
|
const folioID = nextSelection?.left ? `${nextSelection.left.localID}_${nextSelection.left.surfaceID}` : null
|
|
64
98
|
const folioID2 = nextSelection?.right ? `${nextSelection.right.localID}_${nextSelection.right.surfaceID}` : null
|
|
65
99
|
const navParams = `/ec/${folioID || '-1'}/${folioID ? 'f' : 'g'}/${folioID2 || '-1'}/${folioID2 ? 'f' : 'g'}`
|
|
66
100
|
navigate(navParams + location.search)
|
|
67
|
-
}
|
|
101
|
+
}, [location.search, navigate])
|
|
68
102
|
|
|
69
|
-
const updatePageCount = (documentID, numPages) => {
|
|
103
|
+
const updatePageCount = useCallback((documentID, numPages) => {
|
|
70
104
|
const newCount = pageCount
|
|
71
105
|
newCount[documentID] = numPages
|
|
72
106
|
setPageCount(newCount)
|
|
73
|
-
}
|
|
107
|
+
}, [pageCount])
|
|
74
108
|
|
|
75
109
|
useEffect(() => {
|
|
76
110
|
let p = 0
|
|
@@ -80,7 +114,7 @@ function SurfaceBrowser(props) {
|
|
|
80
114
|
setTotalPages(p)
|
|
81
115
|
}, [pageCount, tags])
|
|
82
116
|
|
|
83
|
-
const documentDetails =
|
|
117
|
+
const documentDetails = useMemo(() => filteredDocs.map((doc) => {
|
|
84
118
|
return (
|
|
85
119
|
<DocumentDetail
|
|
86
120
|
key={`document-detail-${doc.id}`}
|
|
@@ -91,11 +125,11 @@ function SurfaceBrowser(props) {
|
|
|
91
125
|
selection={selection}
|
|
92
126
|
navigateToSelection={navigateToSelection}
|
|
93
127
|
updatePageCount={count => updatePageCount(doc.id, count)}
|
|
94
|
-
tags={tags}
|
|
128
|
+
tags={tags?.filter(tag => !docTags.includes(tag))}
|
|
95
129
|
>
|
|
96
130
|
</DocumentDetail>
|
|
97
131
|
)
|
|
98
|
-
})
|
|
132
|
+
}), [db, docTags, filteredDocs, navigateToSelection, selection, tags, updatePageCount])
|
|
99
133
|
|
|
100
134
|
return (
|
|
101
135
|
<Collapse in={open} horizontal>
|
|
@@ -108,34 +142,45 @@ function SurfaceBrowser(props) {
|
|
|
108
142
|
<Divider></Divider>
|
|
109
143
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
110
144
|
<Typography>Contents</Typography>
|
|
111
|
-
<
|
|
112
|
-
startIcon={<TuneIcon />}
|
|
113
|
-
onClick={() => setShowFilters(current => (!current))}
|
|
114
|
-
>
|
|
115
|
-
Filter
|
|
145
|
+
<div>
|
|
116
146
|
{ tags && tags.length
|
|
117
147
|
? (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
backgroundColor: 'red',
|
|
121
|
-
borderRadius: '999px',
|
|
122
|
-
display: 'flex',
|
|
123
|
-
justifyContent: 'center',
|
|
124
|
-
alignItems: 'center',
|
|
125
|
-
padding: '3px',
|
|
126
|
-
color: 'white',
|
|
127
|
-
height: '16px',
|
|
128
|
-
width: '16px',
|
|
129
|
-
position: 'absolute',
|
|
130
|
-
top: '0',
|
|
131
|
-
left: '-12px',
|
|
132
|
-
}}
|
|
148
|
+
<Button
|
|
149
|
+
onClick={clearTags}
|
|
133
150
|
>
|
|
134
|
-
|
|
135
|
-
</
|
|
151
|
+
Clear All
|
|
152
|
+
</Button>
|
|
136
153
|
)
|
|
137
154
|
: null}
|
|
138
|
-
|
|
155
|
+
<Button
|
|
156
|
+
startIcon={<TuneIcon />}
|
|
157
|
+
onClick={() => setShowFilters(current => (!current))}
|
|
158
|
+
>
|
|
159
|
+
Filter
|
|
160
|
+
{ tags && tags.length
|
|
161
|
+
? (
|
|
162
|
+
<div style={{
|
|
163
|
+
fontSize: 'small',
|
|
164
|
+
backgroundColor: 'red',
|
|
165
|
+
borderRadius: '999px',
|
|
166
|
+
display: 'flex',
|
|
167
|
+
justifyContent: 'center',
|
|
168
|
+
alignItems: 'center',
|
|
169
|
+
padding: '3px',
|
|
170
|
+
color: 'white',
|
|
171
|
+
height: '16px',
|
|
172
|
+
width: '16px',
|
|
173
|
+
position: 'absolute',
|
|
174
|
+
top: '0',
|
|
175
|
+
left: '-12px',
|
|
176
|
+
}}
|
|
177
|
+
>
|
|
178
|
+
{tags.length}
|
|
179
|
+
</div>
|
|
180
|
+
)
|
|
181
|
+
: null}
|
|
182
|
+
</Button>
|
|
183
|
+
</div>
|
|
139
184
|
</div>
|
|
140
185
|
<Typography>
|
|
141
186
|
{totalPages}
|
|
@@ -152,18 +197,22 @@ function SurfaceBrowser(props) {
|
|
|
152
197
|
</IconButton>
|
|
153
198
|
</ButtonGroup> */}
|
|
154
199
|
{ showFilters && (
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
200
|
+
<div className="tag-filters">
|
|
201
|
+
<Input placeholder="Search for filters" value={query} onChange={(e) => { setQuery(e.target.value) }} className="tag-filters-search" />
|
|
202
|
+
<TagFilters
|
|
203
|
+
db={db}
|
|
204
|
+
filters={tags}
|
|
205
|
+
query={query}
|
|
206
|
+
onToggleSelected={(tagId) => {
|
|
207
|
+
if (tags.includes(tagId)) {
|
|
208
|
+
setTags(current => (current.filter(t => (t !== tagId))))
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
setTags(current => ([...current, tagId]))
|
|
212
|
+
}
|
|
213
|
+
}}
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
167
216
|
) }
|
|
168
217
|
<Box className="surface-browser-document-details">
|
|
169
218
|
{ documentDetails }
|
|
@@ -22,12 +22,6 @@ function getData(db) {
|
|
|
22
22
|
tags
|
|
23
23
|
LEFT JOIN taxonomies
|
|
24
24
|
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
25
|
GROUP BY
|
|
32
26
|
tags.xml_id`)
|
|
33
27
|
|
|
@@ -38,7 +32,7 @@ function getData(db) {
|
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
function TagFilters(props) {
|
|
41
|
-
const { onToggleSelected, filters } = props
|
|
35
|
+
const { onToggleSelected, filters, query } = props
|
|
42
36
|
const data = useMemo(() => getData(props.db), [props.db])
|
|
43
37
|
const [expanded, setExpanded] = useState(data.taxonomies?.map(() => (false)))
|
|
44
38
|
const [displayedTags, setDisplayedTags] = useState({})
|
|
@@ -47,59 +41,78 @@ function TagFilters(props) {
|
|
|
47
41
|
|
|
48
42
|
useEffect(() => {
|
|
49
43
|
const tags = {}
|
|
44
|
+
const filteredTags = data.tags.filter(tag => (!query || !query.length || tag.name.toLowerCase().includes(query.toLowerCase())))
|
|
50
45
|
for (let i = 0; i < data.taxonomies.length; i++) {
|
|
51
46
|
const tax = data.taxonomies[i]
|
|
52
|
-
const tagList = expanded[i] ?
|
|
53
|
-
|
|
47
|
+
const tagList = expanded[i] ? filteredTags.filter(t => (t.taxonomy_id === tax.id)) : filteredTags.filter(t => (t.taxonomy_id === tax.id))?.slice(0, 5)
|
|
48
|
+
if (tagList?.length) {
|
|
49
|
+
tags[tax.id] = tagList
|
|
50
|
+
}
|
|
54
51
|
}
|
|
55
52
|
setDisplayedTags(tags)
|
|
56
|
-
}, [expanded, data])
|
|
53
|
+
}, [expanded, data, query])
|
|
57
54
|
|
|
58
55
|
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
|
-
|
|
56
|
+
<>
|
|
57
|
+
{
|
|
58
|
+
data?.tags?.length
|
|
59
|
+
? (
|
|
60
|
+
<div className="tag-list">
|
|
61
|
+
<FormGroup>
|
|
62
|
+
{ data.taxonomies.map((tax, idx) => {
|
|
63
|
+
const tagList = displayedTags[tax.id]
|
|
64
|
+
return (
|
|
65
|
+
tagList?.length
|
|
66
|
+
? (
|
|
67
|
+
<div key={tax.id}>
|
|
68
|
+
<Typography>{`${tax.name.slice(0, 1).toUpperCase()}${tax.name.slice(1)}`}</Typography>
|
|
69
|
+
<ul>
|
|
70
|
+
{ tagList?.map(tag => (
|
|
71
|
+
<FormControlLabel
|
|
72
|
+
as="li"
|
|
73
|
+
control={(
|
|
74
|
+
<Checkbox
|
|
75
|
+
checked={filters.includes(tag.id)}
|
|
76
|
+
onChange={() => {
|
|
77
|
+
onToggleSelected(tag.id)
|
|
78
|
+
if (tax.is_surface) {
|
|
79
|
+
toggleTag(tag.xml_id, 'left')
|
|
80
|
+
toggleTag(tag.xml_id, 'right')
|
|
81
|
+
}
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
)}
|
|
85
|
+
key={tag.id}
|
|
86
|
+
label={tag.name}
|
|
87
|
+
/>
|
|
88
|
+
))}
|
|
89
|
+
</ul>
|
|
90
|
+
{ data.tags.filter(t => (t.taxonomy_id === tax.id))?.length && data.tags.filter(t => (t.taxonomy_id === tax.id)).length >= 6
|
|
91
|
+
? (
|
|
92
|
+
<button
|
|
93
|
+
className="tag-filter-button"
|
|
94
|
+
type="button"
|
|
95
|
+
onClick={() => {
|
|
96
|
+
const newState = [...expanded]
|
|
97
|
+
newState[idx] = !expanded[idx]
|
|
98
|
+
setExpanded(newState)
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
{ expanded[idx] ? 'Show less' : 'Show more'}
|
|
102
|
+
</button>
|
|
103
|
+
)
|
|
104
|
+
: null }
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
: null
|
|
108
|
+
)
|
|
109
|
+
})}
|
|
110
|
+
</FormGroup>
|
|
97
111
|
</div>
|
|
98
112
|
)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
</div>
|
|
113
|
+
: null
|
|
114
|
+
}
|
|
115
|
+
</>
|
|
103
116
|
)
|
|
104
117
|
}
|
|
105
118
|
|
|
@@ -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'
|
|
@@ -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: 300px;
|
|
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;
|