diff --git a/packages/sift/src/js/components/StratName.tsx b/packages/sift/src/js/components/StratName.tsx
index 0169a0bb9..9c009c15c 100644
--- a/packages/sift/src/js/components/StratName.tsx
+++ b/packages/sift/src/js/components/StratName.tsx
@@ -363,6 +363,8 @@ class _StratName extends React.Component {
stratHierarchy =
diff --git a/pages/+Page.client.ts b/pages/+Page.client.ts
new file mode 100644
index 000000000..249d43cda
--- /dev/null
+++ b/pages/+Page.client.ts
@@ -0,0 +1,128 @@
+import { Image, Navbar, Footer, useMacrostratAPI } from "./index";
+import h from "./main.module.sass";
+import { PanelCard } from "@macrostrat/map-interface";
+import { LinkCard } from "~/components/cards";
+import { useState } from 'react';
+import { SETTINGS } from "@macrostrat-web/settings";
+import { Loading } from "./index"
+
+export function Page() {
+ const result = useMacrostratAPI('/stats?all')?.success.data;
+
+ if(!result) {
+ return h(Loading)
+ }
+
+ let columns = 0;
+ let units = 0;
+ let polygons = 0;
+
+ result.forEach(project => {
+ columns += project.columns;
+ units += project.units;
+ polygons += project.t_polys;
+ });
+
+ return h('div.total', [
+ h(Navbar),
+
+ h('div.start', [
+ h(Image, { className: "back-img cover-image", src: 'cover_large.jpg' }),
+ h('div.text', [
+ h('div.header', {}, [
+ h('h1.main-title','Macrostrat'),
+ h('h2.version','v2')
+ ]),
+ h('div.stats', {}, [
+ h('div.stat', {}, [
+ h('span.top-stat#n_columns', {}, formatNumber(columns)),
+ h('span.top-stat-label', {}, 'Regional Rock Columns')
+ ]),
+ h('div.stat', {}, [
+ h('span.top-stat#n_units', {}, formatNumber(units)),
+ h('span.top-stat-label', {}, 'Rock Units')
+ ]),
+ h('div.stat', {}, [
+ h('span.top-stat#n_polys', {}, formatNumber(polygons)),
+ h('span.top-stat-label', {}, 'Geologic Map Polygons')
+ ]),
+ h('div.stat', {}, [
+ h('span.top-stat#n_names', {}, formatNumber(result.length)),
+ h('span.top-stat-label', {}, 'Projects')
+ ])
+ ]),
+ h('p.big-text', {}, 'A platform for geological data exploration, integration, and analysis'),
+ ])
+ ]),
+ h('div.buttons', [
+ // h(LinkCard, { title: 'Search', href: '/sift/#/' }),
+ h(LinkCard, { title: "Geologic Map", href: '/map/#3/40.78/-94.13' }, [
+ h('p', { className: 'long'}, [
+ h('div.temp', {}, [
+ 'With over 225 maps from data providers around the world across every scale, Macrostrat is the world\'s largest homogenized geologic map database. Our data processing pipeline links geologic map polygons to Macrostrat column polygons, external stratigraphic name lexicons, and geochronological intervals, enabling the enhancement of the original map data and allowing for direct links into ',
+ h('a', { href: 'https://xdd.wisc.edu', target: '_blank' }, 'xDD'),
+ ' (formly GeoDeepDive).'
+ ]),
+ h('div.temp', {}, [
+ 'Are you affiliated with a state or national geologic survey? ',
+ h('a', { href: 'mailto:contact@macrostrat.org?Subject=Geologic%20Map%20Collaboration' }, 'Get in touch'),
+ ' with us - we\'d love to collaborate and help publicize your maps!'
+ ]),
+ h('div.temp', {}, [
+ 'Get started by ',
+ h('a', { href: '/map' }, 'exploring the map'),
+ ' or ',
+ h('a', { href: '/map/sources' }, 'taking a look at'),
+ ' which maps are currently a part of Macrostrat.'
+ ])
+ ]),
+ ]),
+ h(LinkCard, { title: 'Maps', href: '/maps'}, [
+ h('p', "The spatial footprint of rocks on the Earth\'s surface")
+ ]),
+ h(LinkCard, { title: 'Columns', href: '/columns'}, [
+ h('p', 'Stratigraphic and geological columns showing the organization of rocks in time')
+ ]),
+ h(LinkCard, { title: 'Geologic Lexicon', href: '/lex'}, [
+ h('p', 'Geologic units and data dictionaries')
+ ]),
+ h(LinkCard, { title: 'Projects', href: '/projects'}, [
+ h('p', 'Projects for specific regions or geological problems')
+ ]),
+ h(LinkCard, { title: h('div.rockd-button-container', [
+ h(Image, { className: "rockd-png", src: 'rockd.png', width: '22px' }),
+ h('p', 'Rockd')
+ ]), href: 'https://rockd.org'}, [
+ h('p', 'Go mobile!')
+ ]),
+ h.if(SETTINGS.isDev)(LinkCard, { title: 'Dev Apps', href: '/dev'},
+ h('p', 'Layers and testbed apps that aren\'t ready for prime time'),
+ ),
+ h.if(SETTINGS.isDev)(LinkCard, { title: 'Documentation', href: '/docs'},
+ h('p', "Macrostrat documentation")
+ ),
+ ]),
+ Donate,
+ h(Footer),
+ ])
+}
+
+const Donate =
+ h('div.donate-container', {}, [
+ h(Image, { className: "back-img donate-img", src: 'donate_medium.jpg' }),
+ h('div.text-donate', [
+ h('a', { href: 'https://secure.supportuw.org/give/?id=E0A03FA3-B2A0-431C-83EE-A121A04EEB5D', target: '_blank' }, [
+ h('h1.title.donate-title', 'Donate Now'),
+ ]),
+ h('div.donate-info', {}, [
+ 'Grant funding, principally from the ',
+ h('a', { href: 'http://www.nsf.gov', target: '_blank' }, 'U.S. National Science Foundation'),
+ ', got Macrostrat off the ground and keeps us innovating, but maintaining and growing a free and open digital resource involves ongoing expenses beyond the grant cycle, like annual certificate renewals, cloud server hosting and backup storage that keep your connection safe, domain name registrations that keep us located on the web, and system upgrades to keep us fast and efficient. If you would like to help us continue to grow and provide free resources, you can do so with a one-time or recurring gift to the UW Foundation Paleontology Program Fund in Geology. Thank you!'
+ ])
+ ])
+ ]);
+
+
+ function formatNumber(num) {
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ }
\ No newline at end of file
diff --git a/pages/+Page.mdx b/pages/+Page.mdx
deleted file mode 100644
index 80abf5273..000000000
--- a/pages/+Page.mdx
+++ /dev/null
@@ -1,40 +0,0 @@
-export { ContentPage as default } from "~/layouts";
-import { PageHeader } from "~/components";
-import { LinkCard } from "~/components/cards";
-
-
-
-
- Macrostrat's main map interface showing a harmonized view of the Earth's crust
-
-
-## Data products
-
-Macrostrat integrates a variety of geological data products into a community-accessibe, space-time model of the Earth's crust.
-These products come from a variety of sources throughout the geosciences.
-
-
- The spatial footprint of rocks on the Earth's surface
-
-
-
- Stratigraphic and geological columns showing the organization of rocks in time
-
-
-
- Geologic units and data dictionaries
-
-
-
- Projects for specific regions or geological problems
-
-
-### Development pages
-
-
- Layers and testbed apps that aren't ready for prime time
-
-
-
- Macrostrat documentation
-
diff --git a/pages/_error/+Page.ts b/pages/_error/+Page.ts
index 124d559d8..4f63da041 100644
--- a/pages/_error/+Page.ts
+++ b/pages/_error/+Page.ts
@@ -1,11 +1,16 @@
-import h from "@macrostrat/hyper";
+import h from "./main.module.styl";
import { CenteredContentPage } from "~/layouts";
import { PageHeader } from "~/components";
import { usePageContext } from "vike-react/usePageContext";
import { ClientOnly } from "vike-react/ClientOnly";
-import { Spinner, Button } from "@blueprintjs/core";
+import { Spinner, Button, Card } from "@blueprintjs/core";
+import { BlankImage } from "../index";
+import { LinkCard } from "~/components";
export function Page() {
+ const ctx = usePageContext();
+ const is404 = ctx.is404;
+
return h(CenteredContentPage, [h(PageHeader), h(PageContent)]);
}
@@ -17,9 +22,16 @@ function PageContent() {
const reason = ctx.abortReason;
if (is404) {
- return h([
- h("h1", [h("code.bp5-code", "404"), " Page Not Found"]),
- h("p", ["Could not find a page at path ", h("code.bp5-code", path), "."]),
+ return h('div.error404', [
+ h(BlankImage, { src: "https://storage.macrostrat.org/assets/web/earth-crust.jpg", className: "error-image", width: "100%", height: "100%" }),
+ h('div.error-text', [
+ h('h1', "404"),
+ h('h2', "The rock you are looking for doesn't exist. Keep digging."),
+ h('div.buttons', [
+ h('button', { className: "btn", onClick: () => history.back() }, "Go back"),
+ h('a', { className: "btn", href: "/" }, "Go home")
+ ]),
+ ])
]);
} else if (statusCode == 401) {
return h([
diff --git a/pages/_error/main.module.styl b/pages/_error/main.module.styl
new file mode 100644
index 000000000..1f2a9a1da
--- /dev/null
+++ b/pages/_error/main.module.styl
@@ -0,0 +1,47 @@
+.error404
+ background: black
+ height: 100vh
+ text-align: center
+ color: black
+
+ h1
+ margin-top 0
+ font-size 100px
+
+.error-text
+ position absolute
+ z-index 2
+ top 30%
+ left 50%
+ transform translate(-50%, -50%)
+ color white
+
+.error-image
+ position absolute
+ z-index 1
+ top 0
+ left 0
+ opacity .5
+
+.buttons
+ display flex
+ gap 100px
+ justify-content center
+ margin-top 50px
+
+ a
+ text-decoration none
+
+
+button:hover
+ background-color var(--secondary-background-color)
+ color: var(text-emphasized-color) !important
+
+.btn
+ background-color var(--background-color)
+ color: var(text-emphasized-color) !important
+ cursor: pointer
+ margin 14px 0
+
+a
+ color: var(--text-emphasized-color) !important
\ No newline at end of file
diff --git a/pages/about/+Page.client.ts b/pages/about/+Page.client.ts
new file mode 100644
index 000000000..fa3e2e47c
--- /dev/null
+++ b/pages/about/+Page.client.ts
@@ -0,0 +1,124 @@
+import { Image, Navbar, Footer } from "../index";
+import { Divider } from "@blueprintjs/core"
+import h from "./main.module.sass";
+
+export function Page() {
+ return h('div', [
+ h(Navbar),
+ h('div.body', [
+ h('h1.title-about', 'About Macrostrat'),
+ h(Divider, { className: 'divider', style: { margin: "0 0 0 20%" } }),
+ h('div.table', [
+ h('dv.table-row', [
+ h('p', 'Summary'),
+ h('p', 'Macrostrat is a web-based platform for the visualization and analysis of geologic data.'),
+ ]),
+ h('div.table-row', [
+ h('p', 'License'),
+ h('p', 'All data are provided under a Creative Commons Attribution 4.0 International license'),
+ ]),
+ h('div.table-row', [
+ h('p', 'Citation'),
+ h('p', 'In presentations: Acknowledge Macrostrat by name. You may also include any of the Macrostrat logos accessible on this webpage. In publications: Acknowledge Macrostrat as the source of any information or data. In publications, you may cite our most recent infrastructure paper, Peters et al. (2018). In addition, you should also include citations to the original references associated with the data set that was used. These references are accessible from the API. If you would like your paper listed in the official publications, please contact us and we will provide a citation and link.'),
+ ]),
+ h('div.table-row', [
+ h('p', 'Collaboration'),
+ h('p', 'Our small team has worked hard to compile, format, and make data available via Macrostrat. We strongly encourage and welcome active collaborations, both scientific and geoinformatic. All data are provided freely on under a CC-BY-4.0 license.'),
+ ]),
+ h('div.table-row', [
+ h('p', 'Funding'),
+ h('p', 'Major Macrostrat data infrastructure development was supported by the US National Science Foundation (EAR-1150082, ICER-1440312), with ongoing support for data acquisition supported by NSF EAR-1948843 and ICER-1928323. Continuous and ongoing support has also been provided by the UW-Madison Department of Geoscience. If you use Macrostrat and like what we do, please consider helping out with a donation. Every contribute helps us to maintain infrastructure and keep improving.')
+ ]),
+ ]),
+
+ h('div.api', [
+ h('div.api-circle', [
+ h('div.api-circle-text', 'API')
+ ]),
+ h('div#api-text', [
+ 'All data contained in the Macrostrat database are freely available via our Application Programming Interface (API), which provides a ',
+ 'convenient way to retrieve data for analysis or application creation. For more information head over to the ',
+ h('a', { href: '/api' }, 'API root'),
+ ' to explore available routes.'
+ ])
+ ]),
+
+ h('div.apps', [
+ h('h1.big-apps.app-header', 'Built with Macrostrat'),
+ h('div.items', [
+
+ h('a', { href: '/sift' }, [
+ h('div.app-box', [
+ h(Image, { src: 'logo_red.png' }),
+ h('div.app-background-text', [
+ 'Sift',
+ h('p.blurb', 'Explore Macrostrat (by Macrostrat)')
+ ])
+ ])
+ ]),
+
+ h('a', { href: 'https://rockd.org' }, [
+ h('div.app-box', [
+ h(Image, { src: 'rockd.jpg' }),
+ h('div.app-background-text', [
+ 'Rockd',
+ h('p.blurb', 'A mobile field book, Macrostrat style.')
+ ])
+ ])
+ ]),
+
+ h('a', { href: '/map' }, [
+ h('div.app-box', [
+ h(Image, { src: 'burwell.png' }),
+ h('div.app-background-text', [
+ 'Map',
+ h('p.blurb', "Integrating the world's geologic maps (by Macrostrat)")
+ ])
+ ])
+ ]),
+
+ h('a', {
+ href: 'https://itunes.apple.com/us/app/mancos/id541570878?mt=8',
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ }, [
+ h('div.app-box', [
+ h(Image, { src: 'mancos.jpg' }),
+ h('div.app-background-text', [
+ 'Mancos',
+ h('p.blurb', 'Explore Macrostrat and PBDB in iOS (by Hunt Mountain Software)')
+ ])
+ ])
+ ]),
+
+ h('a', {
+ href: 'http://fc.umn.edu/',
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ }, [
+ h('div.app-box', [
+ h(Image, { src: 'foc.png' }),
+ h('div.app-background-text', [
+ 'FOC',
+ h('p.blurb', 'A glass bottom jet (by Amy Myrbo, Shane Loeffler et al.)')
+ ])
+ ])
+ ]),
+
+ h('a', { href: 'https://github.com/UW-Macrostrat/node-api-template' }, [
+ h('div.app-box', [
+ h(Image, { src: 'api.png' }),
+ h('div.app-background-text.app-background-text-small', [
+ 'API Template',
+ h('p.blurb', 'Foundation of all Macrostrat services (by Macrostrat)')
+ ])
+ ])
+ ])
+
+ ])
+ ]),
+
+ h(Footer)
+ ])
+])
+}
\ No newline at end of file
diff --git a/pages/dev/test-site/about/main.styl b/pages/about/main.module.sass
similarity index 51%
rename from pages/dev/test-site/about/main.styl
rename to pages/about/main.module.sass
index f0d36dff2..390a7dc1a 100644
--- a/pages/dev/test-site/about/main.styl
+++ b/pages/about/main.module.sass
@@ -1,12 +1,10 @@
-.html, .body, #apps
- color: black
- background-color: white
+h1
+ margin: 0
-#body
- background-color: white
- padding: 0 20%
+.body
+ padding-top: 5vh
-#apps
+.apps
padding: 75px 0
a:hover
@@ -23,7 +21,12 @@ a:hover
width: 60%
margin: 0 20%
position: relative
- color: black
+ color: var(--text-color)
+
+ img
+ height: 80%
+ margin: auto
+ margin-left: 6%
.app-background-text
margin: auto
@@ -36,10 +39,7 @@ a:hover
.blurb
font-size: 15px
-.app-img
- height: 80%
- margin: auto
- margin-left: 6%
+
.big-apps
font-size: 72px
@@ -51,43 +51,44 @@ a:hover
color: white
-.big
+.title-about
font-size: 72px
- font-family: "Maven Pro", sans-serif;
- text-align: center
+ font-family: "Maven Pro", sans-serif
+ text-align: left
+ margin-left: 20%
+ padding: 0
-#api
- position: relative
- height: 30vh
- background-color: white
-#api-circle-text
- display: table-cell;
- vertical-align: middle;
- color: #6bbe98;
- font-size: 72px
- font-weight: 500
+.api
+ height: 200px
+ width: 60%
+ margin-left: 20%
.api-circle
float: left
- margin-left: 15%
margin-right: 50px
- background-color: #fff;
- height: 200px;
- width: 200px;
- border-radius: 50%;
- text-align: center;
- display: table;
- border: 11px solid #6bbe98;
- color: #4BABBf;
+ background-color: #fff
+ height: 200px
+ width: 200px
+ border-radius: 50%
+ text-align: center
+ display: table
+ border: 11px solid #6bbe98
+
+ .api-circle-text
+ display: table-cell
+ vertical-align: middle
+ color: #6bbe98 !important
+ font-size: 72px
+ font-weight: 500
#api-text
padding-top: 50px
margin-right: 15%
- color: #4bab7f;
- font-size: 20px;
- line-height: 28px;
- font-weight: 400;
+ color: #4bab7f
+ font-size: 20px
+ line-height: 28px
+ font-weight: 400
#about
@@ -95,14 +96,14 @@ a:hover
.about-row
margin: 4%
- font-size: 18px;
- line-height: 28px;
- font-weight: 200;
+ font-size: 18px
+ line-height: 28px
+ font-weight: 200
.about-body-subtitle
float: left
- font-size: 22px;
- font-weight: 200;
+ font-size: 22px
+ font-weight: 200
.about-body
margin-left: 30%
@@ -113,12 +114,17 @@ a:hover
position: relative
padding-bottom: 0
-.line
- width: 100%;
- border-bottom: 1px solid #E0E1E6;
- position: absolute;
+.divider
+ width: 60%
+ background-color: black
.rock-border
width: 100%
margin: 0
padding: 0
+
+.table
+ margin: 30px 20%
+ .table-row
+ display: grid
+ grid-template-columns: 40% 60%
diff --git a/pages/colors.scss b/pages/colors.scss
new file mode 100644
index 000000000..9f569153b
--- /dev/null
+++ b/pages/colors.scss
@@ -0,0 +1,12 @@
+@use "sass:color";
+@use "@blueprintjs/colors/lib/scss/colors" as *;
+
+$colors: (
+ img-color: invert(0),
+ anti-img-color: invert(1),
+);
+
+$dark-colors: (
+ img-color: invert(1),
+ anti-img-color: invert(0),
+);
\ No newline at end of file
diff --git a/pages/columns/+Page.client.ts b/pages/columns/+Page.client.ts
new file mode 100644
index 000000000..54b52ded3
--- /dev/null
+++ b/pages/columns/+Page.client.ts
@@ -0,0 +1,143 @@
+import { ContentPage } from "~/layouts";
+import { PageHeader, Link, AssistantLinks, DevLinkButton } from "~/components";
+import { Divider, AnchorButton, Card, Icon } from "@blueprintjs/core";
+import { useData } from "vike-react/useData";
+import { useState } from "react";
+import h from "./main.module.scss";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { Loading, ColumnsMap } from "../index";
+
+export function Page(props) {
+ return h(ColumnListPage, props);
+}
+
+function ColumnListPage({ title = "Columns", linkPrefix = "/" }) {
+ let columnGroups;
+ const columnRes = useAPIResult(SETTINGS.apiV2Prefix + "/columns?all")?.success?.data;
+ const [columnInput, setColumnInput] = useState("");
+ const shouldFilter = columnInput.length >= 3;
+
+ if(columnRes) {
+ const grouped = {};
+
+ for (const item of columnRes) {
+ const key = item.col_group_id;
+
+ if (!grouped[key]) {
+ grouped[key] = {
+ name: item.col_group,
+ id: item.col_group_id,
+ columns: []
+ };
+ }
+
+ grouped[key].columns.push(item);
+ }
+
+ columnGroups = Object.values(grouped);
+ }
+
+ const filteredGroups = shouldFilter ? columnGroups?.filter((group) => {
+ const filteredColumns = group.columns.filter((col) => {
+ const name = col.col_name.toLowerCase();
+ const input = columnInput.toLowerCase();
+ return name.includes(input);
+ });
+
+ if (filteredColumns.length > 0 || group.name.toLowerCase().includes(columnInput.toLowerCase())) {
+ return { ...group, columns: filteredColumns };
+ }
+
+ return false;
+ }) : columnGroups;
+
+ const colArr = filteredGroups
+ ?.flatMap(item =>
+ item.columns
+ .filter(col => col.col_name.toLowerCase().includes(columnInput.toLowerCase()))
+ .map(col => col.col_id)
+ );
+
+ const cols = shouldFilter ? "col_id=" + colArr?.join(',') : "all=1";
+
+ const columnData = useAPIResult(SETTINGS.apiV2Prefix + "/columns?" + cols + "&response=long&format=geojson");
+
+ const handleInputChange = (event) => {
+ setColumnInput(event.target.value.toLowerCase());
+ };
+
+ if(!columnData || !columnRes) return h(Loading);
+
+ const columnFeatures = columnData?.success?.data;
+
+ return h("div.column-list-page", [
+ h(AssistantLinks, [
+ h(AnchorButton, { href: "/projects", minimal: true }, "Projects"),
+ h(DevLinkButton, { href: "/columns/correlation" }, "Correlation chart"),
+ ]),
+ h(ContentPage, [
+ h(PageHeader, { title }),
+ h.if(columnFeatures)(ColumnsMap, { columns: columnFeatures}),
+ h(Card, { className: "search-bar" }, [
+ h(Icon, { icon: "search" }),
+ h("input", {
+ type: "text",
+ placeholder: "Search columns...",
+ onChange: handleInputChange,
+ }),
+ ]),
+ h("div.column-groups",
+ filteredGroups.map((d) =>
+ h(ColumnGroup, { data: d, key: d.id, linkPrefix, columnInput, shouldFilter })
+ )
+ ),
+ ]),
+ ]);
+}
+
+function ColumnGroup({ data, linkPrefix, columnInput, shouldFilter }) {
+ const [isOpen, setIsOpen] = useState(false);
+ const filteredColumns = shouldFilter ? data.columns.filter((col) => {
+ const name = col.col_name.toLowerCase();
+ const input = columnInput.toLowerCase();
+ return name.includes(input);
+ }) : data.columns;
+
+ if (filteredColumns?.length === 0) return null;
+
+ const { name } = data;
+ return h('div', { className: 'column-group', onClick : () => setIsOpen(!isOpen) }, [
+ h('div.column-group-header', [
+ h("h2.column-group-name", name + " (Group #" + filteredColumns[0].col_group_id + ")"),
+ ]),
+ h(
+ "div.column-list", [
+ h(Divider),
+ h('div.column-table', [
+ h("div.column-row.column-header", [
+ h("span.col-id", "Id"),
+ h("span.col-name", "Name"),
+ ]),
+ h(Divider),
+ filteredColumns.map((data) =>
+ h(ColumnItem, { data, linkPrefix })
+ )
+ ]),
+ ])
+ ]);
+}
+
+function ColumnItem({ data, linkPrefix = "/" }) {
+ const { col_id, col_name, status } = data;
+ const href = linkPrefix + `columns/${col_id}`;
+ return h("div.column-row", [
+ h("span.col-id", "#" + col_id),
+ h(Link, { className: 'col-link', href }, [col_name]),
+ ]);
+}
+
+function UpperCase(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+
diff --git a/pages/columns/+Page.ts b/pages/columns/+Page.ts
deleted file mode 100644
index ce171f43a..000000000
--- a/pages/columns/+Page.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import h from "@macrostrat/hyper";
-import { ContentPage } from "~/layouts";
-import { PageHeader, Link, AssistantLinks, DevLinkButton } from "~/components";
-import { AnchorButton, Tag } from "@blueprintjs/core";
-import { useData } from "vike-react/useData";
-
-export function Page(props) {
- return h(ColumnListPage, props);
-}
-
-function ColumnListPage({ title = "Columns", linkPrefix = "/" }) {
- const { columnGroups } = useData();
- return h(ContentPage, [
- h(AssistantLinks, [
- h(AnchorButton, { href: "/projects", minimal: true }, "Projects"),
- h(DevLinkButton, { href: "/columns/correlation" }, "Correlation chart"),
- ]),
- h(PageHeader, { title }),
- columnGroups.map((d) => h(ColumnGroup, { data: d, key: d.id, linkPrefix })),
- ]);
-}
-
-function ColumnGroup({ data, linkPrefix }) {
- const { id, name, columns } = data;
- return h("div.column-group", [
- h("h2.column-group", name),
- h(
- "ul",
- columns.map((data) =>
- h(ColumnItem, { data, key: data.col_id, linkPrefix })
- )
- ),
- ]);
-}
-
-function ColumnItem({ data, linkPrefix = "/" }) {
- const { col_id, col_name } = data;
- const href = linkPrefix + `columns/${col_id}`;
- return h("li", [
- h("span.col-id", {}, col_id),
- " ",
- h(Link, { href }, [col_name]),
- h.if(data.status == "in process")([
- " ",
- h(Tag, { minimal: true }, "in process"),
- ]),
- h.if(data.status == "obsolete")([
- " ",
- h(Tag, { minimal: true, intent: "danger" }, "obsolete"),
- ]),
- h.if(data?.t_units == 0)([
- " ",
- h(Tag, { minimal: true, intent: "warning" }, "empty"),
- ]),
- ]);
-}
diff --git a/pages/columns/groups/+Page.ts b/pages/columns/groups/+Page.ts
new file mode 100644
index 000000000..33be07e59
--- /dev/null
+++ b/pages/columns/groups/+Page.ts
@@ -0,0 +1,56 @@
+import h from "./main.module.scss";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { LinkCard, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Divider } from "@blueprintjs/core";
+import { useState } from "react";
+import { ContentPage } from "~/layouts";
+
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/groups?all")?.success.data;
+
+ if (res == null) return h("div", "Loading...");
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ const filtered = res.filter((d) => {
+ const name = d.name.toLowerCase();
+ const col_group = d.col_group.toLowerCase();
+ return name.includes(input) || col_group.includes(input);
+ });
+
+ return h(ContentPage, { className: 'group-list-page'}, [
+ h(PageBreadcrumbs, { title: "Groups" }),
+ h(Card, { className: 'filters' }, [
+ h('h3', "Filters"),
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Search groups...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h(Divider),
+ h('div.group-list', [
+ filtered.map((d) => {
+ return h(GroupItem, { data: d });
+ })
+ ])
+ ]);
+}
+
+function GroupItem({ data }) {
+ const { name, col_group, col_group_id } = data;
+
+ return h(LinkCard, { href: "/columns/groups/" + col_group_id}, [
+ h('h3', name),
+ h('p', col_group),
+ ])
+}
+
diff --git a/pages/columns/groups/main.module.scss b/pages/columns/groups/main.module.scss
new file mode 100644
index 000000000..649ccd811
--- /dev/null
+++ b/pages/columns/groups/main.module.scss
@@ -0,0 +1,31 @@
+h3, h2 {
+ margin: 0;
+ padding: 0;
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.filters {
+ margin-bottom: 14px
+}
\ No newline at end of file
diff --git a/pages/columns/main.module.scss b/pages/columns/main.module.scss
new file mode 100644
index 000000000..28c2b9e8a
--- /dev/null
+++ b/pages/columns/main.module.scss
@@ -0,0 +1,102 @@
+.column-group-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+h2 {
+ margin: 0;
+}
+
+.column-group {
+ cursor: pointer;
+}
+
+.column-groups {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.search-bar {
+ display: flex;
+ flex-direction: row;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+ margin: 1em 0;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.column-row {
+ display: grid;
+ grid-template-columns: 10% 90%
+}
+
+.active, .inprocess, .obsolete {
+ place-self: end start;
+ padding: 0.5em;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ font-weight: bold;
+}
+
+.active {
+ background-color: green;
+ color: white;
+}
+
+.inprocess {
+ background-color: yellow;
+ color: black;
+}
+
+.obsolete {
+ background-color: red;
+ color: white;
+}
+
+.col-id, .col-group, .col-link {
+ margin: auto;
+ margin-left: 0;
+}
+
+.popup {
+ padding: 1em;
+ h3 {
+ font-size: 1.5em;
+ text-align: center;
+ margin: 0;
+ }
+}
+
+.mapboxgl-popup-close-button {
+ padding: 0.5em;
+ margin: 0;
+ font-size: 1.5em;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+#map {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ z-index: 1;
+}
\ No newline at end of file
diff --git a/pages/columns/map.ts b/pages/columns/map.ts
new file mode 100644
index 000000000..1c745a32f
--- /dev/null
+++ b/pages/columns/map.ts
@@ -0,0 +1,24 @@
+import h from "@macrostrat/hyper";
+import { ColumnNavigationMap } from "@macrostrat/column-views";
+import { mapboxAccessToken } from "@macrostrat-web/settings";
+import { ErrorBoundary } from "@macrostrat/ui-components";
+
+export function ColumnMap({
+ projectID,
+ inProcess,
+ className,
+ selectedColumn,
+ onSelectColumn,
+}) {
+ return h(
+ ErrorBoundary,
+ h(ColumnNavigationMap, {
+ className,
+ inProcess,
+ projectID,
+ accessToken: mapboxAccessToken,
+ selectedColumn,
+ onSelectColumn,
+ })
+ );
+}
diff --git a/pages/dev/+Page.mdx b/pages/dev/+Page.mdx
index 39e63460a..59e99aa9b 100644
--- a/pages/dev/+Page.mdx
+++ b/pages/dev/+Page.mdx
@@ -23,7 +23,6 @@ import { PageHeader } from "~/components";
- [Concept app index](/dev/concepts)
- [Built with Macrostrat](/dev/test-site/about)
-- [New homepage](/dev/test-site/main-page)
- [Documentation](/dev/docs)
## Miscellaneous
diff --git a/pages/dev/test-site/about/+Page.mdx b/pages/dev/test-site/about/+Page.mdx
deleted file mode 100644
index a00f9e88c..000000000
--- a/pages/dev/test-site/about/+Page.mdx
+++ /dev/null
@@ -1,148 +0,0 @@
-import { PageHeader } from "~/components";
-import { LinkCard } from "~/components/cards";
-import { Image, Navbar, Footer } from "../index";
-import "./main.styl";
-import "../main.styl";
-import { MacrostratIcon } from "~/components";
-
-[//]: # "Nav Bar"
-
-
-
-
-[//]: # "About"
-
-
- About
-
-
-
-
-
- Summary
-
-
- Macrostrat is a platform for the aggregation and distribution of geological data relevant to the spatial and temporal distribution of sedimentary, igneous, and metamorphic rocks as well as data extracted from them. It is linked to the
xDD (formly GeoDeepDive) digital library and machine reading system, and it aims to become a community resource for the addition, editing, and distribution of new stratigraphic, lithological, environmental, and economic data. Interactive applications built upon Macrostrat are designed for educational and research purposes.
-
-
-
-
-
- License
-
-
- All data are provided under a Creative Commons Attribution 4.0 International license (
CC-BY-4.0 ).
-
-
-
-
-
- Citation
-
-
-
In presentations: Acknowledge Macrostrat by name. You may also include any of the Macrostrat logos accessible on this webpage.
- \
- \
-
In publications: Acknowledge Macrostrat as the source of any information or data. In publications, you may cite our most recent infrastructure paper,
Peters et al. (2018) . In addition, you should also include citations to the original references associated with the data set that was used. These references are accessible from the API. If you would like your paper listed in the official publications, please contact us and we will provide a citation and link.
-
-
-
-
-
- Collaboration
-
-
- Our small team has worked hard to compile, format, and make data available via Macrostrat. We strongly encourage and welcome active collaborations, both scientific and geoinformatic. All data are provided freely on under a
CC-BY-4.0 license.
-
-
-
-
-
- Funding
-
-
- Major Macrostrat data infrastructure development was supported by the US National Science Foundation (EAR-1150082, ICER-1440312), with ongoing support for data acquisition supported by NSF EAR-1948843 and ICER-1928323. Continuous and ongoing support has also been provided by the UW-Madison
Department of Geoscience . If you use Macrostrat and like what we do, please consider helping out with a
donation . Every contribute helps us to maintain infrastructure and keep improving.
-
-
-
-
-[//]: # "API"
-
-
-
All data contained in the Macrostrat database are freely available via our Application Programming Interface (API), which provides a convinient way to retrieve data for analysis or application creation. For more information head over to the
API root to explore available routes.
-
-
-
-
-[//]: # "Apps"
-
-
-
-
-[//]: # "Footer"
-
diff --git a/pages/dev/test-site/donate/+Page.mdx b/pages/dev/test-site/donate/+Page.mdx
deleted file mode 100644
index 9ed280a2b..000000000
--- a/pages/dev/test-site/donate/+Page.mdx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { PageHeader } from "~/components";
-import { PageBreadcrumbs } from "~/components";
-import { Image, Navbar, Footer } from "../index";
-import "./main.styl";
-import "../main.styl";
-import { MacrostratIcon } from "~/components";
-
-[//]: # "Nav Bar"
-
-
-[//]: # "Donate"
-
-
-
-
-
-
- Grant funding, principally from the
U.S. National Science Foundation , got Macrostrat off the ground and keeps us innovating, but maintaining and growing a free and open digital resource involves ongoing expenses beyond the grant cycle, like annual certificate renewals, cloud server hosting and backup storage that keep your connection safe, domain name registrations that keep us located on the web, and system upgrades to keep us fast and efficient. If you would like to help us continue to grow and provide free resources, you can do so with a one-time or recurring gift to the UW Foundation Paleontology Program Fund in Geology. Thank you!
-
-
-
-
-
-[//]: # "Footer"
-
diff --git a/pages/dev/test-site/donate/main.styl b/pages/dev/test-site/donate/main.styl
deleted file mode 100644
index f2d090bf7..000000000
--- a/pages/dev/test-site/donate/main.styl
+++ /dev/null
@@ -1,76 +0,0 @@
-.htnl, .body, .main
- background-color: white
- color: black
-
-a:hover
- text-decoration: none
-
-.big
- font-size: 72px
- font-family: "Maven Pro", sans-serif;
- text-align: center
-
-p
- margin-bottom: 10px;
- margin-top: 0;
-
-.donate-container
- height: 80vh
-
-.title
- margin: 0
- font-size: 72px
- font-family: "Maven Pro", sans-serif;
- padding: 20vh 0
- text-align: center
-
-.donate-title
- a
- color:white
- a:hover
- text-decoration: none
-
- color: white
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
- font-family: "Maven Pro", sans-serif;
- padding: 0
-
-.donate-left
- float: left
- width: 50%
- height: 80vh
- display: flex;
- justify-content: center;
- align-items: center;
-
-.donate-right
- float: right
- width: 50%
- height: 80vh
- display: flex;
- justify-content: center;
- align-items: center;
-
-.donate-info
- background: rgba(255,255,255,0.6);
- padding: 25px
- color: black
- width: 80%
- font-size: 18px
-
- a
- color: black
- font-weight: bold
- text-decoration: none
-
-.donate-img
- position:absolute
- z-index:5
- height: 80vh
- width: 100%
- object-fit: cover
-
-.text
- position:absolute
- z-index: 100
- padding: 0 20px
\ No newline at end of file
diff --git a/pages/dev/test-site/index.ts b/pages/dev/test-site/index.ts
deleted file mode 100644
index 29a075f39..000000000
--- a/pages/dev/test-site/index.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import h from "@macrostrat/hyper";
-import { MacrostratIcon } from "~/components";
-
-export function Image({ src, className, width, height }) {
- const srcWithAddedPrefix = "https://storage.macrostrat.org/assets/web/main-page/" + src;
- return h("img", {src: srcWithAddedPrefix, className, width, height})
-}
-
-export function Navbar() {
- return h("div", {className: "nav"}, [
- h("ul", [
- h("li", h("a", {href: "/dev/test-site/main-page"}, h(MacrostratIcon))),
- h("li", h("a", {href: "/dev/test-site/about"}, "About")),
- h("li", h("a", {href: "/dev/test-site/publications"}, "Publications")),
- h("li", h("a", {href: "/dev/test-site/people"}, "People")),
- h("li", h("a", {href: "/dev/test-site/donate"}, "Donate"))
- ])
- ]);
-}
-
-export function Footer() {
- return h("div", {className: "footer"}, [
- h("div", {className: "footer-container"}, [
- h("div", {className: "col-sm-4"}, [
- h(Image, {className: "logo_white", src: "logo_white.png", width: "100px"}),
- h("p", {className: "f1-text"}, [
- "Produced by the ",
- h("a", {href: "http://strata.geology.wisc.edu", target: "_blank"}, "UW Macrostrat Lab"),
- h("a", {href: "https://github.com/UW-Macrostrat", target: "_blank"}, h(Image, {className: "git_logo", src: "git-logo.png", width: "18px"})),
- ])
- ]),
- h("div", {className: "col-sm-4"}, [
- h("ul", {className: "footer-nav"}, [
- h("li", h("a", {href: "/dev/test-site/about"}, "About")),
- h("li", h("a", {href: "/dev/test-site/publications"}, "Publications")),
- h("li", h("a", {href: "/dev/test-site/people"}, "People")),
- h("li", h("a", {href: "/dev/test-site/donate"}, "Donate"))
- ])
- ]),
- h("div", {className: "col-sm-4"}, [
- h(Image, {className: "funding-logo", src: "nsf.png", width: "100px"}),
- h("div", {className: "funding-line"}, "Current support:"),
- h("div", {className: "funding-line"}, "EAR-1948843"),
- h("div", {className: "funding-line"}, "ICER-1928323"),
- h("div", {className: "funding-line"}, "UW-Madison Dept. Geoscience")
- ])
- ])
- ]);
-}
\ No newline at end of file
diff --git a/pages/dev/test-site/main-page/+Page.mdx b/pages/dev/test-site/main-page/+Page.mdx
deleted file mode 100644
index fe1fad95d..000000000
--- a/pages/dev/test-site/main-page/+Page.mdx
+++ /dev/null
@@ -1,154 +0,0 @@
-import { PageHeader } from "~/components";
-import { LinkCard } from "~/components/cards";
-import { Image, Navbar, Footer } from "../index";
-import "./main.styl";
-import "../main.styl";
-import { MacrostratIcon } from "~/components";
-
-
-
-[//]: # "Nav Bar"
-
-
-[//]: # "Start Page"
-
-
-
-
-
-
- 1,400
- Regional Rock Columns
-
-
- 33,903
- Rock Units
-
-
- 2,500,000
- Geologic Map Polygons
-
-
-
-
A platform for geological data exploration, integration, and analysis
-
-
-
-
-
-[//]: # "Locations"
-
-
-
-
-
North America
-
243 packages. 798 units. 897 collections.
-
-
-
-
Carribean
-
243 packages. 798 units. 897 collections.
-
-
-
-
-
New Zealand
-
828 packages. 2,168 units. 328 collections.
-
-
-
-
Deep Sea
-
388 packages. 7,124 units. 0 collections.
-
-
-
-
-
-[//]: # "Map Interface"
-
-
-
-
With over 225 maps from data providers around the world across every scale, Macrostrat is the world's largest homogenized geologic map database. Our data processing pipeline links geologic map polygons to Macrostrat column polygons, external stratigraphic name lexicons, and geochronological intervals, enabling the enhancement of the original map data and allowing for direct links into
xDD (formly GeoDeepDive).
- \
-
Are you affiliated with a state or national geologic survey?
Get in touch with us - we'd love to collaborate and help publicize your maps!
- \
-
-
-
-
-[//]: # "Maps"
-
-
-
- The spatial footprint of rocks on the Earth's surface
-
-
-
-[//]: # "Columns"
-
-
-
- Stratigraphic and geological columns showing the organization of rocks in time
-
-
-
-[//]: # "Geologic Lexicon"
-
-
-
- Geologic units and data dictionaries
-
-
-
-[//]: # "Projects"
-
-
-
- Projects for specific regions or geological problems
-
-
-
-
-[//]: # "Donate"
-
-
-
-
-
-
- Grant funding, principally from the
U.S. National Science Foundation , got Macrostrat off the ground and keeps us innovating, but maintaining and growing a free and open digital resource involves ongoing expenses beyond the grant cycle, like annual certificate renewals, cloud server hosting and backup storage that keep your connection safe, domain name registrations that keep us located on the web, and system upgrades to keep us fast and efficient. If you would like to help us continue to grow and provide free resources, you can do so with a one-time or recurring gift to the UW Foundation Paleontology Program Fund in Geology. Thank you!
-
-
-
-
-
-[//]: # "Footer"
-
-
-
\ No newline at end of file
diff --git a/pages/dev/test-site/main.styl b/pages/dev/test-site/main.styl
deleted file mode 100644
index 67dc178e8..000000000
--- a/pages/dev/test-site/main.styl
+++ /dev/null
@@ -1,78 +0,0 @@
-.nav
- position: fixed
- width: 100%
- z-index: 10000
-
- ul
- list-style-type: none;
- margin: 0;
- padding: 0;
- overflow: hidden;
- background-color: #015eab;
-
- li
- float: left;
- font-size: 15px
-
- li a
- display: block;
- color: white;
- text-align: center;
- padding: 14px 16px;
- text-decoration: none
-
-
-.footer
- width: 100%
- background-color: #015EAB
-
-.footer-container
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- margin: 0 auto;
- width: 60%
-
-.col-sm-4
- color: white
- width: 33.333%
- color: #E0E1E6;
- font-weight: 200;
- text-align: center;
- min-height: 1px;
- padding-left: 15px;
- padding-right: 15px;
- font-weight: bold
- padding-bottom: 18px
-
-.nav-logo
- padding-top: 5px
-
-.funding-logo
- padding: 10px
-
-.footer-nav
- list-style-type: none
- padding-right: 40px
-
- li
- padding: 5px 0
-
- a
- color: white
-
- a:hover
- text-decoration: none
-
-.git_logo
- vertical-align: sub
-
-.f1-text
- a
- color: white
-
-#who-made-it
- padding-top: 25px
-
-.logo_white
- padding-top: 20px
\ No newline at end of file
diff --git a/pages/dev/test-site/people/+Page.mdx b/pages/dev/test-site/people/+Page.mdx
deleted file mode 100644
index 398eb7d49..000000000
--- a/pages/dev/test-site/people/+Page.mdx
+++ /dev/null
@@ -1,161 +0,0 @@
-import { PageHeader } from "~/components";
-import { PageBreadcrumbs } from "~/components";
-import { Image, Navbar, Footer } from "../index";
-import "./main.styl";
-import "../main.styl";
-import { MacrostratIcon } from "~/components";
-
-
-
-[//]: # "Nav Bar"
-
-[//]: # "People"
-
People
-
major contributors to the project
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Shan Ye \
-
Graduate Student (former)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Erika Ito \
-
Research Intern (former)
-
-
-
-
-
-
-
-
-
-
-
-[//]: # "Footer"
-
-
-
diff --git a/pages/dev/test-site/people/main.styl b/pages/dev/test-site/people/main.styl
deleted file mode 100644
index b83cc223f..000000000
--- a/pages/dev/test-site/people/main.styl
+++ /dev/null
@@ -1,80 +0,0 @@
-.htnl, .body, .main
- background-color: white
- color: black
-
-a:hover
- text-decoration: none
-
-.big
- color: #E0E1E6
- text-align: left
- font-size: 75px
- font-family: "Maven Pro", sans-serif
- margin: 0
- margin-left: 20%
- padding-top: 100px
-
-.line
- border-bottom: 1px solid #E0E1E6;
- width: 60%
- margin: 0 20%
-
-
-.people
- color: white
-
-.left
- float: left
- width: 30%
- margin-left: 20%
-
-.right
- float: left
- width: 30%
- margin-right: 20%
-
-.person-info
- height: 30vh
- width: 90%
- position: relative
- margin: 5%
-
-.text
- text-align: right
- position:absolute
- padding: 5px 20px
- z-index: 100
- background-color: rgba(0, 0, 0, 0.2)
- bottom:0
- right: 0
-
- a
- color: white
-
- a:hover
- color: white
-
-.back-img
- position:absolute
- z-index: 0
- height: 30vh
- object-fit: cover
- width: 100%
-
-n
- font-size: 25px
- font-weight: 200px
-
-t
- font-weight: 400px
-
-e
- font-size: 14px
- font-weight: 200px
-
-.footer
- margin-top: 280vh
-
-.subtitle
- margin-left: 20%
- color: #E0E1E6;
\ No newline at end of file
diff --git a/pages/dev/test-site/publications/+Page.mdx b/pages/dev/test-site/publications/+Page.mdx
deleted file mode 100644
index 95dd7828d..000000000
--- a/pages/dev/test-site/publications/+Page.mdx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { PageHeader } from "~/components";
-import { PageBreadcrumbs } from "~/components";
-import { Image, Navbar, Footer } from "../index";
-import "./main.styl";
-import "../main.styl";
-import { MacrostratIcon } from "~/components";
-
-
-
-[//]: # "Nav Bar"
-
-
-[//]: # "Publications"
-
-
Publications
-
literature utilizing Macrostrat
-
-
- [//]: # "NB: adding pubs to list requires updating css .pub-list counter"
-
- Gazdewich, S., T. Hauck, J. Husson. 2024. Authigenic carbonate burial within the Late Devonian western Canada sedimentary bsain and its impact on the global carbon cycle. Geochemistry, Geophysics, Geosystems 10.1029/2023GC011376. [link]
- Segessenman, D.C. and S.E. Peters. 2024. Transgression-regression cycles drive correlations in Ediacaran-Cambrian rock and fossil records. Paleobiology 10.1017/pab.2023.31. [link]
- Quinn, D.P., C.R. Idzikowski, S.E. Peters. 2023. Building a multi-scale, collaborative, and time-integrated digital crust: The next stage of the Macrostrat data system. Geoscience Data Journal 10.1002/gdj3.189. [link]
- Tasistro-Hart, A.R. and F.A. Macdonald. 2023. Phanerozoic flooding of North America and the Great Unconformity. Proceedings of the National Academy of Sciences 120(37):e2309084120. [link]
- Husson, J.M. and L.A. Coogan. 2023. River chemistry reveals a large decrease in dolomite abundance across the Phanerozoic. Geochemical Perspective Letters 26:1-6. [link]
- Walton, C.R., J. Hao, F. Huang, F.E. Jenner, H. Williams, A.L. Zerkle, A. Lipp, R.M. Hazen, S.E. Peters, O. Shorttle. 2023. Evolution of the crustal phosphorus reservoir. Science Advances 9(18):eade6923. [link]
- Balseiro, D. and M.G. Powell. 2023. Relative oversampling of carbonate rocks in the North American marine fossil record. Paleobiology [link]
- Ye, S., S.E. Peters. 2023. Bedrock geological map predictions for Phanerozoic fossil occurrences. Paleobiology 49(3):394-413. [link]
- Wang, J., Tarhan, L.G., Jacobson, A.D. et al. 2023. The evolution of the marine carbonate factory. Nature https://doi.org/10.1038/s41586-022-05654-5 [link]
- Capel, E., C. Monnet, C.J. Cleal, J. Xue, T. Servais, B. Cascales-Miñana. 2023. The effect of geological biases on our perception of early land plant radiation. Palaeontology 66:e12644 [link]
- Sessa, J.A., A.J. Fraass, LJ. LeVay, K.M. Jamson, S.E. Peters. 2023. The Extending Ocean Drilling Pursuits (eODP) Project: Synthesizing Scientific Ocean Drilling Data. Geochemistry, Geophysics, Geosystems [link]
- Segessenman, D.C. and S.E. Peters. 2023. Macrostratigraphy of the Ediacaran system in North America. In "Laurentia: Turning Points in the Evolution of a Continent." S.J. Whitmeyer, M.L. Williams, D.A. Kellett, B. Tikoff, eds. GSA Memoir. [link]
- Boulila, S., S.E. Peters, R.D. Müller, B.U. Haq, N.Hara. 2023. Earth’s interior dynamics drive marine fossil diversity cycles of tens of millions of years. Proceedings of the National Academy of Sciences e2221149120 [link]
- Peters, S.E., D. Quinn, J.M. Husson, R.R. Gaines. 2022. Macrostratigraphy: insights into cyclic and secular evolution of the Earth-life system. Ann. Rev. Earth & Planet. Sci. 50:419-449 [link]
- Emmings, J.F., S.W. Poulton, J. Walsh, K.A. Leeming, I. Ross, S.E. Peters. 2022. Pyrite mega-analysis reveals modes of anoxia through geologic time. Science Advances 8(11). [link]
- Chen, G., Q. Cheng, S.E. Peters, C.J. Spencer, M. Zhao. 2022. Feedback between surface and deep processes: insight from time series analysis of sedimentary record. Earth and Planet. Sci. Letters. [link]
- Peters, S.E. et al. 2021. Igneous rock area and age in continental crust. Geology. doi:10.1130/G49037.1. [link]
- Loughney, K.M., C. Badgley, A. Bahadori, W.E. Hold, and E.T. Rasbury. 2021. Tectonic influence on Cenozoic mammal richness and sedimentation history of the Basin and Range, western North America. Science Advances 7(45):p.eabh4470. doi:10.1126/sciadv.abh4470
- Key, M.M. Jr., P.N.W. Jackson, C.M. Reid. 2021. Trepostome bryozoans buck the trend and ignore calcite-aragonite seas. Palaeobiodiversity and Palaeoenvironments. doi:10.1007/s12549-021-00507-x. [link]
- Lipp, A.G. et al. 2021. The composition and weathering of the continents over geologic time. Geochemical Perspectives Letters. doi:10.7185/geochemlet.2109. [link]
- Barnes, B.D., J.M. Husson, S.E. Peters. 2020. Authigenic carbonate burial in the Late Devonian–Early Mississippian Bakken Formation (Williston Basin, USA). Sedimentology. doi:10.1111/sed.12695. [link]
- Close, R.A. et al. 2020. The spatial structure of Phanerozoic marine animal diversity. Science doi:10.1126/science.aay8309. [link]
- Balseiro, D. and Powell, M.G. 2019. Carbonate collapse and the Late Paleozoic Ice Age marine biodiversity crisis. Geology doi:10.1130/G46858.1. [link]
- Keller, C.B., J.M. Husson, R.N. Mitchell, W.F. Bottke, T.M. Gernon, P. Boehnke, E.A. Bell, N.L. Swanson-Hysell, S.E. Peters. 2019. Neoproterozoic glacial origin of the Great Unconformity. Proc. Nat. Acad. of Sci. USA. 116(4):1136-1145. doi:10.1073/pnas.1804350116 [link]
- Keating-Bitonti, C.R., and S.E. Peters. 2019. Influence of increasing carbonate saturation in Atlantic bottom water during the late Miocene. Palaeogeography, Palaeoclimatology, Palaeoecology 518:134-142. doi:10.1016/j.palaeo.2019.01.006[link]
- Cohen, P.A., R. Lockwood, S.E. Peters. 2018. Integrating Macrostrat and Rockd into undergraduate Earth Science Teaching. Elements of Paleontology . doi:10.1017/9781108681445 [link]
- Isson, T.T., and N.J. Planavsky. 2018. Reverse weathering as a long-term stabilizer of marine pH and planetary climate. Nature 560:571-475. doi:10.1038/s41586-018-0408-4 [link]
- Husson, J.M. and S.E. Peters. 2018. Nature of the sedimentary rock record and its implications for Earth system evolution. Emerging Topics in Life Sciences . doi:10.1042/ETLS20170152 [link]
- Peters, S.E., J.M. Husson. 2018. We need a global comprehensive stratigraphic database: here’s a start. The Sedimentary Record 16(1). doi:10.2110/sedred.2018.1 [link]
- Peters, S.E., J.M. Husson, J. Czaplewski. 2018. Macrostrat: a platform for geological data integration and deep-time Earth crust research. Geochemistry, Geophysics, Geosystems . [link] \
- Preprint available on EarthArXiv 27,Jan18. doi:10.17605/OSF.IO/YNAXW [link]
- Schachat, S.R., C.C. Labandeira, M.R. Saltzman, B.D. Cramer, J.L. Payne, C.K. Boyce. 2018. Phanerozoic pO2 and the early evolution of terrestrial animals. Proc. Roy. Soc. B. [link]
- Zaffos, A., S. Finnegan, S.E. Peters. 2017. Plate tectonic regulation of global marine animal diversity. Proc. Nat. Acad. of Sci. USA . [link]
- Peters, S.E., J.M. Husson. J. Wilcots. 2017. Rise and fall of stromatolites in shallow marine environments. Geology . [link]
- Peters, S.E., J.M. Husson. 2017. Sediment cycling on continental and oceanic crust. Geology 45:323-326. [link]
- Husson, J.M., S.E. Peters. 2017. Atmospheric oxygenation driven by unsteady growth of the continental sedimentary reservoir. Earth and Planetary Science Letters . 460:68-75. [link]
- Schott, R. 2017. Rockd: Geology at your fingertips in a mobile world. Bulletin of the Eastern Section of the National Association of Geoscience Teachers 67(2):1-4. [link]
- Chan, M.A., S.E. Peters, B. Tikoff. 2016. The future of field geology, open data sharing, and cybertechnology in Earth science. The Sedimentary Record 14:4-10. [link]
- Nelsen, M.P., B.A. DiMichele, S.E. Peters, C.K. Boyce. 2016. Delayed fungal evolution did not cause the Paleozoic peak in coal production. Proc. Nat. Acad. of Sci. USA . [link]
- Heavens, N.G. 2015. Injecting climate modeling into deep time studies: ideas for nearly every project. The Sedimentary Record 13:(4)4-10. [link]
- Carroll, A.R. 2015. Geofuels: energy and the Earth . Cambridge University Press. [link]
- Thomson, T.J. and M.L. Droser. 2015. Swimming reptiles make their mark in the Early Triassic: delayed ecologic recovery increased the preservation potential of vertebrate swim tracks. Geology 43:215-218. [link]
- Fraass, A.J., D.C. Kelly, S.E. Peters. 2015. Macroevolutionary history of the planktic foraminifera. Annual Review of Earth and Planetary Sciences 43:5.1-5.28. [link]
- Fan, Y., S. Richard, R.S. Bristol, S.E. Peters, et al.. 2015. DigitalCrust: A 4D data system of material properties for transforming research on crustal fluid flow. Geofluids 15:372-379. [link]
- Peters, S.E., D.C. Kelly, and A. Fraass. 2013. Oceanographic controls on the diversity and extinction of planktonic foraminifera. Nature . 493:398-401.[link] .
- Benson, R.B.J., P.D. Mannion, R.J. Butler, P. Upchurch, A. Goswami, and S.E. Evans. 2012. Cretaceous tetrapod fossil record sampling and faunal turnover: implications for biogeography and the rise of modern clades. Palaeogeography, Palaeoclimatology, Palaeoecology . [link] .
- Rook, D.L., N.A. Heim, and J. Marcot. 2012.Contrasting patterns and connections of rock and biotic diversity in the marine and non-marine fossil records of North America. Palaeogeography, Palaeoclimatology, Palaeoecology . 372:123-129. [link]
- Halevy, I, S.E. Peters, and W.W. Fischer. 2012. Sulfate burial constraints on the Phanerozoic sulfur cycle. Science 337:331-334. doi:10.1126/science.1220224.[link] .
- Peters, S.E. and R.R. Gaines. 2012. Formation of the ‘Great Unconformity’ as a trigger for the Cambrian explosion. Nature 484:363-366. doi:10.1038/nature10969. [link] .
- Finnegan, S., N.A. Heim, S.E. Peters and W.W. Fischer. 2012. Climate change and the selective signature of the late Ordovician mass extinction. PNAS doi:10.1073/pnas.1117039109. [link] .
- Hannisdal, B. and S.E. Peters. 2011. Phanerozoic Earth system evolution and marine biodiversity. Science 334:1121-1124. [link] .
- Butler, R.J. et al. 2011. Sea level, dinosaur diversity and sampling biases: investigating the ‘common cause’ hypothesis in the terrestrial realm. Proc. Roy. Soc. London B 278:1165-1170. [link] .
- Melott, A.L. and R.K. Bambach 2011. A ubquitous ~62-Myr periodic fluctuation superimposed on general trends in fossil biodiversity II. Evolutionary dynamics associated with period fluctuation in marine diversity. Paleobiology 37:369-382. [link] .
- Heim, N.A. and S.E. Peters. 2011. Regional environmental breadth predicts geographic range and longevity in fossil marine genera. PLoS One 6:(5) e18946; doi:10.1371/journal.pone.0018946 [PDF] .
- Peters, S.E. and N.A. Heim. 2011. Macrostratigraphy and macroevolution in marine environments: testing the common-cause hypothesis. In, Smith, A.B., and A. McGowan, eds. Comparing the rock and fossil records: implications for biodiversity.
- Special Publication of the Geological Society of London 358:95-104. doi: 10.1144/SP358.7. [link]
- Peters, S.E. and N.A. Heim. 2011. The stratigraphic distribution of marine fossils in North America. Geology 39:259-262; doi: 10.1130/G31442.1. [PDF]
- Finnegan, S., S.E. Peters, and W.W. Fischer. 2011. Late Ordovician-Early Silurian selective extinction patterns in Laurentia and their relationship to climate change. In J.C. Gutiérrez-Marco, I. Rábano, and D. Garcia-Bellido, eds. Ordovician of the World. Cuadernos del Museo Geominera 14: 155-159.
- Meyers, S.R. and S.E. Peters. 2011. A 56 million year rhythm in North American sedimentation during the Phanerozoic. EPSL doi:10.1016/j.epsl.2010.12.044. [PDF]
- Heim, N.A. and S.E. Peters. 2011. Covariation in macrostratigraphic and macroevolutionary patterns in the marine record of North America. GSA Bulletin 123:620-630.
- [PDF]
- Peters, S.E. and N.A. Heim. 2010. The geological completeness of paleontological sampling in North America. Paleobiology 36:61-79. [PDF] .
- Marx, F.G. 2009. Marine mammals through time: when less is more in studying palaeodiversity. Proceedings of the Royal Society of London B 138:183-196. [link]
- McGowan, A.J., and A. Smith. 2008. Are global Phanerozoic marine diversity curves truly global? A study of the relationship between regional rock records and global Phanerozoic marine diversity. Paleobiology 34:80-103. [link]
- Mayhew, P.J., G.B. Jenkins, and T.G. Benton. 2008. Long-term association between global temperature and biodiversity, origination and extinction in the fossil record. Proceedings of the Royal Society of London B 275:47-53. [link]
- Peters, S.E. 2008. Environmental determinants of extinction selectivity in the fossil record. Nature 454:626-629.
- [PDF] [supplement]
- Peters, S.E. 2008. Macrostratigraphy and its promise for paleobiology. Pp. 205-232 In P.H. Kelley and R.K. Bambach, eds. From evolution to geobiology: research questions driving paleontology at the start of a new century. The Paleontological Society Papers, Vol. 14. 9.[PDF]
- Peters, S.E. and W.I. Ausich. 2008. A sampling-standardized macroevolutionary history for Ordovician-Early Silurian crinoids. Paleobiology 34:104-116. [PDF]
- Smith, A.B. 2007. Marine diversity through the Phanerozoic: problems and prospects. Journal of the Geological Society, London 164:731-745.[link]
- Peters, S.E. 2007. The problem with the Paleozoic. Paleobiology 33:165-181.[PDF]
- Peters, S.E. 2006. Macrostratigraphy of North America. Journal of Geology 114:391-412.[PDF]
- Peters, S.E. 2005. Geologic constraints on the macroevolutionary history of marine animals. Proceedings of the National Academy of Sciences U.S.A. 102:12326-12331.[PDF]
-
-
-
-[//]: # "Footer"
-
-
-
diff --git a/pages/dev/test-site/publications/main.styl b/pages/dev/test-site/publications/main.styl
deleted file mode 100644
index 7f2d8942a..000000000
--- a/pages/dev/test-site/publications/main.styl
+++ /dev/null
@@ -1,52 +0,0 @@
-.htnl, .body, .main
- background-color: white
- color: black
-
-#container
- background-color: white
-
-a:hover
- text-decoration: none
-
-.big
- font-size: 72px
- font-family: "Maven Pro", sans-serif;
- text-align: center
-
-p
- margin-bottom: 10px;
- margin-top: 0;
- color: #E0E1E6
-
-.pub-line
- width: 60%;
- border-bottom: 1px solid #E0E1E6;
- position: absolute;
-
-#publications
- padding: 50px 20%
-
-#pub-title
- text-align: left
- color: #E0E1E6
- position: relative
- padding-bottom: 0
- margin-bottom: 0
-
-.pub-list
- padding-top: 10px
- margin-left: 20px
- counter-reset: pub-counter 70
- color: black
-
- li
- counter-increment: pub-counter -1
-
- li::marker
- font-size: 35px;
- color: #babdc8;
- content: counter(pub-counter) " "
- counter-increment: pub-counter
-
-.blurb
- font-size: 15px
\ No newline at end of file
diff --git a/pages/donate/+Page.client.ts b/pages/donate/+Page.client.ts
new file mode 100644
index 000000000..3ea947fb1
--- /dev/null
+++ b/pages/donate/+Page.client.ts
@@ -0,0 +1,22 @@
+import { Image, Navbar, Footer } from "../index";
+import h from "./main.module.sass";
+
+export function Page() {
+ return h('div.total', [
+ h(Navbar),
+ h('div.donate-container', [
+ h('div.text-donate', [
+ h('a', { href: 'https://secure.supportuw.org/give/?id=E0A03FA3-B2A0-431C-83EE-A121A04EEB5D', target: '_blank' }, [
+ h('h1.title.donate-title', 'Donate Now'),
+ ]),
+ h('div.donate-info', [
+ 'Grant funding, principally from the ',
+ h('a', { href: 'http://www.nsf.gov', target: '_blank' }, 'U.S. National Science Foundation'),
+ ', got Macrostrat off the ground and keeps us innovating, but maintaining and growing a free and open digital resource involves ongoing expenses beyond the grant cycle, like annual certificate renewals, cloud server hosting and backup storage that keep your connection safe, domain name registrations that keep us located on the web, and system upgrades to keep us fast and efficient. If you would like to help us continue to grow and provide free resources, you can do so with a one-time or recurring gift to the UW Foundation Paleontology Program Fund in Geology. Thank you!'
+ ])
+ ]),
+ h(Image, { className: "back-img donate-img", src: 'donate_medium.jpg' }),
+ ]),
+ h(Footer)
+ ]);
+}
\ No newline at end of file
diff --git a/pages/donate/main.module.sass b/pages/donate/main.module.sass
new file mode 100644
index 000000000..653782bf7
--- /dev/null
+++ b/pages/donate/main.module.sass
@@ -0,0 +1,127 @@
+.htnl, .body, .main
+ background-color: white
+ color: black
+
+a:hover
+ text-decoration: none
+
+.big
+ font-size: 72px
+ font-family: "Maven Pro", sans-serif
+ text-align: center
+
+p
+ margin-bottom: 10px
+ margin-top: 0
+
+.donate-container
+ height: 80vh
+
+.title
+ margin: 0
+ font-size: 72px
+ font-family: "Maven Pro", sans-serif
+ padding: 20vh 0
+ text-align: center
+
+.donate-title
+ a
+ color:white
+ a:hover
+ text-decoration: none
+
+ color: white
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6)
+ font-family: "Maven Pro", sans-serif
+ padding: 0
+
+.donate-left
+ float: left
+ width: 50%
+ height: 80vh
+ display: flex
+ justify-content: center
+ align-items: center
+
+.donate-right
+ float: right
+ width: 50%
+ height: 80vh
+ display: flex
+ justify-content: center
+ align-items: center
+
+.donate-info
+ background: rgba(255,255,255,0.6)
+ padding: 25px
+ color: black
+ width: 80%
+ font-size: 18px
+
+ a
+ color: black
+ font-weight: bold
+ text-decoration: none
+
+.donate-img
+ position:absolute
+ z-index: 1
+ height: 80vh
+ width: 100%
+ object-fit: cover
+
+.text
+ position:absolute
+ z-index: 100
+ padding: 0 20px
+
+.donate-container
+ height: 80vh
+ display: flex
+ justify-content: center
+ align-items: center
+
+.donate-title
+ flex: 0 0 50%
+ width: 100%
+ text-decoration: none
+
+ a
+ color: white
+ text-decoration: none
+
+ &:hover
+ text-decoration: none
+
+ color: white
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6)
+ font-family: "Maven Pro", sans-serif
+ padding: 0
+
+.donate-info
+ flex: 0 0 50%
+ background: rgba(255,255,255,0.6)
+ padding: 25px
+ color: black
+ width: 80%
+ font-size: 18px
+
+ a
+ color: black
+ font-weight: bold
+ text-decoration: none
+
+.donate-img
+ position: absolute
+ z-index: 1
+ height: 80vh
+ width: 100%
+ object-fit: cover
+
+.text-donate
+ position: absolute
+ z-index: 2
+ display: flex
+ gap: 3em
+ justify-content: center
+ align-items: center
\ No newline at end of file
diff --git a/pages/index.ts b/pages/index.ts
new file mode 100644
index 000000000..00e3c970d
--- /dev/null
+++ b/pages/index.ts
@@ -0,0 +1,204 @@
+import { onDemand } from "~/_utils";
+import h from "./layout.module.sass";
+import { MacrostratIcon } from "~/components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { DarkModeButton } from "@macrostrat/ui-components";
+import { Spinner } from "@blueprintjs/core";
+import {
+ MapAreaContainer,
+ MapView,
+} from "@macrostrat/map-interface";
+import { useState, useEffect } from 'react'
+import mapboxgl from 'mapbox-gl';
+
+export function Image({ src, className, width, height }) {
+ const srcWithAddedPrefix = "https://storage.macrostrat.org/assets/web/main-page/" + src;
+ return h("img", {src: srcWithAddedPrefix, className, width, height})
+}
+
+export function Navbar() {
+ return h("div", {className: "nav"}, [
+ h("a", {className: "nav-link", href: "/"}, h(MacrostratIcon)),
+ h("a", {href: "/about"}, "About"),
+ h("a", {href: "/publications"}, "Publications"),
+ h("a", {href: "/people"}, "People"),
+ h("a", {href: "/donate"}, "Donate"),
+ ]);
+}
+
+export function Footer() {
+ return h("div", {className: "footer"}, [
+ h("div", {className: "footer-container"}, [
+ h("div", {className: "footer-text-container"}, [
+ h(Image, {className: "logo_white", src: "logo_white.png", width: "100px"}),
+ h("p", {className: "footer-text"}, [
+ "Produced by the ",
+ h("a", {href: "http://strata.geology.wisc.edu", target: "_blank"}, "UW Macrostrat Lab"),
+ h("a", {href: "https://github.com/UW-Macrostrat", target: "_blank"}, h(Image, {className: "git_logo", src: "git-logo.png", width: "18px"})),
+ ])
+ ]),
+ h("div", {className: "footer-nav"}, [
+ h(DarkModeButton, { showText: true}),
+ h("a", {href: "/dev/test-site/about"}, "About"),
+ h("a", {href: "/dev/test-site/publications"}, "Publications"),
+ h("a", {href: "/dev/test-site/people"}, "People"),
+ h("a", {href: "/dev/test-site/donate"}, "Donate"),
+ ]),
+ h("div", {className: "footer-text-container"}, [
+ h(Image, {className: "funding-logo", src: "nsf.png", width: "100px"}),
+ h("div", {className: "funding-line"}, "Current support:"),
+ h("div", {className: "funding-line"}, "EAR-1948843"),
+ h("div", {className: "funding-line"}, "ICER-1928323"),
+ h("div", {className: "funding-line"}, "UW-Madison Dept. Geoscience")
+ ])
+ ])
+ ]);
+}
+
+export function useMacrostratAPI(str) {
+ return useAPIResult(SETTINGS.apiV2Prefix + str)
+}
+
+export function BlankImage({ src, className, width, height }) {
+ return h("img", {src, className, width, height})
+}
+
+export function Loading() {
+ return h("div", {className: "loading"}, [
+ h(Spinner),
+ h("h3", "Loading..."),
+ ]);
+}
+
+export function ColumnsMap({columns}) {
+ const [mapInstance, setMapInstance] = useState(null);
+
+ const mapPosition = {
+ camera: {
+ lat: 39,
+ lng: -98,
+ altitude: 9000000,
+ },
+ };
+
+ const handleMapLoaded = (map) => {
+ setMapInstance(map);
+ };
+
+ useEffect(() => {
+ if (!mapInstance || !columns || !columns.features?.length) return;
+
+ addGeoJsonLayer(mapInstance, columns);
+ fitMapToColumns(mapInstance, columns);
+ }, [columns, mapInstance]);
+
+ const fitMapToColumns = (map, columns) => {
+ if(columns.features.length > 10) return;
+
+ const bounds = new mapboxgl.LngLatBounds();
+
+ columns.features.forEach((feature) => {
+ const coords = feature.geometry.type === "Point"
+ ? [feature.geometry.coordinates]
+ : feature.geometry.type === "Polygon"
+ ? feature.geometry.coordinates[0]
+ : feature.geometry.type === "MultiPolygon"
+ ? feature.geometry.coordinates.flat(1)
+ : [];
+
+ coords.forEach(([lng, lat]) => {
+ bounds.extend([lng, lat]);
+ });
+ });
+
+ // Fit the map to these bounds
+ map.fitBounds(bounds, {
+ padding: {
+ top: 20,
+ bottom: 20,
+ left: 200,
+ right: 20
+ },
+ animate: false
+ });
+ }
+
+ const addGeoJsonLayer = (map, data) => {
+ if (map.getLayer("highlight-layer")) {
+ map.removeLayer("highlight-layer");
+ }
+ if (map.getLayer("geojson-layer")) {
+ map.removeLayer("geojson-layer");
+ }
+ if (map.getSource("geojson-data")) {
+ map.removeSource("geojson-data");
+ }
+
+ map.addSource("geojson-data", {
+ type: "geojson",
+ data,
+ });
+
+ if (!map.getLayer("highlight-layer")) {
+ map.addLayer({
+ id: "highlight-layer",
+ type: "fill",
+ source: "geojson-data",
+ paint: {
+ "fill-color": "#FFFFFF",
+ "fill-opacity": 0.5,
+ },
+ filter: ["==", "col_id", ""],
+ });
+ }
+
+
+ if (!map.getLayer("geojson-layer")) {
+ map.addLayer({
+ id: "geojson-layer",
+ type: "fill",
+ source: "geojson-data",
+ paint: {
+ "fill-color": "#FFFFFF",
+ "fill-opacity": 0.2,
+ },
+ });
+
+ map.on("click", "geojson-layer", (e) => {
+ const feature = e.features?.[0];
+ const col_id = feature?.properties?.col_id;
+ if (col_id) {
+ window.open(`/columns/${col_id}`, "_blank");
+ }
+ });
+
+ map.on("mousemove", "geojson-layer", (e) => {
+ map.getCanvas().style.cursor = "pointer";
+ const feature = e.features?.[0];
+ const col_id = feature?.properties?.col_id;
+ if (col_id) {
+ map.setFilter("highlight-layer", ["==", "col_id", col_id]);
+ }
+ });
+
+ map.on("mouseleave", "geojson-layer", () => {
+ map.getCanvas().style.cursor = "";
+ map.setFilter("highlight-layer", ["==", "col_id", ""]);
+ });
+ }
+ };
+
+ return h("div.map-container",
+ h(MapAreaContainer, {
+ className: "map-area-container",
+ },
+ h(MapView, {
+ style: "mapbox://styles/jczaplewski/cl5uoqzzq003614o6url9ou9z?optimize=true",
+ mapboxToken: SETTINGS.mapboxAccessToken,
+ mapPosition,
+ onMapLoaded: handleMapLoaded,
+ })
+ )
+ );
+}
diff --git a/pages/layout.module.sass b/pages/layout.module.sass
index c17982efc..1b06c3e3f 100644
--- a/pages/layout.module.sass
+++ b/pages/layout.module.sass
@@ -1,6 +1,3 @@
-.content-page
- margin: 0 4em
-
:global(.in-page-transition)
height: 100vh
overflow: hidden
@@ -18,3 +15,103 @@
height: 100vh
overflow: hidden
position: relative
+
+.app-shell
+ background-color: var(--background-color)
+
+#map
+ height: 100%
+ width: 100%
+ aspect-ratio: 3/2
+ cursor: pointer
+ z-index: 100
+
+.map-area-container
+ width: 100% !important
+ height: 50vh !important
+
+// davids
+.nav
+ position: fixed
+ top: 0
+ left: 0
+ width: 100%
+ z-index: 10000
+ display: flex
+ gap: 20px
+ background-color: #015eab
+ height: 5vh
+ padding: 0 10px
+ align-items: center
+
+ .nav-link
+ display: flex
+ justify-content: center
+ align-items: center
+
+ a
+ color: white !important
+ text-align: center
+ text-decoration: none
+
+
+.footer
+ width: 100%
+ position: absolute
+ left: 0
+ background-color: #015EAB
+ margin: 0
+ a
+ color: white !important
+
+ .footer-nav
+ display: flex
+ flex-direction: column
+ justify-content: center
+ align-items: center
+ gap: 10px
+
+ a
+ color: white !important
+
+ a:hover
+ text-decoration: none
+
+ .footer-container
+ display: flex
+ flex-direction: row
+ justify-content: space-between
+ margin: 0 auto
+ width: 60%
+
+ .footer-text-container
+ display: flex
+ flex-direction: column
+ justify-content: center
+ align-items: center
+ color: white
+ margin: 1em 0
+
+ .nav-logo
+ padding-top: 5px
+
+ .git_logo
+ vertical-align: sub
+
+ .f1-text
+ display: flex
+ gap: 7px
+
+ a
+ color: white
+
+ #who-made-it
+ padding-top: 25px
+
+.loading
+ text-align: center
+ padding-top: 20vh
+ height: 100vh
+ display: flex
+ flex-direction: column
+ gap: 2em
\ No newline at end of file
diff --git a/pages/lex/+Page.mdx b/pages/lex/+Page.mdx
index e4ab1b4a4..9f48af758 100644
--- a/pages/lex/+Page.mdx
+++ b/pages/lex/+Page.mdx
@@ -12,7 +12,18 @@ researchers and data providers.
A tree-based representation of lithologies
+
+ A tree-based representation of environments
+
+
+ A tree-based representation of economics
+
+
+ A tree-based representation of intervals
+
+
+
**[Sift](/sift)**, Macrostrat's legacy lexicon app, is still available for use
as it is gradually brought into this new framework.
diff --git a/pages/lex/StratNameHierarchy.ts b/pages/lex/StratNameHierarchy.ts
new file mode 100644
index 000000000..cb1bf9a80
--- /dev/null
+++ b/pages/lex/StratNameHierarchy.ts
@@ -0,0 +1,94 @@
+import h from "@macrostrat/hyper";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { Hierarchy } from "@macrostrat/data-components";
+import { useState } from "react";
+
+export function StratNameHierarchy( { id } ) {
+ const data = fetchStratNames({ id });
+ if (data == null) return h("div", "Loading...");
+
+ return h(Hierarchy, {...data});
+}
+
+var rankMap = {
+ SGp: null,
+ Gp: "sgp",
+ SubGp: "gp",
+ Fm: "subgp",
+ Mbr: "fm",
+ Bed: "mbr",
+ 1: null,
+ 2: "sgp",
+ 3: "gp",
+ 4: "subgp",
+ 5: "fm",
+ 6: "mbr",
+};
+var rankMapOrder = { SGp: 1, Gp: 2, SubGp: 3, Fm: 4, Mbr: 5, Bed: 6 };
+
+function fetchStratNames({ id }) {
+ const urlBase= "https://macrostrat.org/api/v2/defs";
+ const url = urlBase + "/strat_names?rule=all&strat_name_id=" + id;
+
+ // function to fetch stratnames and orgnize hierarchy
+ const data = useAPIResult(url)?.success?.data;
+
+ if (data == null) return null;
+
+ data.forEach((d) => {
+ // Figure out if this is the target name or not
+ d.active = false;
+ if (d.strat_name_id == id) {
+ d.active = true;
+ }
+
+ d.children = [];
+ d.totalChildren =
+ data.filter((j) => {
+ if (j[d.rank.toLowerCase() + "_id"] == d.strat_name_id) {
+ return j;
+ }
+ }).length - 1;
+ d.total = d.totalChildren;
+ });
+
+ data.forEach((d) => {
+ var belongsTo = d[rankMap[d.rank] + "_id"];
+
+ // Need to make sure belongsTo doesn't = 0 when it shouldn't (ex: strat_name_id=9574)
+ var previousRank = 1;
+ while (belongsTo === 0) {
+ belongsTo = d[rankMap[rankMapOrder[d.rank] - previousRank] + "_id"];
+ previousRank--;
+ }
+
+ // Find the one it belongs to and add it
+ data.forEach((j) => {
+ if (j.strat_name_id == belongsTo && j.strat_name_id != d.strat_name_id) {
+ j.children.push(d);
+ }
+ });
+ });
+
+ const hierarchy = data.sort((a, b) => {
+ return b.totalChildren - a.totalChildren;
+ })[0];
+
+ const mappedData = mapToHier(hierarchy);
+ // Find the top of the hierarchy and return it
+ return mappedData;
+};
+
+const mapToHier = (data) => {
+ const Hier = {};
+ Hier.name = data.strat_name_long;
+ Hier.units = data.t_units;
+ Hier.active = data.active;
+ Hier.onClick = (e) => {
+ e.preventDefault();
+ const url = `/lex/strat-names/${data.strat_name_id}`;
+ window?.open(url, "_blank")?.focus();
+ };
+ Hier.subhierarchy = data.children.map((c) => mapToHier(c));
+ return Hier;
+};
\ No newline at end of file
diff --git a/pages/lex/economics/+Page.client.ts b/pages/lex/economics/+Page.client.ts
new file mode 100644
index 000000000..8f4f4b1ac
--- /dev/null
+++ b/pages/lex/economics/+Page.client.ts
@@ -0,0 +1,122 @@
+import h from "./main.module.scss";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Popover } from "@blueprintjs/core";
+import { useState } from "react";
+import { ContentPage } from "~/layouts";
+import { asChromaColor } from "@macrostrat/color-utils";
+import { Loading } from '../../index';
+
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/econs?all")?.success.data;
+
+ if (res == null) return h(Loading);
+
+ console.log(res);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ const filtered = res.filter((d) => {
+ const name = d.name.toLowerCase();
+ const className = d.class.toLowerCase();
+ const type = d.type ? d.type.toLowerCase() : "";
+ return name.includes(input) || className.includes(input) || type.includes(input);
+ });
+
+ const grouped = groupByClassThenType(filtered);
+
+ return h(ContentPage, { className: 'econ-list-page'}, [
+ h(PageBreadcrumbs, { title: "Economics" }),
+ h(Card, { className: 'filters' }, [
+ h('h3', "Filters"),
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Search economics...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.econ-list',
+ Object.entries(grouped).map(([className, types]) =>
+ h('div.econ-class-group', [
+ h('h2', UpperCase(className)),
+ ...Object.entries(types).map(([type, group]) =>
+ h('div.econ-group', [
+ h('h3', UpperCase(type)),
+ h('div.econ-items', group.map((d) => h(EconItem, { data: d, key: d.environ_id }))),
+ ])
+ )
+ ])
+ )
+ )
+ ]);
+}
+
+function EconItem({ data }) {
+ const { name, color, econ_id, t_units } = data;
+ const luminance = 0.9;
+ const chromaColor = asChromaColor(color);
+
+ return h(Popover, {
+ className: "econ-item-popover",
+ content: h('div.econ-tooltip', [
+ h('div.econ-tooltip-id', "ID - #" + econ_id),
+ h('div.econ-tooltip-t-unit', "Time Units - " + t_units),
+ h('a', { href: `/lex/economics/${econ_id}`, className: 'econ-tooltip-link' }, "View details"),
+ ]),
+ },
+ h('div.econ-item', [
+ h('div.econ-name', { style: { color: chromaColor?.luminance(luminance).hex(), backgroundColor: chromaColor?.luminance(1 - luminance).hex() } }, name),
+ ])
+ )
+
+ return ;
+}
+
+function getContrastTextColor(bgColor) {
+ // Remove '#' if present
+ const color = bgColor.replace('#', '');
+
+ // Parse r, g, b
+ const r = parseInt(color.substr(0, 2), 16);
+ const g = parseInt(color.substr(2, 2), 16);
+ const b = parseInt(color.substr(4, 2), 16);
+
+ // Calculate luminance
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
+
+ // Return black or white depending on luminance
+ return luminance > 0.6 ? '#000000' : '#FFFFFF';
+}
+
+function groupByClassThenType(items) {
+ return items.reduce((acc, item) => {
+ const { class: className, type } = item;
+
+ // Only include items with a valid type (not null, undefined, or empty string)
+ if (!type || type.trim() === '') {
+ return acc; // Skip this item if it has no valid type
+ }
+
+ if (!acc[className]) {
+ acc[className] = {};
+ }
+ if (!acc[className][type]) {
+ acc[className][type] = [];
+ }
+
+ acc[className][type].push(item);
+ return acc;
+ }, {});
+}
+
+function UpperCase(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
\ No newline at end of file
diff --git a/pages/lex/economics/@id/+Page.client.ts b/pages/lex/economics/@id/+Page.client.ts
new file mode 100644
index 000000000..5eaf06ab4
--- /dev/null
+++ b/pages/lex/economics/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "econ_id", "econs")
+}
\ No newline at end of file
diff --git a/pages/lex/economics/main.module.scss b/pages/lex/economics/main.module.scss
new file mode 100644
index 000000000..4d329fde0
--- /dev/null
+++ b/pages/lex/economics/main.module.scss
@@ -0,0 +1,67 @@
+h3, h2 {
+ margin: 0;
+ padding: 0;
+}
+
+.econ-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ .econ-class-group {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+
+ .econ-group {
+ border-left: 2px solid rgb(56, 62, 71);
+ padding-left: 1em;
+
+ .econ-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .econ-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+ }
+ }
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.econ-tooltip {
+ padding: 0.5em;
+}
+
+.filters, .econ-list-page {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
\ No newline at end of file
diff --git a/pages/lex/environments/+Page.client.ts b/pages/lex/environments/+Page.client.ts
new file mode 100644
index 000000000..c03f911d2
--- /dev/null
+++ b/pages/lex/environments/+Page.client.ts
@@ -0,0 +1,103 @@
+import h from "./main.module.scss";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, AssistantLinks, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Popover } from "@blueprintjs/core";
+import { useState } from "react";
+import { ContentPage } from "~/layouts";
+import { asChromaColor } from "@macrostrat/color-utils";
+import { Loading } from "../../index";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/environments?all")?.success.data;
+
+ if (res == null) return h(Loading);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ const filtered = res.filter((d) => {
+ const name = d.name.toLowerCase();
+ const className = d.class.toLowerCase();
+ const type = d.type ? d.type.toLowerCase() : "";
+ return name.includes(input) || className.includes(input) || type.includes(input);
+ });
+
+ const grouped = groupByClassThenType(filtered);
+
+ return h(ContentPage, { className: 'environ-list-page'}, [
+ h(PageBreadcrumbs, { title: "Environments" }),
+ h(Card, [
+ h('h3', "Filters"),
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Search environments...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.environment-list',
+ Object.entries(grouped).map(([className, types]) =>
+ h('div.environment-class-group', [
+ h('h2', UpperCase(className)),
+ ...Object.entries(types).map(([type, group]) =>
+ h('div.environment-group', [
+ h('h3', UpperCase(type)),
+ h('div.environment-items', group.map((d) => h(EnvironmentItem, { data: d, key: d.environ_id }))),
+ ])
+ )
+ ])
+ )
+ )
+ ]);
+}
+
+function EnvironmentItem({ data }) {
+ const { environ_id, name, color, t_units } = data;
+
+ const chromaColor = asChromaColor(color)
+
+ const luminance = 0.9;
+
+ return h(Popover, {
+ className: "environ-item-popover",
+ content: h('div.environ-tooltip', [
+ h('div.environ-tooltip-id', "ID - #" + environ_id),
+ h('div.environ-tooltip-t-unit', "Time Units - " + t_units),
+ h('a', { href: `/lex/environments/${environ_id}` }, "View details")
+ ]),
+ },
+ h('div.environ-item', [
+ h('div.environ-name', { style: { "backgroundColor": chromaColor?.luminance(1 - luminance).hex(), "color": chromaColor?.luminance(luminance).hex()} }, name),
+ ])
+ )
+}
+
+function groupByClassThenType(items) {
+ return items.reduce((acc, item) => {
+ const { class: className, type } = item;
+
+ // Only include items with a valid type (not null, undefined, or empty string)
+ if (!type || type.trim() === '') {
+ return acc; // Skip this item if it has no valid type
+ }
+
+ if (!acc[className]) {
+ acc[className] = {};
+ }
+ if (!acc[className][type]) {
+ acc[className][type] = [];
+ }
+
+ acc[className][type].push(item);
+ return acc;
+ }, {});
+}
+
+function UpperCase(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
\ No newline at end of file
diff --git a/pages/lex/environments/@id/+Page.client.ts b/pages/lex/environments/@id/+Page.client.ts
new file mode 100644
index 000000000..c4acd362b
--- /dev/null
+++ b/pages/lex/environments/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "environ_id", "environments")
+}
\ No newline at end of file
diff --git a/pages/lex/environments/main.module.scss b/pages/lex/environments/main.module.scss
new file mode 100644
index 000000000..1dbd67f39
--- /dev/null
+++ b/pages/lex/environments/main.module.scss
@@ -0,0 +1,73 @@
+h3, h2 {
+ margin: 0;
+ padding: 0;
+}
+
+.environ-list-page {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.environment-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ .environment-class-group {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+
+ .environment-group {
+ border-left: 2px solid rgb(56, 62, 71);
+ padding-left: 1em;
+
+ .environment-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .environ-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+ }
+ }
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.environ-tooltip {
+ padding: 0.5em;
+}
+
+.filters {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
\ No newline at end of file
diff --git a/pages/lex/index.ts b/pages/lex/index.ts
new file mode 100644
index 000000000..b536cc316
--- /dev/null
+++ b/pages/lex/index.ts
@@ -0,0 +1,679 @@
+import h from "./main.module.sass";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, Link, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Popover, Divider, RangeSlider } from "@blueprintjs/core";
+import { ContentPage } from "~/layouts";
+import { BlankImage } from "../index";
+import { useState, useCallback, act } from "react";
+import { asChromaColor } from "@macrostrat/color-utils";
+import { DarkModeButton } from "@macrostrat/ui-components";
+import { PieChart, Pie, Cell, ResponsiveContainer, Label } from 'recharts';
+import { Loading, ColumnsMap } from "../index";
+import { Parenthetical, Hierarchy } from "@macrostrat/data-components";
+import { Duration } from "@macrostrat/column-views";
+import { useDarkMode } from "@macrostrat/ui-components";
+import { StratNameHierarchy } from "./StratNameHierarchy";
+import { LinkCard } from "~/components/cards";
+
+export function titleCase(str) {
+ if (!str) return str;
+ return str
+ .toLowerCase()
+ .split(' ')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
+ .join(' ');
+}
+
+export function IndividualPage(id, type, header) {
+ // for fetching fossil data with strat concept
+ if (type === "concept_id") {
+ type = "strat_name_concept_id";
+ }
+
+ const [activeIndex, setActiveIndex] = useState(null);
+ const intRes = useAPIResult(SETTINGS.apiV2Prefix + "/defs/" + header + "?" + type + "=" + id)?.success.data[0];
+ const fossilResult = useAPIResult(SETTINGS.apiV2Prefix + "/fossils?" + type + "=" + id)?.success;
+ const colDataResult = useAPIResult(SETTINGS.apiV2Prefix + "/columns?" + type + "=" + id + "&response=long&format=geojson")?.success;
+ const fossilRes = fossilResult?.data;
+ const colData = colDataResult?.data;
+ const cols = colData?.features.map((feature) => feature.properties.col_id).join(',')
+ const taxaData = useAPIResult("https://paleobiodb.org/data1.2/occs/prevalence.json?limit=5&coll_id=" + cols)
+
+ const siftLink = header === "intervals" ? "interval" : header === "environments" ? "environment" : header === "lithologies" ? "lithology" : header === "economics" ? "economic" : header === "strat_name_concepts" ? "strat_name_concept" : "strat_name";
+
+ // data for charts
+ const liths = summarizeAttributes(colData?.features, 'lith')
+ const environs = summarizeAttributes(colData?.features, 'environ')
+ const econs = summarizeAttributes(colData?.features, 'econ')
+ const summary = summarize(colData?.features);
+
+ const chromaColor = intRes?.color ? asChromaColor(intRes.color) : null;
+ const luminance = .9;
+
+ if (!intRes || !fossilRes) return h(Loading);
+
+ const { name, abbrev, b_age, t_age, timescales, strat_name, concept_id } = intRes;
+ const { t_units, t_sections, t_int_name, pbdb_collections, b_int_name, max_thick, col_area } = summary
+ const area = parseInt(col_area.toString().split('.')[0]);
+
+ return h(ContentPage, { className: 'int-page'}, [
+ h(PageBreadcrumbs, { title: "#" + id }),
+ h('div.int-header', [
+ h('div.int-names', [
+ h('div.int-name', { style: { "backgroundColor": chromaColor?.luminance(1 - luminance).hex(), "color": chromaColor?.luminance(luminance).hex()} }, UpperCase(strat_name ? strat_name : name)),
+ abbrev ? h('div.int-abbrev', [
+ h('p', " aka "),
+ h('div.int-abbrev-item', { style: { "backgroundColor": chromaColor?.luminance(1 - luminance).hex(), "color": chromaColor?.luminance(luminance).hex()} }, abbrev)
+ ]) : null,
+ ]),
+ h('div.sift-link', [
+ h('p', "This page is is in development."),
+ h('a', { href: "/sift/" + siftLink + "/" + id, target: "_blank" }, "View in Sift")
+ ]),
+ ]),
+ h.if(concept_id)(conceptInfo, { concept_id } ),
+ h.if(colData?.features.length)('div.table', [
+ h('div.table-content', [
+ h('div.packages', t_sections.toLocaleString() + " packages"),
+ h(Divider, { className: 'divider' }),
+ h('div.units', t_units.toLocaleString() + ' units'),
+ h(Divider, { className: 'divider' }),
+ h('div.interval', b_int_name.toLocaleString() + " - " + t_int_name),
+ h.if(b_age && t_age)(Divider, { className: 'divider' }),
+ h.if(b_age && t_age)('div.age-range', [
+ h('div.int-age', b_age + " - " + t_age + " Ma"),
+ // h(Parenthetical, { className: "range"}, h(Duration, { value: b_age - t_age })),
+ ]),
+ h(Divider, { className: 'divider' }),
+ h('div.area', [
+ h('p', area.toLocaleString() + " km"),
+ h('sup', "2"),
+ ]),
+ h(Divider, { className: 'divider' }),
+ h('div.thickness', "≤ " + max_thick.toLocaleString() + 'm thick'),
+ h(Divider, { className: 'divider' }),
+ h('div.collections', pbdb_collections.toLocaleString() + ' collections'),
+ ]),
+ colData ? h(ColumnsMap, { columns: colData }) : h(Loading),
+ ]),
+ h('div.charts', [
+ h.if(liths?.length)('div.chart', Chart(liths, "Lithologies", "lithology", activeIndex, setActiveIndex)),
+ h.if(econs?.length)('div.chart', Chart(econs, "Economics", "economics", activeIndex, setActiveIndex)),
+ h.if(environs?.length)('div.chart', Chart(environs, "Environments", "environments", activeIndex, setActiveIndex)),
+ ]),
+
+ h.if(taxaData)(PrevalentTaxa, { data: taxaData}),
+ h.if(header === "strat_names")(StratNameHierarchy, { id }),
+ // h.if(header === "strat_name_concepts")(ConceptHierarchy, { id}),
+ h.if(timescales?.[0]?.name)('div.int-timescales', [
+ h('h3', "Timescales"),
+ h('ul', timescales?.map((t) => h('li', h(Link, { href: "/lex/timescales/" + t.timescale_id}, titleCase(t.name))))),
+ ]),
+ h(References, { res1: fossilResult, res2: colDataResult}),
+ h(DarkModeButton)
+ ]);
+}
+
+function UpperCase(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+
+function References({ res1, res2 }) {
+ if (res1 == null || res2 == null) return h(Loading);
+
+ const refArray1 = Object.values(res1.refs);
+ const refArray2 = Object.values(res2.refs);
+ const refs = [...refArray1, ...refArray2];
+
+ return h.if(refs?.length != 0)('div.int-references', [
+ h('h3', "Primary Sources"),
+ h(Divider),
+ h('ol.ref-list', refs.map((r) => h('li.ref-item', r))),
+ ]);
+}
+
+function PrevalentTaxa({data}) {
+ const records = data?.records;
+
+ return h(Card, { className: 'prevalent-taxa-container' }, [
+ h('div.taxa-header', [
+ h('h3', "Prevalent Taxa"),
+ h('div.link', [
+ h('p', 'via'),
+ h('a', { href: "https://paleobiodb.org/#/" }, "PaleoBioDB")
+ ]),
+ ]),
+ records?.map((record) => Taxa(record))
+ ])
+}
+
+function Taxa(record) {
+ const imgUrl = "https://paleobiodb.org/data1.2/taxa/thumb.png?id=";
+ const isDarkMode = useDarkMode().isEnabled;
+
+ return h('div.taxa', [
+ h(BlankImage, { src: imgUrl + record.img, className: 'taxa-image' + (isDarkMode ? ' img-dark-mode' : '') }),
+ h('p.name', record.nam)
+ ])
+}
+
+function ConceptHierarchy({ id }) {
+ const url = SETTINGS.apiV2Prefix + "/defs/strat_names?strat_name_concept_id=" + id;
+ const data = useAPIResult(url)?.success?.data;
+ if (!data) return h(Loading);
+
+ console.log("Concept Hierarchy Data:", data);
+
+ return h('div.concept-hierarchy', [
+ data.map((item) => {
+ const { t_units, strat_name, rank } = item;
+ return h(LinkCard, {
+ title: h('div.concept-item', [
+ h('p', strat_name + " " + (rank ? "(" + rank + ")" : "")),
+ h('p', t_units),
+ ]),
+ });
+ }),
+ ])
+}
+
+function conceptInfo({concept_id}) {
+ const url = SETTINGS.apiV2Prefix + "/defs/strat_name_concepts?strat_name_concept_id=" + concept_id;
+ const data = useAPIResult(url)?.success?.data[0];
+
+ if (!data) return h(Loading);
+
+ const { author, name, province, geologic_age, other, usage_notes } = data;
+
+ return h('div.concept-info', [
+ h('h3', "Stratigraphic Concept"),
+ h('div.concept-name', [
+ h("a.title", { href: "/lex/strat-name-concepts/" + concept_id, target: "_blank"}, name),
+ h('a.concept-ref', { href: url, target: "_blank" }, "via " + author)
+ ]),
+ h.if(province)('div.province', [
+ h('span.title', "Province: "),
+ h('span.province-text', province)
+ ]),
+ h.if(geologic_age)('div.geologic-age', [
+ h('span.title', "Geologic Age: "),
+ h('span.geologic-age-text', geologic_age)
+ ]),
+ h.if(other)('div.other', [
+ h('span.title', "Other: "),
+ h('span.other-text', other)
+ ]),
+ h.if(usage_notes)('div.usage-notes', [
+ h('span.title', "Usage: "),
+ h('span.usage-text', usage_notes)
+ ])
+ ])
+}
+
+export function summarizeAttributes(data, type) {
+ var index = {};
+ if(!data) return null
+
+ for (var i = 0; i < data.length; i++) {
+ for (var j = 0; j < data[i].properties[type].length; j++) {
+ // If we have seen this attribute ID before, add to the summary
+ if (index[data[i].properties[type][j][type + "_id"]]) {
+ index[data[i].properties[type][j][type + "_id"]].prop +=
+ data[i].properties[type][j].prop;
+ } else {
+ index[data[i].properties[type][j][type + "_id"]] =
+ data[i].properties[type][j];
+ }
+ }
+ }
+
+
+ var parsed = Object.keys(index).map((d) => {
+ index[d].prop = index[d].prop / data.length;
+ return index[d];
+ });
+
+ return parseAttributes(type, parsed);
+ }
+
+export function summarize(data) {
+ const summary = {
+ col_area: 0,
+ max_thick: 0,
+ min_min_thick: Infinity,
+ b_age: 0,
+ t_age: Infinity,
+ b_int_name: "",
+ t_int_name: "",
+ pbdb_collections: 0,
+ t_units: 0,
+ t_sections: 0,
+ };
+
+ if (!Array.isArray(data)) return summary;
+
+ for (const { properties } of data) {
+ const {
+ col_area,
+ max_thick,
+ min_min_thick,
+ b_age,
+ t_age,
+ b_int_name,
+ t_int_name,
+ pbdb_collections,
+ t_units,
+ t_sections,
+ } = properties;
+
+ summary.col_area += col_area;
+ summary.pbdb_collections += pbdb_collections;
+ summary.t_units += t_units;
+ summary.t_sections += t_sections;
+
+ if (max_thick > summary.max_thick) summary.max_thick = max_thick;
+ if (min_min_thick < summary.min_min_thick) summary.min_min_thick = min_min_thick;
+ if (b_age > summary.b_age) {
+ summary.b_age = b_age;
+ summary.b_int_name = b_int_name;
+ }
+ if (t_age < summary.t_age) {
+ summary.t_age = t_age;
+ summary.t_int_name = t_int_name;
+ }
+ }
+
+ return summary;
+}
+
+const typeLookup = {
+ environ: "environment",
+ lith: "lithology",
+ econ: "economic",
+};
+
+var Config = {
+
+ // http://color.hailpixel.com/#366EA6,F9D862,DD98BC,111111,C96566,3D9970,D06CAD,6D3B22,D76433,BD3239,AB6836,
+ lithColors: {
+ carbonate: "#366EA6",
+ siliciclastic: "#F9D862",
+ evaporite: "#DD98BC",
+ organic: "#111111",
+ chemical: "#c96566",
+ volcanic: "#3D9970",
+ plutonic: "#D06CAD",
+ metamorphic: "#6D3B22",
+ sedimentary: "#D76433",
+ igneous: "#BD3239",
+ metasedimentary: "#AB6836",
+ "1": "#FFF400",
+ "2": "#FFAB00",
+ "3": "#FFCA00",
+ "4": "#919AA3",
+ "5": "#A7ACB0",
+ "6": "#B2B5B7",
+ "7": "#9CA3AA",
+ "8": "#7B8896",
+ "9": "#86919D",
+ "10": "#FFD500",
+ "11": "#FFEA00",
+ "12": "#FFDF00",
+ "14": "#FFC000",
+ "15": "#FFB500",
+ "16": "#FF9600",
+ "17": "#0000FF",
+ "18": "#0508FD",
+ "19": "#0B11FC",
+ "20": "#111AFB",
+ "21": "#1723FA",
+ "22": "#1D2BF9",
+ "23": "#2334F8",
+ "24": "#293DF7",
+ "25": "#2F46F6",
+ "26": "#344EF5",
+ "27": "#3A57F4",
+ "28": "#4060F3",
+ "29": "#4669F2",
+ "30": "#4C71F1",
+ "31": "#527AF0",
+ "32": "#5883EF",
+ "33": "#5E8CEE",
+ "34": "#FFB6C1",
+ "35": "#F9AFBA",
+ "36": "#F3A8B3",
+ "37": "#EEA2AD",
+ "38": "#000000",
+ "39": "#090F0F",
+ "40": "#121F1F",
+ "43": "#1C2F2F",
+ "44": "#253F3F",
+ "45": "#CD5C5C",
+ "46": "#C96566",
+ "47": "#C66F70",
+ "48": "#C37879",
+ "49": "#FFFF00",
+ "52": "#FF4500",
+ "53": "#FF4208",
+ "54": "#FF3F11",
+ "55": "#FF3C19",
+ "56": "#FF3922",
+ "57": "#FF362B",
+ "58": "#FF3333",
+ "59": "#FF303C",
+ "60": "#FF2D45",
+ "61": "#FF2B4D",
+ "62": "#FF2856",
+ "63": "#006400",
+ "64": "#096C09",
+ "65": "#127512",
+ "66": "#1B7D1B",
+ "67": "#248624",
+ "68": "#2C8F2C",
+ "69": "#369736",
+ "70": "#3FA03F",
+ "71": "#48A948",
+ "72": "#51B151",
+ "73": "#59BA59",
+ "74": "#63C263",
+ "75": "#6CCB6C",
+ "76": "#75D475",
+ "77": "#7EDC7E",
+ "78": "#8B4513",
+ "79": "#8E491B",
+ "80": "#914E23",
+ "81": "#94532B",
+ "82": "#985834",
+ "83": "#9B5D3C",
+ "84": "#9E6244",
+ "85": "#A1674C",
+ "86": "#A56C55",
+ "87": "#A8715D",
+ "88": "#AB7665",
+ "89": "#AE7B6D",
+ "90": "#B28076",
+ "91": "#708090",
+ "92": "#6495ED",
+ "93": "#BEBEBE",
+ "94": "#FF255F",
+ "95": "#FF0000",
+ "96": "#87E587",
+ "97": "#FFA000",
+ "98": "#B5857E",
+ "99": "#FF2267",
+ "100": "#FF1F70",
+ "101": "#FF1C79",
+ "102": "#90EE90",
+ "103": "#BF8283",
+ "104": "#BC8B8E",
+ "105": "#FF1981",
+ "106": "#B99598",
+ "107": "#FF168A",
+ "108": "#FF1493",
+ "109": "#B88A86",
+ "110": "#BC8F8F",
+ "111": "#FF8C00",
+ "112": null,
+ "113": "#FFDF00",
+ "114": "#527AF0",
+ },
+
+ // http://color.hailpixel.com/#366EA6,F9D862,33A373,31909B,635A21,BFECF3,B8794C,366EA6,635A21,
+ environColors: {
+ carbonate: "#366EA6",
+ siliciclastic: "#F9D862",
+ fluvial: "#33A373",
+ lacustrine: "#31909B",
+ landscape: "#635A21",
+ glacial: "#BFECF3",
+ eolian: "#B8794C",
+ marine: "#366EA6",
+ "non-marine": "#635A21",
+ Unknown: "#777777",
+ "1": "#B8B8E6",
+ "2": "#3399FF",
+ "3": "#3399FF",
+ "4": "#B8B8E6",
+ "5": "#5CADFF",
+ "6": "#33CCFF",
+ "7": "#33CCFF",
+ "8": "#33CCFF",
+ "9": "#2EB8E6",
+ "10": "#2EB8E6",
+ "11": "#297ACC",
+ "12": "#297ACC",
+ "13": "#246BB2",
+ "14": "#246BB2",
+ "15": "#246BB2",
+ "16": "#1F5C99",
+ "17": "#1F5C99",
+ "18": "#1F5C99",
+ "19": "#1A4C80",
+ "20": "#1A4C80",
+ "21": "#007A5C",
+ "22": "#007A5C",
+ "23": "#007A5C",
+ "24": "#007A5C",
+ "25": "#33D6AD",
+ "26": "#99EBD6",
+ "27": "#80E6CC",
+ "28": "#B2F0E0",
+ "29": "#19D1A3",
+ "30": "#19D1A3",
+ "31": "#00B88A",
+ "32": "#00CC99",
+ "33": "#00CC99",
+ "34": "#00523D",
+ "35": "#00291F",
+ "36": "#00291F",
+ "37": "#00664C",
+ "38": "#CCFFFF",
+ "39": "#00B88A",
+ "41": "#FFD6AD",
+ "42": "#FFD6AD",
+ "43": "#FFCC99",
+ "44": "#FFEAD6",
+ "45": "#669900",
+ "46": "#75A319",
+ "47": "#669900",
+ "48": "#5C8A00",
+ "49": "#5C8A00",
+ "52": "#A3C266",
+ "55": "#94B84D",
+ "56": "#94B84D",
+ "57": "#669900",
+ "58": "#75A319",
+ "59": "#75A319",
+ "61": "#00B88A",
+ "62": "#D6D6FF",
+ "63": "#DBDBFF",
+ "64": "#DBDBFF",
+ "65": "#DBDBFF",
+ "66": "#DBDBFF",
+ "67": "#DBDBFF",
+ "68": "#8AE68A",
+ "69": "#8AE68A",
+ "70": "#8AE68A",
+ "71": "#8AE68A",
+ "72": "#EBFFEB",
+ "73": "#ADFFAD",
+ "74": "#6BB26B",
+ "75": "#7ACC7A",
+ "76": "#A3FFA3",
+ "77": "#ADFFAD",
+ "78": "#E0FFE0",
+ "79": "#D6D6C2",
+ "80": "#D6D6C2",
+ "81": "#3D3D29",
+ "82": "#999966",
+ "83": "#B8B894",
+ "84": "#6B6B47",
+ "85": "#F5F5F0",
+ "86": "#6B6B47",
+ "87": "#D6D6C2",
+ "88": "#CCFFCC",
+ "89": "#74CDCD",
+ "90": "#B8B894",
+ "91": "#00664C",
+ "92": "#CCF5EB",
+ "93": "#D6F5FF",
+ },
+
+ // http://color.hailpixel.com/#4B89C3,000000,B4903C,543A1C,5A7728,
+ econColors: {
+ mineral: "#5A7728",
+ hydrocarbon: "#543A1C",
+ construction: "#777777",
+ nuclear: "#B4903C",
+ coal: "#000000",
+ aquifer: "#4B89C3",
+ "1": "#33334C",
+ "2": "#A3A3C2",
+ "3": "#666699",
+ "4": "#33334C",
+ "5": "#A3A3C2",
+ "6": "#666699",
+ "7": "#666699",
+ "8": "#A3A3C2",
+ "9": "#33334C",
+ "10": "#7A007A",
+ "11": "#000066",
+ "12": "#333300",
+ "13": "#000000",
+ "14": "#E6E600",
+ "15": "#999966",
+ "16": "#E6E600",
+ "17": "#3385FF",
+ "18": "#99C2FF",
+ "19": "#85ADAD",
+ "20": "#5C8A8A",
+ "21": "#3385FF",
+ "22": "#990033",
+ "23": "#FFFF99",
+ },
+};
+
+function parseAttributes(type, data) {
+ var parsed = [];
+
+ if (data.length > 5) {
+ var types = {};
+ data.forEach((d) => {
+ if (types[d.type]) {
+ types[d.type].value += d.prop;
+ } else {
+ types[d.type || d.class] = {
+ id: d[type + "_id"],
+ type: typeLookup[type],
+ value: d.prop,
+ label:
+ type === "environ"
+ ? d.class + ": " + (d.type || d.class)
+ : d.type || d.class,
+ color: Config[type + "Colors"][d.type || d.class],
+ };
+ }
+ });
+
+ Object.keys(types).forEach((d) => {
+ parsed.push(types[d]);
+ });
+ } else {
+ data.forEach((d) => {
+ parsed.push({
+ id: d[type + "_id"],
+ type: typeLookup[type],
+ value: d.prop || 1 / data.length,
+ label: type === "environ" ? d.class + ": " + d.name : d.name,
+ color: Config[type + "Colors"][d[type + "_id"]],
+ });
+ });
+ }
+
+ return parsed;
+}
+
+function Chart(data, title, route, activeIndex, setActiveIndex) {
+ return h('div.chart-container', [
+ h('h3', title),
+ h(ResponsiveContainer, { width: "100%", height: 300 },
+ h(PieChart, {className: 'lithology-chart' },
+ h(Pie, {
+ data,
+ dataKey: "value",
+ nameKey: "label",
+ outerRadius: 120,
+ innerRadius: 80,
+ cx: "50%",
+ cy: "50%",
+ fill: "#8884d8",
+ },
+ data?.map((entry, index) => (
+ h(Cell, {
+ className: `id-${entry.id}`,
+ key: `cell-${index}`,
+ fill: entry.color,
+ stroke:
+ activeIndex?.index === index &&
+ activeIndex.label === entry.label
+ ? '#fff'
+ : '#000',
+ strokeWidth: 2,
+ onMouseEnter: () => {
+ if (
+ !activeIndex ||
+ activeIndex.index !== index ||
+ activeIndex.label !== entry.label
+ ) {
+ setActiveIndex({ index, label: entry.label });
+ }
+ },
+ onMouseLeave: () => {
+ if (activeIndex) {
+ setActiveIndex(null);
+ }
+ },
+ onClick: (e) => {
+ const id = e.target.className.baseVal.split(" ")[1].split("-")[1];
+ const url = "/lex/" + route + "/" + id;
+ window.open(url, "_blank")
+ }
+ })
+ )
+ )
+ ),
+ )
+ ),
+ h('div.legend', data?.map((item, index) => ChartLegend(item, route, activeIndex, setActiveIndex, index))),
+ ])
+}
+
+function ChartLegend(data, route, activeIndex, setActiveIndex, index) {
+ const hovered = activeIndex?.label === data.label;
+
+ return h('div.legend-item', [
+ h('div.box', { style: { "background-color": data.color}}),
+ h('a', {
+ href: "/lex/" + route + "/" + data.id,
+ onMouseEnter: () => {
+ if (
+ !activeIndex ||
+ activeIndex.index !== index ||
+ activeIndex.label !== data.label
+ ) {
+ setActiveIndex({ index, label: data.label });
+ }
+ },
+ onMouseLeave: () => {
+ if (activeIndex) {
+ setActiveIndex(null);
+ }
+ },
+ style: {
+ "font-weight": hovered ? "600" : "300"
+ }
+ },
+ data.label)
+ ]);
+}
\ No newline at end of file
diff --git a/pages/lex/intervals/+Page.client.ts b/pages/lex/intervals/+Page.client.ts
new file mode 100644
index 000000000..054a20021
--- /dev/null
+++ b/pages/lex/intervals/+Page.client.ts
@@ -0,0 +1,139 @@
+import h from "./main.module.scss";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageBreadcrumbs, AssistantLinks, Link } from "~/components";
+import { Card, Icon, Popover, RangeSlider } from "@blueprintjs/core";
+import { useState } from "react";
+import { ContentPage } from "~/layouts";
+import { asChromaColor } from "@macrostrat/color-utils";
+import { Loading } from "../../index";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const [age, setAge] = useState([0, 4600]);
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/intervals?all")?.success.data;
+
+ if (res == null) return h(Loading);
+
+ console.log(res);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ const filtered = res.filter((d) => {
+ const name = d.name?.toLowerCase() || "";
+ const intType = d.int_type?.toLowerCase() || "";
+ const abbrev = d.abbrev?.toLowerCase() || "";
+ const b_age = d.b_age ? parseInt(d.b_age, 10) : 0; // Convert to number
+ const t_age = d.t_age ? parseInt(d.t_age, 10) : 4600; // Convert to number
+
+ // Check if name, intType, abbrev, or age falls within the ranges or input
+ const matchesName = name.includes(input);
+ const matchesType = intType.includes(input);
+ const matchesAbbrev = abbrev.includes(input);
+ const matchesAgeRange =
+ (!isNaN(b_age) && b_age >= age[0]) &&
+ (!isNaN(t_age) && t_age <= age[1]);
+
+ return (matchesName || matchesType || matchesAbbrev) && matchesAgeRange;
+ });
+
+ const grouped = groupByIntType(filtered);
+ console.log(grouped);
+
+ return h('div.int-list-page', [
+ h(ContentPage, [
+ h(PageBreadcrumbs, { title: "Intervals" }),
+ h(Card, { className: "filters" }, [
+ h('h3', "Filters"),
+ h('div', [
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Filter by name, type, or abbreviation...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.age-filter', [
+ h('p', "Filter by ages"),
+ h(RangeSlider, {
+ min: 0,
+ max: 4600,
+ stepSize: 10,
+ labelStepSize: 1000,
+ value: [age[0], age[1]],
+ onChange: (value) => {
+ setAge(value);
+ },
+ }),
+ ]),
+ ]),
+ h('div.int-list',
+ Object.entries(grouped).map(([intType, group]) =>
+ h('div.int-group', [
+ h('h2', UpperCase(intType)),
+ h('div.int-items', group.map((d) => h(EconItem, { data: d, key: d.environ_id })))
+ ])
+ )
+ )
+ ])
+ ]);
+}
+
+function EconItem({ data }) {
+ const { name, color, abbrev, b_age, int_id, t_age, timescales } = data;
+ const chromaColor = color ? asChromaColor(color) : null;
+ const luminance = .9;
+
+ return h(Popover, {
+ className: "int-item-popover",
+ content: h('div.int-tooltip', [
+ h('div.int-tooltip-id', "ID: #" + int_id),
+ h('div.int-tooltip-ages', b_age + " - " + t_age + " Ma"),
+ abbrev ? h('div.int-tooltip-abbrev', "Abbreviation - " + abbrev) : null,
+ h(Link, { href: "/lex/intervals/" + int_id }, "View details")
+ ]),
+ },
+ h('div.int-item', [
+ h('div.int-name', { style: { "backgroundColor": chromaColor?.luminance(1 - luminance).hex(), "color": chromaColor?.luminance(luminance).hex()} }, name),
+ ])
+ )
+}
+
+function getContrastTextColor(bgColor) {
+ // Remove '#' if present
+ const color = bgColor.replace('#', '');
+
+ // Parse r, g, b
+ const r = parseInt(color.substr(0, 2), 16);
+ const g = parseInt(color.substr(2, 2), 16);
+ const b = parseInt(color.substr(4, 2), 16);
+
+ // Calculate luminance
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
+
+ // Return black or white depending on luminance
+ return luminance > 0.6 ? '#000000' : '#FFFFFF';
+}
+
+function groupByIntType(items) {
+ return items.reduce((acc, item) => {
+ const intType = item.int_type?.trim?.();
+ if (!intType) return acc; // Skip items with no int_type
+
+ if (!acc[intType]) {
+ acc[intType] = [];
+ }
+
+ acc[intType].push(item);
+ return acc;
+ }, {});
+}
+
+
+function UpperCase(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
\ No newline at end of file
diff --git a/pages/lex/intervals/@id/+Page.client.ts b/pages/lex/intervals/@id/+Page.client.ts
new file mode 100644
index 000000000..8767d8ec2
--- /dev/null
+++ b/pages/lex/intervals/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "int_id", "intervals")
+}
\ No newline at end of file
diff --git a/pages/lex/intervals/main.module.scss b/pages/lex/intervals/main.module.scss
new file mode 100644
index 000000000..9813016b1
--- /dev/null
+++ b/pages/lex/intervals/main.module.scss
@@ -0,0 +1,68 @@
+h3, h2 {
+ margin: 0;
+ padding: 0;
+}
+
+.int-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ h2 {
+ margin: 0.5em 0;
+ }
+
+ .int-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .int-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.int-tooltip {
+ padding: 0.5em;
+ display: flex;
+ flex-direction: column;
+ gap: 0.5em;
+}
+
+ul, li {
+ margin: 0;
+}
+
+.filters {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+ margin-top: 20px;
+}
\ No newline at end of file
diff --git a/pages/lex/lithology/@id/+Page.client.ts b/pages/lex/lithology/@id/+Page.client.ts
new file mode 100644
index 000000000..da6a6291f
--- /dev/null
+++ b/pages/lex/lithology/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "lith_id", "lithologies")
+}
\ No newline at end of file
diff --git a/pages/lex/main.module.sass b/pages/lex/main.module.sass
new file mode 100644
index 000000000..f63a9e2f7
--- /dev/null
+++ b/pages/lex/main.module.sass
@@ -0,0 +1,157 @@
+.int-names
+ display: flex
+ gap: 5px
+
+ .int-name
+ padding: 2px 6px
+ margin: .2em 0
+ border-radius: 0.2em
+ font-size: 2em
+ display: flex
+ width: fit-content
+
+ .int-abbrev
+ display: flex
+ gap: 5px
+ align-items: center
+
+ p
+ margin: 0
+
+ .int-abbrev-item
+ padding: 2px 6px
+ margin: .2em 0
+ border-radius: 0.2em
+ font-size: 1em
+
+ul, h3
+ margin: 0
+ padding: 0
+ list-style-type: none
+
+.ref-list
+ margin-top: 1em
+
+.table
+ background-color: var(--secondary-color)
+ color: var(--text-emphasized-color)
+ display: grid
+ grid-template-columns: 20% 80%
+
+ p
+ margin: 0
+
+ .table-content
+ padding: 2em
+ display: flex
+ flex-direction: column
+ align-items: center
+ justify-content: space-between
+ gap: .5em
+
+.int-page
+ display: flex
+ flex-direction: column
+ gap: 1em
+
+.map-area-container
+ width: 100% !important
+
+.int-header
+ display: flex
+ justify-content: space-between
+
+ .sift-link
+ text-align: right
+
+.prevalent-taxa-container
+ display: flex
+ justify-content: space-between
+
+ .link
+ display: flex
+ gap: 5px
+ justify-content: center
+
+ .taxa-header
+ display: flex
+ flex-direction: column
+ align-items: center
+ justify-content: center
+
+ .taxa
+ display: flex
+ flex-direction: column
+ align-items: center
+ gap: 10px
+
+.divider
+ width: 100%
+
+.legend-item
+ display: flex
+ gap: 5px
+ align-items: center
+
+ a
+ color: white !important
+
+ p
+ margin: 0
+
+.box
+ height: 15px
+ width: 15px
+ border-radius: 3px
+
+.charts
+ display: flex
+ justify-content: center
+
+ .chart
+ width: 33%
+
+ h3
+ text-align: center
+
+.area
+ display: flex
+ align-items: center
+ justify-content: center
+
+.page-container
+ height: 100%
+
+.chart-container
+ g
+ cursor: pointer
+
+.range
+ color: var(--text-emphasized-color) !important
+
+.img-dark-mode
+ filter: invert(1)
+
+.concept-info
+ display: flex
+ flex-direction: column
+ gap: .5em
+
+ h3
+ font-weight: bold
+ font-size: 1.8em
+
+ .concept-name
+ display: flex
+ gap: 5px
+
+ .title
+ font-size: 1.2em
+
+ .title
+ font-weight: bold
+ color: var(--text-emphasized-color)
+
+.concept-item
+ display: flex
+ justify-content: space-between
diff --git a/pages/lex/strat-name-concepts/+Page.client.ts b/pages/lex/strat-name-concepts/+Page.client.ts
new file mode 100644
index 000000000..d47ed1a49
--- /dev/null
+++ b/pages/lex/strat-name-concepts/+Page.client.ts
@@ -0,0 +1,94 @@
+import h from "./main.module.scss";
+import { useAPIResult, InfiniteScroll, LoadingPlaceholder } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, Link, AssistantLinks, DevLinkButton, LinkCard, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Spinner, RangeSlider } from "@blueprintjs/core";
+import { useState, useEffect, useRef } from "react";
+import { ContentPage } from "~/layouts";
+import { Loading } from "../../index";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const [lastID, setLastID] = useState(0);
+ const [data, setData] = useState([]);
+ const pageSize = 20;
+ const result = useStratData(lastID, input, pageSize);
+
+ useEffect(() => {
+ if (result) {
+ setData(prevData => [...prevData, ...result]);
+ }
+ }, [result]);
+
+ useEffect(() => {
+ // Example: Reset data if lastID changes
+ setData([]);
+ }, [input]);
+
+
+ if (data == null) return h(Loading);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ return h(ContentPage, [
+ h(PageBreadcrumbs, { title: "Strat Name Concepts" }),
+ h('div.sift-link', [
+ h('p', "This page is is in development."),
+ h('a', { href: "/sift/definitions/strat_name_concepts", target: "_blank" }, "View in Sift")
+ ]),
+ h(Card, { className: 'filters'}, [
+ h("h2", 'Filter'),
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Filter by name...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.strat-list',
+ h('div.strat-items',
+ data.map(data =>
+ h(StratItem, { data })
+ )
+ )
+ ),
+ LoadMoreTrigger({ data, setLastID, pageSize, result }),
+ ]);
+}
+
+function StratItem({ data }) {
+ const { name, concept_id } = data;
+
+ return h(LinkCard, { href: "/lex/strat-name-concepts/" + concept_id }, name)
+}
+
+function useStratData(lastID, input, pageSize) {
+ const result = useAPIResult(`${SETTINGS.apiV2Prefix}/defs/strat_name_concepts?page_size=${pageSize}&last_id=${lastID}&concept_like=${input}`);
+ return result?.success?.data;
+}
+
+function LoadMoreTrigger({ data, setLastID, pageSize, result }) {
+ const ref = useRef(null);
+
+ useEffect(() => {
+ if (!ref.current) return;
+
+ const observer = new IntersectionObserver(([entry]) => {
+ if (entry.isIntersecting) {
+ if (data.length > 0) {
+ setLastID(data[data.length - 1].concept_id);
+ }
+ }
+ });
+
+ observer.observe(ref.current);
+
+ return () => observer.disconnect();
+ }, [data, setLastID]);
+
+ return h.if(result?.length == pageSize)('div.load-more', { ref }, h(Spinner));
+}
\ No newline at end of file
diff --git a/pages/lex/strat-name-concepts/@id/+Page.client.ts b/pages/lex/strat-name-concepts/@id/+Page.client.ts
new file mode 100644
index 000000000..86e51d1be
--- /dev/null
+++ b/pages/lex/strat-name-concepts/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "concept_id", "strat_name_concepts")
+}
\ No newline at end of file
diff --git a/pages/lex/strat-name-concepts/@id/main.scss b/pages/lex/strat-name-concepts/@id/main.scss
new file mode 100644
index 000000000..79bba2e52
--- /dev/null
+++ b/pages/lex/strat-name-concepts/@id/main.scss
@@ -0,0 +1,70 @@
+.int-names {
+ display: flex;
+ gap: 5px;
+ flex-direction: column;
+
+ .int-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ font-size: 2em;
+ display: flex;
+ width: fit-content;
+ }
+
+ .int-abbrev {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+
+ p {
+ margin: 0;
+ }
+
+ .int-abbrev-item {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ font-size: 1em;
+ }
+ }
+}
+
+ul, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+.ref-list {
+ margin-top: 1em;
+}
+
+.table {
+ background-color: var(--secondary-color);
+ color: var(--text-emphasized-color);
+ display: grid;
+ grid-template-columns: 20% 80%;
+
+ p {
+ margin: 0;
+ }
+
+ .table-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: .5em;
+ }
+}
+
+
+.int-page {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.map-area-container {
+ width: 100% !important;
+}
\ No newline at end of file
diff --git a/pages/lex/strat-name-concepts/main.module.scss b/pages/lex/strat-name-concepts/main.module.scss
new file mode 100644
index 000000000..0fb3fe468
--- /dev/null
+++ b/pages/lex/strat-name-concepts/main.module.scss
@@ -0,0 +1,64 @@
+.strat-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ .strat-rank-group {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+
+ .strat-subgroup, .strat-group {
+ border-left: 2px solid rgb(56, 62, 71);
+ padding-left: 1em;
+
+ .strat-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .strat-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+ }
+ }
+}
+
+h1, h2, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.filters {
+ margin-bottom: 1em;
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
\ No newline at end of file
diff --git a/pages/lex/strat-names/+Page.ts b/pages/lex/strat-names-crashes/+Page.ts
similarity index 93%
rename from pages/lex/strat-names/+Page.ts
rename to pages/lex/strat-names-crashes/+Page.ts
index f50c53918..9b0ae54ce 100644
--- a/pages/lex/strat-names/+Page.ts
+++ b/pages/lex/strat-names-crashes/+Page.ts
@@ -58,6 +58,8 @@ export function Page() {
const [showSettings, setShowSettings] = useState(false);
const [state, dispatch] = useReducer(filterReducer, startingFilters);
+ console.log("data", data)
+
useEffect(() => {
let s1 = state;
if (s1.match === "") {
@@ -154,3 +156,12 @@ function StratNamesList({ data }) {
data.map((d) => h(StratNameItem, { data: d, key: d.id })),
]);
}
+
+function StratNameItem({ data }) {
+ return h("div.strat-name-item", [
+ h(Link, { href: `/lex/strat-names/${data.id}` }, [
+ h("div.strat-name", data.strat_name),
+ h("div.strat-id", `ID: ${data.id}`),
+ ]),
+ ]);
+}
diff --git a/pages/lex/strat-names/+onBeforeRender.ts b/pages/lex/strat-names-crashes/+onBeforeRender.ts
similarity index 100%
rename from pages/lex/strat-names/+onBeforeRender.ts
rename to pages/lex/strat-names-crashes/+onBeforeRender.ts
diff --git a/pages/lex/strat-names/@id/+Page.ts b/pages/lex/strat-names-crashes/@id/+Page.ts
similarity index 100%
rename from pages/lex/strat-names/@id/+Page.ts
rename to pages/lex/strat-names-crashes/@id/+Page.ts
diff --git a/pages/lex/strat-names/@id/+onBeforeRender.ts b/pages/lex/strat-names-crashes/@id/+onBeforeRender.ts
similarity index 100%
rename from pages/lex/strat-names/@id/+onBeforeRender.ts
rename to pages/lex/strat-names-crashes/@id/+onBeforeRender.ts
diff --git a/pages/lex/strat-names/@id/main.module.sass b/pages/lex/strat-names-crashes/@id/main.module.sass
similarity index 100%
rename from pages/lex/strat-names/@id/main.module.sass
rename to pages/lex/strat-names-crashes/@id/main.module.sass
diff --git a/pages/lex/strat-names/@id/snippets.ts b/pages/lex/strat-names-crashes/@id/snippets.ts
similarity index 100%
rename from pages/lex/strat-names/@id/snippets.ts
rename to pages/lex/strat-names-crashes/@id/snippets.ts
diff --git a/pages/lex/strat-names/data-service.ts b/pages/lex/strat-names-crashes/data-service.ts
similarity index 98%
rename from pages/lex/strat-names/data-service.ts
rename to pages/lex/strat-names-crashes/data-service.ts
index 76eac9bc7..41155219e 100644
--- a/pages/lex/strat-names/data-service.ts
+++ b/pages/lex/strat-names-crashes/data-service.ts
@@ -124,9 +124,9 @@ export async function fetchStratNames(
abortSignal?: AbortSignal
) {
let base = postgrest
- .from("strat_names_units_kg")
+ .from("unit_strat_names")
.select(
- "id,strat_name,rank,concept_id,concept,interval_id,interval_name,units"
+ "*"
);
if (filters.match != null && filters.match != "") {
base = base.ilike("strat_name", `%${filters.match}%`);
diff --git a/pages/lex/strat-names/main.module.sass b/pages/lex/strat-names-crashes/main.module.sass
similarity index 100%
rename from pages/lex/strat-names/main.module.sass
rename to pages/lex/strat-names-crashes/main.module.sass
diff --git a/pages/lex/strat-names/+Page.client.ts b/pages/lex/strat-names/+Page.client.ts
new file mode 100644
index 000000000..3bc89777b
--- /dev/null
+++ b/pages/lex/strat-names/+Page.client.ts
@@ -0,0 +1,94 @@
+import h from "./main.module.scss";
+import { useAPIResult, InfiniteScroll, LoadingPlaceholder } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, Link, AssistantLinks, DevLinkButton, LinkCard, PageBreadcrumbs } from "~/components";
+import { Card, Icon, Spinner, RangeSlider } from "@blueprintjs/core";
+import { useState, useEffect, useRef } from "react";
+import { ContentPage } from "~/layouts";
+import { Loading } from "../../index";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const [lastID, setLastID] = useState(0);
+ const [data, setData] = useState([]);
+ const pageSize = 20;
+ const result = useStratData(lastID, input, pageSize);
+
+ useEffect(() => {
+ if (result) {
+ setData(prevData => [...prevData, ...result]);
+ }
+ }, [result]);
+
+ useEffect(() => {
+ // Example: Reset data if lastID changes
+ setData([]);
+ }, [input]);
+
+
+ if (data == null) return h(Loading);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ return h(ContentPage, [
+ h(PageBreadcrumbs, { title: "Strat Names" }),
+ h('div.sift-link', [
+ h('p', "This page is is in development."),
+ h('a', { href: "/sift/definitions/strat_names", target: "_blank" }, "View in Sift")
+ ]),
+ h(Card, { className: 'filters'}, [
+ h("h2", 'Filter'),
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Filter by name...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.strat-list',
+ h('div.strat-items',
+ data.map(data =>
+ h(StratItem, { data })
+ )
+ )
+ ),
+ LoadMoreTrigger({ data, setLastID, pageSize, result }),
+ ]);
+}
+
+function StratItem({ data }) {
+ const { strat_name, strat_name_id } = data;
+
+ return h(LinkCard, { href: "/lex/strat-names/" + strat_name_id }, strat_name)
+}
+
+function useStratData(lastID, input, pageSize) {
+ const result = useAPIResult(`${SETTINGS.apiV2Prefix}/defs/strat_names?page_size=${pageSize}&last_id=${lastID}&strat_name_like=${input}`);
+ return result?.success?.data;
+}
+
+function LoadMoreTrigger({ data, setLastID, pageSize, result }) {
+ const ref = useRef(null);
+
+ useEffect(() => {
+ if (!ref.current) return;
+
+ const observer = new IntersectionObserver(([entry]) => {
+ if (entry.isIntersecting) {
+ if (data.length > 0) {
+ setLastID(data[data.length - 1].strat_name_id);
+ }
+ }
+ });
+
+ observer.observe(ref.current);
+
+ return () => observer.disconnect();
+ }, [data, setLastID]);
+
+ return h.if(result?.length == pageSize)('div.load-more', { ref }, h(Spinner));
+}
\ No newline at end of file
diff --git a/pages/lex/strat-names/@id/+Page.client.ts b/pages/lex/strat-names/@id/+Page.client.ts
new file mode 100644
index 000000000..7415ceedb
--- /dev/null
+++ b/pages/lex/strat-names/@id/+Page.client.ts
@@ -0,0 +1,8 @@
+import { usePageContext } from 'vike-react/usePageContext';
+import { IndividualPage } from "../../index"
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ return IndividualPage(id, "strat_name_id", "strat_names")
+}
\ No newline at end of file
diff --git a/pages/lex/strat-names/@id/main.scss b/pages/lex/strat-names/@id/main.scss
new file mode 100644
index 000000000..79bba2e52
--- /dev/null
+++ b/pages/lex/strat-names/@id/main.scss
@@ -0,0 +1,70 @@
+.int-names {
+ display: flex;
+ gap: 5px;
+ flex-direction: column;
+
+ .int-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ font-size: 2em;
+ display: flex;
+ width: fit-content;
+ }
+
+ .int-abbrev {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+
+ p {
+ margin: 0;
+ }
+
+ .int-abbrev-item {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ font-size: 1em;
+ }
+ }
+}
+
+ul, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+.ref-list {
+ margin-top: 1em;
+}
+
+.table {
+ background-color: var(--secondary-color);
+ color: var(--text-emphasized-color);
+ display: grid;
+ grid-template-columns: 20% 80%;
+
+ p {
+ margin: 0;
+ }
+
+ .table-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: .5em;
+ }
+}
+
+
+.int-page {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.map-area-container {
+ width: 100% !important;
+}
\ No newline at end of file
diff --git a/pages/lex/strat-names/main.module.scss b/pages/lex/strat-names/main.module.scss
new file mode 100644
index 000000000..08222ec5e
--- /dev/null
+++ b/pages/lex/strat-names/main.module.scss
@@ -0,0 +1,79 @@
+.sift-link {
+ margin-bottom: 1em;
+}
+
+.strat-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ .strat-rank-group {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+
+ .strat-subgroup, .strat-group {
+ border-left: 2px solid rgb(56, 62, 71);
+ padding-left: 1em;
+
+ .strat-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .strat-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+ }
+ }
+}
+
+h1, h2, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.filters {
+ margin-bottom: 1em;
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.page-loader-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ h4 {
+ cursor: pointer;
+ }
+}
\ No newline at end of file
diff --git a/pages/lex/timescales/+Page.client.ts b/pages/lex/timescales/+Page.client.ts
new file mode 100644
index 000000000..37cfa35bf
--- /dev/null
+++ b/pages/lex/timescales/+Page.client.ts
@@ -0,0 +1,131 @@
+import h from "./main.module.scss";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageBreadcrumbs, LinkCard } from "~/components";
+import { Card, Icon, Popover, RangeSlider, Divider } from "@blueprintjs/core";
+import { useState } from "react";
+import { ContentPage } from "~/layouts";
+import { Timescale } from "@macrostrat/timescale";
+import { titleCase } from "../index";
+import { useEffect } from "react";
+import { Loading } from "../../index";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const [age, setAge] = useState([0, 4000]);
+ const [clickedInterval, setClickedInterval] = useState(null);
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/timescales?all")?.success.data;
+
+ useEffect(() => {
+ if (!clickedInterval) return;
+
+ const fetchInterval = async () => {
+ try {
+ const res = await fetch(`https://macrostrat.org/api/defs/intervals?name=${clickedInterval}`);
+ const data = await res.json();
+ const clickedData = data?.success?.data?.[0];
+ if (clickedData) {
+ const url = "/lex/intervals/" + clickedData.int_id;
+ window.open(url, "_blank");
+ }
+ } catch (error) {
+ console.error("Error fetching interval data:", error);
+ }
+ };
+
+ fetchInterval();
+ }, [clickedInterval]);
+
+ if (res == null) return h(Loading);
+
+ const handleChange = (event) => {
+ setInput(event.target.value.toLowerCase());
+ }
+
+ const filtered = res.filter((d) => {
+ const name = d.timescale?.toLowerCase() || "";
+ const max_age = d.max_age ? parseInt(d.max_age, 10) : 4000;
+ const min_age = d.min_age ? parseInt(d.min_age, 10) : 0;
+
+ const matchesName = name.includes(input);
+ const matchesAgeRange = max_age >= age[0] && min_age <= age[1];
+
+ return matchesName && matchesAgeRange;
+ });
+
+ const width = window.screen.width;
+ const timescaleWidth = width * .6 - 40;
+ const handleClick = (timescale) => {
+ const parent = timescale.target.parentElement;
+ let selected;
+
+ // container clicked
+ const containerClickedData = parent.className.split(" ")[1];
+
+ if(containerClickedData === "interval-label") {
+ const labelClickedData = parent.parentElement.parentElement.className.split(" ")[1];
+ selected = labelClickedData
+ } else {
+ selected = containerClickedData
+ }
+
+ setClickedInterval(selected);
+ }
+
+ return h(ContentPage, { className: "timescale-list-page"}, [
+ h(PageBreadcrumbs, { title: "Timescales" }),
+ h(Card, { className: "filters" }, [
+ h('h2', "Filters"),
+ h('div.name-filter', [
+ h('div.search-bar', [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Filter by name...",
+ onChange: handleChange,
+ }),
+ ])
+ ]),
+ h('div.age-filter', [
+ h('p', "Filter by ages"),
+ h(RangeSlider, {
+ min: 0,
+ max: 4000,
+ stepSize: 10,
+ labelStepSize: 1000,
+ value: [age[0], age[1]],
+ onChange: (value) => {
+ setAge(value);
+ },
+ }),
+ ]),
+ h('div.timescale',
+ h(Timescale, {
+ length: timescaleWidth,
+ levels: [1,5],
+ ageRange: [age[0], age[1]],
+ absoluteAgeScale: true,
+ onClick: handleClick
+ }
+ ))
+ ]),
+ h(Divider),
+ h('div.timescale-list', filtered.map((data) => TimescaleItem({ data }))),
+ ])
+}
+
+function TimescaleItem({ data }) {
+
+ const { timescale, min_age, max_age, n_intervals, timescale_id } = data;
+
+ return h(Popover, {
+ className: "timescale-item-popover",
+ content: h('div.timescale-tooltip')
+ },
+ h(LinkCard, { className: 'timescale-item', href: "/lex/timescales/" + timescale_id }, [
+ h('h1.timescale-name', titleCase(timescale)),
+ h('h3', `${max_age} - ${min_age} Ma`),
+ h('p', `Intervals: ${n_intervals}`),
+ ])
+ )
+}
\ No newline at end of file
diff --git a/pages/lex/timescales/@id/+Page.client.ts b/pages/lex/timescales/@id/+Page.client.ts
new file mode 100644
index 000000000..0e198bac1
--- /dev/null
+++ b/pages/lex/timescales/@id/+Page.client.ts
@@ -0,0 +1,81 @@
+import "./main.scss";
+import h from "@macrostrat/hyper";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
+import { PageHeader, Link, AssistantLinks, DevLinkButton, PageBreadcrumbs } from "~/components";
+import { ContentPage } from "~/layouts";
+import { usePageContext } from 'vike-react/usePageContext';
+import { Timescale } from "@macrostrat/timescale";
+import { titleCase } from "../../index";
+import { useState, useEffect } from "react";
+import { Loading } from "../../../index";
+
+export function Page() {
+ const pageContext = usePageContext();
+ const id = parseInt(pageContext.urlParsed.pathname.split("/")[3]);
+ const res = useAPIResult(SETTINGS.apiV2Prefix + "/defs/timescales?all")?.success.data;
+ const [clickedInterval, setClickedInterval] = useState(null);
+
+ console.log('clicked', clickedInterval)
+
+ useEffect(() => {
+ if (!clickedInterval) return;
+
+ const fetchInterval = async () => {
+ try {
+ const res = await fetch(`https://macrostrat.org/api/defs/intervals?name=${clickedInterval}`);
+ const data = await res.json();
+ const clickedData = data?.success?.data?.[0];
+ if (clickedData) {
+ const url = "/lex/intervals/" + clickedData.int_id;
+ window.open(url, "_blank");
+ }
+ } catch (error) {
+ console.error("Error fetching interval data:", error);
+ }
+ };
+
+ fetchInterval();
+ }, [clickedInterval]);
+
+ if (res == null) return h(Loading);
+
+ // temporary till api is fixed
+ const timeRes = res.find((d) => d.timescale_id === id);
+
+ if (timeRes == null) return h("div", "Timescale not found");
+
+ const { min_age, max_age, timescale } = timeRes;
+
+ const handleClick = (timescale) => {
+ const parent = timescale.target.parentElement;
+ let selected;
+
+ // container clicked
+ const containerClickedData = parent.className.split(" ")[1];
+
+ if(containerClickedData === "interval-label") {
+ const labelClickedData = parent.parentElement.parentElement.className.split(" ")[1];
+ selected = labelClickedData
+ } else {
+ selected = containerClickedData
+ }
+
+ setClickedInterval(selected);
+ }
+
+ return h(ContentPage, [
+ h(PageBreadcrumbs, { title: "#" + id }),
+ h('div.timescale-content', [
+ h('h1', titleCase(timescale)),
+ h('h3', max_age + " - " + min_age + " Ma"),
+ h(Timescale, {
+ levels: [0,5],
+ ageRange: [min_age, max_age],
+ orientation: "vertical",
+ absoluteAgeScale: true,
+ onClick: handleClick,
+ })
+ ])
+ ]);
+}
\ No newline at end of file
diff --git a/pages/lex/timescales/@id/main.scss b/pages/lex/timescales/@id/main.scss
new file mode 100644
index 000000000..3c6d75361
--- /dev/null
+++ b/pages/lex/timescales/@id/main.scss
@@ -0,0 +1,19 @@
+ul, h1, h2, p, h3 {
+ margin: 0;
+ padding: 0;
+}
+
+.timescale-content {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+tspan {
+ fill: var(--text-color); // sets the color to deep orange
+ font-size: 14px;
+}
+
+.visx-line {
+ stroke: var(--text-color);
+}
\ No newline at end of file
diff --git a/pages/lex/timescales/main.module.scss b/pages/lex/timescales/main.module.scss
new file mode 100644
index 000000000..6920a11c9
--- /dev/null
+++ b/pages/lex/timescales/main.module.scss
@@ -0,0 +1,77 @@
+h3, h2, h1 {
+ margin: 0;
+ padding: 0;
+}
+
+.timescale-list-page {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.filters {
+ display: flex;
+ flex-direction: column;
+ gap: 1em;
+}
+
+.timescale-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1.3em;
+
+ h2 {
+ margin: 0.5em 0;
+ }
+
+ .timescale-items {
+ display: flex;
+ gap: 5px;
+ flex-wrap: wrap;
+ align-items: center;
+
+ .timescale-name {
+ padding: 2px 6px;
+ margin: .2em 0;
+ border-radius: 0.2em;
+ }
+ }
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.int-tooltip {
+ padding: 0.5em;
+ display: flex;
+ flex-direction: column;
+ gap: 0.5em;
+}
+
+ul, li {
+ margin: 0;
+}
+
+.timescale {
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/pages/dev/test-site/main-page/main.styl b/pages/main.module.sass
similarity index 52%
rename from pages/dev/test-site/main-page/main.styl
rename to pages/main.module.sass
index 1620dea6d..7ad7a57e2 100644
--- a/pages/dev/test-site/main-page/main.styl
+++ b/pages/main.module.sass
@@ -3,24 +3,24 @@ html, body
background-color: white
margin: 0
-#total
- background-color: white
+.total
+ width: 100%
a
color: white
-a:hover
- text-decoration: none
+ &:hover
+ text-decoration: none
.nohighlight
color: white
.start
width: 100%
- display: flex;
- justify-content: center;
- align-items: center;
- height: 95vh
+ display: flex
+ justify-content: center
+ align-items: center
+ height: 50vh
color: white
li
@@ -33,27 +33,56 @@ a:hover
width: 100%
.text
- position:absolute
+ position: absolute
+ top: 5vh
+ left: 0
+ width: 100%
z-index: 100
- padding: 0 20px
- display: grid
- margin: auto
+ display: flex
+ flex-direction: column
+ gap: 20px
+ height: 95vh
+ justify-content: center
+ height: 50vh
+
+ .header
+ text-shadow: black 1px 0 10px
+ text-align: center
+ display: flex
+ justify-content: center
+ gap: 10px
+
+ .main-title
+ font-size: 60px
+ padding: 0
+
+ .version
+ font-size: 40px
+ padding: 0
+ margin: 0
+
+ .big-text
+ text-align: center
+ font-family: Helvetica, sans-serif
+ font-weight: 900
+ font-size: 20px
+ text-shadow: black 1px 0 10px
.cover-image
- position:absolute
- z-index:5
- left:0px
- top:0px
- height: 100vh
+ position: absolute
+ z-index: 5
+ left: 0px
+ top: 0px
+ height: 50vh
width: 100%
object-fit: cover
.sea-image
- position:absolute
+ position: absolute
z-index: 6
height: 100vh
width: 30%
- object-fit: cover
+ object-fit: cover
.parent
display: inline-flex
@@ -61,81 +90,72 @@ a:hover
.big
font-size: 72px
- font-family: "Maven Pro", sans-serif;
+ font-family: "Maven Pro", sans-serif
text-align: center
-.big-text
- font-family: Helvetica, sans-serif
- font-weight: 900
- font-size: 20px
- text-shadow: black 1px 0 10px
-
.top-stat, .top-stat-label
display: grid
margin: auto
color: white
+ a
+ color: white !important
+
.top-stat
font-size: 35px
font-family: Helvetica, sans-serif
.stats
- display: grid
- grid-template-columns: 25% 25% 25% 25%
- margin-bottom: 3%
- text-shadow: black 1px 0 10px;
+ display: flex
+ gap: 50px
+ text-shadow: black 1px 0 10px
+ align-items: center
+ justify-content: center
.stat
- display: grid
- margin: auto
+ display: flex
+ flex-direction: column
+ align-items: center
+ justify-content: center
a
color: white
-
-.rockd
- background-color: green
-
-.btn
- background-color: #363434;
- border: none;
- color: white;
- padding: 13px 10px;
- margin: 5% 15%
- text-align: center;
- text-decoration: none;
- border-radius: 12px;
-
-.btn:hover
- background-color: #545151
-
-.buttons1
+
+.buttons
font-size: 20px
padding: 0px
- display: grid
- grid-template-columns: 33.33% 33.33% 33.33%
+ display: flex
+ flex-direction: column
+ width: 100%
+ padding: 0 20%
+ background-color: var(--text-emphasized-color)
- a
- color: white
+ a
+ color: var(--text-emphasized-color) !important
text-decoration: none
- a:hover
- color: white
+ &:hover
+ color: white
-.rockd-png
- width: 22px
- padding-right: 4px
- float: left
- padding-top: 5px
+.rockd-button-container
+ display: flex
+ align-items: center
+ gap: 5px
+
+ .rockd-png
+ width: 22px
+ height: 22px
+ float: left
-.country_container
+.country_container
height: 100vh
.country
height: 100%
- display: flex;
- justify-content: center;
- align-items: center;
- text-align: center;
+ display: flex
+ justify-content: center
+ align-items: center
+ text-align: center
color: white
.img
@@ -164,22 +184,10 @@ a:hover
.title
margin: 0
font-size: 72px
- font-family: "Maven Pro", sans-serif;
+ font-family: "Maven Pro", sans-serif
padding: 20vh 0
text-align: center
-.header
- margin: 0 20%
- text-shadow: black 1px 0 10px
-
-#main-title
- display: inline-block
-
-.version
- display: inline-block
- margin-left: 20px
- font-size: 40px
-
#about
height: 100vh
background-color: white
@@ -196,49 +204,43 @@ a:hover
.donate-container
height: 80vh
+ display: flex
+ justify-content: center
+ align-items: center
.donate-title
- a
- color:white
- a:hover
+ flex: 0 0 50%
+ width: 100%
+ text-decoration: none
+
+ a
+ color: white
text-decoration: none
+ &:hover
+ text-decoration: none
+
color: white
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
- font-family: "Maven Pro", sans-serif;
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6)
+ font-family: "Maven Pro", sans-serif
padding: 0
-.donate-left
- float: left
- width: 50%
- height: 80vh
- display: flex;
- justify-content: center;
- align-items: center;
-
-.donate-right
- float: right
- width: 50%
- height: 80vh
- display: flex;
- justify-content: center;
- align-items: center;
-
.donate-info
- background: rgba(255,255,255,0.6);
+ flex: 0 0 50%
+ background: rgba(255,255,255,0.6)
padding: 25px
color: black
width: 80%
font-size: 18px
a
- color: black
+ color: black !important
font-weight: bold
text-decoration: none
.donate-img
- position:absolute
- z-index:5
+ position: absolute
+ z-index: 5
height: 80vh
width: 100%
object-fit: cover
@@ -247,7 +249,7 @@ a:hover
margin: 0
padding: 0
-.app-box
+.app-box
height: 15vh
display: flex
width: 60%
@@ -271,16 +273,15 @@ a:hover
margin: auto
margin-left: 6%
-
-#api
+#api
position: relative
height: 30vh
background-color: white
#api-circle-text
- display: table-cell;
- vertical-align: middle;
- color: #6bbe98;
+ display: table-cell
+ vertical-align: middle
+ color: #6bbe98
font-size: 72px
font-weight: 500
@@ -288,27 +289,27 @@ a:hover
float: left
margin-left: 15%
margin-right: 50px
- background-color: #fff;
- height: 200px;
- width: 200px;
- border-radius: 50%;
- text-align: center;
- display: table;
- border: 11px solid #6bbe98;
- color: #4BABBf;
+ background-color: #fff
+ height: 200px
+ width: 200px
+ border-radius: 50%
+ text-align: center
+ display: table
+ border: 11px solid #6bbe98
+ color: #4BABBf
#api-text
padding-top: 50px
margin-right: 15%
- color: #4bab7f;
- font-size: 20px;
- line-height: 28px;
- font-weight: 400;
+ color: #4bab7f
+ font-size: 20px
+ line-height: 28px
+ font-weight: 400
-#publications
+#publications
margin: 100px 10%
-#pub-title
+#pub-title
text-align: left
color: #E0E1E6
position: relative
@@ -324,25 +325,25 @@ a:hover
li
counter-increment: pub-counter -1
- li::marker
- font-size: 35px;
- color: #babdc8;
- content: counter(pub-counter) " "
- counter-increment: pub-counter
+ &::marker
+ font-size: 35px
+ color: #babdc8
+ content: counter(pub-counter) " "
+ counter-increment: pub-counter
-#about
+#about
margin: 0 10%
.about-row
margin: 4%
- font-size: 18px;
- line-height: 28px;
- font-weight: 200;
+ font-size: 18px
+ line-height: 28px
+ font-weight: 200
.about-body-subtitle
float: left
- font-size: 22px;
- font-weight: 200;
+ font-size: 22px
+ font-weight: 200
.about-body
margin-left: 30%
@@ -354,19 +355,19 @@ a:hover
padding-bottom: 0
.line
- width: 100%;
- border-bottom: 1px solid #E0E1E6;
- position: absolute;
+ width: 100%
+ border-bottom: 1px solid #E0E1E6
+ position: absolute
.geology-img
- position:absolute
+ position: absolute
z-index: 0
height: 100vh
width: 100%
object-fit: cover
.map-info
- position:absolute
+ position: absolute
z-index: 1
color: white
font-size: 20px
@@ -375,82 +376,79 @@ a:hover
background-color: rgba(0,0,0,.4)
.map-title
- position:absolute
+ position: absolute
z-index: 1
color: white
width: 50%
margin: 0 25%
.pub-line
- width: 80%;
- border-bottom: 1px solid #E0E1E6;
- position: absolute;
+ width: 80%
+ border-bottom: 1px solid #E0E1E6
+ position: absolute
.text-donate
- position:absolute
+ position: absolute
z-index: 100
padding: 0 20px
+ display: flex
+ width: 100%
+ justify-content: center
+ align-items: center
+ gap: 30px
+.locations
+ display: flex
+ width: 100%
+ flex-wrap: wrap
-.location
- display: grid;
- grid-template-columns: 25% 25% 25% 25%;
- grid-template-rows: 40vh;
-
-.t1
- margin-left: 10%
+ .location-img
+ width: 25%
+ height: 40vh
+ object-fit: cover
+ flex: 0 0 25%
-.t2
- margin-right: 10%
+ .location-text
+ width: 25%
+ color: black
+ background-color: white
+ display: flex
+ flex-direction: column
+ justify-content: center
+ align-items: center
+ flex: 0 0 25%
-.location-img
- width: 100%
- height: 40vh
- display: flex;
- margin: auto
- object-fit: cover
+ h1
+ font-size: 45px
+ font-weight: 600
+ margin: 0
-.location-text
- color: black
- display: grid;
- grid-template-rows: 50% 50%;
-
- h1
- font-size: 45px
- font-weight: 600
- display: grid
- margin: auto
- margin-top: 33%
.caption
font-size: 15px
font-weight: 600
- display: grid
- margin: auto
.temp-class
display: grid
grid-template-columns: 40% 60%
grid-template-rows: 30vh
-
.link-title
display: grid
margin: auto
- margin-left: 20%
+ margin-left: 20%
font-size: 35px
-
+
a
color: black
p
display: grid
margin: auto
- margin-left: 10%
+ margin-left: 10%
margin-right: 10%
color: black
font-size: 16px
-
-
-
\ No newline at end of file
+.hide
+ display: none
\ No newline at end of file
diff --git a/pages/map/sources/components/map/index.ts b/pages/map/sources/components/map/index.ts
index a86e9ae16..1c3f46eb9 100644
--- a/pages/map/sources/components/map/index.ts
+++ b/pages/map/sources/components/map/index.ts
@@ -36,7 +36,7 @@ function IndexMapContainer() {
mapRef.current = mapObj;
});
return () => {
- mapRef.current.remove();
+ mapRef.current?.remove();
};
}, [mapContainerRef]);
diff --git a/pages/maps/+Page.ts b/pages/maps/+Page.ts
index 67e23f23b..b1334927b 100644
--- a/pages/maps/+Page.ts
+++ b/pages/maps/+Page.ts
@@ -1,13 +1,35 @@
import h from "./main.module.scss";
-import { AnchorButton } from "@blueprintjs/core";
+import { AnchorButton, Icon, Card } from "@blueprintjs/core";
import { ContentPage } from "~/layouts";
-import { PageHeader, DevLinkButton, AssistantLinks } from "~/components";
-import { useData } from "vike-react/useData";
+import { PageHeader, DevLinkButton, AssistantLinks, LinkCard } from "~/components";
+import { useState } from "react";
+import { useAPIResult } from "@macrostrat/ui-components";
+import { SETTINGS } from "@macrostrat-web/settings";
export function Page() {
- const { sources } = useData();
+ const [inputValue, setInputValue] = useState("");
+ const sources = useAPIResult(SETTINGS.apiV2Prefix + "/defs/sources?all=true")?.success?.data;
- return h(ContentPage, [
+ if (sources == null) {
+ return h("div.loading", "Loading sources...");
+ }
+
+ console.log("sources", sources[0]);
+
+ const filteredSources = sources.filter((source) => {
+ const name = source.name.toLowerCase();
+ const input = inputValue.toLowerCase();
+ return name.includes(input);
+ });
+
+ console.log("inputValue", inputValue);
+
+ const handleInputChange = (event) => {
+ setInputValue(event.target.value.toLowerCase());
+ }
+
+
+ return h('div.maps-page', [
h(AssistantLinks, [
h(
AnchorButton,
@@ -17,26 +39,35 @@ export function Page() {
h(AnchorButton, { icon: "map", href: "/map/sources" }, "Show on map"),
h(DevLinkButton, { href: "/maps/legend" }, "Legend table"),
]),
- h(PageHeader, { title: "Maps" }),
- h(
- "ul.maps-list",
- sources.map((d) => h(SourceItem, { source: d, key: d.source_id }))
- ),
+ h(ContentPage, [
+ h(PageHeader, { title: "Maps" }),
+ h(Card, { className: "search-bar" }, [
+ h(Icon, { icon: "search" }),
+ h('input', {
+ type: "text",
+ placeholder: "Filter by name...",
+ onChange: handleInputChange
+ }),
+ ]),
+ h(
+ "div.maps-list",
+ filteredSources.map((source) => h(SourceItem, { source })),
+ ),
+ ]),
]);
}
function SourceItem({ source }) {
- const { source_id, slug, name } = source;
+ const { source_id, name, ref_title, url, scale } = source;
const href = `/maps/${source_id}`;
- const href1 = `/map/dev/sources/${slug}`;
-
- return h("li", [
- h("span.source-id", {}, source_id),
- " ",
- h("a", { href }, [name]),
- " ",
- h("span.scale", {}, source.scale),
- h.if(source.raster_url != null)([" ", h("span.raster", "Raster")]),
- h("span", [" ", h("a", { href: href1 }, h("code", {}, slug))]),
+
+ return h(LinkCard, {
+ href,
+ title: h('div.title', [
+ h('h1', name),
+ h('div', { className: "size " + scale }, scale)
+ ]),
+ }, [
+ h('a', { href: url, target: "_blank" }, ref_title),
]);
-}
+}
\ No newline at end of file
diff --git a/pages/maps/@id/+Page.ts b/pages/maps/@id/+Page.ts
index faa91d723..ed31b0569 100644
--- a/pages/maps/@id/+Page.ts
+++ b/pages/maps/@id/+Page.ts
@@ -373,6 +373,7 @@ function MapLegendPanel(params) {
h(ErrorBoundary, [
h(MapReference, { reference: params, showSourceID: false }),
]),
+ h('a.global-link', { href: "/map/dev/sources/" + params.slug, target: "_blank" }, "View on global map")
]),
h("div.flex.row", [
h("h3", "Legend"),
diff --git a/pages/maps/main.module.scss b/pages/maps/main.module.scss
index 4f3b600e1..6fb6df3ce 100644
--- a/pages/maps/main.module.scss
+++ b/pages/maps/main.module.scss
@@ -7,9 +7,37 @@
font-size: 0.8em;
}
+h1 {
+ margin: 0;
+ font-size: 1em;
+}
+
.maps-list {
- list-style: none;
padding: 0;
+ display: flex;
+ flex-direction: column;
+ column-gap: 1em;
+ row-gap: 0;
+
+ .link-title {
+ display: flex;
+ justify-content: space-between;
+
+ p {
+ margin: 0;
+ }
+
+ a {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+
+ p {
+ font-size: .5em;
+ }
}
.source-id {
@@ -32,3 +60,64 @@
padding: 0.5em 0;
}
}
+
+.pages {
+ margin: 10px 0;
+ width: 100%;
+ display: flex;
+ text-align: center;
+ justify-content: center;
+
+ .page-container {
+ display: grid;
+ grid-template-columns: 100px 50px 100px;
+ color: var(--text-emphasized-color);
+
+ .btn-content {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ }
+
+ p {
+ margin: 0;
+ text-align: center;
+ }
+ }
+}
+
+.search-bar {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ justify-content: center;
+
+ input {
+ width: 100%;
+ padding: 0.5em;
+ border-radius: 0.2em;
+ border: none;
+ background-color: var(--background-color);
+ color: var(--text-emphasized-color);
+ font-size: 1em;
+ margin: 3px;
+
+ &:focus {
+ outline: none;
+ box-shadow: 0 0 0.2em var(--text-emphasized-color);
+ }
+ }
+}
+
+.title {
+ display: flex;
+ justify-content: space-between;
+
+ .size {
+ color: var(--text-emphasized-color);
+ padding: 0.2em 0.5em;
+ border-radius: .2em;
+ }
+}
\ No newline at end of file
diff --git a/pages/maps/sources/+Page.ts b/pages/maps/sources/+Page.ts
new file mode 100644
index 000000000..fcc6c27ef
--- /dev/null
+++ b/pages/maps/sources/+Page.ts
@@ -0,0 +1,18 @@
+import { Provider } from "react-redux";
+import { createStore } from "redux";
+import reducers from "./app-state";
+import App from "./components/app";
+import h from "@macrostrat/hyper";
+
+// We should probably make this a little less global
+// import "~/styles/global.styl";
+// import "./searchbar.styl";
+// import "./ui-components.styl";
+
+// Create the data store
+let store = createStore(reducers);
+
+// Render the application
+export function Page() {
+ return h(Provider, { store }, [h(App)]);
+}
diff --git a/pages/maps/sources/+config.ts b/pages/maps/sources/+config.ts
new file mode 100644
index 000000000..e6c205a97
--- /dev/null
+++ b/pages/maps/sources/+config.ts
@@ -0,0 +1,15 @@
+export default {
+ route: "/maps/sources*",
+ meta: {
+ Page: {
+ /* Sift must be rendered as a single-page app, because that is its design.
+ It must only use server-side links to other pages,
+ because of its reliance on global styles that could leak to other pages with client routing
+ */
+ env: {
+ client: true,
+ server: false,
+ },
+ },
+ },
+};
diff --git a/pages/maps/sources/app-state/action-runner.ts b/pages/maps/sources/app-state/action-runner.ts
new file mode 100644
index 000000000..c7ce67488
--- /dev/null
+++ b/pages/maps/sources/app-state/action-runner.ts
@@ -0,0 +1,25 @@
+import { BurwellSourceActions as Action, BurwellState } from "./types";
+import axios from "axios";
+import { apiV2Prefix } from "@macrostrat-web/settings";
+
+async function actionRunner(action: Action): Promise
{
+ switch (action.type) {
+ case "fetch-data":
+ const data = await fetchBurwellMapData();
+ return { type: "recieve-data", maps: data };
+ default:
+ return action;
+ }
+}
+
+async function fetchBurwellMapData() {
+ const url = `${apiV2Prefix}/defs/sources`;
+
+ const res = await axios.get(url, {
+ responseType: "json",
+ params: { all: true, format: "geojson_bare" },
+ });
+ return res.data.features;
+}
+
+export default actionRunner;
diff --git a/pages/maps/sources/app-state/hooks.ts b/pages/maps/sources/app-state/hooks.ts
new file mode 100644
index 000000000..f40aa1557
--- /dev/null
+++ b/pages/maps/sources/app-state/hooks.ts
@@ -0,0 +1,21 @@
+import { useDispatch, useSelector } from "react-redux";
+import { BurwellSourceActions as Action, BurwellState } from "./types";
+import actionRunner from "./action-runner";
+
+function useActionDispatch() {
+ return useDispatch>();
+}
+
+function useBurwellActions(): (action: Action) => Promise {
+ const dispatch = useActionDispatch();
+ return async (action) => {
+ const newAction = await actionRunner(action);
+ if (newAction === undefined) return;
+ dispatch(newAction as Action);
+ };
+}
+function useBurwellState(selectorFn: (state: BurwellState) => T): T {
+ return useSelector(selectorFn) as T;
+}
+
+export { useBurwellActions, useBurwellState };
diff --git a/pages/maps/sources/app-state/index.ts b/pages/maps/sources/app-state/index.ts
new file mode 100644
index 000000000..2560c64c2
--- /dev/null
+++ b/pages/maps/sources/app-state/index.ts
@@ -0,0 +1,5 @@
+import reducers from "./reducer";
+export default reducers;
+export * from "./hooks";
+export * from "./utils";
+export * from "./types";
diff --git a/pages/maps/sources/app-state/reducer.ts b/pages/maps/sources/app-state/reducer.ts
new file mode 100644
index 000000000..94e6e5e84
--- /dev/null
+++ b/pages/maps/sources/app-state/reducer.ts
@@ -0,0 +1,59 @@
+import { BurwellSourceActions, BurwellState } from "./types";
+
+const burwellDefaultState: BurwellState = {
+ isFetching: false,
+ msg: "",
+ clicks: 0,
+ maps: [],
+ selectedScale: "all",
+ selectedFeatures: [],
+ activeFeature: {},
+ menuOpen: false,
+ flyTo: true,
+};
+
+const reducer = (
+ state: BurwellState = burwellDefaultState,
+ action: BurwellSourceActions
+) => {
+ switch (action.type) {
+ case "request-data":
+ return Object.assign({}, state, {
+ isFetching: true,
+ });
+ case "recieve-data":
+ // map ids to features to use mapbox effects appwide
+ const maps = action.maps.map((d, i) => {
+ d.id = i;
+ return d;
+ });
+ return Object.assign({}, state, {
+ isFetching: false,
+ maps: maps,
+ });
+ case "select-scale":
+ return Object.assign({}, state, {
+ selectedScale: action.selectedScale,
+ });
+ case "select-features":
+ return Object.assign({}, state, {
+ selectedFeatures: action.selectedFeatures,
+ });
+ case "activate-feature":
+ return Object.assign({}, state, {
+ activeFeature: action.activeFeature,
+ });
+ case "toggle-menu":
+ return Object.assign({}, state, {
+ menuOpen: action.menuOpen,
+ });
+ case "toggle-fly-option":
+ return Object.assign({}, state, {
+ flyTo: action.flyTo,
+ });
+ default:
+ return state;
+ }
+};
+
+export default reducer;
diff --git a/pages/maps/sources/app-state/types.ts b/pages/maps/sources/app-state/types.ts
new file mode 100644
index 000000000..e5a8a694c
--- /dev/null
+++ b/pages/maps/sources/app-state/types.ts
@@ -0,0 +1,31 @@
+//////////////// Action Types //////////////////
+type FETCH_DATA = { type: "fetch-data" };
+type RECIEVE_DATA = { type: "recieve-data"; maps: object[] };
+type REQUEST_DATA = { type: "request-data" };
+type SELECT_SCALE = { type: "select-scale"; selectedScale: any };
+type SELECT_FEATURES = { type: "select-features"; selectedFeatures: any };
+type ACTIVATE_FEATURE = { type: "activate-feature"; activeFeature: any };
+type TOGGLE_MENU = { type: "toggle-menu"; menuOpen: boolean };
+type TOGGLE_FLY_OPTION = { type: "toggle-fly-option"; flyTo: boolean };
+
+export type BurwellSourceActions =
+ | FETCH_DATA
+ | RECIEVE_DATA
+ | REQUEST_DATA
+ | SELECT_SCALE
+ | SELECT_FEATURES
+ | ACTIVATE_FEATURE
+ | TOGGLE_MENU
+ | TOGGLE_FLY_OPTION;
+
+export interface BurwellState {
+ isFetching: boolean;
+ msg: string;
+ clicks: number;
+ maps: [];
+ selectedScale: string;
+ selectedFeatures: [];
+ activeFeature: {};
+ menuOpen: boolean;
+ flyTo: boolean;
+}
diff --git a/pages/maps/sources/app-state/utils.ts b/pages/maps/sources/app-state/utils.ts
new file mode 100644
index 000000000..5fce7ac1a
--- /dev/null
+++ b/pages/maps/sources/app-state/utils.ts
@@ -0,0 +1,59 @@
+export const addCommas = (x) => {
+ x = parseInt(x);
+ var parts = x.toString().split(".");
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ return parts.join(".");
+};
+
+export const getVisibleScale = (maps, filter) => {
+ switch (filter) {
+ case "all":
+ return maps;
+ case "large":
+ return maps.filter((d) => {
+ if (d.properties.scale === "large") return d;
+ });
+ case "medium":
+ return maps.filter((d) => {
+ if (d.properties.scale === "medium") return d;
+ });
+ case "small":
+ return maps.filter((d) => {
+ if (d.properties.scale === "small") return d;
+ });
+ case "tiny":
+ return maps.filter((d) => {
+ if (d.properties.scale === "tiny") return d;
+ });
+ default:
+ return [];
+ }
+};
+
+export function getCenter(coordinates) {
+ const lat = (coordinates[0][0][1] + coordinates[0][2][1]) / 2;
+ const long = (coordinates[0][0][0] + coordinates[0][2][0]) / 2;
+ return [long, lat];
+}
+
+export const zoomMap = {
+ tiny: 1,
+ small: 3,
+ medium: 4,
+ large: 7,
+};
+
+export const offsetMap = {
+ tiny: 10,
+ small: 10,
+ medium: 4,
+ large: 0.05,
+};
+
+export function flyToData(feature) {
+ const [long, lat] = getCenter(feature.geometry.coordinates);
+ const zoom = zoomMap[feature.properties.scale];
+ let offset = offsetMap[feature.properties.scale];
+
+ return { center: [long + offset, lat], zoom };
+}
diff --git a/pages/maps/sources/archive_/content.ts b/pages/maps/sources/archive_/content.ts
new file mode 100644
index 000000000..46d538c52
--- /dev/null
+++ b/pages/maps/sources/archive_/content.ts
@@ -0,0 +1,9 @@
+import IndexMapContainer from "../components/map";
+import h from "@macrostrat/hyper";
+import { InfoDrawer } from "../components/info-drawer";
+
+const Content = () => {
+ return h("div.full-height", [h(IndexMapContainer), h(InfoDrawer)]);
+};
+
+export default Content;
diff --git a/pages/maps/sources/archive_/css/skeleton.styl b/pages/maps/sources/archive_/css/skeleton.styl
new file mode 100644
index 000000000..2d981d1eb
--- /dev/null
+++ b/pages/maps/sources/archive_/css/skeleton.styl
@@ -0,0 +1,207 @@
+/*
+* Skeleton V2.0.4
+* Copyright 2014, Dave Gamache
+* www.getskeleton.com
+* Free to use under the MIT license.
+* http://www.opensource.org/licenses/mit-license.php
+* 12/29/2014
+*/
+
+
+/* Table of contents
+––––––––––––––––––––––––––––––––––––––––––––––––––
+- Grid
+- Base Styles
+- Typography
+- Links
+- Buttons
+- Forms
+- Lists
+- Code
+- Tables
+- Spacing
+- Utilities
+- Clearing
+- Media Queries
+*/
+
+
+/* Grid
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.container {
+ position: relative;
+ width: 100%;
+ max-width: 960px;
+ margin: 0 auto;
+ padding: 0 20px;
+ box-sizing: border-box; }
+.column,
+.columns {
+ width: 100%;
+ float: left;
+ box-sizing: border-box; }
+
+/* For devices larger than 400px */
+@media (min-width: 400px) {
+ .container {
+ width: 85%;
+ padding: 0; }
+}
+
+/* For devices larger than 550px */
+@media (min-width: 550px) {
+ .container {
+ width: 80%; }
+ .column,
+ .columns {
+ margin-left: 4%; }
+ .column:first-child,
+ .columns:first-child {
+ margin-left: 0; }
+
+ .one.column,
+ .one.columns { width: 4.66666666667%; }
+ .two.columns { width: 13.3333333333%; }
+ .three.columns { width: 22%; }
+ .four.columns { width: 30.6666666667%; }
+ .five.columns { width: 39.3333333333%; }
+ .six.columns { width: 48%; }
+ .seven.columns { width: 56.6666666667%; }
+ .eight.columns { width: 65.3333333333%; }
+ .nine.columns { width: 74.0%; }
+ .ten.columns { width: 82.6666666667%; }
+ .eleven.columns { width: 91.3333333333%; }
+ .twelve.columns { width: 100%; margin-left: 0; }
+
+ .one-third.column { width: 30.6666666667%; }
+ .two-thirds.column { width: 65.3333333333%; }
+
+ .one-half.column { width: 48%; }
+
+ /* Offsets */
+ .offset-by-one.column,
+ .offset-by-one.columns { margin-left: 8.66666666667%; }
+ .offset-by-two.column,
+ .offset-by-two.columns { margin-left: 17.3333333333%; }
+ .offset-by-three.column,
+ .offset-by-three.columns { margin-left: 26%; }
+ .offset-by-four.column,
+ .offset-by-four.columns { margin-left: 34.6666666667%; }
+ .offset-by-five.column,
+ .offset-by-five.columns { margin-left: 43.3333333333%; }
+ .offset-by-six.column,
+ .offset-by-six.columns { margin-left: 52%; }
+ .offset-by-seven.column,
+ .offset-by-seven.columns { margin-left: 60.6666666667%; }
+ .offset-by-eight.column,
+ .offset-by-eight.columns { margin-left: 69.3333333333%; }
+ .offset-by-nine.column,
+ .offset-by-nine.columns { margin-left: 78.0%; }
+ .offset-by-ten.column,
+ .offset-by-ten.columns { margin-left: 86.6666666667%; }
+ .offset-by-eleven.column,
+ .offset-by-eleven.columns { margin-left: 95.3333333333%; }
+
+ .offset-by-one-third.column,
+ .offset-by-one-third.columns { margin-left: 34.6666666667%; }
+ .offset-by-two-thirds.column,
+ .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
+
+ .offset-by-one-half.column,
+ .offset-by-one-half.columns { margin-left: 52%; }
+
+}
+
+
+/* Base Styles
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/* NOTE
+html is set to 62.5% so that all the REM measurements throughout Skeleton
+are based on 10px sizing. So basically 1.5rem = 15px :) */
+html {
+ font-size: 62.5%; }
+body {
+ font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
+ line-height: 1.6;
+ font-weight: 400;
+ font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #222; }
+
+
+/* Typography
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+h1, h2, h3, h4, h5, h6 {
+ margin-top: 0;
+ margin-bottom: 2rem;
+ font-weight: 300; }
+h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
+h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
+h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
+h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
+h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
+h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
+
+/* Larger than phablet */
+@media (min-width: 550px) {
+ h1 { font-size: 5.0rem; }
+ h2 { font-size: 4.2rem; }
+ h3 { font-size: 3.6rem; }
+ h4 { font-size: 3.0rem; }
+ h5 { font-size: 2.4rem; }
+ h6 { font-size: 1.5rem; }
+}
+
+/* Links
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+a {
+ color: #1EAEDB; }
+a:hover {
+ color: #0FA0CE; }
+
+
+
+/* Misc
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+hr {
+ margin-top: 3rem;
+ margin-bottom: 3.5rem;
+ border-width: 0;
+ border-top: 1px solid #E1E1E1; }
+
+
+/* Clearing
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+
+/* Self Clearing Goodness */
+.container:after,
+.row:after,
+.u-cf {
+ content: "";
+ display: table;
+ clear: both; }
+
+
+/* Media Queries
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/*
+Note: The best way to structure the use of media queries is to create the queries
+near the relevant code. For example, if you wanted to change the styles for buttons
+on small devices, paste the mobile query code up in the buttons section and style it
+there.
+*/
+
+
+/* Larger than mobile */
+@media (min-width: 400px) {}
+
+/* Larger than phablet (also point when grid becomes active) */
+@media (min-width: 550px) {}
+
+/* Larger than tablet */
+@media (min-width: 750px) {}
+
+/* Larger than desktop */
+@media (min-width: 1000px) {}
+
+/* Larger than Desktop HD */
+@media (min-width: 1200px) {}
diff --git a/pages/maps/sources/archive_/css/styles.styl b/pages/maps/sources/archive_/css/styles.styl
new file mode 100644
index 000000000..312787f8d
--- /dev/null
+++ b/pages/maps/sources/archive_/css/styles.styl
@@ -0,0 +1,169 @@
+/* Styles go here */
+html, body {
+ color: #333;
+ font-family: 'Roboto', sans-serif;
+ margin: 0;
+ height: 100%;
+ width: 100%;
+ //overflow: hidden;
+}
+
+.full-height {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+}
+.hidden {
+ display: none;
+}
+td {
+ padding: 5px;
+}
+.container {
+ position: relative;
+}
+.feature-list-container {
+ overflow-y: scroll;
+}
+.source-row {
+ padding: 25px;
+ word-wrap: break-word;
+}
+.hide {
+ display: none;
+}
+.index-map-container {
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 56px;
+ width: 100%;
+ bottom: 0;
+}
+
+#index-map {
+ width: 100%;
+ height: 100%;
+}
+.map {
+ height: 350px;
+ margin-top: 15px;
+}
+.title {
+ font-weight: 200;
+ color: #000000 !important;
+ font-family: 'Helvetica Neue', sans-serif !important;
+}
+.scale-badge {
+ margin-left: 0 !important;
+ color: #ffffff !important;
+ padding: 5px;
+ border-radius: 4px;
+}
+.tiny {
+ background-color: #45B29D;
+}
+.small {
+ background-color: #45B29D;
+}
+.medium {
+ background-color: #E27A3F;
+}
+.large {
+ background-color: #3498DB;
+}
+.header {
+ flex: 0 1 56px;
+ width: 100%;
+}
+.filter-button {
+ font-size: 18px;
+ display: inline-block;
+ padding: 10px;
+ border-radius: 4px;
+ margin: 10px;
+ border: 1px solid #aaa;
+}
+.button-group {
+ position: absolute;
+ top: 0;
+ z-index: 999;
+ right: 0;
+ background-color: rgba(255,255,255,0.9);
+ padding: 10px;
+ text-align: center;
+}
+.button-group-title {
+ margin-bottom: 0;
+ font-size: 21px;
+ text-align: center;
+}
+
+.info {
+ position: absolute;
+ width: 100%;
+ height: 35%;
+ bottom: -100%;
+ z-index: 100000;
+ background-color: rgba(255,255,255,.93);
+ color: #333;
+ line-height: 23px;
+ -webkit-transition: all .6s ease;
+ -moz-transition: all .6s ease;
+ -o-transition: all .6s ease;
+ -ms-transition: all .6s ease;
+ transition: all .6s ease;
+ transform: translate3d(0,0,0);
+ -webkit-transform: translate3d(0,0,0);
+ overflow-y: scroll;
+}
+.info.open {
+ bottom: 0 !important;
+}
+.info-header {
+ height: 50px;
+ position: fixed;
+ width: 100%;
+ z-index: 1;
+}
+.info-close {
+ color: #000;
+ position: absolute;
+ cursor: pointer;
+ font-size: 25px;
+ padding: 11px 20px;
+ top: 0;
+}
+.info-content {
+ z-index: 0;
+ height: 100%;
+ margin-top: 40px;
+ overflow-y: scroll;
+}
+.map-source {
+ padding: 10px;
+}
+.map-source-title {
+ font-weight: bold;
+ font-size: 105%;
+}
+.map-source-year {
+ font-style: italic;
+}
+@media(max-width:600px) {
+ .filter-button {
+ font-size: 12px;
+ margin: 5px;
+ }
+ .button-group {
+ width: 100%;
+ }
+ .button-group-title {
+ font-size: 12px;
+ }
+ .leaflet-control-container {
+ display: none;
+ }
+}
diff --git a/pages/maps/sources/archive_/index-map.ts b/pages/maps/sources/archive_/index-map.ts
new file mode 100644
index 000000000..39e78a24e
--- /dev/null
+++ b/pages/maps/sources/archive_/index-map.ts
@@ -0,0 +1,152 @@
+import React from "react";
+class IndexMap extends Component {
+ constructor(props: IndexMapProps) {
+ super(props);
+ this.selectedFeatures = [];
+ this.inactiveStyle = {
+ color: "#333", //stroke color
+ weight: 2, //stroke width
+ fillColor: "#aaaaaa",
+ };
+
+ this.activeStyle = {
+ color: "#FF5335", //stroke color
+ weight: 3, //stroke width
+ };
+ this.highlightStyle = {
+ color: "#FF5335",
+ weight: 3,
+ fillColor: "#FF5335",
+ };
+ this.currentScale = "";
+ }
+
+ renderMap(nextProps) {
+ if (Object.keys(nextProps.activeFeature).length) {
+ Object.keys(this.map._layers).forEach((layer) => {
+ if (this.map._layers[layer]._layers) {
+ Object.keys(this.map._layers[layer]._layers).forEach((obj) => {
+ if (
+ this.map._layers[layer]._layers[obj].feature.properties
+ .source_id === nextProps.activeFeature.source_id
+ ) {
+ this.map._layers[layer]._layers[obj].setStyle(
+ this.highlightStyle
+ );
+ } else {
+ try {
+ this.map._layers[layer]._layers[obj].setStyle(
+ this.inactiveStyle
+ );
+ } catch (e) {}
+ }
+ });
+ }
+ });
+ }
+
+ if (!nextProps.maps.length) {
+ return;
+ }
+ if (
+ (this.map && nextProps.selectedScale != this.currentScale) ||
+ !this.currentScale.length
+ ) {
+ this.currentScale = nextProps.selectedScale;
+ this.features.clearLayers();
+ this.features.addData({
+ type: "FeatureCollection",
+ features: nextProps.maps,
+ });
+ }
+ }
+
+ componentDidMount() {
+ var map = (this.map = L.map("index-map", {
+ minZoom: 0,
+ maxZoom: 14,
+ }).setView([40.8, -94.1], 3));
+
+ this.map.on("click", (event) => {
+ // this.features.setStyle(this.inactiveStyle)
+ let bounds = L.latLngBounds(event.latlng, event.latlng);
+ let intersecting = [];
+
+ Object.keys(this.map._layers).forEach((layer) => {
+ if (this.map._layers[layer]._layers) {
+ Object.keys(this.map._layers[layer]._layers).forEach((obj) => {
+ if (
+ bounds.intersects(this.map._layers[layer]._layers[obj]._bounds)
+ ) {
+ this.map._layers[layer]._layers[obj].setStyle(this.activeStyle);
+ this.map._layers[layer]._layers[obj].bringToFront();
+ intersecting.push(this.map._layers[layer]._layers[obj]);
+ } else {
+ this.map._layers[layer]._layers[obj].setStyle(this.inactiveStyle);
+ }
+ });
+ }
+ });
+
+ let uniques = {};
+ intersecting = intersecting
+ .map((feature) => {
+ feature.feature.properties.geometry = feature.feature.geometry;
+ return feature.feature.properties;
+ })
+ .filter((feature) => {
+ if (!uniques[feature.source_id]) {
+ uniques[feature.source_id] = true;
+ return feature;
+ }
+ });
+
+ this.props.onSelectFeatures(intersecting || []);
+ this.selectedFeatures = intersecting;
+
+ if (intersecting.length) {
+ this.props.openMenu();
+ }
+ });
+
+ L.tileLayer(
+ "https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}",
+ {
+ attribution:
+ '© Mapbox © OpenStreetMap Improve this map ',
+ tileSize: 512,
+ maxZoom: 18,
+ zoomOffset: -1,
+ id: "mapbox/outdoors-v11",
+ accessToken:
+ "pk.eyJ1IjoiamN6YXBsZXdza2kiLCJhIjoiY2tpcjQ1cG1yMGZvcTJ6b3psbXB6bmtweiJ9.TkabsM8gNsZ7bHGJXu6vOQ",
+ }
+ ).addTo(map);
+
+ var features = (this.features = L.geoJson(
+ {
+ type: "FeatureCollection",
+ features: this.props.maps,
+ },
+ {
+ style: {
+ color: "#333", //stroke color
+ weight: 2, //stroke width
+ fillColor: "#aaaaaa",
+ },
+ }
+ ).addTo(map));
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.renderMap(nextProps);
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
diff --git a/pages/maps/sources/archive_/options.tsx b/pages/maps/sources/archive_/options.tsx
new file mode 100644
index 000000000..34a773e16
--- /dev/null
+++ b/pages/maps/sources/archive_/options.tsx
@@ -0,0 +1,157 @@
+// const mapStateToProps = state => {
+// return {
+// optionsOpen: state.handleInteraction.optionsOpen,
+// optionsAnchorElement: state.handleInteraction.optionsAnchorElement,
+// selectedScale: state.handleInteraction.selectedScale,
+// view: state.handleInteraction.view
+// }
+// }
+
+// const mapDispatchToProps = (dispatch) => {
+// return {
+// openOptions: (event) => {
+// dispatch(openOptions(event))
+// },
+// closeOptions: () => {
+// dispatch(closeOptions())
+// },
+// selectScale: (scale) => {
+// dispatch(selectScale(scale))
+// dispatch(closeOptions())
+// },
+// changeView: (view) => {
+// dispatch(changeView(view))
+// dispatch(closeOptions())
+// dispatch(toggleMenu(false))
+// }
+// }
+// }
+
+// const Options = () => {
+// const { optionsOpen, optionsAnchorElement, selectedScale, view } =
+// useBurwellState((state) => state);
+// const runAction = useBurwellActions();
+
+// const openOptions = (el) => {
+// runAction({
+// type: "open-options",
+// optionsAnchorElement: el,
+// optionsOpen: true,
+// });
+// };
+
+// const closeOptions = () => {
+// runAction({ type: "close-options", optionsOpen: false });
+// };
+// const selectScale = (scale) => {
+// runAction({ type: "select-scale", selectedScale: scale });
+// closeOptions();
+// };
+// const changeView = (view) => {
+// runAction({ type: "change-view", view });
+// closeOptions();
+// runAction({ type: "toggle-menu", menuOpen: false });
+// };
+
+// return (
+//
+//
{
+// openOptions(document.getElementById("option-button"));
+// }}
+// label="Options"
+// />
+// {
+// closeOptions();
+// }}
+// animation={PopoverAnimationVertical}
+// >
+//
+// }
+// menuItems={[
+// {
+// changeView("list");
+// }}
+// rightIcon={view === "list" ? : null}
+// />,
+// {
+// changeView("map");
+// }}
+// rightIcon={view === "map" ? : null}
+// />,
+// ]}
+// />
+// }
+// value={selectedScale}
+// menuItems={[
+// {
+// selectScale("all");
+// }}
+// primaryText="All"
+// value="all"
+// rightIcon={selectedScale === "all" ? : null}
+// />,
+// {
+// selectScale("large");
+// }}
+// primaryText="Large"
+// value="large"
+// rightIcon={
+// selectedScale === "large" ? : null
+// }
+// />,
+// {
+// selectScale("medium");
+// }}
+// primaryText="Medium"
+// value="medium"
+// rightIcon={
+// selectedScale === "medium" ? : null
+// }
+// />,
+// {
+// selectScale("small");
+// }}
+// primaryText="Small"
+// value="small"
+// rightIcon={
+// selectedScale === "small" ? : null
+// }
+// />,
+// {
+// selectScale("tiny");
+// }}
+// primaryText="Tiny"
+// value="tiny"
+// rightIcon={
+// selectedScale === "tiny" ? : null
+// }
+// />,
+// ]}
+// />
+//
+//
+//
+// );
+// };
diff --git a/pages/maps/sources/archive_/scale-button.tsx b/pages/maps/sources/archive_/scale-button.tsx
new file mode 100644
index 000000000..7d9f19922
--- /dev/null
+++ b/pages/maps/sources/archive_/scale-button.tsx
@@ -0,0 +1,20 @@
+import React from "react";
+
+interface ScaleButton {
+ onClick: () => void;
+ selectedScale: string;
+ scale: string;
+}
+
+const ScaleButton = ({ onClick, selectedScale, scale }: ScaleButton) => (
+
+ {scale}
+
+);
+export default ScaleButton;
diff --git a/pages/maps/sources/archive_/source-map.tsx b/pages/maps/sources/archive_/source-map.tsx
new file mode 100644
index 000000000..7733e96c2
--- /dev/null
+++ b/pages/maps/sources/archive_/source-map.tsx
@@ -0,0 +1,81 @@
+import h from "@macrostrat/hyper";
+import mapboxgl from "mapbox-gl";
+import React, { Component } from "react";
+import { zoomMap } from "../app-state/utils";
+
+class SourceMap extends Component {
+ constructor(props) {
+ super(props);
+ }
+
+ componentDidMount() {
+ var map = (this.map = L.map(
+ `map-${this.props.feature.properties.source_id}`,
+ {
+ attributionControl: false,
+ minZoom: 0,
+ zoomControl: false,
+ scrollWheelZoom: false,
+ touchZoom: false,
+ boxZoom: false,
+ doubleClickZoom: false,
+ dragging: false,
+ }
+ ).setView([40.8, -94.1], 3));
+
+ L.tileLayer(
+ "https://{s}.tiles.mapbox.com/v3/jczaplewski.j751k57j/{z}/{x}/{y}.png",
+ {
+ attribution:
+ "© Mapbox © OpenStreetMap ",
+ }
+ ).addTo(map);
+
+ var bbox = L.geoJson(
+ {
+ type: "FeatureCollection",
+ features: [this.props.feature],
+ },
+ {
+ style: {
+ color: "#333", //stroke color
+ weight: 2, //stroke width
+ fillColor: "#aaaaaa",
+ },
+ onEachFeature: (feature, layer) => {
+ layer.on("click", (e) => {
+ var centerLng =
+ (this.props.feature.geometry.coordinates[0][0][0] +
+ this.props.feature.geometry.coordinates[0][2][0]) /
+ 2;
+ var centerLat =
+ (this.props.feature.geometry.coordinates[0][0][1] +
+ this.props.feature.geometry.coordinates[0][2][1]) /
+ 2;
+ window.location = `https://dev.macrostrat.org/burwell#${
+ zoomMap[this.props.feature.properties.scale]
+ }/${centerLat}/${centerLng}`;
+ });
+ },
+ }
+ ).addTo(map);
+
+ map.fitBounds(bbox.getBounds());
+ }
+
+ render() {
+ const { feature } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+function StaticSourceMap({ feature }) {
+ // probably have a better way to render static maps.
+
+ return h("div.static-map");
+}
+
+export default StaticSourceMap;
diff --git a/pages/maps/sources/components/app.ts b/pages/maps/sources/components/app.ts
new file mode 100644
index 000000000..1f86f91a2
--- /dev/null
+++ b/pages/maps/sources/components/app.ts
@@ -0,0 +1,27 @@
+import { useEffect } from "react";
+import { useBurwellActions } from "#/map/sources/app-state";
+import hyper from "@macrostrat/hyper";
+import IndexMapContainer from "./map";
+import { InfoDrawer } from "./info-drawer";
+import styles from "./main.module.scss";
+// // Needed for onTouchTap
+// import injectTapEventPlugin from 'react-tap-event-plugin'
+// // http://stackoverflow.com/a/34015469/988941
+// injectTapEventPlugin()
+
+const h = hyper.styled(styles);
+
+function App() {
+ const runAction = useBurwellActions();
+ useEffect(() => {
+ // Fetch the data on load
+ runAction({ type: "request-data" });
+ runAction({ type: "fetch-data" });
+ }, []);
+ return h("div.full-height", [
+ h(IndexMapContainer),
+ h("div.content-overlay", [h(InfoDrawer)]),
+ ]);
+}
+
+export default App;
diff --git a/pages/maps/sources/components/feature-list.tsx b/pages/maps/sources/components/feature-list.tsx
new file mode 100644
index 000000000..f6a7ff0ef
--- /dev/null
+++ b/pages/maps/sources/components/feature-list.tsx
@@ -0,0 +1,106 @@
+import h from "@macrostrat/hyper";
+import { ExpansionPanel } from "@macrostrat/map-interface";
+import { Link } from "~/components";
+import { useBurwellActions } from "#/map/sources/app-state";
+import { zoomMap } from "../app-state/utils";
+
+function FeatureTable(props) {
+ const { d } = props;
+
+ return (
+
+
+
+
+ Source ID
+
+ {d.properties.source_id}
+
+
+
+ Scale
+
+
+
+ {d.properties.scale}
+
+
+
+
+
+ Features
+
+ {d.properties.features}
+
+
+
+ );
+}
+
+function ViewMap({ feature }) {
+ const { geometry, properties } = feature;
+ const { coordinates } = geometry;
+
+ if (coordinates == null) {
+ return null;
+ }
+ // lon lat zoom
+ // #layers=bedrock,lines&x=5.012&y=29.031&z=1.45
+ const zoom = zoomMap[properties.scale];
+ const lat = (coordinates[0][0][1] + coordinates[0][2][1]) / 2;
+ const long = (coordinates[0][0][0] + coordinates[0][2][0]) / 2;
+ const to = `/map#layers=bedrock,lines&x=${long}&y=${lat}&z=${zoom}`;
+
+ return View map;
+}
+
+function FeatureContent({ d, activateFeature }) {
+ return (
+ activateFeature(d)}
+ onMouseLeave={() => activateFeature({})}
+ >
+
+ {d.properties.ref_title}
+ {d.properties.authors} ({d.properties.ref_year}).{" "}
+ {d.properties.ref_title} . {d.properties.ref_source}.
+ {d.properties.isbn_doi}. Retrieved from{" "}
+
+ {d.properties.url}
+
+ .{" "}
+
+
+
+
+ );
+}
+
+const FeatureList = ({ features, open = true }) => {
+ const runAction = useBurwellActions();
+ const activateFeature = (feature) => {
+ runAction({ type: "activate-feature", activeFeature: feature });
+ };
+
+ return (
+
+ {features.map((d, i) => {
+ return h(
+ ExpansionPanel,
+ { title: d.properties.name, expanded: true, key: i },
+ [ ]
+ );
+ })}
+
+ );
+};
+
+export { FeatureContent };
+export default FeatureList;
diff --git a/pages/maps/sources/components/info-drawer.ts b/pages/maps/sources/components/info-drawer.ts
new file mode 100644
index 000000000..fcec5127f
--- /dev/null
+++ b/pages/maps/sources/components/info-drawer.ts
@@ -0,0 +1,79 @@
+import { Button, Navbar } from "@blueprintjs/core";
+import h from "@macrostrat/hyper";
+import { useState, useEffect } from "react";
+import {
+ getVisibleScale,
+ useBurwellActions,
+ useBurwellState,
+} from "../app-state";
+import Options from "./options";
+import { InfoDrawerContainer } from "@macrostrat/map-interface";
+import FeatureList from "./feature-list";
+import { PageBreadcrumbs } from "~/components";
+
+function BackButton() {
+ const runAction = useBurwellActions();
+ const removeSelectedFeatures = () => {
+ runAction({ type: "select-features", selectedFeatures: [] });
+ };
+ return h(
+ Button,
+ {
+ icon: "chevron-left",
+ minimal: true,
+ onClick: removeSelectedFeatures,
+ },
+ ["Back"]
+ );
+}
+
+function Header({ len, btn }) {
+ return h(Navbar, [
+ h.if(len == 0)(Navbar.Group, [h(Navbar.Heading, [h(PageBreadcrumbs)])]),
+ h.if(len > 0)(Navbar.Group, [
+ h(BackButton),
+ h(Navbar.Heading, { style: { marginLeft: "20px" } }, [
+ h("div.expansion-summary-title", ["Selected Sources"]),
+ ]),
+ ]),
+ h(Navbar.Group, { align: "right" }, [h(Options), btn]),
+ ]);
+}
+
+function InfoDrawer() {
+ const { selectedFeatures, maps, selectedScale } = useBurwellState(
+ (state) => state
+ );
+
+ const [open, setOpen] = useState(true);
+
+ const data = getVisibleScale(maps, selectedScale);
+
+ const len = selectedFeatures.length;
+
+ useEffect(() => {
+ if (len > 0 && !open) {
+ setOpen(true);
+ }
+ }, [len]);
+
+ function CloseBtn() {
+ return h(Button, {
+ style: { marginRight: "-12px" },
+ minimal: true,
+ onClick: () => setOpen(!open),
+ icon: open ? "chevron-up" : "chevron-down",
+ });
+ }
+ return h(
+ "div.infodrawer-container-sources",
+ null,
+ h(InfoDrawerContainer, [
+ h(Header, { len, btn: h(CloseBtn) }),
+ h.if(len == 0)(FeatureList, { features: data, open }),
+ h.if(len > 0)(FeatureList, { features: selectedFeatures, open }),
+ ])
+ );
+}
+
+export { InfoDrawer };
diff --git a/pages/maps/sources/components/main.module.scss b/pages/maps/sources/components/main.module.scss
new file mode 100644
index 000000000..533ee0388
--- /dev/null
+++ b/pages/maps/sources/components/main.module.scss
@@ -0,0 +1,8 @@
+.content-overlay {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ right: 20px;
+ bottom: 30px;
+ pointer-events: none;
+}
diff --git a/pages/maps/sources/components/map/index.ts b/pages/maps/sources/components/map/index.ts
new file mode 100644
index 000000000..1c3f46eb9
--- /dev/null
+++ b/pages/maps/sources/components/map/index.ts
@@ -0,0 +1,72 @@
+import h from "@macrostrat/hyper";
+import "mapbox-gl/dist/mapbox-gl.css";
+import { useEffect, useRef, useState } from "react";
+import {
+ flyToData,
+ useBurwellActions,
+ useBurwellState,
+} from "#/map/sources/app-state";
+import { initializeMap } from "./initialize-map";
+import { mapSources } from "./map-sources";
+
+function IndexMapContainer() {
+ const [viewport, setViewport] = useState({
+ longitude: 0,
+ latitude: 40,
+ zoom: 1,
+ });
+ const mapContainerRef = useRef(null);
+ const mapRef = useRef(null);
+
+ const { maps, selectedScale, activeFeature, flyTo } = useBurwellState(
+ (state) => state
+ );
+ const runAction = useBurwellActions();
+ const onSelectFeatures = (features) => {
+ runAction({ type: "select-features", selectedFeatures: features });
+ };
+
+ useEffect(() => {
+ if (mapContainerRef.current == null) return;
+ initializeMap({
+ mapContainer: mapContainerRef.current,
+ viewport,
+ setViewport,
+ }).then((mapObj) => {
+ mapRef.current = mapObj;
+ });
+ return () => {
+ mapRef.current?.remove();
+ };
+ }, [mapContainerRef]);
+
+ useEffect(() => {
+ if (mapRef.current == null) return;
+ mapSources(
+ mapRef.current,
+ maps,
+ onSelectFeatures,
+ activeFeature,
+ selectedScale
+ );
+ return () => {
+ // remove current click events to prevent stack overflow
+ mapRef.current.off(
+ "click",
+ "sources-fill",
+ mapRef.current.sourcesFillListener
+ );
+ mapRef.current.off("click", mapRef.current.clickMap);
+ };
+ }, [mapRef, maps, activeFeature, selectedScale]);
+
+ useEffect(() => {
+ if (mapRef.current == null || !activeFeature.id || !flyTo) return;
+ const map = mapRef.current;
+ map.flyTo(flyToData(activeFeature));
+ }, [activeFeature]);
+
+ return h("div.index-map-container", { ref: mapContainerRef });
+}
+
+export default IndexMapContainer;
diff --git a/pages/maps/sources/components/map/initialize-map.ts b/pages/maps/sources/components/map/initialize-map.ts
new file mode 100644
index 000000000..5a9840440
--- /dev/null
+++ b/pages/maps/sources/components/map/initialize-map.ts
@@ -0,0 +1,41 @@
+import mapboxgl from "mapbox-gl";
+import { mapboxAccessToken } from "@macrostrat-web/settings";
+
+interface viewport {
+ longitude: number;
+ latitude: number;
+ zoom;
+}
+interface MapProps {
+ mapContainer: HTMLDivElement;
+ viewport: viewport;
+ setViewport: (viewport) => void;
+ bounds?: number[];
+ boxZoom?: boolean;
+}
+/*
+shared function to initialize a Mapbox Gl Js map in a useEffect
+*/
+async function initializeMap(props: MapProps): Promise {
+ mapboxgl.accessToken = mapboxAccessToken;
+ var map = new mapboxgl.Map({
+ container: props.mapContainer,
+ style: "mapbox://styles/mapbox/outdoors-v11", // style URL
+ center: [props.viewport.longitude, props.viewport.latitude], // starting position [lng, lat]
+ zoom: props.viewport.zoom, // starting zoom
+ bounds: props.bounds || null,
+ boxZoom: props.boxZoom || true,
+ });
+ map.on("move", () => {
+ const [zoom, latitude, longitude] = [
+ map.getZoom().toFixed(2),
+ map.getCenter().lat.toFixed(4),
+ map.getCenter().lng.toFixed(4),
+ ];
+ props.setViewport({ longitude, latitude, zoom });
+ });
+
+ return map;
+}
+
+export { initializeMap };
diff --git a/pages/maps/sources/components/map/map-sources.ts b/pages/maps/sources/components/map/map-sources.ts
new file mode 100644
index 000000000..dda50d4f7
--- /dev/null
+++ b/pages/maps/sources/components/map/map-sources.ts
@@ -0,0 +1,176 @@
+import { getVisibleScale } from "../../app-state";
+
+function setStyle(props) {
+ const { map, maps, selectedScale, activeFeature } = props;
+ if (map.getSource("burwell-sources")) {
+ if (selectedScale != map.scale) {
+ // if the scale has been changed
+ // reset the data on the burwell-sources source
+ map.scale = selectedScale;
+ const filteredMaps = {
+ type: "FeatureCollection",
+ features: getVisibleScale(maps, selectedScale),
+ };
+ map.getSource("burwell-sources").setData(filteredMaps);
+ }
+
+ if (activeFeature.id !== undefined) {
+ map.activeFeatureId = activeFeature.id;
+ map.setFeatureState(
+ { source: "burwell-sources", id: activeFeature.id },
+ { active: true }
+ );
+ } else {
+ if (map.activeFeatureId) {
+ map.setFeatureState(
+ { source: "burwell-sources", id: map.activeFeatureId },
+ { active: false }
+ );
+ }
+ }
+ }
+}
+
+function validateCoordinates(coordinates) {
+ // If any coordinate is greater than 180 or less than -180, return false,
+ // progress into nested arrays if they exist.
+ // This happens because some of our coordinates are in pixel space.
+ if (coordinates.length == 0) {
+ return true;
+ }
+ if (typeof coordinates[0] == "number") {
+ return (
+ coordinates[0] <= 180 &&
+ coordinates[0] >= -180 &&
+ coordinates[1] <= 90 &&
+ coordinates[1] >= -90
+ );
+ }
+ return coordinates.every(validateCoordinates);
+}
+
+function addMapSources(map, maps) {
+ if (map.getSource("burwell-sources") != null) {
+ map.removeLayer("sources-fill");
+ map.removeLayer("outline");
+ map.removeSource("burwell-sources");
+ }
+
+ // Ensure all maps have valid geometry
+ // This is a temporary fix for a bug in the API and data service
+ maps = maps.filter((f) => {
+ if (f.geometry?.type == null) {
+ return false;
+ }
+ return validateCoordinates(f.geometry.coordinates);
+ });
+
+ const filteredMaps = {
+ type: "FeatureCollection",
+ features: maps,
+ };
+
+ map.addSource("burwell-sources", {
+ type: "geojson",
+ data: filteredMaps,
+ });
+ map.addLayer({
+ id: "sources-fill",
+ type: "fill",
+ source: "burwell-sources", // reference the data source
+ paint: {
+ "fill-opacity": 0.1,
+ "fill-color": [
+ "case",
+ ["boolean", ["feature-state", "active"], false],
+ "#ffae80",
+ "#aaaaaa",
+ ],
+ },
+ });
+ map.addLayer({
+ id: "outline",
+ type: "line",
+ source: "burwell-sources",
+ layout: {},
+ paint: {
+ "line-color": [
+ "case",
+ ["boolean", ["feature-state", "clicked"], false],
+ "#ffae80",
+ "#333",
+ ],
+ "line-width": 2,
+ },
+ });
+}
+
+async function mapSources(
+ map,
+ maps,
+ onSelectFeatures,
+ activeFeature,
+ selectedScale
+) {
+ map.scale = selectedScale;
+
+ const filteredMaps = getVisibleScale(maps, selectedScale).filter(
+ (f) => f.properties.source_id != 154
+ );
+
+ if (!map.isStyleLoaded()) {
+ map.on("load", () => {
+ addMapSources(map, filteredMaps);
+ setStyle({ map, maps, selectedScale, activeFeature });
+ });
+ } else {
+ addMapSources(map, filteredMaps);
+ setStyle({ map, maps, selectedScale, activeFeature });
+ }
+
+ map.sourcesFillListener = (e) => {
+ if (map.clickedFeatures) {
+ map.clickedFeatures.map((f) => {
+ map.setFeatureState(
+ { source: "burwell-sources", id: f.id },
+ { clicked: false }
+ );
+ });
+ }
+ let features_ = [];
+ e.features.map((f) => {
+ if (f.state.clicked) {
+ map.setFeatureState(
+ { source: "burwell-sources", id: f.id },
+ { clicked: false }
+ );
+ } else {
+ features_.push(f);
+ map.setFeatureState(
+ { source: "burwell-sources", id: f.id },
+ { clicked: true }
+ );
+ }
+ });
+ if (e.features.length) {
+ map.clickedFeatures = features_;
+ onSelectFeatures(features_);
+ }
+ };
+
+ map.clickMap = (e) => {
+ if (map.clickedFeatures) {
+ map.clickedFeatures.map((f) => {
+ map.setFeatureState(
+ { source: "burwell-sources", id: f.id },
+ { clicked: false }
+ );
+ });
+ }
+ };
+
+ map.on("click", map.clickMap);
+ map.on("click", "sources-fill", map.sourcesFillListener);
+}
+
+export { mapSources };
diff --git a/pages/maps/sources/components/options.tsx b/pages/maps/sources/components/options.tsx
new file mode 100644
index 000000000..be9780732
--- /dev/null
+++ b/pages/maps/sources/components/options.tsx
@@ -0,0 +1,67 @@
+import {
+ Button,
+ Icon,
+ Menu,
+ MenuDivider,
+ MenuItem,
+ Popover,
+ Switch,
+} from "@blueprintjs/core";
+import h from "@macrostrat/hyper";
+import { useBurwellActions, useBurwellState } from "#/map/sources/app-state";
+
+const capitalizeWord = (word) => {
+ return word.charAt(0).toUpperCase() + word.slice(1);
+};
+
+function OptionsMenu() {
+ const { selectedScale, flyTo } = useBurwellState((state) => state);
+ const runAction = useBurwellActions();
+
+ const onChange = () => {
+ runAction({ type: "toggle-fly-option", flyTo: !flyTo });
+ };
+
+ const sizes = ["all", "large", "medium", "small", "tiny"];
+
+ return h(Menu, [
+ h(Switch, {
+ style: { margin: "3px" },
+ checked: flyTo,
+ alignIndicator: "right",
+ innerLabel: "off",
+ innerLabelChecked: "on",
+ label: "Fly To Source",
+ onChange,
+ }),
+ h(MenuDivider, { title: "Scale" }),
+ sizes.map((size, i) => {
+ const onClick = (e) => {
+ runAction({ type: "select-scale", selectedScale: size });
+ };
+ const iconName = size === selectedScale ? "tick" : null;
+ const intent = size === selectedScale ? "primary" : "none";
+ return h(MenuItem, {
+ onClick,
+ intent,
+ key: i,
+ text: capitalizeWord(size),
+ labelElement: h(Icon, { icon: iconName }),
+ });
+ }),
+ ]);
+}
+
+function Options() {
+ return h(
+ Popover,
+ { content: h(OptionsMenu), minimal: true, position: "bottom-right" },
+ [
+ h(Button, { minimal: true }, [
+ h("h5", { style: { margin: "0" } }, ["Options"]),
+ ]),
+ ]
+ );
+}
+
+export default Options;
diff --git a/pages/people/+Page.client.ts b/pages/people/+Page.client.ts
new file mode 100644
index 000000000..ffe0ad2d1
--- /dev/null
+++ b/pages/people/+Page.client.ts
@@ -0,0 +1,191 @@
+import { Image, Navbar, Footer } from "../index";
+import h from "./main.module.sass"
+import { Card, Icon } from "@blueprintjs/core";
+import { useState } from "react";
+
+export function Page() {
+ const [input, setInput] = useState("");
+ const [tags, setTags] = useState([]);
+ const res = [
+ {
+ "name": "Shanan Peters",
+ "role": "Professor, Database Developer",
+ "email": "peters@geology.wisc.edu",
+ "link": "http://strata.geology.wisc.edu",
+ "image": "shanan.jpg"
+ },
+ {
+ "name": "Daven Quinn",
+ "role": "Research Scientist, Developer",
+ "email": "daven.quinn@wisc.edu",
+ "link": "https://davenquinn.com",
+ "image": "daven.jpg"
+ },
+ {
+ "name": "Evgeny Mazko",
+ "role": "Graduate Student",
+ "email": "mazko@wisc.edu",
+ "link": null,
+ "image": "evgeny.jpg"
+ },
+ {
+ "name": "Michael McClennen",
+ "role": "Senior Programmer Analyst",
+ "email": "mmcclenn@geology.wisc.edu",
+ "link": "https://geoscience.wisc.edu/geoscience/people/staff/name/michael-mcclennen/",
+ "image": "michael.jpg"
+ },
+ {
+ "name": "Casey Idzikowski",
+ "role": "Research Specialist, Developer (former)",
+ "email": null,
+ "link": "https://idzikowski-casey.github.io/personal-site/",
+ "image": "casey.jpg"
+ },
+ {
+ "name": "David Sklar",
+ "role": "Undergraduate Research Assistant",
+ "email": "dsklar@wisc.edu",
+ "link": null,
+ "image": "david.jpg"
+ },
+ {
+ "name": "Amy Fromandi",
+ "role": null,
+ "email": "punkish@eidesis.org",
+ "link": null,
+ "image": "amy.jpg"
+ },
+ {
+ "name": "Daniel Segessenmen",
+ "role": "Graduate Student (former)",
+ "email": null,
+ "link": "http://strata.geology.wisc.edu",
+ "image": "daniel.jpg"
+ },
+ {
+ "name": "Shan Ye",
+ "role": "Graduate Student (former)",
+ "email": null,
+ "link": "https://www.wisc.edu/directories/person.php?name=Victoria+Khoo&email=vkhoo%40wisc.edu&query=victoria%20khoo",
+ "image": "shan.jpg"
+ },
+ {
+ "name": "Ben Linzmeier",
+ "role": "Postdoctoral Scholar (former)",
+ "email": null,
+ "link": "http://strata.geology.wisc.edu",
+ "image": "ben.jpg"
+ },
+ {
+ "name": "Afiqah Rafi",
+ "role": "Undergrad Student (former)",
+ "email": null,
+ "link": "https://www.wisc.edu/directories/person.php?name=Victoria+Khoo&email=vkhoo%40wisc.edu&query=victoria%20khoo",
+ "image": "afiqah.jpg"
+ },
+ {
+ "name": "Sharon McMullen",
+ "role": "Researcher (former)",
+ "email": null,
+ "link": "http://geoscience.wisc.edu/geoscience/people/student/?id=1007",
+ "image": "sharon.jpg"
+ },
+ {
+ "name": "Andrew Zaffos",
+ "role": "Data Mobilization and Research Scientist",
+ "email": "azaffos@email.arizona.edu",
+ "link": "http://www.azstrata.org",
+ "image": "andrew.jpg"
+ },
+ {
+ "name": "Jon Husson",
+ "role": "Postdoctoral Researcher (former)",
+ "email": "jhusson@uvic.ca",
+ "link": "http://www.jonhusson.com",
+ "image": "jon.jpg"
+ }
+ ];
+
+ console.log(tags)
+
+ const tagList = [
+ "Student",
+ "Researcher",
+ "Developer",
+ "Postdoc",
+ "Research Scientist",
+ "Former"
+ ]
+
+ const handleInputChange = (e) => {
+ const value = e.target.value;
+ setInput(value);
+ };
+
+ const filteredPeople = res.filter(person => {
+ const name = person.name.toLowerCase();
+ const role = person.role ? person.role.toLowerCase() : "";
+ const email = person.email ? person.email.toLowerCase() : "";
+
+ const roleTags = tagList.map(tag => {
+ if (role.includes(tag.toLowerCase())) {
+ return tag;
+ }
+ return null;
+ }).filter(tag => tag !== null);
+ const tagMatch = tags.length === 0 || tags.some(tag => roleTags.includes(tag));
+
+ return (name.includes(input) || role.includes(input) || email.includes(input)) && tagMatch;
+ });
+
+ return h('div.main', [
+ h(Navbar),
+ h('h1.big', "People"),
+ h('p.subtitle', "major contributors to the project"),
+ h(Card, { className: "search-bar" }, [
+ h('div.input-container', [
+ h(Icon, { icon: "search", style: { color: "white" } }),
+ h("input", {
+ type: "text",
+ placeholder: "Search people...",
+ onChange: handleInputChange,
+ }),
+ ]),
+ h('div.tags', [
+ tagList.map(tag => {
+ return h('div', {
+ onClick: () => {
+ setTags(prevTags => {
+ if (prevTags.includes(tag)) {
+ return prevTags.filter(t => t !== tag);
+ } else {
+ return [...prevTags, tag];
+ }
+ }
+ )
+ },
+ className: tags.includes(tag) ? "filter-card selected" : "filter-card"
+ }, tag);
+ })
+ ])
+ ]),
+ h('div.people', [
+ filteredPeople.map(person => {
+ return h(PersonCard, person);
+ })
+ ]),
+ h(Footer)
+ ])
+}
+
+function PersonCard({ name, role, email, link, image }) {
+ return h('div.person-info', [
+ h(Image, { src: image, className: "back-img" }),
+ h('div.description', [
+ h('a.name', { href: link }, name),
+ role ? h('p.role', role) : null,
+ email ? h('a.email', { href: "mailto: " + email}, email) : null,
+ ]),
+ ]);
+}
\ No newline at end of file
diff --git a/pages/people/main.module.sass b/pages/people/main.module.sass
new file mode 100644
index 000000000..6a9226dea
--- /dev/null
+++ b/pages/people/main.module.sass
@@ -0,0 +1,116 @@
+.html, .body, .main
+ color: black
+ background-color: var(--background-color)
+
+a:hover
+ text-decoration: none
+
+.big
+ color: var(--text-color)
+ text-align: left
+ font-size: 75px
+ font-family: "Maven Pro", sans-serif
+ margin: 0
+ margin-left: 20%
+ padding-top: 100px
+
+.line
+ border-bottom: 1px solid black
+ width: 60%
+ margin: 0 20%
+
+
+.people
+ display: flex
+ flex-wrap: wrap
+ align-items: center
+ justify-content: center
+ gap: 30px
+ padding: 50px 20%
+
+ .person-info
+ flex-basis: 45%
+ height: 30vh
+ width: 45%
+ position: relative
+
+ .back-img
+ position: relative
+ z-index: 0
+ object-fit: cover
+ width: 100%
+ height: 100%
+
+ a
+ color: white !important
+
+ .description
+ position: absolute
+ bottom: 0
+ right: 0
+ display: flex
+ flex-direction: column
+ gap: .25em
+ text-align: right
+ padding: 5px 20px
+ z-index: 100
+ color: white
+ background-color: rgba(0, 0, 0, 0.2)
+ white-space: nowrap
+ margin: 5px
+
+ p
+ margin: 0 !important
+
+ a
+ color: white
+
+ a:hover
+ color: white
+
+.role
+ font-weight: 400px
+
+.email
+ font-size: 14px
+ font-weight: 200px
+
+.subtitle
+ margin-left: 20%
+ color: var(--text-color)
+
+.search-bar
+ margin: .5em 20%
+
+ input
+ margin: 0
+
+.divider
+ background-color: black
+ margin: 0 20% !important
+
+.input-container
+ display: flex
+ align-items: center
+ justify-content: center
+ gap: 5px
+ width: 100%
+ margin-bottom: 1em
+
+.tags
+ display: flex
+ gap: 5px
+ justify-content: center
+
+ .filter-card
+ padding: 2px 5px
+ background-color: var(--secondary-background-color)
+ color: var(--text-color)
+ border-radius: 5%
+
+ .selected
+ background-color: var(--background-color)
+
+.search-bar
+ display: flex
+ flex-direction: column
\ No newline at end of file
diff --git a/pages/projects/+Page.ts b/pages/projects/+Page.ts
index 6bcac9488..aa079dcce 100644
--- a/pages/projects/+Page.ts
+++ b/pages/projects/+Page.ts
@@ -1,31 +1,50 @@
-import h from "@macrostrat/hyper";
+import h from "./main.module.scss";
import { ContentPage } from "~/layouts";
import { PageHeader, LinkCard } from "~/components";
import { useData } from "vike-react/useData";
+import { Image } from "../index";
+
export function Page() {
+ // static list of projects with pictures
+ const pictures = {
+ 1: 'north_america_med.jpg',
+ 4: 'deep_sea_new_medium.jpg',
+ 5: 'new_zealand_new_medium.jpg',
+ 7: 'caribbean_new_medium.jpg',
+ }
+
const { projects } = useData();
+
return h(ContentPage, [
h(PageHeader, { title: "Projects" }),
- projects.map((d) => h(ProjectItem, { data: d, key: d.project_id })),
+ projects.map((d) => h(ProjectItem, { data: d, key: d.project_id, pictures })),
]);
}
-function ProjectItem({ data }) {
+function ProjectItem({ data, pictures }) {
+ // check if has picture
+ const hasPicture = pictures[data.project_id] != null;
+
const { project_id, project, descrip } = data;
const href = `/projects/${project_id}`;
- return h(LinkCard, { href, title: project }, [
- h("p", descrip),
- h("p.col_stats", [
- h(KeyValue, { name: "Columns", value: data.t_cols }),
- ", ",
- h(KeyValue, { name: "in process", value: data.in_proccess_cols }),
- ", ",
- h(KeyValue, { name: "obsolete", value: data.obsolete_cols }),
- "; ",
- h(KeyValue, { name: "Units", value: data.t_units }),
- ]),
- ]);
+ return h(LinkCard, { href, title: project },
+ h('div.project', [
+ h('div.project-body', [
+ h("p", descrip),
+ h("p.col_stats", [
+ h(KeyValue, { name: "Columns", value: data.t_cols }),
+ ", ",
+ h(KeyValue, { name: "in process", value: data.in_proccess_cols }),
+ ", ",
+ h(KeyValue, { name: "obsolete", value: data.obsolete_cols }),
+ "; ",
+ h(KeyValue, { name: "Units", value: data.t_units }),
+ ]),
+ ]),
+ hasPicture ? h(Image, {src: pictures[data.project_id]}) : null,
+ ])
+ );
}
function KeyValue({ name, value }) {
diff --git a/pages/projects/@project/+Page.ts b/pages/projects/@project/+Page.client.ts
similarity index 80%
rename from pages/projects/@project/+Page.ts
rename to pages/projects/@project/+Page.client.ts
index 2d22e1300..d0b9a21f9 100644
--- a/pages/projects/@project/+Page.ts
+++ b/pages/projects/@project/+Page.client.ts
@@ -1,5 +1,5 @@
import h from "@macrostrat/hyper";
-import { Page as ColumnListPage } from "#/columns/+Page";
+import { Page as ColumnListPage } from "#/columns/+Page.client.ts";
import { useData } from "vike-react/useData";
export function Page() {
diff --git a/pages/projects/main.module.scss b/pages/projects/main.module.scss
new file mode 100644
index 000000000..905722ffa
--- /dev/null
+++ b/pages/projects/main.module.scss
@@ -0,0 +1,10 @@
+.project {
+ display: flex;
+ justify-content: space-between;
+ gap: .5em;
+
+ img {
+ height: 15vh;
+ width: 20%;
+ }
+}
\ No newline at end of file
diff --git a/pages/publications/+Page.client.ts b/pages/publications/+Page.client.ts
new file mode 100644
index 000000000..849b82b53
--- /dev/null
+++ b/pages/publications/+Page.client.ts
@@ -0,0 +1,322 @@
+import { Image, Navbar, Footer } from "../index";
+import { Divider } from "@blueprintjs/core"
+import h from "./main.module.sass"
+
+
+export function Page() {
+ return h('div.container', [
+ h(Navbar),
+
+
+ h('div.publications', [
+ h('h1.pub-title', "Publications"),
+ h('p.blurb', "literature utilizing Macrostrat"),
+ h(Divider, { className: 'divider' }),
+ h('ol', { class: 'pub-list', reversed: true }, [
+ h('li', [
+ h('span', "Hammarlund, E. et al. 2025. Benthic diel oxygen variability and stress as potential drivers for animal diversification in the Neoproterozoic-Palaeozoic. Nature Communications 16:2223."),
+ h('a', { href: 'https://doi.org/10.1038/s41467-025-57345-0', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Lovelace, D. M., Kufner, A.M., et al. 2025. Rethinking dinosaur origins: oldest known equatorial dinosaur-bearing assemblage (mid-late Carnian Popo Agie FM, Wyoming, USA). Zoological Journal of the Linnean Society, 203(1),zlae153."),
+ h('a', { href: 'https://doi.org/10.1093/zoolinnean/zlae153', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Jones, L.A., C.D. Dean, W. Gearty, B.J. Allen. 2024. rmacrostrat : An R package for accessing and retrieving data from the Macrostrat geological database. Geosphere, 20(6):1456–1467. 10.1130/GES02815.1."),
+ h('a', { href: 'https://doi.org/10.1130/GES02815.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Evans, S.D., E.F. Smith, P. Vayda, L.L. Nelson, S. Xiao. 2024. The Ediacara Biota of the Wood Canyon formation: Latest Precambrian macrofossils and sedimentary structures from the southern Great Basin. Global and Planetary Change, 242:104851. 10.1016/j.gloplacha.2024.104547."),
+ h('a', { href: 'https://doi.org/10.1016/j.gloplacha.2024.104547', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Howes, B., A. Mehra, E. Geyman, J. Wilcots, R. Manzuk, C. Deutsch, A. Maloof. 2024. The where, when, and how of ooid formation: what ooids tell us about ancient seawater chemistry. Earth and Planetary Science Letters, 637:118697. 10.1016/j.epsl.2024.118697."),
+ h('a', { href: 'https://doi.org/10.1016/j.epsl.2024.118697', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Smiley, T.M., A.Bahadori, E.T. Rasbury, W.E. Holt, C. Badgley. 2024. Tectonic extension and paleoelevation influence mammalian diversity dynamics in the Basin and Range Province of western North America. Science Advances, 10:eadn6842. 10.1126/sciadv.adn6842."),
+ h('a', { href: 'https://www.science.org/doi/10.1126/sciadv.adn6842', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Gazdewich, S., T. Hauck, J. Husson. 2024. Authigenic carbonate burial within the Late Devonian western Canada sedimentary bsain and its impact on the global carbon cycle. Geochemistry, Geophysics, Geosystems 10.1029/2023GC011376."),
+ h('a', { href: 'https://doi.org/10.1029/2023GC011376', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Segessenman, D.C. and S.E. Peters. 2024. Transgression-regression cycles drive correlations in Ediacaran-Cambrian rock and fossil records. Paleobiology 10.1017/pab.2023.31."),
+ h('a', { href: 'https://doi.org/10.1017/pab.2023.31', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Quinn, D.P., S.E. Peters, J.M. Husson, R.R. Gaines. 2024. The Macrostrat data system: a platform for Earth crust research and education. Geochemistry, Geophysics, Geosystems 10.1029/2023GC013098."),
+ h('a', { href: 'https://doi.org/10.1029/2023GC013098', target: '_blank' }, "[link]")
+ ]),
+
+
+ h('li', [
+ h('span', "Husson, J.M., S.E. Peters, D.C. Segessenman, R.R. Gaines. 2024. The sedimentary rock record of the Ediacaran-Cambrian transition in North America. Geological Society of America Bulletin 10.1130/B37058.1."),
+ h('a', { href: 'https://doi.org/10.1130/B37058.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Walton, C.R., J. Hao, F. Huang, F.E. Jenner, H. Williams, A.L. Zerkle, A. Lipp, R.M. Hazen, S.E. Peters, O. Shorttle. 2023. Evolution of the crustal phosphorus reservoir. Science Advances 9(18):eade6923."),
+ h('a', { href: 'https://doi.org/10.1126/sciadv.ade6923', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Balseiro, D. and M.G. Powell. 2023. Relative oversampling of carbonate rocks in the North American marine fossil record. Paleobiology"),
+ h('a', { href: 'https://doi.org/10.1017/pab.2023.16', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Ye, S., S.E. Peters. 2023. Bedrock geological map predictions for Phanerozoic fossil occurrences. Paleobiology 49(3):394-413."),
+ h('a', { href: 'https://doi.org/10.1017/pab.2022.46', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Wang, J., Tarhan, L.G., Jacobson, A.D. et al. 2023. The evolution of the marine carbonate factory. Nature https://doi.org/10.1038/s41586-022-05654-5."),
+ h('a', { href: 'https://www.nature.com/articles/s41586-022-05654-5', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Capel, E., C. Monnet, C.J. Cleal, J. Xue, T. Servais, B. Cascales-Miñana. 2023. The effect of geological biases on our perception of early land plant radiation. Palaeontology 66:e12644."),
+ h('a', { href: 'https://onlinelibrary.wiley.com/doi/epdf/10.1111/pala.12644', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Sessa, J.A., A.J. Fraass, LJ. LeVay, K.M. Jamson, S.E. Peters. 2023. The Extending Ocean Drilling Pursuits (eODP) Project: Synthesizing Scientific Ocean Drilling Data. Geochemistry, Geophysics, Geosystems"),
+ h('a', { href: 'https://doi.org/10.1029/2022GC010655', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Segessenman, D.C. and S.E. Peters. 2023. Macrostratigraphy of the Ediacaran system in North America. In 'Laurentia: Turning Points in the Evolution of a Continent.' S.J. Whitmeyer, M.L. Williams, D.A. Kellett, B. Tikoff, eds. GSA Memoir."),
+ h('a', { href: 'https://doi.org/10.1130/2022.1220(21)', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Boulila, S., S.E. Peters, R.D. Müller, B.U. Haq, N.Hara. 2023. Earth's interior dynamics drive marine fossil diversity cycles of tens of millions of years. Proceedings of the National Academy of Sciences e2221149120."),
+ h('a', { href: 'https://doi.org/0.1073/pnas.2221149120', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., D. Quinn, J.M. Husson, R.R. Gaines. 2022. Macrostratigraphy: insights into cyclic and secular evolution of the Earth-life system. Ann. Rev. Earth & Planet. Sci. 50:419-449."),
+ h('a', { href: 'https://doi.org/10.1146/annurev-earth-032320-081427', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Emmings, J.F., S.W. Poulton, J. Walsh, K.A. Leeming, I. Ross, S.E. Peters. 2022. Pyrite mega-analysis reveals modes of anoxia through geologic time. Science Advances 8(11)."),
+ h('a', { href: 'https://doi.org/10.1126/sciadv.abj5687', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Chen, G., Q. Cheng, S.E. Peters, C.J. Spencer, M. Zhao. 2022. Feedback between surface and deep processes: insight from time series analysis of sedimentary record. Earth and Planet. Sci. Letters."),
+ h('a', { href: 'https://doi.org/10.1016/j.epsl.2021.117352', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. et al. 2021. Igneous rock area and age in continental crust. Geology. doi:10.1130/G49037.1."),
+ h('a', { href: 'https://doi.org/10.1130/G49037.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Loughney, K.M., C. Badgley, A. Bahadori, W.E. Hold, and E.T. Rasbury. 2021. Tectonic influence on Cenozoic mammal richness and sedimentation history of the Basin and Range, western North America. Science Advances 7(45):p.eabh4470."),
+ h('a', { href: 'https://doi.org/10.1126/sciadv.abh4470', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Key, M.M. Jr., P.N.W. Jackson, C.M. Reid. 2021. Trepostome bryozoans buck the trend and ignore calcite-aragonite seas. Palaeobiodiversity and Palaeoenvironments. doi:10.1007/s12549-021-00507-x."),
+ h('a', { href: 'https://link.springer.com/article/10.1007/s12549-021-00507-x', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Lipp, A.G. et al. 2021. The composition and weathering of the continents over geologic time. Geochemical Perspectives Letters. doi:10.7185/geochemlet.2109."),
+ h('a', { href: 'https://doi.org/10.7185/geochemlet.2109', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Barnes, B.D., J.M. Husson, S.E. Peters. 2020. Authigenic carbonate burial in the Late Devonian–Early Mississippian Bakken Formation (Williston Basin, USA). Sedimentology. doi:10.1111/sed.12695."),
+ h('a', { href: 'https://doi.org/10.1111/sed.12695', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Close, R.A. et al. 2020. The spatial structure of Phanerozoic marine animal diversity. Science doi:10.1126/science.aay8309."),
+ h('a', { href: 'https://doi.org/10.1126/science.aay8309', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Balseiro, D. and M.G. Powell. 2019. Carbonate collapse and the Late Paleozoic Ice Age marine biodiversity crisis. Geology doi:10.1130/G46858.1."),
+ h('a', { href: 'https://doi.org/10.1130/G46858.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Keller, C.B., J.M. Husson, R.N. Mitchell, W.F. Bottke, T.M. Gernon, P. Boehnke, E.A. Bell, N.L. Swanson-Hysell, S.E. Peters. 2019. Neoproterozoic glacial origin of the Great Unconformity. Proc. Nat. Acad. of Sci. USA. 116(4):1136-1145."),
+ h('a', { href: 'https://doi.org/10.1073/pnas.1804350116', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Keating-Bitonti, C.R., and S.E. Peters. 2019. Influence of increasing carbonate saturation in Atlantic bottom water during the late Miocene. Palaeogeography, Palaeoclimatology, Palaeoecology 518:134-142."),
+ h('a', { href: 'https://doi.org/10.1016/j.palaeo.2019.01.006', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Cohen, P.A., R. Lockwood, S.E. Peters. 2018. Integrating Macrostrat and Rockd into undergraduate Earth Science Teaching. Elements of Paleontology."),
+ h('a', { href: 'https://doi.org/10.1017/9781108681445', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Isson, T.T., and N.J. Planavsky. 2018. Reverse weathering as a long-term stabilizer of marine pH and planetary climate. Nature 560:571-475."),
+ h('a', { href: 'https://doi.org/10.1038/s41586-018-0408-4', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Husson, J.M. and S.E. Peters. 2018. Nature of the sedimentary rock record and its implications for Earth system evolution. Emerging Topics in Life Sciences."),
+ h('a', { href: 'https://doi.org/10.1042/ETLS20170152', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., J.M. Husson. 2018. We need a global comprehensive stratigraphic database: here’s a start. The Sedimentary Record 16(1)."),
+ h('a', { href: 'https://www.sepm.org/files/161article.l5vs1la4j8g2gxzu.pdf', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., J.M. Husson, J. Czaplewski. 2018. Macrostrat: a platform for geological data integration and deep-time Earth crust research. Geochemistry, Geophysics, Geosystems."),
+ h('a', { href: 'https://doi.org/10.1029/2018GC007467', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Schachat, S.R., C.C. Labandeira, M.R. Saltzman, B.D. Cramer, J.L. Payne, C.K. Boyce. 2018. Phanerozoic pO2 and the early evolution of terrestrial animals. Proc. Roy. Soc. B."),
+ h('a', { href: 'http://dx.doi.org/10.1098/rspb.2017.2631', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Husson, J.M., S.E. Peters. 2017. The sedimentary rock record of the Ediacaran-Cambrian transition in North America. Geological Society of America Bulletin."),
+ h('a', { href: 'https://doi.org/10.1130/B31670.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Zaffos, A., S. Finnegan, S.E. Peters. 2017. Plate tectonic regulation of global marine animal diversity. Proc. Nat. Acad. of Sci. USA."),
+ h('a', { href: 'http://www.pnas.org/cgi/doi/10.1073/pnas.1702297114', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., J.M. Husson. J. Wilcots. 2017. Rise and fall of stromatolites in shallow marine environments. Geology."),
+ h('a', { href: 'http://dx.doi.org/10.1130/G38931.1', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., J.M. Husson. 2017. Sediment cycling on continental and oceanic crust. Geology 45:323-326."),
+ h('a', { href: 'http://geology.geoscienceworld.org/content/45/4/323.full?ijkey=UZ6cbXCii4p8w&keytype=ref&siteid=gsgeology', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Husson, J.M., S.E. Peters. 2017. Atmospheric oxygenation driven by unsteady growth of the continental sedimentary reservoir. Earth and Planetary Science Letters."),
+ h('a', { href: 'http://www.sciencedirect.com/science/article/pii/S0012821X16307129', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Schott, R. 2017. Rockd: Geology at your fingertips in a mobile world. Bulletin of the Eastern Section of the National Association of Geoscience Teachers 67(2):1-4."),
+ h('a', { href: 'https://www.hcc.edu/Documents/Faculty-Staff/winters-trobaugh%20%27cli-fi%20@%202y%27%20Spring%202017%20NAGT-ES%20Bulletin%20CB.pdf', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Chan, M.A., S.E. Peters, B. Tikoff. 2016. The future of field geology, open data sharing, and cybertechnology in Earth science. The Sedimentary Record 14:4-10."),
+ h('a', { href: 'http://www.sepm.org/CM_Files/SedimentaryRecord/SedRecord14-1%234.pdf', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Nelsen, M.P., B.A. DiMichele, S.E. Peters, C.K. Boyce. 2016. Delayed fungal evolution did not cause the Paleozoic peak in coal production. Proc. Nat. Acad. of Sci. USA."),
+ h('a', { href: 'http://www.pnas.org/cgi/doi/10.1073/pnas.1517943113', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Heavens, N.G. 2016. The role of climate in the evolution of the terrestrial biosphere: a review of the evidence from the fossil record. Earth-Science Reviews 159:1-27."),
+ h('a', { href: 'http://dx.doi.org/10.1016/j.earscirev.2016.05.004', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Carroll, A.R. 2016. Geofuels: energy and the Earth. Cambridge University Press."),
+ h('a', { href: 'http://www.cambridge.org/us/academic/subjects/earth-and-environmental-science/environmental-science/geofuels-energy-and-earth?format=PB&isbn=9781107401204', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Thomson, T.J. and M.L. Droser. 2015. Swimming reptiles make their mark in the Early Triassic: delayed ecologic recovery increased the preservation potential of vertebrate swim tracks. Geology 44:215-218."),
+ h('a', { href: 'http://geology.gsapubs.org/content/44/3/215.abstract?sid=8573a247-dfc8-482b-960d-ee8afe846a40', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Fraass, A.J., D.C. Kelly, S.E. Peters. 2015. Macroevolutionary history of the planktic foraminifera. Annual Review of Earth and Planetary Sciences 43:5.1-5.28."),
+ h('a', { href: 'http://dx.doi.org/10.1146/annurev-earth-060614-105059', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Fan, Y., S. Richard, R.S. Bristol, S.E. Peters, et al. 2015. DigitalCrust: A 4D data system of material properties for transforming research on crustal fluid flow. Geofluids 15:372-379."),
+ h('a', { href: 'http://dx.doi.org/10.1111/gfl.12114', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E., D.C. Kelly, and A. Fraass. 2013. Oceanographic controls on the diversity and extinction of planktonic foraminifera. Nature. 493:398-401."),
+ h('a', { href: 'http://www.nature.com/nature/journal/v493/n7432/full/nature11815.html', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Benson, R.B.J., P.D. Mannion, R.J. Butler, P. Upchurch, A. Goswami, and S.E. Evans. 2012. Cretaceous tetrapod fossil record sampling and faunal turnover: implications for biogeography and the rise of modern clades. Palaeogeography, Palaeoclimatology, Palaeoecology."),
+ h('a', { href: 'http://www.sciencedirect.com/science/article/pii/S0031018212006116', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Rook, D.L., N.A. Heim, and J. Marcot. 2012. Contrasting patterns and connections of rock and biotic diversity in the marine and non-marine fossil records of North America. Palaeogeography, Palaeoclimatology, Palaeoecology. 372:123-129."),
+ h('a', { href: 'http://www.sciencedirect.com/science/article/pii/S0031018212005718', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Halevy, I, S.E. Peters, and W.W. Fischer. 2012. Sulfate burial constraints on the Phanerozoic sulfur cycle. Science 337:331-334."),
+ h('a', { href: 'http://www.sciencemag.org/content/337/6092/331.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. and R.R. Gaines. 2012. Formation of the ‘Great Unconformity’ as a trigger for the Cambrian explosion. Nature 484:363-366."),
+ h('a', { href: 'http://www.nature.com/nature/journal/v484/n7394/full/nature10969.html', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Finnegan, S., N.A. Heim, S.E. Peters and W.W. Fischer. 2012. Climate change and the selective signature of the late Ordovician mass extinction. PNAS."),
+ h('a', { href: 'http://www.pnas.org/content/early/2012/04/16/1117039109.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Hannisdal, B. and S.E. Peters. 2011. Phanerozoic Earth system evolution and marine biodiversity. Science 334:1121-1124."),
+ h('a', { href: 'http://www.sciencemag.org/content/334/6059/1121.short', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Butler, R.J. et al. 2011. Sea level, dinosaur diversity and sampling biases: investigating the ‘common cause’ hypothesis in the terrestrial realm. Proc. Roy. Soc. London B 278:1165-1170."),
+ h('a', { href: 'http://rspb.royalsocietypublishing.org/content/278/1709/1165.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Melott, A.L. and R.K. Bambach 2011. A ubiquitous ~62-Myr periodic fluctuation superimposed on general trends in fossil biodiversity II. Evolutionary dynamics associated with period fluctuation in marine diversity. Paleobiology 37:369-382."),
+ h('a', { href: 'http://paleobiol.geoscienceworld.org/cgi/content/abstract/37/3/383', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Heim, N.A. and S.E. Peters. 2011. Regional environmental breadth predicts geographic range and longevity in fossil taxa. Geology 39:1079-1082."),
+ h('a', { href: 'http://geology.gsapubs.org/content/39/11/1079.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. and N.A. Heim. 2011. Macrostratigraphy and macroevolution in marine environments: testing the common-cause hypothesis. In, Smith, A.B., and A. McGowan, eds. Comparing the rock and fossil records: implications for biodiversity. Special Publication of the Geological Society of London 358:95-104."),
+ h('a', { href: 'http://sp.lyellcollection.org/content/358/1/95.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. and N.A. Heim. 2011. The stratigraphic distribution of marine fossils in North America. Geology 39:259-262; doi: 10.1130/G31442.1."),
+ h('a', { href: 'http://geology.geoscienceworld.org/cgi/content/full/39/3/259?ijkey=ziaWozfgcb82w&keytype=ref&siteid=gsgeology', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Finnegan, S., S.E. Peters, and W.W. Fischer. 2011. Late Ordovician-Early Silurian selective extinction patterns in Laurentia and their relationship to climate change. In J.C. Gutiérrez-Marco, I. Rábano, and D. Garcia-Bellido, eds. Ordovician of the World. Cuadernos del Museo Geominera 14: 155-159.")
+ ]),
+ h('li', [
+ h('span', "Meyers, S.R. and S.E. Peters. 2011. A 56 million year rhythm in North American sedimentation during the Phanerozoic. EPSL doi:10.1016/j.epsl.2010.12.044."),
+ h('a', { href: 'http://dx.doi.org/10.1016/j.epsl.2010.12.044', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Heim, N.A. and S.E. Peters. 2011. Covariation in macrostratigraphic and macroevolutionary patterns in the marine record of North America. GSA Bulletin 123:620-630."),
+ h('a', { href: 'http://bulletin.geoscienceworld.org/cgi/content/full/123/3-4/620?ijkey=PALfAKR8a3Yio&keytype=ref&siteid=gsabull', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. and N.A. Heim. 2010. The geological completeness of paleontological sampling in North America. Paleobiology 36:61-79."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/PetersHeim2010.pdf', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Marx, F.G. 2009. Marine mammals through time: when less is more in studying palaeodiversity. Proceedings of the Royal Society of London B 138:183-196."),
+ h('a', { href: 'http://rspb.royalsocietypublishing.org/content/276/1658/887.abstract', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "McGowan, A.J., and A. Smith. 2008. Are global Phanerozoic marine diversity curves truly global? A study of the relationship between regional rock records and global Phanerozoic marine diversity. Paleobiology 34:80-103."),
+ h('a', { href: 'http://paleobiol.geoscienceworld.org/cgi/content/abstract/34/1/80', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Mayhew, P.J., G.B. Jenkins, and T.G. Benton. 2008. Long-term association between global temperature and biodiversity, origination and extinction in the fossil record. Proceedings of the Royal Society of London B 275:47-53."),
+ h('a', { href: 'http://rspb.royalsocietypublishing.org/content/275/1630/47', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. 2008. Environmental determinants of extinction selectivity in the fossil record. Nature 454:626-629."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters2008.pdf', target: '_blank' }, "[PDF]"),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters2008sup.pdf', target: '_blank' }, "[supplement]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. 2008. Macrostratigraphy and its promise for paleobiology. Pp. 205-232 In P.H. Kelley and R.K. Bambach, eds. From evolution to geobiology: research questions driving paleontology at the start of a new century. The Paleontological Society Papers, Vol. 14."),
+ h('a', { href: 'http://paleosoc.org/psp/psp14.html', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. and W.I. Ausich. 2008. A sampling-standardized macroevolutionary history for Ordovician-Early Silurian crinoids. Paleobiology 34:104-116."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters&Ausich2008.pdf', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Smith, A.B. 2007. Marine diversity through the Phanerozoic: problems and prospects. Journal of the Geological Society, London 164:731-745."),
+ h('a', { href: 'http://jgs.geoscienceworld.org/cgi/content/abstract/164/4/731', target: '_blank' }, "[link]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. 2007. The problem with the Paleozoic. Paleobiology 33:165-181."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters2007.pdf', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. 2006. Macrostratigraphy of North America. Journal of Geology 114:391-412."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters2006.pdf', target: '_blank' }, "[PDF]")
+ ]),
+ h('li', [
+ h('span', "Peters, S.E. 2005. Geologic constraints on the macroevolutionary history of marine animals. Proceedings of the National Academy of Sciences U.S.A. 102:12326-12331."),
+ h('a', { href: 'http://strata.geology.wisc.edu/vita/reprints/Peters2005.pdf', target: '_blank' }, "[PDF]")
+ ]),
+ ]),
+ ]),
+ h(Footer)
+ ])
+}
\ No newline at end of file
diff --git a/pages/publications/main.module.sass b/pages/publications/main.module.sass
new file mode 100644
index 000000000..ca399c891
--- /dev/null
+++ b/pages/publications/main.module.sass
@@ -0,0 +1,41 @@
+.publications
+ padding: 8vh 20% 5vh 20%
+
+.container
+ background-color: var(--background-color)
+
+a:hover
+ text-decoration: none
+
+.big
+ font-size: 72px
+ font-family: "Maven Pro", sans-serif
+ text-align: center
+
+.pub-line
+ width: 60%
+ border-bottom: 1px solid black
+ position: absolute
+
+.pub-title
+ text-align: left
+ position: relative
+ margin: 0
+ padding: 0
+
+.pub-list
+ padding-top: 10px
+ margin-left: 20px
+ counter-reset: pub-counter 70
+
+ li
+ counter-increment: pub-counter -1
+
+ li::marker
+ font-size: 35px
+ color: #babdc8
+ content: counter(pub-counter) " "
+ counter-increment: pub-counter
+
+.blurb
+ font-size: 15px
diff --git a/src/components/icon.module.sass b/src/components/icon.module.sass
index 0256f4428..b156fbafe 100644
--- a/src/components/icon.module.sass
+++ b/src/components/icon.module.sass
@@ -20,7 +20,7 @@
color: unset
.page-header
- margin: 1.2em 0 1.2em
+ padding: 0 0 1.2em
display: flex
flex-direction: row
align-items: start
diff --git a/src/components/lithology/index.ts b/src/components/lithology/index.ts
index fdc34c5fd..a0e8a05e0 100644
--- a/src/components/lithology/index.ts
+++ b/src/components/lithology/index.ts
@@ -68,6 +68,7 @@ function DefaultTooltip({ data, showExternalLinks = false }) {
]),
h("ul.tight-list", [
h(LinkItem, { href: `/map#lithologies=${data.lith_id}` }, "Filter map"),
+ h(LinkItem, { href: `/lex/lithology/${data.lith_id}` }, "View details"),
h.if(showExternalLinks)([
h(
LinkItem,
diff --git a/src/components/navigation/PageBreadcrumbs.ts b/src/components/navigation/PageBreadcrumbs.ts
index ceacc7c8a..28f4fea4b 100644
--- a/src/components/navigation/PageBreadcrumbs.ts
+++ b/src/components/navigation/PageBreadcrumbs.ts
@@ -213,6 +213,81 @@ export const sitemap: Routes = {
},
],
},
+ {
+ slug: "strat-name-concepts",
+ name: "Strat Name Concepts",
+ children: [
+ {
+ param: "@id",
+ name(urlPart, ctx) {
+ return h(
+ "code",
+ urlPart
+ );
+ },
+ },
+ ],
+ },
+ {
+ slug: "intervals",
+ name: "Intervals",
+ children: [
+ {
+ param: "@id",
+ name(urlPart, ctx) {
+ return h(
+ "code",
+ ctx.pageProps?.interval?.int_id ?? urlPart
+ );
+ },
+ },
+ ],
+ },
+ {
+ slug: "environments",
+ name: "Environments",
+ children: [
+ {
+ param: "@id",
+ name(urlPart, ctx) {
+ return h(
+ "code",
+ ctx.pageProps?.environment?.environ_id ?? urlPart
+ );
+ },
+ },
+ ],
+ },
+ {
+ slug: "economics",
+ name: "Economics",
+ children: [
+ {
+ param: "@id",
+ name(urlPart, ctx) {
+ return h(
+ "code",
+ ctx.pageProps?.economic?.econ_id ?? urlPart
+ );
+ },
+ },
+ ],
+ },
+ {
+ slug: "timescales",
+ name: "Timescales",
+ children: [
+ {
+ param: "@id",
+ name(urlPart, ctx) {
+ return h(
+ "code",
+ ctx.pageProps?.timescale?.timescale_id ?? urlPart
+ );
+ },
+ },
+ ],
+ },
],
},
columnsSubtree,
diff --git a/src/layouts/main.module.sass b/src/layouts/main.module.sass
index ef4e81a74..111464244 100644
--- a/src/layouts/main.module.sass
+++ b/src/layouts/main.module.sass
@@ -7,8 +7,7 @@
left: 0
.content-page
- margin: 2em auto 3em
- max-width: 78em
+ padding: 2em 20% !important
padding: 0 4em
@media only screen and (max-width: 900px)
padding: 0 1em
diff --git a/vite.config.ts b/vite.config.ts
index 3914fcf90..c6d6dc3f4 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -130,6 +130,7 @@ export default defineConfig({
"@macrostrat/map-interface",
"@macrostrat/feedback-components",
"@macrostrat/timescale",
+ "@macrostrat/mapbox-react",
],
resolve: {
conditions: ["source"],
diff --git a/yarn.lock b/yarn.lock
index b0103e228..491e22bc5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3524,6 +3524,7 @@ __metadata:
react-router-dom: "npm:^6.8.2"
react-router-hash-link: "npm:^2.4.3"
react-spring: "npm:^9.7.3"
+ recharts: "npm:^2.13.0"
reduce-reducers: "npm:^1.0.4"
redux: "npm:^4.0.5"
sass-embedded: "npm:^1.79.1"
@@ -5344,7 +5345,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/d3-array@npm:^3.0.0":
+"@types/d3-array@npm:^3.0.0, @types/d3-array@npm:^3.0.3":
version: 3.2.1
resolution: "@types/d3-array@npm:3.2.1"
checksum: 10/4a9ecacaa859cff79e10dcec0c79053f027a4749ce0a4badeaff7400d69a9c44eb8210b147916b6ff5309be049030e7d68a0e333294ff3fa11c44aa1af4ba458
@@ -5388,6 +5389,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-ease@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "@types/d3-ease@npm:3.0.2"
+ checksum: 10/d8f92a8a7a008da71f847a16227fdcb53a8938200ecdf8d831ab6b49aba91e8921769761d3bfa7e7191b28f62783bfd8b0937e66bae39d4dd7fb0b63b50d4a94
+ languageName: node
+ linkType: hard
+
"@types/d3-format@npm:3.0.1":
version: 3.0.1
resolution: "@types/d3-format@npm:3.0.1"
@@ -5418,7 +5426,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/d3-interpolate@npm:*":
+"@types/d3-interpolate@npm:*, @types/d3-interpolate@npm:^3.0.1":
version: 3.0.4
resolution: "@types/d3-interpolate@npm:3.0.4"
dependencies:
@@ -5477,6 +5485,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-scale@npm:^4.0.2":
+ version: 4.0.9
+ resolution: "@types/d3-scale@npm:4.0.9"
+ dependencies:
+ "@types/d3-time": "npm:*"
+ checksum: 10/2cae90a5e39252ae51388f3909ffb7009178582990462838a4edd53dd7e2e08121b38f0d2e1ac0e28e41167e88dea5b99e064ca139ba917b900a8020cf85362f
+ languageName: node
+ linkType: hard
+
"@types/d3-selection@npm:*, @types/d3-selection@npm:^3.0.0, @types/d3-selection@npm:^3.0.10":
version: 3.0.11
resolution: "@types/d3-selection@npm:3.0.11"
@@ -5493,7 +5510,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/d3-shape@npm:^3":
+"@types/d3-shape@npm:^3, @types/d3-shape@npm:^3.1.0":
version: 3.1.7
resolution: "@types/d3-shape@npm:3.1.7"
dependencies:
@@ -5509,7 +5526,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/d3-time@npm:*":
+"@types/d3-time@npm:*, @types/d3-time@npm:^3.0.0":
version: 3.0.4
resolution: "@types/d3-time@npm:3.0.4"
checksum: 10/b1eb4255066da56023ad243fd4ae5a20462d73bd087a0297c7d49ece42b2304a4a04297568c604a38541019885b2bc35a9e0fd704fad218e9bc9c5f07dc685ce
@@ -5530,6 +5547,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-timer@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "@types/d3-timer@npm:3.0.2"
+ checksum: 10/1643eebfa5f4ae3eb00b556bbc509444d88078208ec2589ddd8e4a24f230dd4cf2301e9365947e70b1bee33f63aaefab84cd907822aae812b9bc4871b98ab0e1
+ languageName: node
+ linkType: hard
+
"@types/d3-transition@npm:^3.0.8":
version: 3.0.9
resolution: "@types/d3-transition@npm:3.0.9"
@@ -7993,6 +8017,13 @@ __metadata:
languageName: node
linkType: hard
+"clsx@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "clsx@npm:2.1.1"
+ checksum: 10/cdfb57fa6c7649bbff98d9028c2f0de2f91c86f551179541cf784b1cfdc1562dcb951955f46d54d930a3879931a980e32a46b598acaea274728dbe068deca919
+ languageName: node
+ linkType: hard
+
"color-convert@npm:^1.9.0":
version: 1.9.3
resolution: "color-convert@npm:1.9.3"
@@ -8476,7 +8507,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.1.1, d3-array@npm:^3.2.4":
+"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.1.1, d3-array@npm:^3.1.6, d3-array@npm:^3.2.4":
version: 3.2.4
resolution: "d3-array@npm:3.2.4"
dependencies:
@@ -8657,7 +8688,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-ease@npm:1 - 3":
+"d3-ease@npm:1 - 3, d3-ease@npm:^3.0.1":
version: 3.0.1
resolution: "d3-ease@npm:3.0.1"
checksum: 10/985d46e868494e9e6806fedd20bad712a50dcf98f357bf604a843a9f6bc17714a657c83dd762f183173dcde983a3570fa679b2bc40017d40b24163cdc4167796
@@ -8781,7 +8812,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3.0.1":
+"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3.0.1, d3-interpolate@npm:^3.0.1":
version: 3.0.1
resolution: "d3-interpolate@npm:3.0.1"
dependencies:
@@ -8930,7 +8961,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-shape@npm:^3.2.0":
+"d3-shape@npm:^3.1.0, d3-shape@npm:^3.2.0":
version: 3.2.0
resolution: "d3-shape@npm:3.2.0"
dependencies:
@@ -8982,7 +9013,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3.1.0":
+"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3.1.0, d3-time@npm:^3.0.0":
version: 3.1.0
resolution: "d3-time@npm:3.1.0"
dependencies:
@@ -8998,7 +9029,7 @@ __metadata:
languageName: node
linkType: hard
-"d3-timer@npm:1 - 3":
+"d3-timer@npm:1 - 3, d3-timer@npm:^3.0.1":
version: 3.0.1
resolution: "d3-timer@npm:3.0.1"
checksum: 10/004128602bb187948d72c7dc153f0f063f38ac7a584171de0b45e3a841ad2e17f1e40ad396a4af9cce5551b6ab4a838d5246d23492553843d9da4a4050a911e2
@@ -9236,6 +9267,13 @@ __metadata:
languageName: node
linkType: hard
+"decimal.js-light@npm:^2.4.1":
+ version: 2.5.1
+ resolution: "decimal.js-light@npm:2.5.1"
+ checksum: 10/6360911e31221a9b8b90e23020aa969d104e182c5c6518589cdfedc3ced31bf1f19cf931e265bd451ae6ee3a35ee15e81f5456a86813606fda96f8374616688f
+ languageName: node
+ linkType: hard
+
"decode-named-character-reference@npm:^1.0.0":
version: 1.0.2
resolution: "decode-named-character-reference@npm:1.0.2"
@@ -10619,7 +10657,7 @@ __metadata:
languageName: node
linkType: hard
-"eventemitter3@npm:^4.0.0":
+"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.1":
version: 4.0.7
resolution: "eventemitter3@npm:4.0.7"
checksum: 10/8030029382404942c01d0037079f1b1bc8fed524b5849c237b80549b01e2fc49709e1d0c557fa65ca4498fc9e24cff1475ef7b855121fcc15f9d61f93e282346
@@ -10768,6 +10806,13 @@ __metadata:
languageName: node
linkType: hard
+"fast-equals@npm:^5.0.1":
+ version: 5.2.2
+ resolution: "fast-equals@npm:5.2.2"
+ checksum: 10/87939dc01c6634f844369c2d774c9bf82b6c5935eb45c698fdfd2e708439c6c94a67a41c67c7e063759394e319850ee563e717e65776c8f5997566b0cbb17c7a
+ languageName: node
+ linkType: hard
+
"fast-glob@npm:^3.0.0, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9":
version: 3.3.2
resolution: "fast-glob@npm:3.3.2"
@@ -16080,7 +16125,7 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^18.0.0":
+"react-is@npm:^18.0.0, react-is@npm:^18.3.1":
version: 18.3.1
resolution: "react-is@npm:18.3.1"
checksum: 10/d5f60c87d285af24b1e1e7eaeb123ec256c3c8bdea7061ab3932e3e14685708221bf234ec50b21e10dd07f008f1b966a2730a0ce4ff67905b3872ff2042aec22
@@ -16377,6 +16422,20 @@ __metadata:
languageName: node
linkType: hard
+"react-smooth@npm:^4.0.4":
+ version: 4.0.4
+ resolution: "react-smooth@npm:4.0.4"
+ dependencies:
+ fast-equals: "npm:^5.0.1"
+ prop-types: "npm:^15.8.1"
+ react-transition-group: "npm:^4.4.5"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 10/cc5593356d154253f61a2c0b7b2fa8a979527495e2fe47c4252628d86e93c72c75df988c5438867d373de4e5a47d871ab9262474c02e66c411f94f047ecb5b0f
+ languageName: node
+ linkType: hard
+
"react-spring@npm:^9.7.3, react-spring@npm:^9.7.5":
version: 9.7.5
resolution: "react-spring@npm:9.7.5"
@@ -16647,6 +16706,34 @@ __metadata:
languageName: node
linkType: hard
+"recharts-scale@npm:^0.4.4":
+ version: 0.4.5
+ resolution: "recharts-scale@npm:0.4.5"
+ dependencies:
+ decimal.js-light: "npm:^2.4.1"
+ checksum: 10/6e1118635018bd0622b5e978e56a8764ced5741140709e025c5989a0cb40c4b0bebb7c4e231c11ab8d6127a85fef8c68d92662c6f3c22af9551737a767cea014
+ languageName: node
+ linkType: hard
+
+"recharts@npm:^2.13.0":
+ version: 2.15.3
+ resolution: "recharts@npm:2.15.3"
+ dependencies:
+ clsx: "npm:^2.0.0"
+ eventemitter3: "npm:^4.0.1"
+ lodash: "npm:^4.17.21"
+ react-is: "npm:^18.3.1"
+ react-smooth: "npm:^4.0.4"
+ recharts-scale: "npm:^0.4.4"
+ tiny-invariant: "npm:^1.3.1"
+ victory-vendor: "npm:^36.6.8"
+ peerDependencies:
+ react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 10/611315edc8f25238c7eaa4842e549abff59e4df51a2c8b5bdd80ce9778717e0097e35e56ea4a3c4f6139ad3083fbf6041065c8a5c6c6a3d950cb04490bd54237
+ languageName: node
+ linkType: hard
+
"reduce-css-calc@npm:^1.3.0":
version: 1.3.0
resolution: "reduce-css-calc@npm:1.3.0"
@@ -18543,7 +18630,7 @@ __metadata:
languageName: node
linkType: hard
-"tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.0.6":
+"tiny-invariant@npm:^1.0.2, tiny-invariant@npm:^1.0.6, tiny-invariant@npm:^1.3.1":
version: 1.3.3
resolution: "tiny-invariant@npm:1.3.3"
checksum: 10/5e185c8cc2266967984ce3b352a4e57cb89dad5a8abb0dea21468a6ecaa67cd5bb47a3b7a85d08041008644af4f667fb8b6575ba38ba5fb00b3b5068306e59fe
@@ -19694,6 +19781,28 @@ __metadata:
languageName: node
linkType: hard
+"victory-vendor@npm:^36.6.8":
+ version: 36.9.2
+ resolution: "victory-vendor@npm:36.9.2"
+ dependencies:
+ "@types/d3-array": "npm:^3.0.3"
+ "@types/d3-ease": "npm:^3.0.0"
+ "@types/d3-interpolate": "npm:^3.0.1"
+ "@types/d3-scale": "npm:^4.0.2"
+ "@types/d3-shape": "npm:^3.1.0"
+ "@types/d3-time": "npm:^3.0.0"
+ "@types/d3-timer": "npm:^3.0.0"
+ d3-array: "npm:^3.1.6"
+ d3-ease: "npm:^3.0.1"
+ d3-interpolate: "npm:^3.0.1"
+ d3-scale: "npm:^4.0.2"
+ d3-shape: "npm:^3.1.0"
+ d3-time: "npm:^3.0.0"
+ d3-timer: "npm:^3.0.1"
+ checksum: 10/db67b3d9b8070d4eae4122edc72be7067b4e32363340cdd4d5b628e7dd65bea0c7c5b4116016658d223adaa575bcc6b7b3a71507aa4f34b2609ed61dbfbba1ea
+ languageName: node
+ linkType: hard
+
"vike-react@npm:^0.5.12":
version: 0.5.12
resolution: "vike-react@npm:0.5.12"