@cu-mkp/editioncrafter 1.3.1-beta.1 → 1.3.1-beta.2

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.
@@ -1,29 +1,42 @@
1
- import { Box, Button, ButtonGroup, Collapse, Divider, IconButton, Typography } from '@material-ui/core'
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, 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'
12
10
  import TagFilters from './TagFilters'
13
11
 
14
12
  function getData(db) {
15
13
  const docStmt = db.prepare(`
16
14
  SELECT
17
- documents.id AS id,
18
- documents.name AS name,
19
- documents.local_id AS local_id
15
+ d.id AS id,
16
+ d.name AS name,
17
+ d.local_id AS local_id,
18
+ json_group_array(document_taggings.tag) as tags
20
19
  FROM
21
- documents
20
+ documents d
21
+ LEFT JOIN document_taggings ON d.id = document_taggings.document
22
+ GROUP BY d.id, d.name, d.local_id
22
23
  `)
23
-
24
24
  return getObjs(docStmt)
25
25
  }
26
26
 
27
+ function getDocTags(db) {
28
+ const tagsStmt = db.prepare(`
29
+ SELECT
30
+ tags.id AS id
31
+ FROM
32
+ tags
33
+ LEFT JOIN taxonomies ON tags.taxonomy_id = taxonomies.id
34
+ WHERE
35
+ taxonomies.is_surface = 0 OR taxonomies.is_surface IS NULL
36
+ `)
37
+ return getObjs(tagsStmt)
38
+ }
39
+
27
40
  function parseFolioID(folioID) {
28
41
  if (!folioID) {
29
42
  return null
@@ -50,27 +63,46 @@ function getSelection(path) {
50
63
  function SurfaceBrowser(props) {
51
64
  const { db, open, toggleOpen } = props
52
65
  const documents = useMemo(() => getData(db), [db])
66
+ const docTags = useMemo(() => getDocTags(db)?.map(tag => (tag.id)), [db])
53
67
  const [pageCount, setPageCount] = useState({})
54
68
  const [totalPages, setTotalPages] = useState(0)
55
69
  const [tags, setTags] = useState([])
56
70
  const [showFilters, setShowFilters] = useState(false)
71
+ const [query, setQuery] = useState(undefined)
72
+
73
+ const filterDocs = useCallback((docs, tags) => {
74
+ return docs.filter((doc) => {
75
+ const docID = doc.id
76
+ for (const tag of tags) {
77
+ if (docTags.includes(tag) && !JSON.parse(doc.tags)?.includes(tag)) {
78
+ const newCount = pageCount
79
+ newCount[docID] = 0
80
+ setPageCount(newCount)
81
+ return false
82
+ }
83
+ }
84
+ return true
85
+ })
86
+ }, [docTags, pageCount])
87
+
88
+ const filteredDocs = useMemo(() => (filterDocs(documents, tags)), [filterDocs, documents, tags])
57
89
 
58
90
  const navigate = useNavigate()
59
91
  const location = useLocation()
60
92
  const selection = useMemo(() => getSelection(location.pathname), [location])
61
93
 
62
- const navigateToSelection = (nextSelection) => {
94
+ const navigateToSelection = useCallback((nextSelection) => {
63
95
  const folioID = nextSelection?.left ? `${nextSelection.left.localID}_${nextSelection.left.surfaceID}` : null
64
96
  const folioID2 = nextSelection?.right ? `${nextSelection.right.localID}_${nextSelection.right.surfaceID}` : null
65
97
  const navParams = `/ec/${folioID || '-1'}/${folioID ? 'f' : 'g'}/${folioID2 || '-1'}/${folioID2 ? 'f' : 'g'}`
66
98
  navigate(navParams + location.search)
67
- }
99
+ }, [location.search, navigate])
68
100
 
69
- const updatePageCount = (documentID, numPages) => {
101
+ const updatePageCount = useCallback((documentID, numPages) => {
70
102
  const newCount = pageCount
71
103
  newCount[documentID] = numPages
72
104
  setPageCount(newCount)
73
- }
105
+ }, [pageCount])
74
106
 
75
107
  useEffect(() => {
76
108
  let p = 0
@@ -80,7 +112,7 @@ function SurfaceBrowser(props) {
80
112
  setTotalPages(p)
81
113
  }, [pageCount, tags])
82
114
 
83
- const documentDetails = documents.map((doc) => {
115
+ const documentDetails = useMemo(() => filteredDocs.map((doc) => {
84
116
  return (
85
117
  <DocumentDetail
86
118
  key={`document-detail-${doc.id}`}
@@ -91,11 +123,11 @@ function SurfaceBrowser(props) {
91
123
  selection={selection}
92
124
  navigateToSelection={navigateToSelection}
93
125
  updatePageCount={count => updatePageCount(doc.id, count)}
94
- tags={tags}
126
+ tags={tags?.filter(tag => !docTags.includes(tag))}
95
127
  >
96
128
  </DocumentDetail>
97
129
  )
98
- })
130
+ }), [db, docTags, filteredDocs, navigateToSelection, selection, tags, updatePageCount])
99
131
 
100
132
  return (
101
133
  <Collapse in={open} horizontal>
@@ -152,18 +184,22 @@ function SurfaceBrowser(props) {
152
184
  </IconButton>
153
185
  </ButtonGroup> */}
154
186
  { showFilters && (
155
- <TagFilters
156
- db={db}
157
- filters={tags}
158
- onToggleSelected={(tagId) => {
159
- if (tags.includes(tagId)) {
160
- setTags(current => (current.filter(t => (t !== tagId))))
161
- }
162
- else {
163
- setTags(current => ([...current, tagId]))
164
- }
165
- }}
166
- />
187
+ <div className="tag-filters">
188
+ <Input placeholder="Search for filters" value={query} onChange={(e) => { setQuery(e.target.value) }} className="tag-filters-search" />
189
+ <TagFilters
190
+ db={db}
191
+ filters={tags}
192
+ query={query}
193
+ onToggleSelected={(tagId) => {
194
+ if (tags.includes(tagId)) {
195
+ setTags(current => (current.filter(t => (t !== tagId))))
196
+ }
197
+ else {
198
+ setTags(current => ([...current, tagId]))
199
+ }
200
+ }}
201
+ />
202
+ </div>
167
203
  ) }
168
204
  <Box className="surface-browser-document-details">
169
205
  { 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,8 +32,9 @@ 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])
37
+ console.log(data.taxonomies)
43
38
  const [expanded, setExpanded] = useState(data.taxonomies?.map(() => (false)))
44
39
  const [displayedTags, setDisplayedTags] = useState({})
45
40
 
@@ -47,59 +42,78 @@ function TagFilters(props) {
47
42
 
48
43
  useEffect(() => {
49
44
  const tags = {}
45
+ const filteredTags = data.tags.filter(tag => (!query || !query.length || tag.name.toLowerCase().includes(query.toLowerCase())))
50
46
  for (let i = 0; i < data.taxonomies.length; i++) {
51
47
  const tax = data.taxonomies[i]
52
- const tagList = expanded[i] ? data.tags.filter(t => (t.taxonomy_id === tax.id)) : data.tags.filter(t => (t.taxonomy_id === tax.id))?.slice(0, 5)
53
- tags[tax.id] = tagList
48
+ const tagList = expanded[i] ? filteredTags.filter(t => (t.taxonomy_id === tax.id)) : filteredTags.filter(t => (t.taxonomy_id === tax.id))?.slice(0, 5)
49
+ if (tagList?.length) {
50
+ tags[tax.id] = tagList
51
+ }
54
52
  }
55
53
  setDisplayedTags(tags)
56
- }, [expanded, data])
54
+ }, [expanded, data, query])
57
55
 
58
56
  return (
59
- <div className="tag-filters">
60
- <div className="tag-list">
61
- <FormGroup>
62
- { data.taxonomies.map((tax, idx) => {
63
- const tagList = displayedTags[tax.id]
64
- return (
65
- <div key={tax.id}>
66
- <Typography>{tax.name}</Typography>
67
- <ul>
68
- { tagList?.map(tag => (
69
- <FormControlLabel
70
- as="li"
71
- control={(
72
- <Checkbox
73
- checked={filters.includes(tag.id)}
74
- onChange={() => {
75
- onToggleSelected(tag.id)
76
- toggleTag(tag.xml_id, 'left')
77
- toggleTag(tag.xml_id, 'right')
78
- }}
79
- />
80
- )}
81
- key={tag.id}
82
- label={tag.name}
83
- />
84
- ))}
85
- </ul>
86
- <button
87
- className="tag-filter-button"
88
- type="button"
89
- onClick={() => {
90
- const newState = [...expanded]
91
- newState[idx] = !expanded[idx]
92
- setExpanded(newState)
93
- }}
94
- >
95
- { !data.tags.filter(t => (t.taxonomy_id === tax.id))?.length || data.tags.filter(t => (t.taxonomy_id === tax.id)).length < 6 ? null : expanded[idx] ? 'Show less' : 'Show more'}
96
- </button>
57
+ <>
58
+ {
59
+ data?.tags?.length
60
+ ? (
61
+ <div className="tag-list">
62
+ <FormGroup>
63
+ { data.taxonomies.map((tax, idx) => {
64
+ const tagList = displayedTags[tax.id]
65
+ return (
66
+ tagList?.length
67
+ ? (
68
+ <div key={tax.id}>
69
+ <Typography>{`${tax.name.slice(0, 1).toUpperCase()}${tax.name.slice(1)}`}</Typography>
70
+ <ul>
71
+ { tagList?.map(tag => (
72
+ <FormControlLabel
73
+ as="li"
74
+ control={(
75
+ <Checkbox
76
+ checked={filters.includes(tag.id)}
77
+ onChange={() => {
78
+ onToggleSelected(tag.id)
79
+ if (tax.is_surface) {
80
+ toggleTag(tag.xml_id, 'left')
81
+ toggleTag(tag.xml_id, 'right')
82
+ }
83
+ }}
84
+ />
85
+ )}
86
+ key={tag.id}
87
+ label={tag.name}
88
+ />
89
+ ))}
90
+ </ul>
91
+ { data.tags.filter(t => (t.taxonomy_id === tax.id))?.length && data.tags.filter(t => (t.taxonomy_id === tax.id)).length >= 6
92
+ ? (
93
+ <button
94
+ className="tag-filter-button"
95
+ type="button"
96
+ onClick={() => {
97
+ const newState = [...expanded]
98
+ newState[idx] = !expanded[idx]
99
+ setExpanded(newState)
100
+ }}
101
+ >
102
+ { expanded[idx] ? 'Show less' : 'Show more'}
103
+ </button>
104
+ )
105
+ : null }
106
+ </div>
107
+ )
108
+ : null
109
+ )
110
+ })}
111
+ </FormGroup>
97
112
  </div>
98
113
  )
99
- })}
100
- </FormGroup>
101
- </div>
102
- </div>
114
+ : null
115
+ }
116
+ </>
103
117
  )
104
118
  }
105
119
 
@@ -1,5 +1,5 @@
1
- import { useEffect, useMemo, useState } from 'react'
2
- import { BrowserRouter, HashRouter } from 'react-router-dom'
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
- <Router>
99
+ <HashRouter>
102
100
  <TagFilterProvider>
103
101
  <TagExploreSidebar db={db} />
104
102
  <EditionCrafter {...ecProps} />
105
103
  </TagFilterProvider>
106
- </Router>
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: 0;
29
+ left: 400px;
30
30
  background-color: #242629;
31
31
  z-index: 10000;
32
32
  padding: 12px 0 12px 12px;
33
- width: 100%;
33
+ width: 300px;
34
34
  height: 100%;
35
- max-height: 100dvh;
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: 100vh;
157
- min-width: 300px;
161
+ height: 97dvh;
162
+ width: 400px;
158
163
  display: flex;
159
164
  flex-direction: column;
160
165
  background-color: #242629;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cu-mkp/editioncrafter",
3
3
  "type": "module",
4
- "version": "1.3.1-beta.1",
4
+ "version": "1.3.1-beta.2",
5
5
  "private": false,
6
6
  "description": "A simple digital critical edition publication tool",
7
7
  "license": "MIT",