Skip to content

Commit 778902e

Browse files
authored
feat!: initial v2 with export (#416)
Initial stab at packaging things correctly for use in downstreams. Heavily constructed by Claude.
1 parent 638382c commit 778902e

34 files changed

Lines changed: 878 additions & 180 deletions

.env.example

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# STAC Natural Query API endpoint
2-
VITE_STAC_NATURAL_QUERY_API=https://api.stac-semantic-search.k8s.labs.ds.io
3-
41
# Base URL for STAC Browser external links
52
# Default: https://radiantearth.github.io/stac-browser/#/external/
63
VITE_STAC_BROWSER_URL="https://radiantearth.github.io/stac-browser/#/external/"

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
cache: yarn
2323
- run: yarn install
2424
- run: yarn playwright install
25-
- run: yarn build
2625
- run: yarn test
26+
- run: yarn build:lib
2727
- name: Read version and publish
2828
run: npm publish --access public

README.md

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,63 @@ Includes:
1919
</picture>
2020
<!-- markdownlint-enable MD033 -->
2121

22+
## Deploying
23+
24+
There's two ways to deploy your own version of **stac-map**:
25+
26+
- [Build-time configuration](#build-time-configuration)
27+
- [React component](#react-component)
28+
29+
### Build-time configuration
30+
31+
If you only need to customize a few things (default href or auth), you can simply clone this repository and configure the app with environment variables.
32+
See [deploy.yaml](./.github/workflows/deploy.yaml) for a (drop-dead simple) example of deploying this application as a static site via Github Pages.
33+
The environment variables are:
34+
35+
| Variable | Description | Default |
36+
| --------------------- | ---------------------------------- | ------------------ |
37+
| `VITE_BASE_PATH` | URL path prefix (e.g., `/my-app/`) | `/stac-map/` |
38+
| `VITE_DEFAULT_HREF` | STAC resource to load on startup | None (shows intro) |
39+
| `VITE_AUTH_AUTHORITY` | The OIDC authority to use for auth | None |
40+
| `VITE_AUTH_CLIENT_ID` | The OIDC client id to use for auth | None |
41+
42+
Example:
43+
44+
```shell
45+
VITE_BASE_PATH=/ VITE_DEFAULT_HREF=https://my-stac-api.com yarn build
46+
```
47+
48+
Or create a `.env` file:
49+
50+
```shell
51+
VITE_BASE_PATH=/
52+
VITE_DEFAULT_HREF=https://my-stac-api.com
53+
```
54+
55+
Then run `yarn build` and deploy the `dist/` directory to your static hosting provider.
56+
57+
### React component
58+
59+
For more flexible configuration, we provide a `StacMap` React component via [@developmentseed/stac-map](https://www.npmjs.com/package/@developmentseed/stac-map).
60+
To use it:
61+
62+
```javascript
63+
import { StrictMode } from "react";
64+
import { createRoot } from "react-dom/client";
65+
import { StacMap } from "@development-seed/stac-map";
66+
67+
createRoot(document.getElementById("root")!).render(
68+
<StrictMode>
69+
<StacMap />
70+
</StrictMode>
71+
);
72+
```
73+
74+
See [src/main.tsx](./src/main.tsx) for a real-world example of using the component (it's what drives https://developmentseed.org/stac-map).
75+
76+
> [!NOTE]
77+
> We plan to provide JSDocs for all available properties before releasing v2 of **stac-map**
78+
2279
## Development
2380

2481
Get [yarn](https://yarnpkg.com/), then:
@@ -53,34 +110,3 @@ We use Github [Pull Requests](https://github.com/developmentseed/stac-map/pulls)
53110

54111
We use [release-please](https://github.com/googleapis/release-please) to create [releases](https://github.com/developmentseed/stac-map/releases).
55112
This requires our commit messages to conform to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
56-
57-
## Deploying
58-
59-
See [deploy.yaml](./.github/workflows/deploy.yaml) for a (drop-dead simple) example of deploying this application as a static site via Github Pages.
60-
61-
### White-label deployment
62-
63-
You can deploy your own customized version of stac-map using environment variables:
64-
65-
| Variable | Description | Default |
66-
| --------------------- | ---------------------------------- | ------------------ |
67-
| `VITE_BASE_PATH` | URL path prefix (e.g., `/my-app/`) | `/stac-map/` |
68-
| `VITE_DEFAULT_HREF` | STAC resource to load on startup | None (shows intro) |
69-
| `VITE_AUTH_AUTHORITY` | The OIDC authority to use for auth | None |
70-
| `VITE_AUTH_CLIENT_ID` | The OIDC client id to use for auth | None |
71-
72-
Example:
73-
74-
```shell
75-
VITE_BASE_PATH=/ VITE_DEFAULT_HREF=https://my-stac-api.com yarn build
76-
```
77-
78-
Or create a `.env` file:
79-
80-
```shell
81-
VITE_BASE_PATH=/
82-
VITE_DEFAULT_HREF=https://my-stac-api.com
83-
```
84-
85-
Then run `yarn build` and deploy the `dist/` directory to your static hosting provider.
86-
For an example of white-labeling **stac-map**, see https://github.com/gadomski/eoapi.stac-map.io.

package.json

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
"dev": "vite",
2828
"build": "tsc -b && vite build",
2929
"build-preview": "tsc -b && vite build --base=/",
30+
"build:lib": "vite build --config vite.lib.config.ts",
31+
"prepublishOnly": "yarn build:lib",
3032
"lint": "eslint .",
3133
"format": "prettier . --write",
3234
"format:check": "prettier . --check",
@@ -35,18 +37,15 @@
3537
},
3638
"dependencies": {
3739
"@apidevtools/json-schema-ref-parser": "^15.3.5",
38-
"@chakra-ui/react": "^3.35.0",
3940
"@deck.gl/core": "^9.3.1",
4041
"@deck.gl/layers": "^9.3.1",
4142
"@deck.gl/mapbox": "^9.3.1",
4243
"@developmentseed/deck.gl-geotiff": "^0.5.0",
4344
"@developmentseed/proj": "^0.5.0",
4445
"@devseed-ui/collecticons-chakra": "^4.0.0",
4546
"@duckdb/duckdb-wasm": "^1.32.0",
46-
"@emotion/react": "^11.13.5",
4747
"@geoarrow/deck.gl-layers": "^0.3.2",
4848
"@geoarrow/geoarrow-js": "github:smohiudd/geoarrow-js#feature/wkb",
49-
"@tanstack/react-query": "^5.100.5",
5049
"@turf/bbox": "^7.3.5",
5150
"@turf/bbox-polygon": "^7.3.5",
5251
"@turf/boolean-valid": "^7.3.5",
@@ -55,26 +54,24 @@
5554
"deck.gl": "^9.3.1",
5655
"duckdb-wasm-kit": "^0.1.38",
5756
"geotiff-geokeys-to-proj4": "^2024.4.13",
58-
"maplibre-gl": "^5.24.0",
5957
"next-themes": "^0.4.3",
60-
"oidc-client-ts": "^3.5.0",
61-
"react": "^19.2.5",
62-
"react-dom": "^19.2.5",
6358
"react-error-boundary": "^6.1.1",
6459
"react-icons": "^5.6.0",
65-
"react-map-gl": "^8.1.1",
6660
"react-markdown": "^10.1.0",
67-
"react-oidc-context": "^3.3.1",
6861
"shiki": "^4.0.2",
6962
"stac-ts": "^1.0.5",
7063
"stac-wasm": "^0.1.0",
7164
"zustand": "^5.0.12"
7265
},
7366
"devDependencies": {
67+
"@chakra-ui/react": "^3.35.0",
68+
"@emotion/react": "^11.13.5",
7469
"@eslint/js": "^10.0.1",
70+
"@microsoft/api-extractor": "^7.58.7",
71+
"@tanstack/react-query": "^5.100.5",
7572
"@types/geojson": "^7946.0.16",
7673
"@types/react": "^19.2.14",
77-
"@types/react-dom": "^19.1.2",
74+
"@types/react-dom": "^19.2.3",
7875
"@vitejs/plugin-react": "^6.0.1",
7976
"@vitest/browser": "^4.1.5",
8077
"@vitest/browser-playwright": "^4.1.5",
@@ -84,21 +81,62 @@
8481
"eslint-plugin-react-hooks": "^7.1.1",
8582
"eslint-plugin-react-refresh": "^0.5.2",
8683
"globals": "^17.5.0",
84+
"maplibre-gl": "^5.24.0",
85+
"oidc-client-ts": "^3.5.0",
8786
"playwright": "^1.59.1",
8887
"prettier": "^3.8.3",
8988
"prettier-plugin-organize-imports": "^4.1.0",
89+
"react": "^19.2.5",
90+
"react-dom": "^19.2.5",
91+
"react-map-gl": "^8.1.1",
92+
"react-oidc-context": "^3.3.1",
9093
"rollup": "^4.60.2",
9194
"semantic-release": "^25.0.3",
9295
"typescript": "~6.0.3",
9396
"typescript-eslint": "^8.59.1",
9497
"vite": "^8.0.10",
98+
"vite-plugin-dts": "^5.0.0",
9599
"vite-plugin-top-level-await": "^1.5.0",
96100
"vite-plugin-wasm": "^3.6.0",
97101
"vitest": "^4.1.5",
98102
"vitest-browser-react": "^2.2.0"
99103
},
100104
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
101-
"main": "eslint.config.js",
105+
"main": "./dist/lib.js",
106+
"module": "./dist/lib.js",
107+
"types": "./dist/lib.d.ts",
108+
"exports": {
109+
".": {
110+
"types": "./dist/lib.d.ts",
111+
"import": "./dist/lib.js"
112+
},
113+
"./style.css": "./dist/style.css"
114+
},
115+
"files": [
116+
"dist"
117+
],
118+
"sideEffects": [
119+
"**/*.css"
120+
],
121+
"peerDependencies": {
122+
"@chakra-ui/react": "^3.35.0",
123+
"@emotion/react": "^11.13.5",
124+
"@tanstack/react-query": "^5.100.5",
125+
"maplibre-gl": "^5.24.0",
126+
"oidc-client-ts": "^3.5.0",
127+
"react": "^19.2.5",
128+
"react-dom": "^19.2.5",
129+
"react-map-gl": "^8.1.1",
130+
"react-oidc-context": "^3.3.1"
131+
},
132+
"peerDependenciesMeta": {
133+
"oidc-client-ts": {
134+
"optional": true
135+
},
136+
"react-oidc-context": {
137+
"optional": true
138+
}
139+
},
102140
"directories": {
103141
"doc": "docs",
104142
"test": "tests"

release-please-config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
".": {
44
"changelog-path": "CHANGELOG.md",
55
"release-type": "node",
6-
"include-component-in-tag": false
6+
"include-component-in-tag": false,
7+
"prerelease": true,
8+
"prerelease-type": "alpha"
79
}
810
},
911
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"

src/app.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { AbsoluteCenter, Box, Center, FileUpload } from "@chakra-ui/react";
22
import { useDuckDb } from "duckdb-wasm-kit";
3-
import { useEffect } from "react";
3+
import { type ReactNode, useEffect } from "react";
44
import { ErrorBoundary } from "react-error-boundary";
5-
import Footer from "./components/footer";
65
import Map from "./components/map";
76
import Overlay from "./components/overlay";
87
import { ErrorBoundaryAlert } from "./components/ui/error-alert";
@@ -27,28 +26,11 @@ function OverlayFallback({ error }: { error: unknown }) {
2726
);
2827
}
2928

30-
export default function App() {
31-
const href = useStore((state) => state.href);
32-
const setHref = useStore((state) => state.setHref);
29+
export default function App({ footer }: { footer?: ReactNode }) {
3330
const setUploadedFile = useStore((state) => state.setUploadedFile);
3431
const setConnection = useStore((state) => state.setConnection);
3532
const { db } = useDuckDb();
3633

37-
useEffect(() => {
38-
if (href && new URLSearchParams(location.search).get("href") !== href)
39-
history.pushState(null, "", "?href=" + href);
40-
else history.replaceState(null, "", null);
41-
}, [href]);
42-
43-
useEffect(() => {
44-
function handlePopState() {
45-
setHref(new URLSearchParams(location.search).get("href"));
46-
}
47-
window.addEventListener("popstate", handlePopState);
48-
49-
return () => window.removeEventListener("popstate", handlePopState);
50-
}, [setHref]);
51-
5234
useEffect(() => {
5335
if (db) {
5436
(async () => {
@@ -92,7 +74,7 @@ export default function App() {
9274
<ErrorBoundary FallbackComponent={OverlayFallback}>
9375
<Overlay />
9476
</ErrorBoundary>
95-
<Footer />
77+
{footer}
9678
</>
9779
);
9880
}

src/components/footer.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import { CloseButton, Dialog, HStack, Link, Portal } from "@chakra-ui/react";
33
import { CollecticonBrandDevelopmentSeed2 } from "@devseed-ui/collecticons-chakra";
44
import { LuGithub, LuHeart } from "react-icons/lu";
55
import Markdown from "react-markdown";
6-
import changelog from "../../CHANGELOG.md?raw";
7-
import { version } from "../../package.json";
86

9-
export default function Footer() {
7+
export interface FooterProps {
8+
version: string;
9+
changelog?: string;
10+
}
11+
12+
export default function Footer({ version, changelog }: FooterProps) {
1013
return (
1114
<HStack
1215
position={"absolute"}
@@ -35,11 +38,13 @@ export default function Footer() {
3538
</Link>
3639
</Dialog.Title>
3740
</Dialog.Header>
38-
<Dialog.Body>
39-
<Prose>
40-
<Markdown>{changelog}</Markdown>
41-
</Prose>
42-
</Dialog.Body>
41+
{changelog && (
42+
<Dialog.Body>
43+
<Prose>
44+
<Markdown>{changelog}</Markdown>
45+
</Prose>
46+
</Dialog.Body>
47+
)}
4348
<Dialog.CloseTrigger asChild>
4449
<CloseButton size="sm" />
4550
</Dialog.CloseTrigger>

src/components/header.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { Button, HStack } from "@chakra-ui/react";
2+
import { useAuthEnabled } from "../contexts/auth-enabled";
23
import { Examples } from "./examples";
34
import HrefInput from "./href-input";
4-
import { authConfig, UserButton } from "./ui/auth";
5+
import { UserButton } from "./ui/auth";
56
import { ColorModeButton } from "./ui/color-mode";
67
import { ProjectionButton } from "./ui/projection";
78
import { SettingsButton } from "./ui/settings";
89

910
export default function Header() {
11+
const authEnabled = useAuthEnabled();
1012
return (
1113
<HStack pointerEvents={"auto"}>
1214
<HrefInput />
@@ -18,7 +20,7 @@ export default function Header() {
1820
<ProjectionButton variant={"surface"} />
1921
<ColorModeButton variant={"surface"} />
2022
<SettingsButton variant={"surface"} />
21-
{authConfig && <UserButton variant={"surface"} />}
23+
{authEnabled && <UserButton variant={"surface"} />}
2224
</HStack>
2325
);
2426
}

0 commit comments

Comments
 (0)