Skip to content

Commit dad0079

Browse files
committed
feat: use an accordion in the panel
Kind of a major rewrite, as we also get rid of the context and just prop drill to our heart's content.
1 parent 30df364 commit dad0079

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1273
-3293
lines changed

src/app.tsx

Lines changed: 110 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
1-
import {
2-
Alert,
3-
Box,
4-
Container,
5-
FileUpload,
6-
Flex,
7-
GridItem,
8-
SimpleGrid,
9-
useBreakpointValue,
10-
useFileUpload,
11-
} from "@chakra-ui/react";
12-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
1+
import { Box, Container, FileUpload, useFileUpload } from "@chakra-ui/react";
132
import { useEffect, useState } from "react";
14-
import { ErrorBoundary } from "react-error-boundary";
15-
import { MapProvider } from "react-map-gl/dist/esm/exports-maplibre";
16-
import Header from "./components/header";
173
import Map from "./components/map";
18-
import Panel from "./components/panel";
194
import { Toaster } from "./components/ui/toaster";
20-
import { StacMapProvider } from "./provider";
5+
import Overlay from "./components/overlay";
6+
import useStacValue from "./hooks/stac-value";
7+
import type { BBox2D, Color } from "./types/map";
8+
import type { StacCollection } from "stac-ts";
9+
10+
const lineColor: Color = [207, 63, 2, 100];
11+
const fillColor: Color = [207, 63, 2, 50];
2112

2213
export default function App() {
23-
const queryClient = new QueryClient({});
14+
// The href of a STAC value. Everything is derived from the href.
2415
const [href, setHref] = useState<string | undefined>(getInitialHref());
25-
const fileUpload = useFileUpload({ maxFiles: 1 });
26-
const isHeaderAbovePanel = useBreakpointValue({ base: true, md: false });
27-
2816
useEffect(() => {
2917
function handlePopState() {
3018
setHref(new URLSearchParams(location.search).get("href") ?? "");
@@ -35,7 +23,6 @@ export default function App() {
3523
window.removeEventListener("popstate", handlePopState);
3624
};
3725
}, []);
38-
3926
useEffect(() => {
4027
if (href && new URLSearchParams(location.search).get("href") != href) {
4128
history.pushState(null, "", "?href=" + href);
@@ -44,73 +31,92 @@ export default function App() {
4431
}
4532
}, [href]);
4633

34+
// Uploading a file sets the href to its local name.
35+
const fileUpload = useFileUpload({ maxFiles: 1 });
4736
useEffect(() => {
4837
// It should never be more than 1.
4938
if (fileUpload.acceptedFiles.length == 1) {
5039
setHref(fileUpload.acceptedFiles[0].name);
5140
}
5241
}, [fileUpload.acceptedFiles]);
5342

54-
const header = (
55-
<Header href={href} setHref={setHref} fileUpload={fileUpload}></Header>
56-
);
43+
// State derived from the href.
44+
const { value, error, collections } = useStacValue({ href, fileUpload });
45+
useEffect(() => {
46+
if (value && (value.title || value.id)) {
47+
document.title = "stac-map | " + (value.title || value.id);
48+
} else {
49+
document.title = "stac-map";
50+
}
51+
}, [value]);
5752

58-
return (
59-
<QueryClientProvider client={queryClient}>
60-
<MapProvider>
61-
<StacMapProvider href={href} fileUpload={fileUpload}>
62-
<Box zIndex={0} position={"absolute"} top={0} left={0}>
63-
<FileUpload.RootProvider value={fileUpload} unstyled={true}>
64-
<FileUpload.Dropzone
65-
disableClick={true}
66-
style={{
67-
height: "100dvh",
68-
width: "100dvw",
69-
}}
70-
>
71-
<ErrorBoundary FallbackComponent={MapFallback}>
72-
<Map></Map>
73-
</ErrorBoundary>
74-
</FileUpload.Dropzone>
75-
</FileUpload.RootProvider>
76-
</Box>
77-
<Container zIndex={1} fluid h={"dvh"} py={4} pointerEvents={"none"}>
78-
<SimpleGrid columns={{ base: 1, md: 3 }} gap={4}>
79-
{isHeaderAbovePanel && <GridItem colSpan={1}>{header}</GridItem>}
80-
<GridItem colSpan={1}>
81-
<Panel
82-
href={href}
83-
setHref={setHref}
84-
fileUpload={fileUpload}
85-
></Panel>
86-
</GridItem>
87-
{!isHeaderAbovePanel && (
88-
<GridItem colSpan={2} hideBelow={"md"}>
89-
{header}
90-
</GridItem>
91-
)}
92-
</SimpleGrid>
93-
</Container>
94-
<Toaster></Toaster>
95-
</StacMapProvider>
96-
</MapProvider>
97-
</QueryClientProvider>
98-
);
99-
}
53+
// User-controlled state.
54+
const [bbox, setBbox] = useState<BBox2D>();
55+
const [datetimeBounds, setDatetimeBounds] = useState();
56+
const [filter, setFilter] = useState(true);
57+
const [filteredCollections, setFilteredCollections] =
58+
useState<StacCollection[]>();
59+
60+
useEffect(() => {
61+
if (filter && collections && bbox) {
62+
setFilteredCollections(
63+
collections.filter((collection) =>
64+
isCollectionInBbox(collection, bbox),
65+
),
66+
);
67+
} else {
68+
setFilteredCollections(undefined);
69+
}
70+
}, [collections, filter, bbox]);
10071

101-
function MapFallback({ error }: { error: Error }) {
10272
return (
103-
<Flex h={"100dvh"} w={"100dvw"} alignItems="center" justifyContent="center">
104-
<Box>
105-
<Alert.Root status="error">
106-
<Alert.Indicator />
107-
<Alert.Content>
108-
<Alert.Title>Error while rendering the map</Alert.Title>
109-
<Alert.Description>{error.message}</Alert.Description>
110-
</Alert.Content>
111-
</Alert.Root>
73+
<>
74+
<Box zIndex={-1} position={"absolute"} top={0} left={0} h="100dvh">
75+
<FileUpload.RootProvider value={fileUpload} unstyled={true}>
76+
<FileUpload.Dropzone
77+
disableClick={true}
78+
style={{
79+
height: "100dvh",
80+
width: "100dvw",
81+
}}
82+
></FileUpload.Dropzone>
83+
</FileUpload.RootProvider>
84+
</Box>
85+
<Box h={"100dvh"}>
86+
<Map
87+
value={value}
88+
collections={collections}
89+
filteredCollections={filteredCollections}
90+
fillColor={fillColor}
91+
lineColor={lineColor}
92+
setBbox={setBbox}
93+
></Map>
11294
</Box>
113-
</Flex>
95+
<Container
96+
zIndex={1}
97+
fluid
98+
h="100dvh"
99+
pointerEvents={"none"}
100+
position={"absolute"}
101+
top={0}
102+
left={0}
103+
pt={2}
104+
>
105+
<Overlay
106+
href={href}
107+
setHref={setHref}
108+
fileUpload={fileUpload}
109+
value={value}
110+
error={error}
111+
collections={collections}
112+
filteredCollections={filteredCollections}
113+
filter={filter}
114+
setFilter={setFilter}
115+
bbox={bbox}
116+
></Overlay>
117+
</Container>
118+
<Toaster></Toaster>
119+
</>
114120
);
115121
}
116122

@@ -123,3 +129,29 @@ function getInitialHref() {
123129
}
124130
return href;
125131
}
132+
133+
function isCollectionInBbox(collection: StacCollection, bbox: BBox2D) {
134+
if (bbox[2] - bbox[0] >= 360) {
135+
// A global bbox always contains every collection
136+
return true;
137+
}
138+
const collectionBbox = collection?.extent?.spatial?.bbox?.[0];
139+
if (collectionBbox) {
140+
return (
141+
!(
142+
collectionBbox[0] < bbox[0] &&
143+
collectionBbox[1] < bbox[1] &&
144+
collectionBbox[2] > bbox[2] &&
145+
collectionBbox[3] > bbox[3]
146+
) &&
147+
!(
148+
collectionBbox[0] > bbox[2] ||
149+
collectionBbox[1] > bbox[3] ||
150+
collectionBbox[2] < bbox[0] ||
151+
collectionBbox[3] < bbox[1]
152+
)
153+
);
154+
} else {
155+
return false;
156+
}
157+
}

src/components/about.tsx

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/components/assets.tsx

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)