@cu-mkp/editioncrafter 1.1.0 → 1.2.0-beta.1

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 (118) hide show
  1. package/dist/editioncrafter.js +20709 -18672
  2. package/dist/es/src/{action → EditionCrafter/action}/DocumentActions.js +8 -0
  3. package/dist/es/src/{action → EditionCrafter/action}/initialState/documentInitialState.js +7 -0
  4. package/dist/es/src/{component → EditionCrafter/component}/DiploMatic.js +17 -14
  5. package/dist/es/src/{component → EditionCrafter/component}/DocumentView.js +16 -6
  6. package/dist/es/src/EditionCrafter/component/Navigation.js +446 -0
  7. package/dist/es/src/{component → EditionCrafter/component}/RouteListener.js +3 -3
  8. package/dist/es/src/EditionCrafter/component/TagToolbar.jsx +57 -0
  9. package/dist/es/src/{component → EditionCrafter/component}/TranscriptionView.js +27 -7
  10. package/dist/es/src/EditionCrafter/context/TagFilter.jsx +61 -0
  11. package/dist/es/src/EditionCrafter/context/TagFilterContext.js +8 -0
  12. package/dist/es/src/EditionCrafter/icons/DocumentPagesIcon.jsx +18 -0
  13. package/dist/es/src/{model → EditionCrafter/model}/Folio.js +27 -1
  14. package/dist/es/src/{model → EditionCrafter/model}/folioLayout.js +6 -5
  15. package/dist/es/src/{saga → EditionCrafter/saga}/RouteListenerSaga.js +44 -3
  16. package/dist/es/src/{scss → EditionCrafter/scss}/_base.scss +11 -1
  17. package/dist/es/src/{scss → EditionCrafter/scss}/_diplomatic.scss +15 -24
  18. package/dist/es/src/EditionCrafter/scss/_navigation.scss +468 -0
  19. package/dist/es/src/{scss → EditionCrafter/scss}/_transcriptView.scss +50 -41
  20. package/dist/es/src/{scss → EditionCrafter/scss}/editioncrafter.scss +2 -1
  21. package/dist/es/src/RecordList/component/CollapsibleMenu.jsx +22 -0
  22. package/dist/es/src/RecordList/component/Loading.jsx +12 -0
  23. package/dist/es/src/RecordList/component/Pill.jsx +10 -0
  24. package/dist/es/src/RecordList/component/Record.jsx +82 -0
  25. package/dist/es/src/RecordList/component/RecordListView.jsx +109 -0
  26. package/dist/es/src/RecordList/component/Sidebar.jsx +83 -0
  27. package/dist/es/src/RecordList/component/SidebarTagList.jsx +38 -0
  28. package/dist/es/src/RecordList/context/FilterContext.jsx +8 -0
  29. package/dist/es/src/RecordList/index.jsx +92 -0
  30. package/dist/es/src/RecordList/lib/sql.js +9 -0
  31. package/dist/es/src/RecordList/styles/base.css +78 -0
  32. package/dist/es/src/RecordList/styles/record.css +84 -0
  33. package/dist/es/src/RecordList/styles/sidebar.css +39 -0
  34. package/dist/es/src/{index.js → index.jsx} +6 -3
  35. package/package.json +6 -3
  36. package/dist/es/src/component/Navigation.js +0 -402
  37. package/dist/es/src/hooks/useIsWidthUp.js +0 -9
  38. package/dist/es/src/lib/registerServiceWorker.js +0 -111
  39. package/dist/es/src/scss/_navigation.scss +0 -209
  40. /package/dist/es/src/{action → EditionCrafter/action}/DiplomaticActions.js +0 -0
  41. /package/dist/es/src/{action → EditionCrafter/action}/GlossaryActions.js +0 -0
  42. /package/dist/es/src/{action → EditionCrafter/action}/initialState/diplomaticInitialState.js +0 -0
  43. /package/dist/es/src/{action → EditionCrafter/action}/initialState/glossaryInitialState.js +0 -0
  44. /package/dist/es/src/{action → EditionCrafter/action}/rootReducer.js +0 -0
  45. /package/dist/es/src/{component → EditionCrafter/component}/AlphabetLinks.js +0 -0
  46. /package/dist/es/src/{component → EditionCrafter/component}/CustomizedTooltops.js +0 -0
  47. /package/dist/es/src/{component → EditionCrafter/component}/EditorComment.js +0 -0
  48. /package/dist/es/src/{component → EditionCrafter/component}/ErrorBoundary.js +0 -0
  49. /package/dist/es/src/{component → EditionCrafter/component}/FigureImage.js +0 -0
  50. /package/dist/es/src/{component → EditionCrafter/component}/GlossaryView.js +0 -0
  51. /package/dist/es/src/{component → EditionCrafter/component}/HelpPopper.js +0 -0
  52. /package/dist/es/src/{component → EditionCrafter/component}/ImageGridView.js +0 -0
  53. /package/dist/es/src/{component → EditionCrafter/component}/ImageView.js +0 -0
  54. /package/dist/es/src/{component → EditionCrafter/component}/ImageZoomControl.js +0 -0
  55. /package/dist/es/src/{component → EditionCrafter/component}/JumpToFolio.js +0 -0
  56. /package/dist/es/src/{component → EditionCrafter/component}/Pagination.js +0 -0
  57. /package/dist/es/src/{component → EditionCrafter/component}/Parser.js +0 -0
  58. /package/dist/es/src/{component → EditionCrafter/component}/RingSpinner.js +0 -0
  59. /package/dist/es/src/{component → EditionCrafter/component}/SeaDragonComponent.js +0 -0
  60. /package/dist/es/src/{component → EditionCrafter/component}/SinglePaneView.js +0 -0
  61. /package/dist/es/src/{component → EditionCrafter/component}/SplitPaneView.js +0 -0
  62. /package/dist/es/src/{component → EditionCrafter/component}/Watermark.js +0 -0
  63. /package/dist/es/src/{component → EditionCrafter/component}/XMLView.js +0 -0
  64. /package/dist/es/src/{icons → EditionCrafter/icons}/ByIcon.js +0 -0
  65. /package/dist/es/src/{icons → EditionCrafter/icons}/CcIcon.js +0 -0
  66. /package/dist/es/src/{icons → EditionCrafter/icons}/NcIcon.js +0 -0
  67. /package/dist/es/src/{icons → EditionCrafter/icons}/SaIcon.js +0 -0
  68. /package/dist/es/src/{icons → EditionCrafter/icons}/SideMenuIconLeft.js +0 -0
  69. /package/dist/es/src/{icons → EditionCrafter/icons}/SideMenuIconRight.js +0 -0
  70. /package/dist/es/src/{icons → EditionCrafter/icons}/howtouse-asterisk.png +0 -0
  71. /package/dist/es/src/{icons → EditionCrafter/icons}/howtouse-curly.png +0 -0
  72. /package/dist/es/src/{icons → EditionCrafter/icons}/howtouse-square.png +0 -0
  73. /package/dist/es/src/{icons → EditionCrafter/icons}/howtouse-ups.png +0 -0
  74. /package/dist/es/src/{img → EditionCrafter/img}/banner-about.png +0 -0
  75. /package/dist/es/src/{img → EditionCrafter/img}/banner-essays.jpg +0 -0
  76. /package/dist/es/src/{img → EditionCrafter/img}/banner-essays.png +0 -0
  77. /package/dist/es/src/{img → EditionCrafter/img}/banner-how-to.png +0 -0
  78. /package/dist/es/src/{img → EditionCrafter/img}/banner-resources.png +0 -0
  79. /package/dist/es/src/{img → EditionCrafter/img}/book-open-cropped.png +0 -0
  80. /package/dist/es/src/{img → EditionCrafter/img}/book-open.png +0 -0
  81. /package/dist/es/src/{img → EditionCrafter/img}/book-spine.png +0 -0
  82. /package/dist/es/src/{img → EditionCrafter/img}/bookcover-cropped.png +0 -0
  83. /package/dist/es/src/{img → EditionCrafter/img}/cropped-MKLizardFilled-32x32.jpg +0 -0
  84. /package/dist/es/src/{img → EditionCrafter/img}/editioncrafterlogo.png +0 -0
  85. /package/dist/es/src/{img → EditionCrafter/img}/folio48r-drawing.png +0 -0
  86. /package/dist/es/src/{img → EditionCrafter/img}/howtouse-asterisk.png +0 -0
  87. /package/dist/es/src/{img → EditionCrafter/img}/howtouse-beaker.png +0 -0
  88. /package/dist/es/src/{img → EditionCrafter/img}/howtouse-curly.png +0 -0
  89. /package/dist/es/src/{img → EditionCrafter/img}/howtouse-square.png +0 -0
  90. /package/dist/es/src/{img → EditionCrafter/img}/howtouse-ups.png +0 -0
  91. /package/dist/es/src/{img → EditionCrafter/img}/lizard-no-bg.png +0 -0
  92. /package/dist/es/src/{img → EditionCrafter/img}/logo_center_multi_line.png +0 -0
  93. /package/dist/es/src/{img → EditionCrafter/img}/logo_center_single_line.png +0 -0
  94. /package/dist/es/src/{img → EditionCrafter/img}/logo_columbia.png +0 -0
  95. /package/dist/es/src/{img → EditionCrafter/img}/mk-banner-logo.png +0 -0
  96. /package/dist/es/src/{img → EditionCrafter/img}/mk-homepage-logo.png +0 -0
  97. /package/dist/es/src/{img → EditionCrafter/img}/spinner.gif +0 -0
  98. /package/dist/es/src/{img → EditionCrafter/img}/text-bg.png +0 -0
  99. /package/dist/es/src/{img → EditionCrafter/img}/watermark.png +0 -0
  100. /package/dist/es/src/{lib → EditionCrafter/lib}/copyObject.js +0 -0
  101. /package/dist/es/src/{model → EditionCrafter/model}/DocumentHelper.js +0 -0
  102. /package/dist/es/src/{model → EditionCrafter/model}/ReduxStore.js +0 -0
  103. /package/dist/es/src/{saga → EditionCrafter/saga}/rootSaga.js +0 -0
  104. /package/dist/es/src/{scss → EditionCrafter/scss}/_CETEIcean.scss +0 -0
  105. /package/dist/es/src/{scss → EditionCrafter/scss}/_globalNavigation.scss +0 -0
  106. /package/dist/es/src/{scss → EditionCrafter/scss}/_glossary.scss +0 -0
  107. /package/dist/es/src/{scss → EditionCrafter/scss}/_imageGridView.scss +0 -0
  108. /package/dist/es/src/{scss → EditionCrafter/scss}/_imageView.scss +0 -0
  109. /package/dist/es/src/{scss → EditionCrafter/scss}/_imageZoomControl.scss +0 -0
  110. /package/dist/es/src/{scss → EditionCrafter/scss}/_jumpbox.scss +0 -0
  111. /package/dist/es/src/{scss → EditionCrafter/scss}/_pagination.scss +0 -0
  112. /package/dist/es/src/{scss → EditionCrafter/scss}/_ringSpinner.scss +0 -0
  113. /package/dist/es/src/{scss → EditionCrafter/scss}/_singlePaneView.scss +0 -0
  114. /package/dist/es/src/{scss → EditionCrafter/scss}/_spinner.scss +0 -0
  115. /package/dist/es/src/{scss → EditionCrafter/scss}/_splitPaneView.scss +0 -0
  116. /package/dist/es/src/{scss → EditionCrafter/scss}/_thumbnails.scss +0 -0
  117. /package/dist/es/src/{scss → EditionCrafter/scss}/_watermark.scss +0 -0
  118. /package/dist/es/src/{scss → EditionCrafter/scss}/_xmlView.scss +0 -0
@@ -0,0 +1,22 @@
1
+ import { useState } from 'react'
2
+ import { FaChevronDown, FaChevronUp } from 'react-icons/fa'
3
+
4
+ function CollapsibleMenu(props) {
5
+ const [open, setOpen] = useState(true)
6
+
7
+ return (
8
+ <>
9
+ <div className="collapsible-menu">
10
+ <button className="collapsible-menu-toggle" onClick={() => setOpen(!open)} type="button">
11
+ <p className="collapsible-menu-title">{props.title}</p>
12
+ {open
13
+ ? <FaChevronUp />
14
+ : <FaChevronDown />}
15
+ </button>
16
+ </div>
17
+ {open && props.children}
18
+ </>
19
+ )
20
+ }
21
+
22
+ export default CollapsibleMenu
@@ -0,0 +1,12 @@
1
+ import { HiOutlineBookOpen } from 'react-icons/hi2'
2
+
3
+ function Loading() {
4
+ return (
5
+ <div className="loading">
6
+ <HiOutlineBookOpen />
7
+ <span>Loading</span>
8
+ </div>
9
+ )
10
+ }
11
+
12
+ export default Loading
@@ -0,0 +1,10 @@
1
+ function Pill(props) {
2
+ return (
3
+ <button className={props.isActive ? 'active pill' : 'pill'} onClick={props.onClick} type="button">
4
+ {props.children}
5
+ {props.label}
6
+ </button>
7
+ )
8
+ }
9
+
10
+ export default Pill
@@ -0,0 +1,82 @@
1
+ import { useContext, useMemo } from 'react'
2
+ import FilterContext from '../context/FilterContext'
3
+ import Pill from './Pill'
4
+
5
+ function getRecordName(div) {
6
+ if (div.element_name) {
7
+ return `${div.element_name} - ${div.surface_name}`
8
+ }
9
+
10
+ return div.surface_name
11
+ }
12
+
13
+ function getTagObjects(ids, allTags) {
14
+ return ids
15
+ .map(xmlId => allTags.find(t => t.xml_id === xmlId))
16
+ .filter(Boolean)
17
+ }
18
+
19
+ function getSurfaceLink(baseUrl, div, cats, tags) {
20
+ return (
21
+ `${baseUrl}&viewMode=story#/ec/${div.surface_xml_id}/f/${div.surface_xml_id}/${div.layer_xml_id}?tags=${[...cats, ...tags].join(',')}`
22
+ )
23
+ }
24
+
25
+ function Record(props) {
26
+ const ctx = useContext(FilterContext)
27
+
28
+ const categories = useMemo(
29
+ () => getTagObjects(props.div.tagging_ids, props.tags),
30
+ [props.div.tagging_ids, props.tags],
31
+ )
32
+
33
+ const tagCounts = useMemo(() => {
34
+ const result = {}
35
+
36
+ props.childElements.forEach((el) => {
37
+ const tags = getTagObjects(el.tagging_ids, props.tags)
38
+ tags.forEach((tag) => {
39
+ if (result[tag.name]) {
40
+ result[tag.name].count++
41
+ }
42
+ else {
43
+ result[tag.name] = {
44
+ id: tag.xml_id,
45
+ count: 1,
46
+ }
47
+ }
48
+ })
49
+ })
50
+
51
+ return result
52
+ }, [props.childElements, props.tags])
53
+
54
+ return (
55
+ <div className="record-box">
56
+ <p>
57
+ <a
58
+ href={getSurfaceLink(props.viewerUrl, props.div, ctx.categories, ctx.tags)}
59
+ target="_blank"
60
+ rel="noopener noreferrer"
61
+ >
62
+ {getRecordName(props.div)}
63
+ </a>
64
+ </p>
65
+ <div className="category-list">
66
+ {categories.map(cat => (
67
+ <Pill key={cat.id} label={cat.name} isActive={ctx.categories.includes(cat.xml_id)} />
68
+ ))}
69
+ </div>
70
+ <div className="tag-list">
71
+ <span className="tag-list-label">Tags</span>
72
+ {Object.keys(tagCounts).map(tagName => (
73
+ <Pill key={tagName} label={tagName} isActive={ctx.tags.includes(tagCounts[tagName].id)}>
74
+ <span className="tag-count">{tagCounts[tagName].count}</span>
75
+ </Pill>
76
+ ))}
77
+ </div>
78
+ </div>
79
+ )
80
+ }
81
+
82
+ export default Record
@@ -0,0 +1,109 @@
1
+ import { useContext, useMemo } from 'react'
2
+ import FilterContext from '../context/FilterContext'
3
+ import { getObjs } from '../lib/sql'
4
+ import Record from './Record'
5
+
6
+ function cleanUpTagIds(obj) {
7
+ return {
8
+ ...obj,
9
+ tagging_ids: obj.tagging_ids.split(','),
10
+ }
11
+ }
12
+
13
+ function getData(db) {
14
+ const elementsStmt = db.prepare(`
15
+ SELECT
16
+ elements.id AS id,
17
+ elements.name AS element_name,
18
+ elements.type AS element_type,
19
+ elements.parent_id AS parent_id,
20
+ surfaces.name AS surface_name,
21
+ surfaces.xml_id AS surface_xml_id,
22
+ layers.xml_id AS layer_xml_id,
23
+ GROUP_CONCAT(tags.xml_id) as tagging_ids
24
+ FROM
25
+ taggings
26
+ INNER JOIN elements
27
+ ON elements.id = taggings.element_id
28
+ INNER JOIN tags
29
+ ON tags.id = taggings.tag_id
30
+ INNER JOIN surfaces
31
+ ON surfaces.id = elements.surface_id
32
+ INNER JOIN layers
33
+ ON layers.id = elements.layer_id
34
+ GROUP BY elements.id`)
35
+
36
+ const tagsStmt = db.prepare('SELECT * from tags')
37
+
38
+ return {
39
+ elements: getObjs(elementsStmt).map(cleanUpTagIds),
40
+ tags: getObjs(tagsStmt),
41
+ }
42
+ }
43
+
44
+ function isFilterMatch(ctx, divData) {
45
+ const categoryMatch = (ctx.categories.length === 0
46
+ || divData.element.tagging_ids.some(id => ctx.categories.includes(id)))
47
+
48
+ const tagMatch = (ctx.tags.length === 0
49
+ || divData.childTags.some(id => ctx.tags.includes(id)))
50
+
51
+ return categoryMatch && tagMatch
52
+ }
53
+
54
+ function RecordListView(props) {
55
+ const ctx = useContext(FilterContext)
56
+
57
+ const { elements, tags } = useMemo(() => getData(props.db), [props.db])
58
+
59
+ const divs = useMemo(() => {
60
+ const arr = []
61
+
62
+ for (const element of elements) {
63
+ if (element.element_type !== 'div') {
64
+ continue
65
+ }
66
+
67
+ const children = elements.filter(childEl => childEl.parent_id === element.id)
68
+ const childTags = children.flatMap(childEl => childEl.tagging_ids)
69
+
70
+ arr.push({
71
+ element,
72
+ children,
73
+ childTags,
74
+ })
75
+ }
76
+
77
+ return arr
78
+ }, [elements])
79
+
80
+ return (
81
+ <div className="record-list-view">
82
+ <h1 className="entries-header">
83
+ {props.recordLabel || 'Records'}
84
+ {' '}
85
+ (
86
+ {divs.length}
87
+ )
88
+ </h1>
89
+ {divs.map((divData) => {
90
+ if (isFilterMatch(ctx, divData)) {
91
+ return (
92
+ <Record
93
+ childElements={elements.filter(el => el.parent_id === divData.element.id)}
94
+ div={divData.element}
95
+ key={divData.element.id}
96
+ tags={tags}
97
+ viewerUrl={props.viewerUrl}
98
+ />
99
+ )
100
+ }
101
+
102
+ return null
103
+ },
104
+ )}
105
+ </div>
106
+ )
107
+ }
108
+
109
+ export default RecordListView
@@ -0,0 +1,83 @@
1
+ import { useMemo } from 'react'
2
+ import { getObjs } from '../lib/sql'
3
+ import CollapsibleMenu from './CollapsibleMenu'
4
+ import SidebarTagList from './SidebarTagList'
5
+
6
+ function getData(db) {
7
+ const tagsStmt = db.prepare(`
8
+ SELECT
9
+ tags.id AS id,
10
+ tags.name AS name,
11
+ tags.xml_id AS xml_id
12
+ FROM
13
+ tags
14
+ INNER JOIN taggings
15
+ ON taggings.tag_id = tags.id
16
+ INNER JOIN elements
17
+ ON elements.id = taggings.element_id
18
+ WHERE
19
+ elements.type = 'seg'
20
+ GROUP BY
21
+ tags.xml_id`)
22
+
23
+ const tags = getObjs(tagsStmt)
24
+
25
+ const categoriesStmt = db.prepare(`
26
+ SELECT
27
+ tags.id AS id,
28
+ tags.name AS name,
29
+ tags.xml_id AS xml_id
30
+ FROM
31
+ tags
32
+ INNER JOIN taggings
33
+ ON taggings.tag_id = tags.id
34
+ INNER JOIN elements
35
+ ON elements.id = taggings.element_id
36
+ WHERE
37
+ elements.type = 'div'
38
+ GROUP BY
39
+ tags.xml_id`)
40
+
41
+ const categories = getObjs(categoriesStmt)
42
+
43
+ const taggingsStmt = db.prepare('SELECT * FROM taggings')
44
+ const taggings = getObjs(taggingsStmt)
45
+
46
+ const labeledTags = tags.map((tag) => {
47
+ if (tag.parent_id) {
48
+ const parent = tags.find(pt => pt.id === tag.parent_id)
49
+ return {
50
+ ...tag,
51
+ name: `${parent.name} - ${tag.name}`,
52
+ }
53
+ }
54
+
55
+ return tag
56
+ })
57
+
58
+ return {
59
+ tags: labeledTags,
60
+ categories,
61
+ taggings,
62
+ }
63
+ }
64
+
65
+ function RecordListSidebar(props) {
66
+ const data = useMemo(() => getData(props.db), [props.db])
67
+
68
+ return (
69
+ <div className="ec-sidebar">
70
+ <h2>Filters</h2>
71
+ <div className="h-separator" />
72
+ <CollapsibleMenu title="Categories">
73
+ <SidebarTagList tags={data.categories} type="categories" />
74
+ </CollapsibleMenu>
75
+ <div className="h-separator" />
76
+ <CollapsibleMenu title="Tags">
77
+ <SidebarTagList tags={data.tags} type="tags" />
78
+ </CollapsibleMenu>
79
+ </div>
80
+ )
81
+ }
82
+
83
+ export default RecordListSidebar
@@ -0,0 +1,38 @@
1
+ import { useContext, useMemo } from 'react'
2
+ import { IoCheckmarkSharp } from 'react-icons/io5'
3
+ import FilterContext from '../context/FilterContext'
4
+ import Pill from './Pill'
5
+
6
+ function TagPill(props) {
7
+ const { categories, toggleCategoryFilter, tags, toggleTagFilter } = useContext(FilterContext)
8
+
9
+ const toggleFilter = props.type === 'categories'
10
+ ? toggleCategoryFilter
11
+ : toggleTagFilter
12
+
13
+ const isActive = useMemo(() => props.type === 'categories'
14
+ ? categories.includes(props.tag.xml_id)
15
+ : tags.includes(props.tag.xml_id), [props.type, props.tag.xml_id, categories, tags])
16
+
17
+ return (
18
+ <Pill
19
+ isActive={isActive}
20
+ onClick={() => toggleFilter(props.tag.xml_id)}
21
+ label={props.tag.name}
22
+ >
23
+ {isActive && <IoCheckmarkSharp />}
24
+ </Pill>
25
+ )
26
+ }
27
+
28
+ function SidebarTagList(props) {
29
+ return (
30
+ <div className="sidebar-tag-list">
31
+ {props.tags.map(tag => (
32
+ <TagPill key={tag.id} type={props.type} tag={tag} />
33
+ ))}
34
+ </div>
35
+ )
36
+ }
37
+
38
+ export default SidebarTagList
@@ -0,0 +1,8 @@
1
+ import { createContext } from 'react'
2
+
3
+ const FilterContext = createContext({
4
+ categories: [],
5
+ tags: [],
6
+ })
7
+
8
+ export default FilterContext
@@ -0,0 +1,92 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import initSqlJs from 'sql.js'
3
+ import Loading from './component/Loading'
4
+ import RecordListView from './component/RecordListView'
5
+ import Sidebar from './component/Sidebar'
6
+
7
+ import FilterContext from './context/FilterContext'
8
+
9
+ import './styles/base.css'
10
+ import './styles/record.css'
11
+ import './styles/sidebar.css'
12
+
13
+ const initialFilters = {
14
+ categories: [],
15
+ tags: [],
16
+ }
17
+
18
+ async function initDb(url) {
19
+ const file = await fetch(url)
20
+
21
+ if (!file.ok) {
22
+ throw new Error('Failed fetching SQLite file.')
23
+ }
24
+
25
+ const buf = await file.arrayBuffer()
26
+ const arr = new Uint8Array(buf)
27
+
28
+ const SQL = await initSqlJs({
29
+ locateFile: file => `https://sql.js.org/dist/${file}`,
30
+ })
31
+
32
+ const db = new SQL.Database(arr)
33
+
34
+ return db
35
+ }
36
+
37
+ function RecordList(props) {
38
+ const [db, setDb] = useState(null)
39
+ const [filters, setFilters] = useState(initialFilters)
40
+
41
+ const toggleCategoryFilter = useCallback(id => setFilters({
42
+ ...filters,
43
+ categories: filters.categories.includes(id)
44
+ ? filters.categories.filter(existing => existing !== id)
45
+ : [...filters.categories, id],
46
+ }), [filters])
47
+
48
+ const toggleTagFilter = useCallback(id => setFilters({
49
+ ...filters,
50
+ tags: filters.tags.includes(id)
51
+ ? filters.tags.filter(existing => existing !== id)
52
+ : [...filters.tags, id],
53
+ }), [filters])
54
+
55
+ const initialContext = useMemo(() => ({
56
+ ...filters,
57
+ toggleCategoryFilter,
58
+ toggleTagFilter,
59
+ }), [filters, toggleCategoryFilter, toggleTagFilter])
60
+
61
+ useEffect(() => {
62
+ const loadDb = async () => {
63
+ const db = await initDb(props.dbUrl)
64
+ setDb(db)
65
+ }
66
+
67
+ if (!db) {
68
+ loadDb()
69
+ }
70
+
71
+ return () => {
72
+ if (db) {
73
+ db.close()
74
+ }
75
+ }
76
+ }, [props.dbUrl, db])
77
+
78
+ if (!db) {
79
+ return <Loading />
80
+ }
81
+
82
+ return (
83
+ <FilterContext.Provider value={initialContext}>
84
+ <div className="editioncrafter-record-list">
85
+ <Sidebar db={db} />
86
+ <RecordListView db={db} recordLabel={props.recordLabel} viewerUrl={props.viewerUrl} />
87
+ </div>
88
+ </FilterContext.Provider>
89
+ )
90
+ }
91
+
92
+ export default RecordList
@@ -0,0 +1,9 @@
1
+ export function getObjs(statement) {
2
+ const records = []
3
+
4
+ while (statement.step()) {
5
+ records.push(statement.getAsObject())
6
+ }
7
+
8
+ return records
9
+ }
@@ -0,0 +1,78 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
2
+
3
+ .editioncrafter-record-list {
4
+ width: 100%;
5
+ height: 100%;
6
+ display: flex;
7
+ gap: 20px;
8
+ font-family: 'Inter', sans-serif;
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+
13
+ .editioncrafter-record-list h1, h2, h3, h4, p {
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ .editioncrafter-record-list h1 {
19
+ font-size: 32px;
20
+ font-style: normal;
21
+ font-weight: 600;
22
+ }
23
+
24
+ .editioncrafter-record-list h2 {
25
+ font-size: 24px;
26
+ font-style: normal;
27
+ font-weight: 600;
28
+ }
29
+
30
+ .editioncrafter-record-list div.h-separator {
31
+ border-top: 1px solid #E1E3E6;
32
+ width: 100%;
33
+ }
34
+
35
+ .editioncrafter-record-list * {
36
+ box-sizing: border-box;
37
+ }
38
+
39
+ .editioncrafter-record-list a {
40
+ color: #07529A;
41
+ font-family: Inter;
42
+ font-size: 18px;
43
+ font-style: normal;
44
+ font-weight: 700;
45
+ text-decoration: none;
46
+ }
47
+
48
+ .editioncrafter-record-list button:hover {
49
+ cursor: pointer;
50
+ }
51
+
52
+ .editioncrafter-record-list .loading {
53
+ height: 100%;
54
+ width: 100%;
55
+ display: flex;
56
+ flex-flow: column;
57
+ align-items: center;
58
+ justify-content: center;
59
+ gap: 20px;
60
+ background-color: #ffffff;
61
+ }
62
+
63
+ .editioncrafter-record-list .pill {
64
+ appearance: none;
65
+ display: flex;
66
+ height: 32px;
67
+ padding: 4px 12px;
68
+ justify-content: center;
69
+ align-items: center;
70
+ gap: 4px;
71
+ border-radius: 50px;
72
+ border: 1px solid #CEDAE7;
73
+ background: #CEDAE7;
74
+ color: #0A0A0A;
75
+ font-family: Inter;
76
+ font-size: 14px;
77
+ font-weight: 500;
78
+ }
@@ -0,0 +1,84 @@
1
+ .editioncrafter-record-list .record-list-view {
2
+ flex-grow: 1;
3
+ display: flex;
4
+ flex-flow: column;
5
+ gap: 16px;
6
+ }
7
+
8
+ .editioncrafter-record-list .record-list-view .entries-header {
9
+ padding: 10px 0;
10
+ }
11
+
12
+ .editioncrafter-record-list .record-list-view .record-box {
13
+ width: 100%;
14
+ border-radius: 5px;
15
+ border: 1px solid #E1E3E6;
16
+ display: flex;
17
+ flex-flow: column;
18
+ gap: 8px;
19
+ padding: 16px;
20
+ transition: 0.3s;
21
+ }
22
+
23
+ .editioncrafter-record-list .record-list-view .record-box:hover {
24
+ box-shadow: 1px 1px 6px 0px rgba(0, 0, 0, 0.25);
25
+ }
26
+
27
+ .editioncrafter-record-list .record-list-view .record-box .category-list {
28
+ display: flex;
29
+ gap: 6px;
30
+ }
31
+
32
+ .editioncrafter-record-list .record-list-view .record-box .tag-list {
33
+ display: flex;
34
+ flex-wrap: wrap;
35
+ gap: 8px;
36
+ align-items: center;
37
+ font-size: 14px;
38
+ font-weight: 500;
39
+ }
40
+
41
+ .editioncrafter-record-list .record-list-view .record-box .tag-list .tag-list-label {
42
+ font-weight: 600;
43
+ }
44
+
45
+ .editioncrafter-record-list .record-list-view .record-box .tag-list .pill {
46
+ background: #ffffff;
47
+ display: flex;
48
+ height: 32px;
49
+ padding: 4px 12px 4px 4px;
50
+ justify-content: center;
51
+ align-items: center;
52
+ gap: 8px;
53
+ border-radius: 50px;
54
+ border: 1px solid #E1E3E6;
55
+ }
56
+
57
+ .editioncrafter-record-list .record-list-view .record-box .category-list .pill.active {
58
+ background: #07529A;
59
+ color: #ffffff
60
+ }
61
+
62
+ .editioncrafter-record-list .record-list-view .record-box .tag-list .pill .tag-count {
63
+ display: inline-flex;
64
+ height: 24px;
65
+ min-width: 24px;
66
+ padding: 4px;
67
+ flex-direction: column;
68
+ justify-content: center;
69
+ align-items: center;
70
+ gap: 10px;
71
+ flex-shrink: 0;
72
+ border-radius: 50px;
73
+ background: #B5C8DC99;
74
+ }
75
+
76
+ .editioncrafter-record-list .record-list-view .record-box .tag-list .pill.active {
77
+ border: 1px solid #07529A;
78
+ color: #07529A;
79
+ }
80
+
81
+ .editioncrafter-record-list .record-list-view .record-box .tag-list .pill.active .tag-count {
82
+ background: #07529A;
83
+ color: #ffffff;
84
+ }
@@ -0,0 +1,39 @@
1
+ .editioncrafter-record-list .ec-sidebar {
2
+ background-color: #F3F4F7;
3
+ padding: 32px 24px;
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: 20px;
7
+ width: 380px;
8
+ flex-grow: 0;
9
+ }
10
+
11
+ .editioncrafter-record-list .collapsible-menu .collapsible-menu-toggle {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: space-between;
15
+ appearance: none;
16
+ background: none;
17
+ border: none;
18
+ width: 100%;
19
+ }
20
+
21
+ .editioncrafter-record-list .collapsible-menu .collapsible-menu-title {
22
+ font-size: 16px;
23
+ font-weight: 700;
24
+ }
25
+
26
+ .editioncrafter-record-list .sidebar-tag-list {
27
+ display: flex;
28
+ flex-wrap: wrap;
29
+ gap: 6px;
30
+ }
31
+
32
+ .editioncrafter-record-list .sidebar-tag-list .pill.active {
33
+ background: #07529A;
34
+ color: #ffffff;
35
+ }
36
+
37
+ .editioncrafter-record-list .sidebar-tag-list .hidden {
38
+ visibility: hidden;
39
+ }
@@ -1,8 +1,9 @@
1
1
  import { createTheme, ThemeProvider } from '@material-ui/core/styles'
2
2
  import React from 'react'
3
- import DiploMatic from './component/DiploMatic'
4
- import { createReduxStore } from './model/ReduxStore'
5
- import './scss/editioncrafter.scss'
3
+ import DiploMatic from './EditionCrafter/component/DiploMatic'
4
+ import { createReduxStore } from './EditionCrafter/model/ReduxStore'
5
+ import _RecordList from './RecordList'
6
+ import './EditionCrafter/scss/editioncrafter.scss'
6
7
 
7
8
  /**
8
9
  * Default instantiation
@@ -26,4 +27,6 @@ function EditionCrafter(props) {
26
27
  )
27
28
  }
28
29
 
30
+ export { _RecordList as RecordList }
31
+
29
32
  export default EditionCrafter