diff --git a/pages/columns/+Page.ts b/pages/columns/+Page.ts index f8bd69b2b..25337aad3 100644 --- a/pages/columns/+Page.ts +++ b/pages/columns/+Page.ts @@ -50,7 +50,12 @@ function ColumnMapContainer(props) { ); } -type ColumnFilterKey = "liths" | "stratNames" | "intervals"; +type ColumnFilterKey = + | "liths" + | "stratNames" + | "intervals" + | "concepts" + | "environments"; type ColumnFilterDef = { type: ColumnFilterKey; @@ -366,9 +371,18 @@ function ColumnGroup({ data, linkPrefix }) { } function ColumnItem({ data, linkPrefix = "/" }) { - const { col_id, col_name, units } = data; + const { col_id, col_name, t_units, t_sections } = data; - const unitsText = units?.length > 0 ? `${units?.length} units` : "empty"; + const unitsText = t_units > 0 ? `${t_units} units` : "no units"; + + let gbpTag = null; + if (t_sections > 0) { + gbpTag = h( + Tag, + { minimal: true, color: "goldenrod", size: "small" }, + `${t_sections} packages` + ); + } const href = linkPrefix + `columns/${col_id}`; return h( @@ -388,13 +402,13 @@ function ColumnItem({ data, linkPrefix = "/" }) { { minimal: true, color: "lightgreen", size: "small" }, "in process" ), - " ", + gbpTag, h( Tag, { minimal: true, size: "small", - color: units?.length === 0 ? "orange" : "dodgerblue", + color: t_units == 0 ? "orange" : "dodgerblue", }, unitsText ), @@ -432,7 +446,7 @@ function LexFilters() { async function _fetchFilterItems(inputText: string) { // Fetch filter items from the API based on input text, using the PostgREST client API const res = postgrest - .from("col_filter") + .from("col_filters") .select("*") .ilike("name", `%${inputText}%`) .limit(5); @@ -473,6 +487,10 @@ function routeForFilterKey(key: ColumnFilterKey): string { return "strat-names"; case "intervals": return "intervals"; + case "concepts": + return "concepts"; + case "environments": + return "environments"; } } @@ -484,12 +502,18 @@ function filterKeyFromType(type: string): ColumnFilterKey | null { return "stratNames"; case "interval": return "intervals"; + case "concept": + return "concepts"; + case "environment": + return "environments"; default: return null; } } -function paramNameForFilterKey(key: ColumnFilterKey): string { +function paramNameForFilterKey( + key: ColumnFilterKey +): keyof ColumnFilterOptions { switch (key) { case "liths": return "liths"; @@ -497,20 +521,23 @@ function paramNameForFilterKey(key: ColumnFilterKey): string { return "strat_names"; case "intervals": return "intervals"; + case "concepts": + return "strat_name_concepts"; + case "environments": + return "environments"; } } function buildParamsFromFilters( - filters: ColumnFilterDef[], - // Allow multiple filters per category (not supported in API v2) - allowMultiple = false + filters: ColumnFilterDef[] ): Partial { const params: Record = {}; if (filters == null) return params; let filterData: Partial = {}; for (const filter of filters) { const key = paramNameForFilterKey(filter.type); - if (allowMultiple) { + if (key == "strat_names" || key == "strat_name_concepts") { + // We can add multiple parameters of each type filterData[key] ??= []; } else { filterData[key] = []; diff --git a/pages/columns/grouped-cols.ts b/pages/columns/grouped-cols.ts index 4b6c62d2b..f84fe8c94 100644 --- a/pages/columns/grouped-cols.ts +++ b/pages/columns/grouped-cols.ts @@ -12,6 +12,8 @@ interface ColumnResponseShort { col_area: number; col_type: "column" | "section"; refs: number[]; + t_units: number; + t_sections: number; } export interface ColumnGroup { @@ -66,6 +68,8 @@ export interface ColumnFilterOptions { status_code?: string; empty?: boolean; strat_names?: number[]; + strat_name_concepts?: number[]; + environments?: number[]; intervals?: number[]; liths?: number[]; nameFuzzyMatch?: string; @@ -84,8 +88,19 @@ async function fetchColumns(opts: ColumnFilterOptions) { // Empty and name fuzzy match are not supported yet if (opts.strat_names) { - for (const sn of opts.strat_names) { - params.append("strat_name_id", sn.toString()); + params.append("strat_name_id", buildQueryArg(opts.strat_names)); + } + + if (opts.strat_name_concepts) { + params.append( + "strat_name_concept_id", + buildQueryArg(opts.strat_name_concepts) + ); + } + + if (opts.environments) { + for (const env of opts.environments) { + params.append("env_id", env.toString()); } } @@ -101,6 +116,11 @@ async function fetchColumns(opts: ColumnFilterOptions) { } } + function buildQueryArg(values: number[]) { + d; + return values.map((v) => v.toString()).join(","); + } + return (await fetchAPIV2Result("/columns", params)) as Promise<{ data: ColumnResponseShort[]; refs: { [key: number]: string }; diff --git a/pages/dev/columns-test/+Page.ts b/pages/dev/columns-test/+Page.ts deleted file mode 100644 index 0332396e6..000000000 --- a/pages/dev/columns-test/+Page.ts +++ /dev/null @@ -1,333 +0,0 @@ -import hyper from "@macrostrat/hyper"; -import styles from "./main.module.sass"; -import React, { useState, useEffect, useRef, useMemo } from "react"; - -import { ContentPage } from "~/layouts"; -import { - Link, - DevLinkButton, - PageBreadcrumbs, - StickyHeader, -} from "~/components"; -import { FlexRow } from "~/components/lex/tag"; -import { SearchBar } from "~/components/general"; -import { getGroupedColumns } from "./grouped-cols"; - -import { AnchorButton, ButtonGroup, Switch } from "@blueprintjs/core"; -import { Tag, Icon } from "@blueprintjs/core"; -import { useData } from "vike-react/useData"; -import { ClientOnly } from "vike-react/ClientOnly"; -import { navigate } from "vike/client/router"; - -import { LexSelection } from "@macrostrat/form-components"; -import { postgrestPrefix } from "@macrostrat-web/settings"; -import { useAPIResult, PostgRESTInfiniteScrollView } from "@macrostrat/ui-components" -import { cdrPrefix } from "packages/settings"; - -const h = hyper.styled(styles); - -export function Page(props) { - return h(ColumnListPage, props); -} - -function ColumnMapContainer(props) { - return h( - ClientOnly, - { - load: () => import("./map.client").then((d) => d.ColumnsMapContainer), - fallback: h("div.loading", "Loading map..."), - deps: [props.columnIDs, props.projectID, props.hideColumns], - }, - (component) => h(component, props) - ); -} - -function ColumnListPage({ title = "Columns", linkPrefix = "/" }) { - const { allColumnGroups, project } = useData(); - - const [columnGroups, setColumnGroups] = useState(null); - const [loading, setLoading] = useState(false); - const [extraParams, setExtraParams] = useState({}); - - const [columnInput, setColumnInput] = useState(""); - const [showEmpty, setShowEmpty] = useState(true); - const [filteredInput, setFilteredInput] = useState(""); - const [showInProcess, setShowInProcess] = useState(true); - - const [selectedLiths, setSelectedLiths] = useState(null); - const [selectedUnits, setSelectedUnits] = useState(null); - const [selectedStratNames, setSelectedStratNames] = useState(null); - - const isEmpty = Object.keys(extraParams).length === 0; - const filteredGroups = isEmpty ? allColumnGroups : columnGroups ?? []; - - useEffect(() => { - const params: any = {}; - - if (filteredInput.length >= 3) { - params.name = `ilike.%${filteredInput}%`; - } - if (!showEmpty) { - params.empty = `is.false`; - } - if (!showInProcess) { - params.status_code = 'eq.active'; - } - if (selectedLiths) { - params.liths = `cs.[${selectedLiths}]`; - } - if (selectedUnits) { - params.units = `cs.[${selectedUnits}]`; - } - if (selectedStratNames) { - params.strat_names = `cs.[${selectedStratNames}]`; - } - - setExtraParams(params); - }, [filteredInput, showEmpty, showInProcess, selectedLiths, selectedUnits, selectedStratNames]); - - - // set filtered input - useEffect(() => { - const prevLength = prevInputLengthRef.current; - - if (columnInput.length >= 3) { - setFilteredInput(columnInput); - } else if (prevLength >= 3 && columnInput.length === 2) { - setFilteredInput(""); - } - - prevInputLengthRef.current = columnInput.length; - }, [columnInput, showEmpty, showInProcess]); - - const prevInputLengthRef = useRef(columnInput.length); - - useEffect(() => { - if (!isEmpty) { - setLoading(true); - getGroupedColumns(project?.project_id, extraParams) - .then((groups) => setColumnGroups(groups)) - .finally(() => setLoading(false)); - } - }, [project?.project_id, extraParams]); - - - const columnIDs = useMemo(() => { - return filteredGroups?.flatMap((item) => - item.columns.map((col) => col.col_id) - ); - }, [filteredGroups]); - - console.log("extraparams", extraParams); - - return h("div.column-list-page", [ - h(ContentPage, [ - h("div.flex-row", [ - h("div.main", [ - h(StickyHeader, [ - h(PageBreadcrumbs, { showLogo: true }), - h(LexFilters, { - selectedLiths, - setSelectedLiths, - selectedUnits, - setSelectedUnits, - selectedStratNames, - setSelectedStratNames, - }) - ]), - h(PostgRESTInfiniteScrollView, { - route: postgrestPrefix + `/col_data`, - id_key: "col_id", - order_key: "col_group_id", - limit: 50, - itemComponent: ColumnItem, - filterable: true, - extraParams, - searchColumns: [{ label: "Name", value: "name" }], - toggles: h('div.switches', [ - h(Switch, { - checked: showEmpty, - label: "Show empty", - onChange: () => setShowEmpty(!showEmpty), - }), - h(Switch, { - checked: showInProcess, - label: "Show in process", - onChange: () => setShowInProcess(!showInProcess), - }), - ]), - }) - ]), - h("div.sidebar", [ - h("div.sidebar-content", [ - h(ButtonGroup, { vertical: true, large: true }, [ - h(AnchorButton, { href: "/projects", minimal: true }, "Projects"), - h( - DevLinkButton, - { href: "/columns/correlation" }, - "Correlation chart" - ), - ]), - h(ColumnMapContainer, { - columnIDs, - projectID: project?.project_id, - className: "column-map-container", - }), - ]), - ]), - ]), - ]), - ]); -} - -function ColumnGroup({ data, linkPrefix }) { - const [isOpen, setIsOpen] = useState(false); - const filteredColumns = 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(Link, { href: `/columns/groups/${data.id}`, target: "_self" }, [ - h( - "h2.column-group-name", - name + " (Group #" + filteredColumns[0].col_group_id + ")" - ), - ]), - ]), - h("div.column-list", [ - h("table.column-table", [ - h("thead.column-row.column-header", [ - h("tr", [ - h("th.col-id", "ID"), - h("th.col-name", "Name"), - h("th.col-status", "Status"), - ]), - ]), - h("tbody", [ - filteredColumns.map((data) => h(ColumnItem, { data, linkPrefix })), - ]), - ]), - ]), - ] - ); -} - -const ColumnItem = React.memo( - function ColumnItem({ data, linkPrefix = "/" }) { - const { col_id, name, units, col_group_id } = data; - - const unitsText = units?.length > 0 ? `${units?.length} units` : "empty"; - - const href = linkPrefix + `columns/${col_id}`; - return h( - "tr.column-row", - { - onClick() { - navigate(href); - }, - }, - [ - h("td.col-id", h("code.bp5-code", col_id)), - h("td.col-name", h("a", { href }, name)), - h("td.col-status", [ - data.status_code === "in process" && - h( - Tag, - { minimal: true, color: "lightgreen", size: "small" }, - "in process" - ), - " ", - h( - Tag, - { - minimal: true, - size: "small", - color: units?.length === 0 ? "orange" : "dodgerblue", - }, - unitsText - ), - " ", - h(Tag, { minimal: true, color: "lightgreen", size: "small" }, - h(Link, { href: `/columns/groups/${data.id}`, target: "_self" }, "#" + col_group_id), - ), - ]), - ] - ); - }, - (prevProps, nextProps) => { - return ( - prevProps.data.col_id === nextProps.data.col_id && - prevProps.data.col_name === nextProps.data.col_name && - prevProps.data.status === nextProps.data.status && - prevProps.data.t_units === nextProps.data.t_units && - prevProps.linkPrefix === nextProps.linkPrefix - ); - } -); - -function LexFilters({ selectedLiths, setSelectedLiths, selectedUnits, setSelectedUnits, selectedStratNames, setSelectedStratNames }) { - const liths = useLiths(); - const units = useUnits(); - const stratNames = useStratNames(); - - if(!liths || !units || !stratNames) return null - - return h('div.lex-filters', [ - h(FlexRow, { - align: "center", - gap: ".5em", - }, [ - h('p', "Filtering columns by "), - h(LexSelection, { - value: selectedLiths, - onConfirm: (value) => setSelectedLiths(value), - items: liths, - placeholder: "Select a lithology", - }), - h.if(selectedLiths)(Icon, { className: 'close-btn', icon: "cross", onClick: () => setSelectedLiths(null) }) - ]), - h(FlexRow, { - align: "center", - gap: ".5em", - }, [ - h('p', "Filtering columns by "), - h(LexSelection, { - value: selectedUnits, - onConfirm: (value) => setSelectedUnits(value), - items: units, - placeholder: "Select a unit", - }), - h.if(selectedUnits)(Icon, { className: 'close-btn', icon: "cross", onClick: () => setSelectedUnits(null) }) - ]), - h(FlexRow, { - align: "center", - gap: ".5em", - }, [ - h('p', "Filtering columns by "), - h(LexSelection, { - value: selectedStratNames, - onConfirm: (value) => setSelectedStratNames(value), - items: stratNames, - placeholder: "Select a strat name", - }), - h.if(selectedStratNames)(Icon, { className: 'close-btn', icon: "cross", onClick: () => setSelectedStratNames(null) }) - ]), - ]); -} - -function useLiths() { - return useAPIResult(postgrestPrefix + "/liths?select=id,name:lith,color:lith_color"); -} - -function useUnits() { - return useAPIResult(postgrestPrefix + "/units?select=id,name:strat_name"); -} - -function useStratNames() { - return useAPIResult(postgrestPrefix + "/strat_names?select=id,name:strat_name"); -} diff --git a/pages/dev/columns-test/+config.ts b/pages/dev/columns-test/+config.ts deleted file mode 100644 index 249258eb5..000000000 --- a/pages/dev/columns-test/+config.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default { - title: "Columns", - pageStyle: "content", -}; diff --git a/pages/dev/columns-test/+data.ts b/pages/dev/columns-test/+data.ts deleted file mode 100644 index c9dc2d575..000000000 --- a/pages/dev/columns-test/+data.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { getGroupedColumns } from "./grouped-cols"; - -export async function data(pageContext) { - // https://v2.macrostrat.org/api/v2/columns?col_id=3&response=lon - const allColumnGroups = await getGroupedColumns(1); - return { allColumnGroups }; -} diff --git a/pages/dev/columns-test/@column/+Page.ts b/pages/dev/columns-test/@column/+Page.ts deleted file mode 100644 index 01d98879d..000000000 --- a/pages/dev/columns-test/@column/+Page.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ColumnPage } from "./column-inspector"; -import h from "@macrostrat/hyper"; -import { useData } from "vike-react/useData"; - -export function Page() { - const props = useData(); - return h(ColumnPage, props); -} diff --git a/pages/dev/columns-test/@column/+config.ts b/pages/dev/columns-test/@column/+config.ts deleted file mode 100644 index 07f6df164..000000000 --- a/pages/dev/columns-test/@column/+config.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default { - pageStyle: "fullscreen", - meta: { - Page: { - env: { - client: true, // This page will be rendered on the client - server: false, // No server-side rendering for this page - }, - }, - data: { - env: { - client: true, // Data is available on the client - server: true, // No server-side data fetching - }, - }, - }, -}; diff --git a/pages/dev/columns-test/@column/+data.ts b/pages/dev/columns-test/@column/+data.ts deleted file mode 100644 index 5681b1ab1..000000000 --- a/pages/dev/columns-test/@column/+data.ts +++ /dev/null @@ -1,119 +0,0 @@ -// https://vike.dev/onBeforeRender - -import { apiV2Prefix } from "@macrostrat-web/settings"; -import { preprocessUnits } from "@macrostrat/column-views"; -import fetch from "cross-fetch"; - -import { ColumnSummary } from "#/map/map-interface/app-state/handlers/columns"; - -export async function data(pageContext) { - // `.page.server.js` files always run in Node.js; we could use SQL/ORM queries here. - const col_id = pageContext.routeParams.column; - - // In cases where we are in a project context, we need to fetch the project data - const project_id = pageContext.routeParams.project; - - // https://v2.macrostrat.org/api/v2/columns?col_id=3&response=long - - const linkPrefix = project_id == null ? "/" : `/projects/${project_id}/`; - - let projectID = null; - if (project_id != null) { - projectID = parseInt(project_id); - } - - /** This is a hack to make sure that all requisite data is on the table. */ - const responses = await Promise.all([ - getData( - "columns", - { col_id, project_id: projectID, format: "geojson" }, - (res) => res?.features - ), - getData( - `units`, - { - project_id, - col_id, - }, - (res) => res - ), - ]); - - const [columns, units]: [any, any] = responses; - - const col = columns?.[0] ?? {}; - - if (!columns?.[0]?.properties) { - console.warn("Column has no properties:", columns); - } - - const columnInfo: ColumnSummary = { - ...(col.properties ?? {}), - geometry: col.geometry ?? null, - units: units ?? [], - }; - return { - columnInfo, - linkPrefix, - projectID, - }; -} - -async function getAndUnwrap(url: string): Promise { - console.log("Fetching", url); - const res = await fetch(url); - const res1 = await res.json(); - return res1.success.data; -} - -async function getData( - entity: string, - args: { col_id: number; project_id: number }, - unwrapResponse: (res: any) => any[] -) { - /** Fetch column data without knowing if it is an 'in process' column, a priori. This - * gets around the current limitation that there's no way to request any column data - * without knowing the status_code. - */ - let res = await getAndUnwrap( - assembleURL(entity, { ...args, status_code: "active" }) - ); - let data = unwrapResponse(res); - - if (data.length > 0) { - return data; - } - - let res2 = await getAndUnwrap( - assembleURL(entity, { ...args, status_code: "in process" }) - ); - return unwrapResponse(res2); -} - -function assembleURL( - entity, - { - col_id, - project_id, - status_code = "active", - ...rest - }: { - col_id: number; - project_id: number; - status_code?: "active" | "in process"; - [key: string]: string | number; - } -) { - const base = apiV2Prefix + "/" + entity; - let params = new URLSearchParams({ - col_id: col_id.toString(), - response: "long", - status_code, - ...rest, - }); - if (project_id != null) { - params.set("project_id", project_id.toString()); - } - - return `${base}?${params}`; -} diff --git a/pages/dev/columns-test/@column/__archive/column-renderer-demo.ts b/pages/dev/columns-test/@column/__archive/column-renderer-demo.ts deleted file mode 100644 index 8a433752b..000000000 --- a/pages/dev/columns-test/@column/__archive/column-renderer-demo.ts +++ /dev/null @@ -1,638 +0,0 @@ -$(document).ready(function () { - /* - Macrostrat's first strat column renderer, by Lance Weaver - - ISSUES TO SOLVE - -some formations, have themselves as the fisrt 'member', but aren't labeled as members in the db. see #495 - -some formations are ordered wrong. this breaks the UnMergedColun function (because it uses filter) - - -UNCONFORMITIES need to be in the db, and displayed with a wavy or dashed line and note! - -fossils, unconforms, and other notes need to be added to db, and displayed in borderless column on right - - */ - - var utable = $( - "" + - "" + - "" + - "" + - "" + - "
Period /Epoch Groups Formations & Members Thick-  nessRock Type
" - ); - - // get the uri variables and store them in the global app[] array - function URLToArray(url) { - //decode the URL, put vars in array - var t = []; - var nohash = url.replace("#", ""); - var pairs = nohash.substring(url.indexOf("?") + 1).split("&"); - for (var i = 0; i < pairs.length; i++) { - if (!pairs[i]) continue; - var pair = pairs[i].split("="); - t[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); - } - return t; - } - - var app = URLToArray(document.location.href); - if (app.col_id) { - //console.log(app.col_id); - $("#strat-column").append(utable); - getStrats( - "https://macrostrat.org/api/v2/units?response=long&col_id=" + app.col_id - ); - $("#addUnit").hide(); - } - - // add new unit inputs - $("#addUnit").click(function () { - console.log("you clicked me"); - $("#strat-column").append(utable); - getStrats("https://macrostrat.org/api/v2/units?col_id=482&response=long"); //484, 483, 482, 473, 491, 490, 495 482,491best (484 has carmel group,fm&mbrs together) - }); - - // ajax to get the units api - function getStrats(url) { - $.ajax({ - type: "GET", - //data:'json', - url: url, - //data: { postVar1: 'theValue1', postVar2: 'theValue2' }, - beforeSend: function () { - // this is where we append a loading image - $("#ajax-panel").html( - '
Loading...
' - ); - }, - success: function (data) { - // successful request; do something with the data - $("#ajax-panel").empty(); - prepareColumn(data); // - }, - error: function (msg) { - // failed request; give feedback to user - $("#ajax-panel").html( - '

Oops! Try that again in a few moments.

' - ); - }, - }); - } // end function - - //steps - // first we loop through and assign t_period and b_periods as well as t_epoch and b_epoch so they're in the array - // then loop through and find out the SPAN values by counting matching values for period, group, formation, and member (assign p_span, g_span, f_span, g_span) - - // set things up before creating the columns - function prepareColumn(data) { - var data = data.success.data; - - // loop through the array and asign top & bottom ages/periods (age names not numbers) - // the unit_periods should be in the db, but since they aren't - // we must get them BEFORE our main loop since we need the ajoining values for grep to work - $.each(data, function (n, unit) { - unit.b_period = getGeolPeriod(unit.b_age); - unit.t_period = getGeolPeriod(unit.t_age); - //console.log(unit); - }); - - // get rid of all the 'Unnamed' units, they are useless & ugly - data = $.grep(data, function (value) { - if (value.unit_name != "Unnamed") { - return value; - } - }); - - // two options here, merge strat columns before or AFTER creating them - $.each(data, function (n, unit) { - createUnmergedColumn(unit, n); - }); - mergeHtmlCells(); - /* - // because the api json data is so unpredictable, this option is problematic - data = getRowSpans(data); // prep the data by calculating rowspan values for the html table - $.each(data, function( n,unit ) { - createMergedColumn(unit, n); - }); -*/ - // get the size of time rows & add long, short or reg images - adjustPeriodText(); - } // end function - - // loop through columns, then rows- find duplicates and add rowspan attribute to data - function getRowSpans(data) { - //console.log(data); //helps me know which loop we're on - - var tablecolumns = ["t_period", "Gp", "Fm"]; //.Mbr? - $.each(tablecolumns, function (i, prop) { - // outer loop..esentially through main table coluns. time, group, period - //console.log(prop); - - var previous = ""; - var count = 1; - data = $.each(data, function (n, row) { - //data.filter(function(row,n) { // basically the same as .each - - current = row[prop]; - //console.log(prop); - //console.log(row[prop]); // or data[n][prop] - - // a lot of surficials units have row names, but no formal Groups, Fms, OR Mbrs - // if we don't do this, the Fms & Groups will get screwed up. - if (previous == current && row[prop] != "") { - // if repeated value - count = count + 1; - //console.log("rowspan-"+prop+"= "+count); - data[n]["rowspan_" + prop] = "null"; // tag cells that need to be hidden - - var i = n - count + 1; //row# minus the matching value count (+1 since n starts at 0) - // with each new value go BACK to beginning of last value and add the count before we reset it. - if (data[i]) { - //since 0-1 = undefined - //console.log('add to row: '+ i); - data[i]["rowspan_" + prop] = count; // name the property - } - } else { - // new value - - count = 1; //restart the count - console.log("rowspan-" + prop + "= " + count); - } - - previous = row[prop]; - //console.log(data[n-1].t_period); - }); // .each(row) - }); // .each(prop) - console.log(data); - return data; - } - - // these are mostly identical.... compare them, and see if I can combine them! use class=hide instead of not printing rows. - - // creat column nearly EXACTLY like php file, merging duplicate cells @ creation time - function createMergedColumn(row, n) { - console.log("creating merged columns (like my php script)"); - - // SKIP UNIDENTIFIED UNITS - if (row.unit_name == "Unnamed" || row.unit_name == "") { - //row.strat_name_id == null || row.strat_name_id == '' - //return; - } - var td = "\n"; - - // IF FMS AND GRP ARE BLANK, USE THE UNIT NAME (sadly this happens a lot) - // we have to do the same thing in the getRowSpan function - if (row.unit_name != "" && row.Gp == "" && row.Fm == "") { - row.Fm = row.unit_name; - } - - // EACH NEW PERIOD, ADD THE APPROPRIATE ROW SPAN (DONT PRINT REPEATS) - if (row.t_period && row.rowspan_t_period != "null") { - // how do we only print the first instance? - td += - "

" + - row.t_period + - "

\n"; - } - // GROUPS WITHOUT FORMATIONS, PRINT 180 WIDE - if (row.Gp != "" && row.Fm == "" && row.Mbr == "") { - td += - "

" + - row.Gp + - "

\n"; - } - // GROUPS WITH FORMATIONS, PRINT IT 60 WIDE, WITH THE APPROP ROW SPAN - if (row.Gp != "" && row.rowspan_Gp != "null" && row.Fm != "") { - td += - "

" + - row.Gp + - "

\n"; - } - // FORMATION WITH NO GROUPS OR MEMBERS, MAKE IT FULL 180 WIDE - if (row.Fm != "" && row.Gp == "" && row.Mbr == "") { - //xxchange in other? - td += - "

" + - row.Fm + - "

\n"; - } - // FORMATIONS ARE UNDER A GROUP BUT NO MEMBERS, PRINT THEM 120 WIDE - if (row.Fm != "" && row.Gp != "" && row.Mbr == "") { - td += - "

" + - row.Fm + - "

\n"; - } - // FORMATION HAS MEMBERS UNDER IT, PRINT THE FORMATION 60 WIDE - if (row.Fm != "" && row.rowspan_Fm != "null" && row.Mbr != "") { - var rspan = 1; - td += - "

" + - row.Fm + - "

\n"; - } - // MEMBER UNDER ONLY A FORMATION - if (row.Mbr != "" && row.Fm != "" && row.Gp == "") { - td += - "

" + - row.Mbr + - "

\n"; - } - // MEMBER UNDER A FORMATION AND GROUP - if (row.Mbr != "" && row.Fm != "" && row.Gp != "") { - td += - "

" + - row.Mbr + - "

\n"; - } - - // PRINT THE DEPTH AND ROCK_TYPE COLUMNS - // var thickness = getThickness(row); // we don't want 20-20ft, so format it. - var time = parseFloat(row.b_age - row.t_age).toFixed(3); // get the totally length of unit's age - td += - "

" + - getThickness(row) + - "

\n"; - - // PRINT THE ROCK Type - var lith = getLithImg(row); //use the lith array to get righ lith - td += - " \n"; - td += ""; - - $("#my_table tr:last").after(td); - } // end createColumn() - - // create column without merging duplicate cells. NOT like php file - function createUnmergedColumn(row, n) { - console.log("creating UNmerged columns"); - - // SKIP UNIDENTIFIED UNITS - if (row.strat_name_id == null || row.strat_name_id == "") { - return; - } - var td = "\n"; - - // IF THERE'S A PERIOD, PRINT IT WITH THE APPROPRIATE ROW SPAN - if (row.t_period != "") { - // how do we only print the first instance? - td += - "

" + - row.t_period + - "

\n"; - } - // IF THERES A GROUP AND FM, PRINT IT 60 WIDE, WITH THE APPROP ROW SPAN - if (row.Gp != "" && row.Fm != "") { - td += - "

" + - row.Gp + - "

\n"; - } - // IF THE FORMATIONS ARE UNDER A GROUP BUT NO MEMBERS, PRINT THEM 60 WIDE - if (row.Fm != "" && row.Gp != "" && row.Mbr == "") { - td += - "

" + - row.Fm + - "

\n"; - } - // IF THERE'S A GROUP & NO FMS OR MBRS, PRINT THE GROUP FULL SPAN - if (row.Gp != "" && row.Fm == "" && row.Mbr == "") { - td += - "

" + - row.Gp + - "

\n"; - } - // IF THERE'S A FM BUT NO GROUPS OR MEMBERS, PRINT THE FORMATION FULL SPAN - if (row.Fm != "" && row.Gp == "" && row.Mbr == "") { - td += - "

" + - row.Fm + - "

\n"; - } - // IF THE FORMATION HAS MEMBERS UNDER IT, PRINT THE FORMATION 60 WIDE - if (row.Fm != "" && row.Mbr != "" && row.Gp == "") { - var rspan = 1; - td += - "

" + - row.Fm + - "

\n"; - } - // IF THERE'S A MEMBER, WITHOUT A GROUP PRINT IT - if (row.Mbr != "" && row.Gp == "") { - td += - "

" + - row.Mbr + - "

\n"; - } - - // IF THE FORMATION IS UNDER A GROUP AND HAS MEMBERS UNDER IT - if (row.Fm != "" && row.Mbr != "" && row.Gp != "") { - var rspan = 1; - td += - "

" + - row.Fm + - "

\n"; - } - // IF THERE'S A MEMBER, WITH A GROUP PRINT IT - if (row.Mbr != "" && row.Gp != "") { - td += - "

" + - row.Mbr + - "

\n"; - } - - // PRINT THE DEPTH AND ROCK_TYPE COLUMNS - var time = parseFloat(10 * (row.b_age - row.t_age)).toFixed(3); // get the totally length of unit's age - td += - "

" + - getThickness(row) + - "

\n"; - - // PRINT THE ROCK Type - var lith = getLithImg(row); //use the lith array to get righ lith - td += - " \n"; - td += ""; - - $("#my_table tr:last").after(td); - } // end createColumn() - - function getThickness(row) { - var thick = ""; - // if min & max thicknes are same, only display one of them - if (row.min_thick == row.max_thick) { - thick = row.max_thick; - } else { - //display the range - thick = row.min_thick + "-" + row.max_thick; - } - return thick; - } - - // this is wrong. We need to get the t_age and assign it a t_period and t_epic (we have t_ages) we'll use mostly periods - function getGeolPeriod(t) { - //t=top_age OR bottom age (get both) - var p = ""; - if (t > 0 && t <= 2.588) { - p = "Quaternary"; - } else if (t > 2.588 && t <= 5.332) { - p = "Plicene"; - } else if (t > 5.332 && t <= 23.03) { - p = "Neogene"; - } else if (t > 23.03 && t <= 65.5) { - p = "Paleogene"; - } else if (t > 65.5 && t <= 145.5) { - p = "Cretaceous"; - } else if (t > 145.5 && t <= 199.6) { - p = "Jurassic"; - } else if (t > 199.6 && t <= 251.0) { - p = "Triassic"; - } else if (t > 251.0 && t <= 299.0) { - p = "Permian"; - } else if (t > 299.0 && t <= 359.2) { - p = "Carboniferous"; - } else if (t > 359.2 && t <= 416.0) { - p = "Devonian"; - } else if (t > 416.0 && t <= 443.7) { - p = "Silurian"; - } else if (t > 443.7 && t <= 488.3) { - p = "Ordovician"; - } else if (t > 488.3 && t <= 542.0) { - p = "Cambrian"; - } else if (t > 542.0 && t <= 2500) { - p = "Proterozoic"; - } else if (t > 2500 && t <= 4000) { - p = "Archean"; - } else { - p = "unknown"; - } - // return the age and store it in t_period - return p; - } - - function getLithImg(unit) { - var lith = unit.lith; - // go through lit array and return the one with largest percentage - var pl = lith.reduce(function (max, obj) { - return obj.num > max.num ? obj : max; - }); - //console.log(pl); - var primarylith = pl.name; // this should be the predominate lithology - var rockImage = "usgs_sandstone.jpg"; - - if (primarylith == "sandstone") { - rockImage = "usgs_sandstone.jpg"; - } - if (primarylith == "limestone") { - rockImage = "627-limestone.svg"; - } - if (primarylith == "shale") { - rockImage = "620-shale-or-clay2.svg"; - } - if (primarylith == "siltstone") { - rockImage = "usgs_siltstone.jpg"; - } - if (primarylith == "coal") { - rockImage = "usgs_coal.jpg"; - } - if (primarylith == "conglomerate") { - rockImage = "601-conglomerate-matrix.svg"; - } - if (primarylith == "dolomite") { - rockImage = "usgs_dolomite.jpg"; - } - if (primarylith == "alluvium") { - rockImage = "usgs_alluvium.jpg"; - } - if (primarylith == "basalt") { - rockImage = "usgs_flows.jpg"; - } - if (primarylith == "gneiss") { - rockImage = "usgs_gneiss.jpg"; - } - if (primarylith == "gypsum") { - rockImage = "usgs_gypsum.jpg"; - } - if (primarylith == "limyshale") { - rockImage = "usgs_limyshale.jpg"; - } - if (primarylith == "marble") { - rockImage = "usgs_marble.jpg"; - } - if (primarylith == "quartizite") { - rockImage = "usgs_quartzite.jpg"; - } - if (primarylith == "salt") { - rockImage = "usgs_salt.jpg"; - } - if (primarylith == "schist") { - rockImage = "usgs_schist.jpg"; - } - if (primarylith == "igneous1") { - rockImage = "usgs_igneous1.jpg"; - } - if (primarylith == "igneous2") { - rockImage = "usgs_igneous2.jpg"; - } - if (primarylith == "igneous3") { - rockImage = "usgs_igneous3.jpg"; - } - if (primarylith == "igneous4") { - rockImage = "usgs_igneous4.jpg"; - } - if (primarylith == "igneous5") { - rockImage = "usgs_igneous5.jpg"; - } - if (primarylith == "igneous6") { - rockImage = "usgs_igneous6.jpg"; - } - - return rockImage; - } - - // go through table after creation and merge all the duplicates - // loop through columns, then rows- researching entire table on EACH row (intensive) - function mergeHtmlCells() { - console.log("merging duplicate table cells"); - // loop through each column using this class array (each column has seperate class) (we don't want to merge thickness or rocktype columns!) - var tablecolumns = [".period", ".group", ".formation", ".member"]; - $.each(tablecolumns, function (i, value) { - //console.log("loop number: "+i); - var previous = ""; - // we dont want to merge individual Gr, Fms or Mbrs (rowspan=3) with the same units below that may be with a group. - var prev_cSpan = ""; - var count = 1; - - // create a simply array of JUST this column/field - // use this to backtrack and change rowspans in the next loop - var column = $("#my_table tr " + value).each(function () { - return $(this); - }); - - // now loop through column values & find duplicates - column.each(function (n, cell) { - //console.log(" 90) { - $(this).attr("class", function (n, val) { - return val + "-long"; - }); - } - }); - } // end function - - // add new unit inputs - $("#expandTime").click(function () { - expandTime(20); - }); - function expandTime(multiplier) { - console.log("expanding by time..."); - var mult = parseInt(multiplier); - // loop through each cell, get max_thickness - $("#my_table tr .thickness").each(function (n, cell) { - var t = $(this).attr("data-time"); - var w = Math.round(Math.log(t) * mult); //.toFixed(0); - $(this).parent().height(w); //.height(); - }); - } - // add new unit inputs - $("#expandThickness").click(function () { - expandThickness(20); - }); - function expandThickness(multiplier) { - console.log("expanding by thickness"); - var mult = parseInt(multiplier); - // loop through each cell, get max_thickness - $("#my_table tr .thickness").each(function (n, cell) { - //console.log($(this).parent() ); - var t = $(this).attr("data-maxthick"); - //console.log(t); - var w = Math.round(Math.log(t) * mult); //.toFixed(0); - if ($(this).parent()[0].id == "2") { - // for texting.... - //console.log("n:"+mult+" t:"+t+" w:"+w); - } - //$(this).parent().attr("height", w); //.height(); - $(this).parent().height(w); //.height(); - }); - } - - $("#thickness-slider").slider({ - orientation: "horizontal", - range: "min", - min: 1, - max: 100, - value: 1, - step: 10, - slide: function (event, ui) { - console.log(ui.value); - expandThickness(ui.value); - }, - }); -}); // end document.ready diff --git a/pages/dev/columns-test/@column/column-inspector/index.module.sass b/pages/dev/columns-test/@column/column-inspector/index.module.sass deleted file mode 100644 index 89a7a2643..000000000 --- a/pages/dev/columns-test/@column/column-inspector/index.module.sass +++ /dev/null @@ -1,111 +0,0 @@ -.page-container - overflow-y: scroll - height: 100vh - position: relative - -.main - --column-background-color: var(--background-color) - --column-stroke-color: var(--text-color) - - display: flex - flex-direction: row - - max-width: 80rem - margin: 0 auto - - -.left-column - flex-grow: 1 - -.right-column - min-width: 200px - width: 40% - max-width: 500px - height: 100vh - position: sticky - top: 0 - display: flex - flex-direction: column - padding: 2em 0 - - & > * - border-radius: 4px - -.right-column-boxes - display: flex - flex-direction: column - gap: 1em - - -.column-view - margin: 0 4em 4em - padding: 0 - -.column-header - margin: 1em 4em - - h1 - font-size: 1.5em - - .subtitle - font-weight: normal - - nav - position: sticky - top: 2em - -.column-nav - position: sticky - top: 2.2em - - h3 - color: #444 - margin-bottom: 0.3em - -.default-buttons - width: 100% - margin: 0 -10px - -.column-map - width: 100% - aspect-ratio: 3/2 - cursor: pointer - z-index: 100 - - &.expanded - cursor: inherit - - .columns path:hover - stroke: rgba(255, 0, 0, .4) !important - - - .close-button - position: absolute - top: 1em - right: 1em - - .land - background-color: rgb(233, 252, 234) - -div.section - display: flex - flex-direction: row - - div.timescale - width: 7em - --timescale-level-size: 1.5em - - -.section .divisions .unit - cursor: pointer - -rect.selection-overlay - fill: rgba(255, 0, 0, .5) - -.unit-details-panel - flex: 1 - min-height: 0 - -.column-map, .unit-details-panel - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3) - border-radius: 6px diff --git a/pages/dev/columns-test/@column/column-inspector/index.ts b/pages/dev/columns-test/@column/column-inspector/index.ts deleted file mode 100644 index 46a923ec3..000000000 --- a/pages/dev/columns-test/@column/column-inspector/index.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { - ColoredUnitComponent, - MacrostratDataProvider, - Column, -} from "@macrostrat/column-views"; -import { hyperStyled } from "@macrostrat/hyper"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { apiV2Prefix } from "@macrostrat-web/settings"; -import { PatternProvider } from "~/_providers"; -import styles from "./index.module.sass"; -import { navigate } from "vike/client/router"; - -import { ModalUnitPanel } from "./modal-panel"; - -import { PageBreadcrumbs } from "~/components"; -import { onDemand } from "~/_utils"; - -const ColumnMap = onDemand(() => import("./map").then((mod) => mod.ColumnMap)); - -const h = hyperStyled(styles); - -export function ColumnPage(props) { - return h( - MacrostratDataProvider, - { baseURL: apiV2Prefix }, - h(PatternProvider, h(ColumnPageInner, props)) - ); -} - -function ColumnPageInner({ columnInfo, linkPrefix = "/", projectID }) { - console.log(columnInfo); - const { units } = columnInfo; - - const [selectedUnitID, setSelectedUnitID] = useState( - getInitialSelectedUnitID - ); - - const selectedUnit = useMemo(() => { - if (selectedUnitID == null) return null; - return units.find((d) => d.unit_id == selectedUnitID); - }, [selectedUnitID]); - - useEffect(() => { - setHashString(selectedUnitID); - }, [selectedUnitID]); - - console.log(columnInfo); - - const lon = new Number(columnInfo.lng); - const lat = new Number(columnInfo.lat); - const zoom = 7; - - const onSelectColumn = useCallback( - (col_id: number) => { - // do nothing - // We could probably find a more elegant way to do this - navigate(`${linkPrefix}columns/${col_id}${window.location.hash}`, { - overwriteLastHistoryEntry: true, - }); - }, - [setSelectedUnitID] - ); - - let assistantContent = h("div.column-info", [ - h("h1.page-title", [ - h("span.col-name", columnInfo.col_name), - h.if(columnInfo.col_group != null)("span.subtitle", [ - h("span.separator", " – "), - h("span.col-group", `${columnInfo.col_group}`), - ]), - ]), - h("p.column-details", [ - h("span.column-id", ["#", columnInfo.col_id]), - ", ", - h("span.project", ["project ", columnInfo.project_id]), - ", ", - h( - "a", - { - href: `/map/loc/${lon}/${lat}/column#z=${zoom}&show=columns,geology`, - }, - "show in map" - ), - ".", - ]), - ]); - - if (selectedUnit != null) { - assistantContent = h(ModalUnitPanel, { - unitData: units, - className: "unit-details-panel", - selectedUnit, - onSelectUnit: setSelectedUnitID, - }); - } - - return h("div.page-container", [ - h("div.main", [ - h("div.left-column", [ - h("div.column-header", [ - h("nav", [ - h(PageBreadcrumbs, { showLogo: true, title: columnInfo.col_name }), - ]), - ]), - h("div.column-view", [ - h(Column, { - units, - unitComponent: ColoredUnitComponent, - unconformityLabels: true, - collapseSmallUnconformities: true, - columnWidth: 300, - width: 450, - onUnitSelected: setSelectedUnitID, - selectedUnit: selectedUnitID, - }), - ]), - ]), - h("div.right-column", [ - h("div.right-column-boxes", [ - h(ColumnMap, { - className: "column-map", - inProcess: true, - projectID, - selectedColumn: columnInfo.col_id, - onSelectColumn, - }), - assistantContent, - ]), - ]), - ]), - ]); -} - -function getHashParams() { - // Harvest selected unit ID from hash string - const currentHash = document.location.hash.substring(1); - return new URLSearchParams(currentHash); -} - -function getInitialSelectedUnitID() { - // Harvest selected unit ID from hash string - const params = getHashParams(); - const unit_id = params.get("unit"); - // If no unit_id, return null - if (unit_id == null) return null; - const id = parseInt(unit_id); - if (isNaN(id)) return null; - return id; -} - -function setHashString(selectedUnitID: number) { - const params = getHashParams(); - params.delete("unit"); - if (selectedUnitID != null) { - params.set("unit", selectedUnitID.toString()); - } - console.log(selectedUnitID, params); - const newHash = params.toString(); - if (newHash !== document.location.hash) { - document.location.hash = newHash; - } -} diff --git a/pages/dev/columns-test/@column/column-inspector/map.ts b/pages/dev/columns-test/@column/column-inspector/map.ts deleted file mode 100644 index 1c745a32f..000000000 --- a/pages/dev/columns-test/@column/column-inspector/map.ts +++ /dev/null @@ -1,24 +0,0 @@ -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/columns-test/@column/column-inspector/modal-panel.ts b/pages/dev/columns-test/@column/column-inspector/modal-panel.ts deleted file mode 100644 index 03d67a964..000000000 --- a/pages/dev/columns-test/@column/column-inspector/modal-panel.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Button } from "@blueprintjs/core"; -import { UnitDetailsPanel } from "@macrostrat/column-views"; -import { useKeyHandler } from "@macrostrat/ui-components"; -import h from "@macrostrat/hyper"; - -export function ModalUnitPanel(props) { - const { unitData, className, selectedUnit, onSelectUnit, features } = props; - - const ix = unitData?.findIndex( - (unit) => unit.unit_id === selectedUnit?.unit_id - ); - - const keyMap = { - 38: ix - 1, - 40: ix + 1, - }; - - useKeyHandler( - (event) => { - const nextIx = keyMap[event.keyCode]; - if (nextIx == null || nextIx < 0 || nextIx >= unitData.length) return; - onSelectUnit(unitData[nextIx].unit_id); - event.stopPropagation(); - }, - [unitData, ix] - ); - - if (selectedUnit == null) return null; - - const actions = h([ - h(Button, { - icon: "arrow-up", - disabled: ix === 0, - onClick() { - onSelectUnit(unitData[ix - 1]?.unit_id); - }, - }), - h(Button, { - icon: "arrow-down", - disabled: ix === unitData.length - 1, - onClick() { - onSelectUnit(unitData[ix + 1]?.unit_id); - }, - }), - ]); - - return h(UnitDetailsPanel, { - unit: selectedUnit, - onClose(event) { - console.log("close"); - onSelectUnit(null); - }, - className, - actions, - showLithologyProportions: true, - onSelectUnit, - columnUnits: unitData, - features, - onClickItem: (e, unit) => { - if(unit?.lith_id) { - window.open('/lex/lithologies/' + unit.lith_id, '_self'); - } - - if(unit?.environ_id) { - window.open('/lex/environments/' + unit.environ_id, '_self'); - } - - if(unit?.int_id) { - window.open('/lex/intervals/' + unit.int_id, '_self'); - } - - if(unit?.strat_name_id) { - window.open('/lex/strat-names/' + unit.strat_name_id, '_self'); - } - }, - }); -} diff --git a/pages/dev/columns-test/correlation/+Page.ts b/pages/dev/columns-test/correlation/+Page.ts deleted file mode 100644 index 86e7e7160..000000000 --- a/pages/dev/columns-test/correlation/+Page.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { FullscreenPage } from "~/layouts"; -import { C } from "@macrostrat/hyper"; -import h from "./main.module.sass"; -import { compose } from "@macrostrat/hyper"; -import { mapboxAccessToken, apiV2Prefix } from "@macrostrat-web/settings"; -import { - Alignment, - FormGroup, - Popover, - SegmentedControl, - Switch, -} from "@blueprintjs/core"; -import { PageBreadcrumbs } from "~/components"; -import { useEffect, useMemo } from "react"; -import { DisplayDensity, useCorrelationDiagramStore } from "./state"; -import { PatternProvider } from "~/_providers"; -import { useRef } from "react"; - -import { Button, OverlaysProvider } from "@blueprintjs/core"; -import { DarkModeProvider } from "@macrostrat/ui-components"; -import { - ColumnCorrelationMap, - ColumnCorrelationProvider, - useCorrelationMapStore, - MacrostratDataProvider, - fetchUnits, - UnitDetailsPanel, - CorrelationChart, - CorrelationChartProps, - useMacrostratStore, -} from "@macrostrat/column-views"; -import { - getCorrelationHashParams, - setHashStringForCorrelation, -} from "./hash-string"; - -import { ErrorBoundary, useAsyncMemo } from "@macrostrat/ui-components"; - -export function Page() { - const hashData = useMemo(getCorrelationHashParams, []); - - const setSelectedUnit = useCorrelationDiagramStore( - (state) => state.setSelectedUnit - ); - useEffect(() => { - // Set the initial selected unit from the hash if available - if (hashData.unit != null) { - setSelectedUnit(hashData.unit, undefined); - } - }, []); - - return h( - PageWrapper, - h( - ColumnCorrelationProvider, - { - baseURL: apiV2Prefix, - focusedLine: hashData.section, - }, - h(PageInner, { selectedUnit: hashData.unit }) - ) - ); -} - -export function PageInner() { - const expanded = useCorrelationDiagramStore((state) => state.mapExpanded); - const ref = useRef(); - - return h("div.main-panel", { ref }, [ - h("header.page-header", [ - h(PageBreadcrumbs), - h(CorrelationSettingsPopup, { boundary: ref.current }), - ]), - h( - "div.diagram-container", - { className: expanded ? "map-expanded" : "map-inset" }, - [ - h("div.main-area", [ - h(CorrelationDiagramWrapper), - h("div.overlay-safe-area"), - ]), - h("div.assistant", [ - h("div.column-selection-map", [ - h(ColumnCorrelationMap, { - accessToken: mapboxAccessToken, - className: "correlation-map", - apiBaseURL: apiV2Prefix, - showLogo: false, - padding: expanded ? 100 : 20, - }), - h(MapExpandedButton), - ]), - h(UnitDetailsExt), - ]), - ] - ), - ]); -} - -function CorrelationDiagramWrapper(props: Omit) { - /** This state management is a bit too complicated, but it does kinda sorta work */ - - // Sync focused columns with map - const focusedColumns = useCorrelationMapStore( - (state) => state.focusedColumns - ); - - const focusedLine = useCorrelationMapStore((state) => state.focusedLine); - const selectedUnitID = useCorrelationDiagramStore( - (state) => state.selectedUnitID - ); - - useEffect(() => { - setHashStringForCorrelation({ section: focusedLine, unit: selectedUnitID }); - }, [focusedLine, selectedUnitID]); - - // selected unit management - // const selectedUnit = useCorrelationDiagramStore( - // (state) => state.selectedUnit - // ); - const onUnitSelected = useCorrelationDiagramStore( - (state) => state.setSelectedUnit - ); - - const expanded = useCorrelationDiagramStore((state) => state.mapExpanded); - - const fetch = useMacrostratStore((state) => state.fetch); - const columnUnits = useAsyncMemo(async () => { - const col_ids = focusedColumns.map((col) => col.properties.col_id); - return await fetchUnits(col_ids, fetch); - }, [focusedColumns]); - - return h("div.correlation-diagram", [ - h( - ErrorBoundary, - h(OverlaysProvider, [ - h(CorrelationChart, { - data: columnUnits, - selectedUnit: null, - onUnitSelected, - showUnitPopover: !expanded, - collapseSmallUnconformities: true, - ...props, - }), - ]) - ), - ]); -} - -function CorrelationSettings() { - const colorize = useCorrelationDiagramStore((d) => d.colorizeUnits); - const applySettings = useCorrelationDiagramStore((d) => d.applySettings); - - return h("div.correlation-settings.settings", [ - h("h3", "Settings"), - h(DisplayDensitySelector), - h(Switch, { - label: "Colorize", - isOn: colorize, - alignIndicator: Alignment.RIGHT, - onChange() { - applySettings({ colorizeUnits: !colorize }); - }, - }), - ]); -} - -function DisplayDensitySelector() { - const displayDensity = useCorrelationDiagramStore((d) => d.displayDensity); - const applySettings = useCorrelationDiagramStore((d) => d.applySettings); - const options = [ - { label: "Low", value: DisplayDensity.LOW }, - { label: "Medium", value: DisplayDensity.MEDIUM }, - { label: "High", value: DisplayDensity.HIGH }, - ]; - - return h( - FormGroup, - { label: "Display density" }, - h(SegmentedControl, { - options, - value: displayDensity, - onValueChange(value) { - applySettings({ displayDensity: value }); - }, - small: true, - defaultValue: DisplayDensity.MEDIUM, - }) - ); -} - -function CorrelationSettingsPopup({ boundary }) { - console.log("Boundary ref", boundary); - return h( - Popover, - { - content: h(CorrelationSettings), - }, - h(Button, { icon: "settings", minimal: true }) - ); -} - -const PageWrapper = compose( - FullscreenPage, - DarkModeProvider, - PatternProvider, - OverlaysProvider, - C(MacrostratDataProvider, { baseURL: apiV2Prefix }) -); - -function UnitDetailsExt() { - const selectedUnit = useCorrelationDiagramStore( - (state) => state.selectedUnit - ); - const expanded = useCorrelationDiagramStore((state) => state.mapExpanded); - const setSelectedUnit = useCorrelationDiagramStore( - (state) => state.setSelectedUnit - ); - - if (selectedUnit == null || !expanded) { - return null; - } - - return h("div.unit-details-panel", [ - h(UnitDetailsPanel, { - unit: selectedUnit, - onClose: () => setSelectedUnit(null), - }), - ]); -} - -function MapExpandedButton() { - const toggleMapExpanded = useCorrelationDiagramStore( - (state) => state.toggleMapExpanded - ); - const mapExpanded = useCorrelationDiagramStore((state) => state.mapExpanded); - - const icon = mapExpanded ? "collapse-all" : "expand-all"; - - return h(Button, { - className: "map-expanded-button", - icon, - onClick: toggleMapExpanded, - }); -} diff --git a/pages/dev/columns-test/correlation/+config.ts b/pages/dev/columns-test/correlation/+config.ts deleted file mode 100644 index 61f09934c..000000000 --- a/pages/dev/columns-test/correlation/+config.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default { - meta: { - Page: { - /* Ideally we'd make it so only the column inset map was rendered client-side, - but this will work for now. - */ - env: { - client: true, - server: false, - }, - }, - }, - title: "Correlation chart", -}; diff --git a/pages/dev/columns-test/correlation/hash-string.ts b/pages/dev/columns-test/correlation/hash-string.ts deleted file mode 100644 index 7342dd489..000000000 --- a/pages/dev/columns-test/correlation/hash-string.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { LineString } from "geojson"; -import { setHashString } from "@macrostrat/ui-components"; -import { parseLineFromString, stringifyLine } from "@macrostrat/column-views"; - -interface CorrelationHashParams { - section?: LineString | null; - unit?: number; -} - -export function getCorrelationHashParams(): CorrelationHashParams { - if (typeof window === "undefined") { - return null; - } - - const hash = new URLSearchParams(window.location.hash.slice(1)); - const _section = hash.get("section"); - const _unit = hash.get("unit"); - - let section = parseLineFromString(_section); - let unit: number = null; - - if (_unit != null) { - unit = Number(_unit); - } - - return { - section, - unit, - }; -} - -export function setHashStringForCorrelation(state: CorrelationHashParams) { - const { section, unit } = state; - if (section == null) { - return; - } - if (section.coordinates.length < 2) { - return; - } - let _unit = unit; - if (unit == null) { - _unit = undefined; - } - - let hash = { - section: stringifyLine(section), - unit: _unit, - }; - setHashString(hash); -} diff --git a/pages/dev/columns-test/correlation/main.module.sass b/pages/dev/columns-test/correlation/main.module.sass deleted file mode 100644 index 46b259537..000000000 --- a/pages/dev/columns-test/correlation/main.module.sass +++ /dev/null @@ -1,139 +0,0 @@ -$map-size: 40em -$map-size-inset: 12em - -.page-header - display: flex - flex-direction: row - justify-content: space-between - margin-bottom: 1em - -.diagram-container - flex: 1 - position: relative - min-height: 0 - display: flex - - &.map-inset - .column-selection-map - position: absolute - top: 1em - right: 1em - height: $map-size-inset - width: $map-size-inset - z-index: 1000 - - &.map-expanded - flex-direction: row - gap: 1em - - .assistant - width: 40em - position: relative - -.column-selection-map, .unit-details-panel, .main-area - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3) - border-radius: 6px - -.column-selection-map - overflow: hidden - - .correlation-map - height: 100% - position: relative - - flex: 1 - min-height: $map-size-inset - max-height: $map-size - width: $map-size - position: relative - top: 0 - right: 0 - -.unit-details-panel - overflow: scroll - background: var(--panel-secondary-background-color) - flex: 2 - max-width: 100% - -.main-area - position: relative - flex: 1 - min-height: 0 - min-width: 0 - overflow: scroll - background-color: var(--panel-secondary-background-color) - -.diagram-container - position: relative - -.correlation-diagram - margin-right: 2em - width: fit-content - background-color: var(--panel-secondary-background-color) - --column-background-color: var(--background-color) - --column-stroke-color: var(--text-color) - - -.package - position: relative - - .package-overlay - position: absolute - top: 9px - left: 0 - border: 2px solid red - - .laterally-extensive-unit .strat-col-span - position: absolute - border: 2px solid red - - .column-container - display: flex - flex-direction: row - -.map-expanded-button - position: absolute - top: 0.5em - right: 0.5em - z-index: 100 - -.main-panel - position: relative - height: 100% - display: flex - flex-direction: column - - -.correlation-chart-inner - display: flex - flex-direction: row - -.overlay-safe-area - position: absolute - top: 1em - left: 1em - right: 1em - bottom: 1em - pointer-events: none - -.map-inset - .overlay-safe-area - margin-right: $map-size-inset + 1em - - .column-selection-map - z-index: 1000 - -.assistant - display: flex - flex-direction: column - gap: 1em - -.settings - padding: 1em - min-width: 10em - - > :first-child - margin-top: 0 - - > :last-child - margin-bottom: 0 diff --git a/pages/dev/columns-test/correlation/state.ts b/pages/dev/columns-test/correlation/state.ts deleted file mode 100644 index fad1bd86e..000000000 --- a/pages/dev/columns-test/correlation/state.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Point } from "geojson"; -import { create } from "zustand"; -import type { ColumnGeoJSONRecord } from "@macrostrat/api-types"; -import { UnitLong } from "@macrostrat/api-types"; -import { LocalStorage } from "@macrostrat/ui-components"; - -export interface CorrelationState extends CorrelationLocalStorageState { - focusedColumns: FocusedColumnGeoJSONRecord[]; - selectedUnitID: number | null; - selectedUnit: UnitLong | null; - toggleMapExpanded: () => void; - setSelectedColumns: (columns: FocusedColumnGeoJSONRecord[]) => void; - setSelectedUnit: (unit_id: number, unit: UnitLong) => void; - applySettings: (settings: Partial) => void; - setDisplayDensity: (value: DisplayDensity) => void; -} - -export enum DisplayDensity { - LOW = 0, - MEDIUM = 1, - HIGH = 2, -} - -interface CorrelationLocalStorageState { - mapExpanded: boolean; - displayDensity: DisplayDensity; - colorizeUnits: boolean; -} - -const localStorage = new LocalStorage( - "macrostrat.correlation.settings" -); - -/** Store management with Zustand. - * This is a newer and somewhat more subtle approach than the Redux store - * used in the mapping application. - * */ -export const useCorrelationDiagramStore = create( - (set, get): CorrelationState => { - const { - mapExpanded = false, - displayDensity = DisplayDensity.MEDIUM, - colorizeUnits = true, - } = localStorage.get() ?? ({} as CorrelationLocalStorageState); - - return { - focusedColumns: [], - mapExpanded, - displayDensity, - selectedUnitID: null, - selectedUnit: null, - colorizeUnits, - setSelectedColumns(columns) { - set({ focusedColumns: columns }); - }, - setSelectedUnit( - unit_id: number, - selectedUnit: UnitLong | null = undefined - ) { - console.log("setSelectedUnit", unit_id, selectedUnit); - set({ selectedUnitID: unit_id, selectedUnit }); - }, - setDisplayDensity(displayDensity: DisplayDensity) { - set({ displayDensity }); - setLocalStorageState(get()); - }, - applySettings(settings: Partial) { - set(settings); - setLocalStorageState(get()); - }, - toggleMapExpanded: () => { - set((state) => { - const partial = { mapExpanded: !state.mapExpanded }; - localStorage.set(partial); - return partial; - }); - - setLocalStorageState(get()); - }, - }; - } -); - -function setLocalStorageState(state: CorrelationState) { - localStorage.set({ - mapExpanded: state.mapExpanded, - displayDensity: state.displayDensity, - colorizeUnits: state.colorizeUnits, - }); -} - -interface FocusedColumnGeoJSONRecord extends ColumnGeoJSONRecord { - properties: { - centroid: Point; - nearestPointOnLine: Point; - distanceAlongLine: number; - } & ColumnGeoJSONRecord["properties"]; -} diff --git a/pages/dev/columns-test/grouped-cols.ts b/pages/dev/columns-test/grouped-cols.ts deleted file mode 100644 index 075a1e86e..000000000 --- a/pages/dev/columns-test/grouped-cols.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { fetchAPIData, fetchPGData } from "~/_utils"; - -export async function getGroupedColumns(project_id: number | null, params?: any) { - let columnURL = "/col_data"; - - const pgParams = project_id != null ? { ...params, project_id: `eq.${project_id}` } : params; - - const [columns, groups] = await Promise.all([ - fetchPGData(columnURL, pgParams), - fetchAPIData(`/defs/groups`, { all: true }), - ]); - - if(!columns) { - return null - } - - columns.sort((a, b) => a.col_id - b.col_id); - - // Group by col_group - // Create a map of column groups - const groupMap = new Map( - groups.map((g) => [ - g.col_group_id, - { name: g.name, id: g.col_group_id, columns: [] }, - ]) - ); - groupMap.set(-1, { - id: -1, - name: "Ungrouped", - columns: [], - }); - - for (const col of columns) { - const col_group_id = col.col_group_id ?? -1; - const group = groupMap.get(col_group_id); - group.columns.push(col); - } - - const groupsArray = Array.from(groupMap.values()).filter( - (g) => g.columns.length > 0 - ); - - // Sort the groups by id - groupsArray.sort((a, b) => { - if (a.id === -1) return 1; // Ungrouped should come last - return a.id - b.id; - }); - - return groupsArray; -} \ No newline at end of file diff --git a/pages/dev/columns-test/groups/+Page.client.ts b/pages/dev/columns-test/groups/+Page.client.ts deleted file mode 100644 index 40c455567..000000000 --- a/pages/dev/columns-test/groups/+Page.client.ts +++ /dev/null @@ -1,8 +0,0 @@ -import h from "@macrostrat/hyper"; -import { Page as ColumnListPage } from "#/columns/+Page.ts"; - -export function Page() { - return h(ColumnListPage, { - title: "Groups", - }); -} diff --git a/pages/dev/columns-test/groups/+data.ts b/pages/dev/columns-test/groups/+data.ts deleted file mode 100644 index 1b5fe3814..000000000 --- a/pages/dev/columns-test/groups/+data.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { fetchAPIData } from "~/_utils/fetch-helpers"; - -export async function data() { - const res = await fetchAPIData(`/columns`, { all: true }); - - const grouped = {}; - - for (const item of res) { - 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); - } - - const columnGroups = Object.values(grouped); - - return { - columnGroups, - }; -} diff --git a/pages/dev/columns-test/groups/@group/+Page.client.ts b/pages/dev/columns-test/groups/@group/+Page.client.ts deleted file mode 100644 index 493af7236..000000000 --- a/pages/dev/columns-test/groups/@group/+Page.client.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { useData } from "vike-react/useData"; -import h from "@macrostrat/hyper"; -import { - LexItemPage, - ColumnsTable, - Charts, - PrevalentTaxa, - Timescales, -} from "~/components/lex"; - -export function Page() { - const { resData, colData, taxaData, refs } = useData(); - - const id = resData.col_group_id; - const features = colData?.features || []; - const timescales = resData?.timescales || []; - - const children = [ - h(ColumnsTable, { - resData, - colData, - }), - h(Charts, { features }), - h(PrevalentTaxa, { taxaData }), - h(Timescales, { timescales }), - ]; - - return LexItemPage({ children, id, refs, resData, siftLink: "groups" }); -} diff --git a/pages/dev/columns-test/groups/@group/+data.ts b/pages/dev/columns-test/groups/@group/+data.ts deleted file mode 100644 index 2b82facec..000000000 --- a/pages/dev/columns-test/groups/@group/+data.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { pbdbDomain } from "@macrostrat-web/settings"; -import { fetchAPIData, fetchAPIRefs } from "~/_utils"; -import { getPrevalentTaxa } from "~/components/lex/data-helper"; - -export async function data(pageContext) { - const col_group_id = parseInt(pageContext.urlParsed.pathname.split("/")[3]); - - // Await all API calls - const [resData, colData, fossilsData,refs1, refs2] = await Promise.all([ - fetchAPIData("/defs/groups", { col_group_id }), - fetchAPIData("/columns", { - col_group_id, - response: "long", - format: "geojson", - }), - fetchAPIData("/fossils", { col_group_id, format: "geojson" }), - fetchAPIRefs("/fossils", { col_group_id }), - fetchAPIRefs("/columns", { col_group_id }), - ]); - - const refValues1 = Object.values(refs1); - const refValues2 = Object.values(refs2); - const refs = [...refValues1, ...refValues2]; - - const taxaData = await getPrevalentTaxa(fossilsData); - - return { resData: resData[0], colData, taxaData, refs }; -} diff --git a/pages/dev/columns-test/main.module.sass b/pages/dev/columns-test/main.module.sass deleted file mode 100644 index 16449fbec..000000000 --- a/pages/dev/columns-test/main.module.sass +++ /dev/null @@ -1,134 +0,0 @@ -.flex-row - display: flex - flex-direction: row - position: relative - gap: 2em - -.main, .sidebar - flex: 1 - -:root - --main-extra-width: 200px - - -@media (min-width: 1100px) - .flex-row - margin-right: calc(-1 * var(--main-extra-width)) - - .sidebar - max-width: calc(50% - var(--main-extra-width) / 2) - -.sidebar-content - padding-top: 2em - position: sticky - top: 0 - display: flex - flex-direction: column - gap: 1em - -.column-map-container - position: relative - min-height: 300px - width: 100% - aspect-ratio: 1/1 - -.column-group-header - display: flex - justify-content: space-between - align-items: center - -.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 - -.active, -.inprocess, -.obsolete - place-self: end start - padding: 0.5em - margin: 0.2em 0 - border-radius: 0.2em - font-weight: bold - -.active - background-color: green - color: white - -.column-list table - width: 100% - position: relative - - th - text-align: left - background-color: var(--panel-background-color) - - tr - align-items: baseline - - &:hover - background-color: var(--tertiary-background) - - td.col-id - width: 60px - - td.col-name - max-width: 60% - - .col-status - text-align: right - -.inprocess - background-color: yellow - color: black - -.obsolete - background-color: red - color: white - - -.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 - -.search-bar - flex: 1 1 0 - -.switches - flex: 0 0 auto - -.lex-filters - display: flex - flex-direction: column - gap: .5em - -.close-btn - cursor: pointer - -.filters - display: flex - gap: 1em - align-items: center \ No newline at end of file diff --git a/pages/dev/columns-test/map.client.ts b/pages/dev/columns-test/map.client.ts deleted file mode 100644 index 0d03b63ca..000000000 --- a/pages/dev/columns-test/map.client.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - ColumnNavigationMap, - useMacrostratColumns, -} from "@macrostrat/column-views"; -import h from "@macrostrat/hyper"; -import { mapboxAccessToken } from "@macrostrat-web/settings"; -import { ErrorBoundary } from "@macrostrat/ui-components"; -import { useMapRef, useMapStyleOperator } from "@macrostrat/mapbox-react"; -import mapboxgl from "mapbox-gl"; - -export function ColumnsMapContainer(props) { - return h(ErrorBoundary, h(ColumnsMapInner, props)); -} - -function ColumnsMapInner({ columnIDs = null, projectID = null, className, hideColumns }) { - const columnData = useMacrostratColumns(projectID, projectID != null); - - if(!columnData) { - return h("div", { className }, "Loading map..."); - } - - return h( - "div", - { className }, - h(ColumnNavigationMap, - { - style: { height: "100%" }, - accessToken: mapboxAccessToken, - onSelectColumn: (col) => { - if (col) { - window.open(`/columns/${col}`, "_self"); - } - }, - columnIDs, - }, - h(FitBounds, { columnData }) - ), - ); -} - -function FitBounds({ columnData }) { - useMapStyleOperator((map) => { - if (!map || columnData.length === 0) return; - - // Extract coordinates - const coords = columnData - .map(col => col.geometry.coordinates[0][0]); - if (coords.length === 0) return; - - // Build bounds using the first coordinate - const bounds = coords.reduce( - (b, coord) => b.extend(coord), - new mapboxgl.LngLatBounds(coords[0], coords[0]) - ); - - map.fitBounds(bounds, { - padding: 50, - duration: 0, - }); - }); - - return null; -} diff --git a/pages/dev/columns-test/utils.ts b/pages/dev/columns-test/utils.ts deleted file mode 100644 index 111eba353..000000000 --- a/pages/dev/columns-test/utils.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { Button, MenuItem, MenuItemProps } from "@blueprintjs/core"; -import { ItemPredicate, ItemRenderer, Select2 } from "@blueprintjs/select"; -import { Cell, EditableCell2Props } from "@blueprintjs/table"; -import React, { useMemo, memo } from "react"; -import { useInDarkMode } from "@macrostrat/ui-components"; -import { getColorPair } from "@macrostrat/color-utils"; -import { useAPIResult } from "@macrostrat/ui-components"; -import "@blueprintjs/select/lib/css/blueprint-select.css"; -import h from "@macrostrat/hyper"; - -interface Timescale { - timescale_id: number; - name: string; -} - -export interface Interval { - int_id: number; - name: string; - abbrev: string; - t_age: number; - b_age: number; - int_type: string; - timescales: Timescale[]; - color: string; -} - -interface IntervalOptionProps extends MenuItemProps { - interval: Interval; - handleClick: (e: React.MouseEvent) => void; - handleFocus: (e: React.FocusEvent) => void; - modifiers: { - active: boolean; - disabled: boolean; - }; -} - -function IntervalOption({ - interval, - handleClick, - handleFocus, - modifiers, - ...restProps -}: IntervalOptionProps) { - const inDarkMode = useInDarkMode(); - const colors = getColorPair(interval?.color, inDarkMode); - - if (interval == null) { - return h( - MenuItem, - { - shouldDismissPopover: true, - active: modifiers.active, - disabled: modifiers.disabled, - key: "", - label: "", - onClick: handleClick, - onFocus: handleFocus, - text: "", - roleStructure: "listoption", - ...restProps, - }, - [], - ); - } - - return h( - MenuItem, - { - style: colors, - shouldDismissPopover: true, - active: modifiers.active, - disabled: modifiers.disabled, - key: interval.int_id, - label: interval.int_id.toString(), - onClick: handleClick, - onFocus: handleFocus, - text: interval.name, - roleStructure: "listoption", - ...restProps, - }, - [], - ); -} - -const IntervalOptionMemo = memo(IntervalOption); - -const intervalOptionRenderer: ItemRenderer = ( - interval: Interval, - props: any, -) => { - return h(IntervalOptionMemo, { - key: interval.int_id, - interval, - ...props, - }); -}; - -const filterInterval: ItemPredicate = (query, interval) => { - if (interval?.name == undefined) { - return false; - } - return interval.name.toLowerCase().indexOf(query.toLowerCase()) >= 0; -}; - -export interface IntervalSelectionProps extends EditableCell2Props { - intervals: Interval[]; - onPaste: (e) => Promise; - onCopy: (e) => Promise; - selectedInterval: Interval | null; - setSelectedInterval: (interval: Interval | null) => void; - value: string; - intent: any; -} - -export const LexDropdown = ({ - value, - intent, - intervals: providedIntervals, - onPaste, - onCopy, - selectedInterval, - setSelectedInterval, - ...props -}: IntervalSelectionProps) => { - const [active, setActive] = React.useState(false); - - const intervals = providedIntervals ?? useIntervals(); - - const interval = useMemo(() => { - if (intervals == null) { - return null; - } - let interval = null; - if (intervals.length != 0) { - interval = intervals.filter( - (interval) => interval.int_id == parseInt(value), - )[0]; - } - - return interval; - }, [value, intervals, intent]); - - if (intervals == null) { - return null; - } - - const items = active ? intervals : []; - - return h( - Cell, - { - ...props, - style: { ...props.style, padding: 0 }, - }, - [ - h( - Select2, - { - fill: true, - items, - className: "update-input-group", - popoverProps: { - position: "bottom", - minimal: true, - }, - popoverContentProps: { - onWheelCapture: (event) => event.stopPropagation(), - }, - itemPredicate: filterInterval, - itemRenderer: intervalOptionRenderer, - onItemSelect: (interval: Interval, e) => { - setSelectedInterval(interval); - }, - noResults: h(MenuItem, { - disabled: true, - text: "No results.", - roleStructure: "listoption", - }), - }, - h(IntervalButton, { interval: selectedInterval, intent, setActive }), - ), - ], - ); -}; - -function IntervalButton({ interval, intent, setActive }) { - const inDarkMode = useInDarkMode(); - const colors = getColorPair(interval?.color, inDarkMode); - - return h( - Button, - { - style: { - ...colors, - fontSize: "12px", - minHeight: "0px", - padding: intent ? "0px 10px" : "1.7px 10px", - boxShadow: "none", - border: intent ? "2px solid green" : "none", - }, - fill: true, - alignText: "left", - text: h( - "span", - { style: { overflow: "hidden", textOverflow: "ellipses" } }, - interval?.name ?? "Select an interval", - ), - rightIcon: "double-caret-vertical", - className: "update-input-group", - onClick: () => setActive(true), - }, - [], - ); -} - -function useIntervals(timescaleID: number | null = null): Interval[] { - const params = useMemo(() => { - if (timescaleID == null) { - return { all: true }; - } - return { timescale_id: timescaleID }; - }, [timescaleID]); - - return useAPIResult( - "https://macrostrat.org/api/v2/defs/intervals", - params, - (res) => res.success.data, - ); -} \ No newline at end of file