@macrostrat/map-interface 1.4.0 → 1.4.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 (43) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/esm/index.d.ts +0 -9
  5. package/dist/esm/index.d.ts.map +1 -1
  6. package/dist/esm/index.js +1 -0
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/node/index.js +1 -1
  9. package/dist/node/index.js.map +1 -1
  10. package/dist/node/{map-interface.7295b0a2.js → map-interface.7aaa58c9.js} +2 -2
  11. package/dist/node/map-interface.7aaa58c9.js.map +1 -0
  12. package/dist/node/{map-interface.f3e12e03.js → map-interface.7e13bea8.js} +2 -2
  13. package/dist/node/{map-interface.f3e12e03.js.map → map-interface.7e13bea8.js.map} +1 -1
  14. package/dist/node/{map-interface.0dc4417b.js → map-interface.ce86a010.js} +2 -2
  15. package/dist/node/{map-interface.0dc4417b.js.map → map-interface.ce86a010.js.map} +1 -1
  16. package/package.json +2 -2
  17. package/src/index.ts +1 -0
  18. package/src/map-panel/components/buttons.module.styl +5 -0
  19. package/src/map-panel/components/buttons.ts +56 -0
  20. package/src/map-panel/components/card.module.styl +43 -0
  21. package/src/map-panel/components/closeable-card.ts +64 -0
  22. package/src/map-panel/components/docs.module.styl +93 -0
  23. package/src/map-panel/components/docs.ts +92 -0
  24. package/src/map-panel/components/info-blocks.module.styl +39 -0
  25. package/src/map-panel/components/info-blocks.ts +88 -0
  26. package/src/map-panel/components/info-drawer/fossil-collections/collections.tsx +156 -0
  27. package/src/map-panel/components/info-drawer/fossil-collections/index.ts +21 -0
  28. package/src/map-panel/components/info-drawer/fossil-collections/main.module.sass +16 -0
  29. package/src/map-panel/components/info-drawer/index.ts +117 -0
  30. package/src/map-panel/components/info-drawer/macrostrat-linked.ts +399 -0
  31. package/src/map-panel/components/info-drawer/main.module.styl +67 -0
  32. package/src/map-panel/components/info-drawer/physiography.ts +29 -0
  33. package/src/map-panel/components/info-drawer/reg-strat.ts +74 -0
  34. package/src/map-panel/components/info-drawer/xdd-panel/Article.tsx +69 -0
  35. package/src/map-panel/components/info-drawer/xdd-panel/Journal.tsx +48 -0
  36. package/src/map-panel/components/info-drawer/xdd-panel/index.ts +69 -0
  37. package/src/map-panel/components/transitions/index.ts +24 -0
  38. package/src/map-panel/components/transitions/main.module.styl +55 -0
  39. package/src/map-panel/index.ts +1 -0
  40. package/src/map-panel/utils/formatting.ts +14 -0
  41. package/src/map-panel/utils/fossils.ts +209 -0
  42. package/src/map-panel/utils/index.ts +157 -0
  43. package/dist/node/map-interface.7295b0a2.js.map +0 -1
@@ -0,0 +1,399 @@
1
+ import hyper from "@macrostrat/hyper";
2
+ import { AgeChip, AttrChip } from "../info-blocks";
3
+ import {
4
+ ExpansionPanel,
5
+ ExpandableDetailsPanel,
6
+ ExpansionBody,
7
+ } from "@macrostrat/map-interface";
8
+ import styles from "./main.module.styl";
9
+ import { scaleLinear } from "@visx/scale";
10
+ import { AxisBottom } from "@visx/axis";
11
+ import chroma from "chroma-js";
12
+ import { LithologyList } from "@macrostrat/data-components";
13
+
14
+ const h = hyper.styled(styles);
15
+
16
+ function MacrostratLinkedData(props) {
17
+ const { mapInfo, bedrockMatchExpanded, source } = props;
18
+
19
+ if (!mapInfo.mapData[0]) return h("div");
20
+
21
+ return h(
22
+ ExpansionPanel,
23
+ {
24
+ className: "regional-panel",
25
+ title: "Macrostrat-linked data",
26
+ helpText: "via Macrostrat",
27
+ expanded: bedrockMatchExpanded,
28
+ },
29
+ [
30
+ h("div", { classes: expansionPanelDetailClasses }, [
31
+ h(MatchBasis, { source }),
32
+ h(AgeInformation, { mapInfo, source }),
33
+ h(Thickness, { source }),
34
+ h(MinorFossilCollections, { source }),
35
+ h(FossilOccs, { source }),
36
+ h(LithsAndClasses, { source }),
37
+ h(Environments, { source }),
38
+ h(Economy, { source }),
39
+ ]),
40
+ ],
41
+ );
42
+ }
43
+
44
+ const expansionPanelDetailClasses = {
45
+ root: "expansion-panel-detail",
46
+ };
47
+
48
+ function AgeInformation(props) {
49
+ const { source, mapInfo } = props;
50
+ const { macrostrat } = source;
51
+
52
+ if (!macrostrat?.b_age) return h(MapAgeRenderer, { mapInfo });
53
+
54
+ return h(MacrostratAgeInfo, { macrostrat, mapInfo });
55
+ }
56
+
57
+ function MapAgeRenderer(props) {
58
+ const { mapInfo, ...rest } = props;
59
+ return h(
60
+ DescribedAgeInfo,
61
+ {
62
+ ageElement: h(AgeChip, {
63
+ b_int: mapInfo.mapData[0].b_int,
64
+ t_int: mapInfo.mapData[0].t_int,
65
+ }),
66
+ },
67
+ "Based on geologic map description.",
68
+ );
69
+ }
70
+
71
+ function DescribedAgeInfo(props) {
72
+ const { ageElement, children, className } = props;
73
+
74
+ return h("div.described-age.macrostrast-detail", [
75
+ h("div.expansion-summary-title", "Age"),
76
+ h("div.age-chips", null, ageElement),
77
+ h("div.description", children),
78
+ ]);
79
+ }
80
+
81
+ function AgeRefinementBar({ scale, data, color, label = null }) {
82
+ const { b_int, t_int } = data;
83
+ const b_age = data.b_age ?? b_int.b_age;
84
+ const t_age = data.t_age ?? t_int.t_age;
85
+ const backgroundColor = color ?? b_int.color;
86
+ const accentColor = chroma(backgroundColor).darken(0.5).hex();
87
+ const labelColor = chroma(backgroundColor).darken(2).hex();
88
+
89
+ const left = scale(b_age);
90
+ const width = scale(t_age) - scale(b_age);
91
+
92
+ let labelTranslate = 5;
93
+ let textAlign = "start";
94
+
95
+ // Adjust label placement
96
+
97
+ if (width < 100) {
98
+ if (left < 100) {
99
+ labelTranslate = width + 5;
100
+ } else {
101
+ labelTranslate = -305;
102
+ textAlign = "end";
103
+ }
104
+ }
105
+
106
+ return h(
107
+ "div.age-refinement-bar",
108
+ {
109
+ style: {
110
+ marginLeft: `${left}px`,
111
+ width: `${width}px`,
112
+ height: "18px",
113
+ backgroundColor,
114
+ border: `2px solid ${accentColor}`,
115
+ position: "relative",
116
+ },
117
+ },
118
+ h(
119
+ "div.age-refinement-bar-label",
120
+ {
121
+ style: {
122
+ transform: `translateX(${labelTranslate}px)`,
123
+ color: labelColor,
124
+ fontSize: "10px",
125
+ width: 300,
126
+ textAlign,
127
+ },
128
+ },
129
+ label,
130
+ ),
131
+ );
132
+ }
133
+
134
+ function AgeRefinementPlot({ macrostrat, mapInfo }) {
135
+ // Plot the amount by which the age was refined
136
+
137
+ const mapData = mapInfo.mapData[0];
138
+ const b_age = Math.max(mapData.b_int.b_age, macrostrat.b_age);
139
+ const t_age = Math.min(mapData.t_int.t_age, macrostrat.t_age);
140
+
141
+ const scale = scaleLinear({
142
+ domain: [1.02 * b_age, t_age * 0.98],
143
+ range: [20, 360],
144
+ });
145
+
146
+ // use visx to plot the age refinement
147
+ return h("div.age-refinement-plot", [
148
+ h(AgeRefinementBar, {
149
+ scale,
150
+ data: macrostrat,
151
+ label: "Macrostrat age model",
152
+ }),
153
+ h(AgeRefinementBar, {
154
+ scale,
155
+ data: mapData,
156
+ label: "Map legend",
157
+ }),
158
+ // Age axis
159
+ h("svg", { width: "100%", height: "40px" }, [
160
+ h(AxisBottom, {
161
+ scale,
162
+ numTicks: 5,
163
+ top: 1,
164
+ left: 0,
165
+ label: "Age (Ma)",
166
+ }),
167
+ ]),
168
+ ]);
169
+ }
170
+
171
+ function MacrostratAgeInfoCore({ macrostrat }) {
172
+ const { b_age, t_age, b_int, t_int } = macrostrat;
173
+
174
+ if (!b_age) return null;
175
+
176
+ let age = b_int.int_name;
177
+ if (b_int.int_id !== t_int.int_id) {
178
+ age += ` - ${t_int.int_name}`;
179
+ }
180
+ return h(
181
+ DescribedAgeInfo,
182
+ {
183
+ ageElement: h(AgeChip, {
184
+ b_int: { ...b_int, int_name: age, b_age, t_age },
185
+ t_int: { ...b_int, int_name: age, b_age, t_age },
186
+ }),
187
+ },
188
+ "Refined using the Macrostrat age model.",
189
+ );
190
+ }
191
+
192
+ function MacrostratAgeInfo(props) {
193
+ return h(
194
+ ExpandableDetailsPanel,
195
+ { headerElement: h(MacrostratAgeInfoCore, props) },
196
+ h(ExpansionBody, { title: "Age refinement" }, h(AgeRefinementPlot, props)),
197
+ );
198
+ }
199
+
200
+ function MatchBasis(props) {
201
+ const { source } = props;
202
+ if (!source.macrostrat?.strat_names) return null;
203
+
204
+ return h(
205
+ ExpandableDetailsPanel,
206
+ {
207
+ className: "macrostrat-unit",
208
+ headerElement: h([
209
+ h("h3", source.macrostrat.strat_names[0].rank_name),
210
+ h("div.description", "Matched stratigraphic unit"),
211
+ ]),
212
+ },
213
+ h(ExpansionBody, { title: "All matched names" }, [
214
+ source.macrostrat.strat_names.map((name, i) => {
215
+ let lastElement: boolean =
216
+ i == source.macrostrat.strat_names.length - 1;
217
+ return h("span", { key: i }, [
218
+ h(
219
+ "a.externalLink",
220
+ {
221
+ href: "/lex/strat-names/" + name.strat_name_id,
222
+ key: i,
223
+ },
224
+ [name.rank_name],
225
+ ),
226
+ h.if(!lastElement)([", "]),
227
+ ]);
228
+ }),
229
+ ]),
230
+ );
231
+ }
232
+
233
+ function Thickness(props) {
234
+ const { source } = props;
235
+ if (!source.macrostrat.max_thick) return h("div");
236
+
237
+ return h.if(source.macrostrat && source.macrostrat.max_thick)(
238
+ "div.macrostrat-detail",
239
+ [
240
+ h("div.expansion-summary-title", "Thickness"),
241
+ h("div", [
242
+ source.macrostrat.min_min_thick,
243
+ " - ",
244
+ source.macrostrat.max_thick,
245
+ "m",
246
+ ]),
247
+ ],
248
+ );
249
+ }
250
+
251
+ function MinorFossilCollections(props) {
252
+ const { source } = props;
253
+ const { macrostrat } = source;
254
+ if (!macrostrat.pbdb_collections) return h("div");
255
+
256
+ return h.if(macrostrat && macrostrat.pbdb_collections)(
257
+ "div.macrostrat-detail",
258
+ [
259
+ h("div.expansion-summary-title", "Fossil collections"),
260
+ h("div", [macrostrat.pbdb_collections]),
261
+ ],
262
+ );
263
+ }
264
+
265
+ function FossilOccs(props) {
266
+ const { source } = props;
267
+ const { macrostrat } = source;
268
+
269
+ if (!macrostrat?.pbdb_occs) return null;
270
+
271
+ return h("div.macrostrat-detail", [
272
+ h("div.expansion-summary-title", "Fossil occurrences"),
273
+ h("div", [macrostrat.pbdb_occs]),
274
+ ]);
275
+ }
276
+
277
+ function LithTypes(props) {
278
+ const { lith_types } = props;
279
+
280
+ return h.if(lith_types && lith_types.length > 0)(
281
+ "div.lithologies.lithology-types",
282
+ [
283
+ h(LithologyList, {
284
+ lithologies: lith_types,
285
+ }),
286
+ ],
287
+ );
288
+ }
289
+
290
+ function LithsAndClasses(props) {
291
+ const { source } = props;
292
+ const { macrostrat } = source;
293
+ const { liths = null, lith_types = null } = macrostrat;
294
+
295
+ if (!liths || liths.length == 0) return null;
296
+
297
+ const lithologies = liths.map((lith) => {
298
+ return {
299
+ ...lith,
300
+ name: lith.lith,
301
+ color: lith.color || "#000000",
302
+ };
303
+ });
304
+
305
+ return h(
306
+ ExpandableDetailsPanel,
307
+ {
308
+ title: "Lithology",
309
+ value: h(LithTypes, { lith_types }),
310
+ },
311
+ h(ExpansionBody, { title: "Matched lithologies" }, [
312
+ h(LithologyList, {
313
+ lithologies,
314
+ onClickItem: (e, lith) => {
315
+ window.open("/lex/lithology/" + lith.lith_id, "_self");
316
+ },
317
+ }),
318
+ ]),
319
+ );
320
+ }
321
+
322
+ function EnvironTypes(props) {
323
+ const { environ_types } = props;
324
+ return h.if(environ_types && environ_types.length > 0)(LithologyList, {
325
+ lithologies: environ_types?.filter((e) => e.name != ""),
326
+ });
327
+ }
328
+
329
+ function Environments(props) {
330
+ const { source } = props;
331
+ const { macrostrat } = source;
332
+ const { environs = null, environ_types = null } = macrostrat;
333
+
334
+ if (!environs || environs.length == 0) return null;
335
+
336
+ const lithologies = environs.map((environ) => {
337
+ return {
338
+ ...environ,
339
+ name: environ.environ,
340
+ color: environ.color || "#000000",
341
+ };
342
+ });
343
+
344
+ return h(
345
+ ExpandableDetailsPanel,
346
+ {
347
+ title: "Environment",
348
+ value: h(EnvironTypes, { environ_types }),
349
+ },
350
+ h(ExpansionBody, { title: "Matched environments" }, [
351
+ h(LithologyList, {
352
+ lithologies,
353
+ onClickItem: (e, environ) => {
354
+ window.open("/lex/environments/" + environ.environ_id, "_self");
355
+ },
356
+ }),
357
+ ]),
358
+ );
359
+ }
360
+
361
+ function EconType(props) {
362
+ const { econ_types } = props;
363
+
364
+ return h.if(econ_types && econ_types.length > 0)("div", [
365
+ econ_types.map((econClass, i) => {
366
+ return h(AttrChip, {
367
+ key: i,
368
+ name: econClass.name,
369
+ color: econClass.color,
370
+ });
371
+ }),
372
+ ]);
373
+ }
374
+
375
+ function Economy(props) {
376
+ const { source } = props;
377
+ const { macrostrat } = source;
378
+ const { econs = null, econ_types = null } = macrostrat;
379
+ if (!econs) return h("div");
380
+
381
+ return h.if(econs && econs.length > 0)(
382
+ ExpandableDetailsPanel,
383
+ {
384
+ title: "Economy ",
385
+ value: h(EconType, { econ_types }),
386
+ },
387
+ h(ExpansionBody, { title: "Matched economic attributes" }, [
388
+ econs.map((econ, i) => {
389
+ return h(AttrChip, {
390
+ key: i,
391
+ name: econ.econ,
392
+ color: econ.color,
393
+ });
394
+ }),
395
+ ]),
396
+ );
397
+ }
398
+
399
+ export { MacrostratLinkedData };
@@ -0,0 +1,67 @@
1
+ .spacer
2
+ flex-grow 1
3
+ pointer-events none
4
+
5
+ .infodrawer-content
6
+ margin: 0;
7
+
8
+ .macrostrat-detail
9
+ display: flex;
10
+ align-items: center;
11
+ margin 0.2em 0 0.4em;
12
+
13
+ .expansion-summary-title
14
+ margin-right: 0.8em;
15
+
16
+ &:after
17
+ content: ":";
18
+
19
+ .described-age, .macrostrat-detail
20
+ display: flex;
21
+ align-items: center;
22
+
23
+ .expansion-summary-title
24
+ margin-right: 0.8em;
25
+
26
+ &:after
27
+ content: ":";
28
+
29
+ .description
30
+ font-style italic
31
+ font-size 0.7em
32
+ max-width: 100px
33
+ text-align: right
34
+
35
+ .age-chips
36
+ flex-grow 1
37
+
38
+
39
+ // &.loading
40
+ // max-height: 200px
41
+ // max-height: calc(100vh - 60px)
42
+ // transition: max-height 0.5s ease-in-out 0.25s
43
+
44
+
45
+ .spacer
46
+ flex-grow 1
47
+ pointer-events none
48
+
49
+ .macrostrat-unit
50
+ h3
51
+ margin: 0.5em 0 0.5em;
52
+ flex-grow: 1;
53
+
54
+ .description
55
+ margin-right: 1em
56
+
57
+ .description
58
+ font-style italic
59
+
60
+ .age-refinement-plot
61
+ position relative
62
+
63
+ .age-refinement-bar
64
+ border-radius: 3px
65
+ margin-bottom: 1px
66
+
67
+
@@ -0,0 +1,29 @@
1
+ import h from "@macrostrat/hyper";
2
+ import { ExpansionPanel } from "@macrostrat/map-interface";
3
+
4
+ function Physiography(props) {
5
+ const { mapInfo } = props;
6
+ const { regions } = mapInfo;
7
+
8
+ if (!mapInfo || !regions) return h("div");
9
+
10
+ return h.if(regions.length > 0)(
11
+ ExpansionPanel,
12
+ {
13
+ classes: { root: "regional-panel" },
14
+ title: "Physiography",
15
+ expanded: true,
16
+ },
17
+ [
18
+ regions.map((region, i) => {
19
+ return h("div.region", { key: i }, [
20
+ h("h3", [region.name]),
21
+ h("p.region-group", [region.boundary_group]),
22
+ h("p.region-description", [region.descrip]),
23
+ ]);
24
+ }),
25
+ ],
26
+ );
27
+ }
28
+
29
+ export { Physiography };
@@ -0,0 +1,74 @@
1
+ import h from "@macrostrat/hyper";
2
+ import { ExpansionPanel } from "@macrostrat/map-interface";
3
+ import { addCommas } from "../../utils";
4
+
5
+ export function RegionalStratigraphy(props) {
6
+ const { mapInfo, columnInfo } = props;
7
+ if (mapInfo?.mapData == null || !columnInfo) return null;
8
+
9
+ return h(
10
+ ExpansionPanel,
11
+ {
12
+ classes: { root: "regional-panel" },
13
+ title: "Regional stratigraphy",
14
+ expanded: true,
15
+ },
16
+ [h.if(columnInfo != null)(ColumnData, { columnInfo })],
17
+ );
18
+ }
19
+
20
+ function ColumnData({ columnInfo }) {
21
+ return h("div.column-data", [
22
+ h("a", { href: "/columns/" + columnInfo.col_id }, "View column page"),
23
+ h(MapAttribute, {
24
+ label: "Name: ",
25
+ content: [columnInfo.col_name],
26
+ }),
27
+ h(MapAttribute, {
28
+ label: "Column ID: ",
29
+ content: [columnInfo.col_id],
30
+ }),
31
+ h(MapAttribute, {
32
+ label: "Group: ",
33
+ content: [columnInfo.col_group],
34
+ }),
35
+ h(MapAttribute, {
36
+ label: "Group ID: ",
37
+ content: [columnInfo.col_group_id],
38
+ }),
39
+ h.if(columnInfo.min_min_thick || columnInfo.max_thick)(MapAttribute, {
40
+ label: "Thickness: ",
41
+ content: [
42
+ addCommas(parseInt(columnInfo.min_min_thick)),
43
+ " - ",
44
+ addCommas(parseInt(columnInfo.max_thick)),
45
+ h("span.age-ma", ["m"]),
46
+ ],
47
+ }),
48
+ h(MapAttribute, {
49
+ label: "Age: ",
50
+ content: [
51
+ columnInfo.b_age,
52
+ " - ",
53
+ columnInfo.t_age,
54
+ " ",
55
+ h("span.age-ma", ["Ma"]),
56
+ ],
57
+ }),
58
+ h(MapAttribute, {
59
+ label: "Area: ",
60
+ content: [addCommas(columnInfo.col_area), " ", h("span.age-ma", ["km2"])],
61
+ }),
62
+ h(MapAttribute, {
63
+ label: "Fossil collections: ",
64
+ content: [addCommas(columnInfo.pbdb_collections)],
65
+ }),
66
+ ]);
67
+ }
68
+
69
+ function MapAttribute(props) {
70
+ return h("div.map-source-attr", [
71
+ h("span.attr", [props.label]),
72
+ ...props.content,
73
+ ]);
74
+ }
@@ -0,0 +1,69 @@
1
+ import React, { useState } from "react";
2
+ import { Collapse, Button } from "@blueprintjs/core";
3
+ import { AuthorList } from "@macrostrat/ui-components";
4
+ import h from "@macrostrat/hyper";
5
+
6
+ function Article(props) {
7
+ const [expanded, setExpanded] = useState(false);
8
+ const { data } = props;
9
+
10
+ const toggleExpand = () => {
11
+ setExpanded(!expanded);
12
+ };
13
+
14
+ // Attempt to pull out only the year and not the whole date
15
+ let year;
16
+ try {
17
+ year = data.coverDate ? data.coverDate.match(/\d{4}/)[0] : "";
18
+ } catch (e) {
19
+ year = "";
20
+ }
21
+
22
+ const authors = data?.authors?.split("; ") ?? [];
23
+
24
+ const authorList =
25
+ authors.length > 0 ? h(AuthorList, { names: authors }) : "Unknown";
26
+
27
+ const iconName = expanded ? "chevron-up" : "chevron-down";
28
+
29
+ return (
30
+ <div className="article">
31
+ <div className="article-title">
32
+ <p className="article-author">
33
+ {authorList}, {year.length ? " " + year + ". " : ""}
34
+ </p>
35
+ <a href={data.URL} target="_blank" className="title-link">
36
+ <strong>{data.title}.</strong>
37
+ </a>
38
+
39
+ <span>
40
+ <Button
41
+ onClick={toggleExpand}
42
+ minimal={true}
43
+ rightIcon={iconName}
44
+ className="flat-btn"
45
+ ></Button>
46
+ </span>
47
+ </div>
48
+ <Collapse isOpen={expanded}>
49
+ <span className={expanded ? "" : "hidden"}>
50
+ <div className="quotes">
51
+ {data.highlight.map((snippet, si) => {
52
+ let text = snippet;
53
+
54
+ return (
55
+ <p
56
+ className="gdd-snippet"
57
+ key={si}
58
+ dangerouslySetInnerHTML={{ __html: `...${snippet}...` }}
59
+ ></p>
60
+ );
61
+ })}
62
+ </div>
63
+ </span>
64
+ </Collapse>
65
+ </div>
66
+ );
67
+ }
68
+
69
+ export default Article;
@@ -0,0 +1,48 @@
1
+ import Article from "./Article";
2
+ import { Divider } from "@blueprintjs/core";
3
+ import h from "@macrostrat/hyper";
4
+ import { SubExpansionPanel } from "@macrostrat/map-interface";
5
+ import { XDDSnippet } from "./index";
6
+
7
+ function Journal(props) {
8
+ return h("div.journal", [
9
+ h("div.journal-title", [
10
+ h("h2.journal-title-text", [
11
+ props.data.name,
12
+ h("small.journal-source", [props.data]),
13
+ ]),
14
+ ]),
15
+ h(Divider),
16
+ props.data.articles.map((article, i) => {
17
+ return h(Article, { key: i, data: article });
18
+ }),
19
+ ]);
20
+ }
21
+
22
+ type JournalProps = {
23
+ articles: XDDSnippet[];
24
+ name: string;
25
+ publisher: string;
26
+ };
27
+
28
+ // Still up for review
29
+ function Journal_(props: JournalProps) {
30
+ const { articles, name, publisher } = props;
31
+
32
+ const helpText = articles[0].pubname;
33
+
34
+ return h(
35
+ SubExpansionPanel,
36
+ {
37
+ title: name,
38
+ helpText: publisher,
39
+ },
40
+ [
41
+ articles.map((article, i) => {
42
+ return h(Article, { key: i, data: article });
43
+ }),
44
+ ],
45
+ );
46
+ }
47
+
48
+ export default Journal_;