@cu-mkp/editioncrafter 1.3.0-beta.1 → 1.3.0-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.
Files changed (42) hide show
  1. package/README.md +7 -0
  2. package/dist/editioncrafter.js +33739 -30730
  3. package/dist/es/src/EditionCrafter/component/DiploMatic.js +19 -17
  4. package/dist/es/src/EditionCrafter/component/DocumentView.js +13 -9
  5. package/dist/es/src/EditionCrafter/component/EmptyPaneView.js +22 -0
  6. package/dist/es/src/EditionCrafter/component/ImageView.js +61 -40
  7. package/dist/es/src/EditionCrafter/component/Navigation.js +1 -0
  8. package/dist/es/src/EditionCrafter/component/SplitPaneView.js +10 -9
  9. package/dist/es/src/EditionCrafter/component/TagToolbar.jsx +14 -4
  10. package/dist/es/src/EditionCrafter/context/TagFilter.jsx +22 -11
  11. package/dist/es/src/EditionCrafter/context/TagFilterContext.js +2 -1
  12. package/dist/es/src/EditionCrafter/index.jsx +31 -0
  13. package/dist/es/src/EditionCrafter/model/Folio.js +27 -1
  14. package/dist/es/src/EditionCrafter/saga/RouteListenerSaga.js +22 -7
  15. package/dist/es/src/EditionCrafter/scss/_imageView.scss +1 -1
  16. package/dist/es/src/RecordList/component/Record.jsx +1 -1
  17. package/dist/es/src/RecordList/component/RecordListView.jsx +1 -1
  18. package/dist/es/src/RecordList/component/Sidebar.jsx +1 -1
  19. package/dist/es/src/RecordList/component/SidebarTagList.jsx +1 -1
  20. package/dist/es/src/RecordList/index.jsx +1 -1
  21. package/dist/es/src/RecordList/styles/base.css +0 -16
  22. package/dist/es/src/TagExplore/assets/InsertLeft.jsx +18 -0
  23. package/dist/es/src/TagExplore/assets/InsertRight.jsx +18 -0
  24. package/dist/es/src/TagExplore/assets/Left.jsx +17 -0
  25. package/dist/es/src/TagExplore/assets/Right.jsx +17 -0
  26. package/dist/es/src/TagExplore/assets/insert_left.svg +12 -0
  27. package/dist/es/src/TagExplore/assets/insert_right.svg +12 -0
  28. package/dist/es/src/TagExplore/assets/left.svg +11 -0
  29. package/dist/es/src/TagExplore/assets/right.svg +11 -0
  30. package/dist/es/src/TagExplore/components/DocumentDetail.jsx +224 -0
  31. package/dist/es/src/TagExplore/components/NarrowSidebar.jsx +35 -0
  32. package/dist/es/src/TagExplore/components/SurfaceBrowser.jsx +176 -0
  33. package/dist/es/src/TagExplore/components/TagExploreSidebar.jsx +55 -0
  34. package/dist/es/src/TagExplore/components/TagFilters.jsx +106 -0
  35. package/dist/es/src/TagExplore/index.jsx +108 -0
  36. package/dist/es/src/TagExplore/styles/base.css +192 -0
  37. package/dist/es/src/{RecordList/component → common/components}/Pill.jsx +2 -0
  38. package/dist/es/src/common/components/Pill.style.css +16 -0
  39. package/dist/es/src/index.jsx +3 -27
  40. package/package.json +1 -27
  41. /package/dist/es/src/{RecordList/component → common/components}/Loading.jsx +0 -0
  42. /package/dist/es/src/{RecordList → common}/lib/sql.js +0 -0
@@ -0,0 +1,106 @@
1
+ import { Checkbox, FormControlLabel, FormGroup, Typography } from '@material-ui/core'
2
+ import { useContext, useEffect, useMemo, useState } from 'react'
3
+ import { getObjs } from '../../common/lib/sql'
4
+ import TagFilterContext from '../../EditionCrafter/context/TagFilterContext'
5
+
6
+ function getData(db) {
7
+ const taxonomiesStmt = db.prepare(`
8
+ SELECT
9
+ *
10
+ FROM
11
+ taxonomies;
12
+ `)
13
+
14
+ const tagsStmt = db.prepare(`
15
+ SELECT
16
+ tags.id AS id,
17
+ tags.name AS name,
18
+ tags.xml_id AS xml_id,
19
+ taxonomies.name as taxonomy,
20
+ taxonomies.id as taxonomy_id
21
+ FROM
22
+ tags
23
+ LEFT JOIN taxonomies
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
+ GROUP BY
32
+ tags.xml_id`)
33
+
34
+ return {
35
+ tags: getObjs(tagsStmt),
36
+ taxonomies: getObjs(taxonomiesStmt),
37
+ }
38
+ }
39
+
40
+ function TagFilters(props) {
41
+ const { onToggleSelected, filters } = props
42
+ const data = useMemo(() => getData(props.db), [props.db])
43
+ const [expanded, setExpanded] = useState(data.taxonomies?.map(() => (false)))
44
+ const [displayedTags, setDisplayedTags] = useState({})
45
+
46
+ const { toggleTag } = useContext(TagFilterContext)
47
+
48
+ useEffect(() => {
49
+ const tags = {}
50
+ for (let i = 0; i < data.taxonomies.length; i++) {
51
+ 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
54
+ }
55
+ setDisplayedTags(tags)
56
+ }, [expanded, data])
57
+
58
+ 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>
97
+ </div>
98
+ )
99
+ })}
100
+ </FormGroup>
101
+ </div>
102
+ </div>
103
+ )
104
+ }
105
+
106
+ export default TagFilters
@@ -0,0 +1,108 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { HashRouter } from 'react-router-dom'
3
+ import initSqlJs from 'sql.js'
4
+ import Loading from '../common/components/Loading'
5
+ import { getObjs } from '../common/lib/sql'
6
+ import EditionCrafter from '../EditionCrafter'
7
+ import TagFilterProvider from '../EditionCrafter/context/TagFilter'
8
+ import TagExploreSidebar from './components/TagExploreSidebar'
9
+ import './styles/base.css'
10
+
11
+ const initialFilters = {
12
+ categories: [],
13
+ tags: [],
14
+ }
15
+
16
+ async function initDb(url) {
17
+ const file = await fetch(url)
18
+
19
+ if (!file.ok) {
20
+ throw new Error('Failed fetching SQLite file.')
21
+ }
22
+
23
+ const buf = await file.arrayBuffer()
24
+ const arr = new Uint8Array(buf)
25
+
26
+ const db = await initSqlJs({
27
+ locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.12.0/${file}`,
28
+ }).then((SQL) => {
29
+ const db = new SQL.Database(arr)
30
+ return db
31
+ })
32
+
33
+ return db
34
+ }
35
+
36
+ function getData(db) {
37
+ const documentStmt = db.prepare(`
38
+ SELECT
39
+ documents.name AS name,
40
+ documents.local_id AS local_id
41
+ FROM
42
+ documents
43
+ `)
44
+
45
+ return getObjs(documentStmt)
46
+ }
47
+
48
+ function generateECProps(props, db) {
49
+ const documents = getData(db)
50
+ const { documentName, baseURL, transcriptionTypes } = props
51
+ const documentInfo = {}
52
+
53
+ for (const document of documents) {
54
+ documentInfo[document.local_id] = {
55
+ documentName: document.name,
56
+ transcriptionTypes,
57
+ iiifManifest: `${baseURL}/${document.local_id}/iiif/manifest.json`,
58
+ }
59
+ }
60
+
61
+ return {
62
+ documentName,
63
+ documentInfo,
64
+ tagExplorerMode: true,
65
+ }
66
+ }
67
+
68
+ function TagExplore(props) {
69
+ const [db, setDb] = useState(null)
70
+ const [ecProps, setECProps] = useState(null)
71
+ const [filters, setFilters] = useState(initialFilters)
72
+
73
+ useEffect(() => {
74
+ const loadDb = async () => {
75
+ const db = await initDb(props.dbUrl)
76
+ const ecProps = generateECProps(props, db)
77
+ setDb(db)
78
+ setECProps(ecProps)
79
+ }
80
+
81
+ if (!db) {
82
+ loadDb()
83
+ }
84
+
85
+ return () => {
86
+ if (db) {
87
+ db.close()
88
+ }
89
+ }
90
+ }, [props.dbUrl, db])
91
+
92
+ if (!db || !ecProps) {
93
+ return <Loading />
94
+ }
95
+
96
+ return (
97
+ <div className="tag-explore">
98
+ <HashRouter>
99
+ <TagFilterProvider>
100
+ <TagExploreSidebar db={db} />
101
+ <EditionCrafter {...ecProps} />
102
+ </TagFilterProvider>
103
+ </HashRouter>
104
+ </div>
105
+ )
106
+ }
107
+
108
+ export default TagExplore
@@ -0,0 +1,192 @@
1
+ .tag-explore {
2
+ display: grid;
3
+ max-height: 100vh;
4
+ grid-template-columns: 50px 1fr;
5
+ }
6
+
7
+ .tag-explore-sidebar {
8
+ position: relative;
9
+ z-index: 999;
10
+ height: 100%;
11
+ max-height: 100dvh;
12
+ }
13
+
14
+ .tag-explore .narrow-sidebar {
15
+ height: 100vh;
16
+ width: 48px;
17
+ }
18
+
19
+ .tag-explore-sidebar {
20
+ overflow-y: none;
21
+ height: 100%;
22
+ background-color: black;
23
+ }
24
+
25
+ .tag-explore .tag-filters {
26
+ overflow-y: auto;
27
+ position: absolute;
28
+ top: 48px;
29
+ left: 0;
30
+ background-color: #242629;
31
+ z-index: 10000;
32
+ padding: 12px 0 12px 12px;
33
+ width: 100%;
34
+ height: 100%;
35
+ max-height: 100dvh;
36
+ }
37
+
38
+ .tag-explore .tag-filter-button {
39
+ background-color: #242629;
40
+ padding: 12px;
41
+ color: white;
42
+ border: 1px solid white;
43
+ border-radius: 6px;
44
+ margin: 6px auto 12px auto;
45
+ cursor: pointer;
46
+ }
47
+
48
+ .tag-explore .tag-filter-button:hover {
49
+ background-color: white;
50
+ color: black;
51
+ }
52
+
53
+ .tag-explore .tag-filters ul {
54
+ display: flex;
55
+ flex-direction: column;
56
+ }
57
+
58
+ .tag-explore .surface-browser-close {
59
+ position: absolute;
60
+ top: 0;
61
+ right: -24px;
62
+ background-color: #242629;
63
+ }
64
+
65
+ .tag-explore .tag-filters .tag-list, .tag-explore-sidebar {
66
+ display: flex;
67
+ gap: 4px;
68
+ flex-wrap: wrap;
69
+ }
70
+
71
+ .surface-thumbnail-caption {
72
+ text-align: center;
73
+ }
74
+
75
+ .surface-thumbnail-overlay {
76
+ position: absolute;
77
+ width: 100%;
78
+ height: 100%;
79
+ inset: 0;
80
+ background-color: #2426297d;
81
+ opacity: 0%;
82
+ display: flex;
83
+ justify-content: center;
84
+ align-items: center;
85
+ gap: 12px;
86
+ }
87
+
88
+ .surface-thumbnail-overlay-selected {
89
+ position: absolute;
90
+ width: 100%;
91
+ height: 100%;
92
+ inset: 0;
93
+ display: flex;
94
+ justify-content: flex-end;
95
+ align-items: flex-end;
96
+ }
97
+
98
+ .surface-thumbnail-overlay-selected.left {
99
+ border: 2px solid #008F81;
100
+ }
101
+
102
+ .surface-thumbnail-overlay-selected.right {
103
+ border: 2px solid #A31621;
104
+ }
105
+
106
+ .surface-thumbnail-overlay-selected > div {
107
+ color: white;
108
+ display: flex;
109
+ flex-direction: row;
110
+ justify-content: space-around;
111
+ gap: 6px;
112
+ align-items: center;
113
+ padding: 6px;
114
+ border-top-left-radius: 6px;
115
+ font-size: small;
116
+ }
117
+
118
+ .surface-thumbnail-overlay-selected.left > div {
119
+ background-color: #008F81;
120
+ }
121
+
122
+ .surface-thumbnail-overlay-selected.right > div {
123
+ background-color: #A31621;
124
+ }
125
+
126
+ .surface-thumbnail-overlay .surface-thumbnail-overlay-content {
127
+ opacity: 100%;
128
+ display: flex;
129
+ flex-direction: row;
130
+ gap: 12px;
131
+ justify-content: center;
132
+ align-items: center;
133
+ border-radius: 12px;
134
+ padding: 8px;
135
+ background-color: #242629;
136
+ }
137
+
138
+ .surface-thumbnail-overlay:hover {
139
+ opacity: 100%;
140
+ }
141
+
142
+ .surface-thumbnail-overlay a {
143
+ cursor: pointer;
144
+ }
145
+
146
+ .surface-thumbnail-figure {
147
+ padding: 0;
148
+ margin: 16px;
149
+ position: relative;
150
+ }
151
+
152
+ .tag-explore .surface-browser {
153
+ position: absolute;
154
+ top: 0;
155
+ left: 48px;
156
+ height: 100vh;
157
+ min-width: 300px;
158
+ display: flex;
159
+ flex-direction: column;
160
+ background-color: #242629;
161
+ color: white;
162
+ padding: 12px;
163
+ }
164
+
165
+ .tag-explore .surface-browser-document-details {
166
+ overflow-y: auto;
167
+ position: relative;
168
+ }
169
+
170
+ .tag-explore .accordion-summary {
171
+ flex-direction: row-reverse;
172
+ background-color: #242629
173
+ }
174
+
175
+ .tag-explore .accordion-summary div {
176
+ display: flex;
177
+ flex-direction: row;
178
+ justify-content: space-between;
179
+ }
180
+
181
+ /* .tag-explore .accordion-summary .MuiAccordionSummary-expandIcon {
182
+ padding-left: 0;
183
+ } */
184
+
185
+ .tag-explore .accordion-summary .MuiAccordionSummary-content {
186
+ padding-left: 12px;
187
+ gap: 12px;
188
+ }
189
+
190
+ .tag-explore .accordion-detail {
191
+ background-color: #242629;
192
+ }
@@ -1,3 +1,5 @@
1
+ import './Pill.style.css'
2
+
1
3
  function Pill(props) {
2
4
  return (
3
5
  <button className={props.isActive ? 'active pill' : 'pill'} onClick={props.onClick} type="button">
@@ -0,0 +1,16 @@
1
+ .pill {
2
+ appearance: none;
3
+ display: flex;
4
+ height: 32px;
5
+ padding: 4px 12px;
6
+ justify-content: center;
7
+ align-items: center;
8
+ gap: 4px;
9
+ border-radius: 50px;
10
+ border: 1px solid #CEDAE7;
11
+ background: #CEDAE7;
12
+ color: #0A0A0A;
13
+ font-family: Inter;
14
+ font-size: 14px;
15
+ font-weight: 500;
16
+ }
@@ -1,32 +1,8 @@
1
- import { createTheme, ThemeProvider } from '@material-ui/core/styles'
2
- import React from 'react'
3
- import DiploMatic from './EditionCrafter/component/DiploMatic'
4
- import { createReduxStore } from './EditionCrafter/model/ReduxStore'
1
+ import EditionCrafter from './EditionCrafter'
5
2
  import _RecordList from './RecordList'
6
- import './EditionCrafter/scss/editioncrafter.scss'
7
-
8
- /**
9
- * Default instantiation
10
- */
11
- function EditionCrafter(props) {
12
- const theme = createTheme({
13
- palette: {
14
- primary: {
15
- main: '#792421',
16
- },
17
- secondary: {
18
- main: '#EBE3DD',
19
- },
20
- },
21
- })
22
-
23
- return (
24
- <ThemeProvider theme={theme}>
25
- <DiploMatic config={props} store={createReduxStore(props)} />
26
- </ThemeProvider>
27
- )
28
- }
3
+ import _TagExplore from './TagExplore'
29
4
 
30
5
  export { _RecordList as RecordList }
6
+ export { _TagExplore as TagExplore }
31
7
 
32
8
  export default EditionCrafter
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cu-mkp/editioncrafter",
3
3
  "type": "module",
4
- "version": "1.3.0-beta.1",
4
+ "version": "1.3.0-beta.2",
5
5
  "private": false,
6
6
  "description": "A simple digital critical edition publication tool",
7
7
  "license": "MIT",
@@ -51,42 +51,16 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@antfu/eslint-config": "^3.8.0",
54
- "@chromatic-com/storybook": "^3.2.2",
55
54
  "@eslint-react/eslint-plugin": "^1.15.2",
56
- "@storybook/addon-essentials": "^8.4.3",
57
- "@storybook/addon-interactions": "^8.4.3",
58
- "@storybook/addon-links": "^8.4.3",
59
- "@storybook/blocks": "^8.4.3",
60
55
  "@storybook/builder-vite": "^8.4.3",
61
- "@storybook/react": "^8.4.3",
62
56
  "@storybook/react-vite": "^8.4.3",
63
- "@storybook/test": "^8.4.3",
64
57
  "@vitejs/plugin-react": "^4.3.3",
65
- "bundlewatch": "^0.3.3",
66
- "chalk": "^4.1.0",
67
- "codecov": "^3.7.0",
68
- "core-js": "^3.21.1",
69
- "css-loader": "^6.7.3",
70
- "enzyme": "^3.11.0",
71
58
  "eslint": "^9.14.0",
72
59
  "eslint-plugin-astro": "^1.3.0",
73
60
  "eslint-plugin-react-hooks": "^5.0.0",
74
- "eslint-plugin-react-refresh": "^0.4.14",
75
- "glob": "^7.1.4",
76
- "http-server": "^14.1.0",
77
- "jsdom": "^19.0.0",
78
61
  "react": "^17.0.2",
79
62
  "react-dom": "^17.0.2",
80
- "react-refresh": "^0.14.0",
81
- "redux-mock-store": "^1.5.1",
82
- "redux-saga-test-plan": "^4.0.6",
83
- "resolve-url-loader": "^5.0.0",
84
- "sass": "^1.61.0",
85
- "sass-loader": "^13.2.2",
86
63
  "storybook": "^8.4.2",
87
- "style-loader": "^3.3.2",
88
- "unfetch": "^4.1.0",
89
- "url-polyfill": "^1.1.7",
90
64
  "vite": "^5.4.11",
91
65
  "vite-plugin-css-injected-by-js": "^3.5.2"
92
66
  },
File without changes