Skip to content

Commit 4db440e

Browse files
authored
Merge pull request #7 from openwatersio/neaps-react
Use @neaps/react
2 parents e415a80 + 36beda1 commit 4db440e

38 files changed

Lines changed: 9809 additions & 9193 deletions

package-lock.json

Lines changed: 9002 additions & 7639 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
"concurrently": "^9.2.1"
1717
},
1818
"dependencies": {
19-
"@neaps/api": "^0.4.0",
20-
"@neaps/tide-database": "^0.6.20260220",
21-
"@neaps/tide-predictor": "^0.8.0",
22-
"neaps": "^0.6.0"
19+
"@neaps/api": "https://pkg.pr.new/openwatersio/neaps/@neaps/api@638b20d",
20+
"@neaps/react": "https://pkg.pr.new/openwatersio/neaps/@neaps/react@638b20d",
21+
"@neaps/tide-database": "^0.7.20260304",
22+
"@neaps/tide-predictor": "https://pkg.pr.new/openwatersio/neaps/@neaps/tide-predictor@638b20d",
23+
"neaps": "https://pkg.pr.new/openwatersio/neaps@638b20d"
2324
}
2425
}

website/astro.config.mjs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,53 @@
11
import { defineConfig } from "astro/config";
2-
import tailwind from "@astrojs/tailwind";
2+
import tailwindcss from "@tailwindcss/vite";
33
import react from "@astrojs/react";
44
import vercel from "@astrojs/vercel";
55

66
import icon from "astro-icon";
77

8+
// Derive API URL for Vercel preview deployments
9+
if (
10+
!process.env.PUBLIC_TIDES_API_URL &&
11+
process.env.VERCEL_ENV === "preview" &&
12+
process.env.VERCEL_BRANCH_URL
13+
) {
14+
process.env.PUBLIC_TIDES_API_URL = `https://api-${process.env.VERCEL_BRANCH_URL}`;
15+
}
16+
817
// https://astro.build/config
918
export default defineConfig({
1019
site: "https://openwaters.io",
11-
integrations: [
12-
tailwind({
13-
applyBaseStyles: false,
14-
}),
15-
react(),
16-
icon(),
17-
],
20+
integrations: [react(), icon()],
1821
vite: {
22+
plugins: [tailwindcss()],
23+
optimizeDeps: {
24+
include: ["maplibre-gl"],
25+
esbuildOptions: {
26+
target: "es2022",
27+
},
28+
},
29+
resolve: {
30+
// Deduplicate React to ensure a single instance across the file: symlink boundary.
31+
dedupe: ["react", "react-dom", "react/jsx-runtime"],
32+
},
1933
ssr: {
20-
noExternal: ["maplibre-gl"],
34+
// Process these through Vite's bundler for SSR (instead of externalizing to Node)
35+
// so that resolve.dedupe applies to React, and browser-only packages don't fail.
36+
// Includes @neaps/react and all its dependencies (which live in the neaps workspace
37+
// and have ESM extensionless imports that Node.js can't resolve natively).
38+
noExternal: [
39+
"@neaps/react",
40+
// @neaps/react dependencies (and their transitive deps that use ESM
41+
// extensionless imports, which Node.js can't resolve natively)
42+
/^@visx\//,
43+
"@tanstack/react-query",
44+
"astronomy-engine",
45+
"d3-array",
46+
"date-fns",
47+
// map dependencies
48+
"maplibre-gl",
49+
"react-map-gl",
50+
],
2151
},
2252
},
2353
adapter: vercel({}),

website/package.json

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,30 @@
1414
"dependencies": {
1515
"@astrojs/check": "^0.9.6",
1616
"@astrojs/react": "^4.4.2",
17-
"@astrojs/tailwind": "^6.0.2",
1817
"@astrojs/vercel": "^9.0.4",
1918
"@iconify-json/mdi": "^1.2.3",
20-
"@js-temporal/polyfill": "^0.5.1",
2119
"@neaps/api": "*",
20+
"@neaps/react": "*",
2221
"@neaps/tide-predictor": "*",
2322
"@tailwindcss/typography": "^0.5.19",
23+
"@tailwindcss/vite": "^4.2.1",
24+
"@tanstack/react-query": "^5.90.21",
2425
"astro": "^5.17.1",
2526
"astro-icon": "^1.1.5",
26-
"chart.js": "^4.4.0",
27-
"chartjs-adapter-date-fns": "^3.0.0",
2827
"clsx": "^2.1.1",
2928
"coordinate-format": "^1.0.0",
30-
"date-fns": "^3.0.0",
31-
"maplibre-gl": "^4.7.0",
29+
"maplibre-gl": "^5.19.0",
3230
"neaps": "*",
33-
"react": "^18.3.1",
34-
"react-chartjs-2": "^5.2.0",
35-
"react-dom": "^18.3.1",
31+
"react": "^19.0.0",
32+
"react-dom": "^19.0.0",
3633
"react-map-gl": "^8.1.0",
3734
"tailwind-merge": "^2.5.0",
38-
"tailwindcss": "^3.4.1",
35+
"tailwindcss": "^4.2.1",
3936
"typescript": "^5.6.0"
4037
},
4138
"devDependencies": {
42-
"@types/react": "^18.3.0",
43-
"@types/react-dom": "^18.3.0",
39+
"@types/react": "^19.2.14",
40+
"@types/react-dom": "^19.2.3",
4441
"husky": "^9.1.7",
4542
"lint-staged": "^16.2.7",
4643
"prettier": "^3.8.1",

website/src/components/TideHeight.tsx

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

website/src/components/api/ApiEndpoint.astro

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ interface Props {
1010
const { endpoint } = Astro.props;
1111
1212
const methodColors: Record<string, string> = {
13-
GET: "bg-green-100 text-green-800",
14-
POST: "bg-blue-100 text-blue-800",
15-
PUT: "bg-yellow-100 text-yellow-800",
16-
PATCH: "bg-orange-100 text-orange-800",
17-
DELETE: "bg-red-100 text-red-800",
13+
GET: "bg-(--status-green-bg) text-(--status-green-text)",
14+
POST: "bg-(--status-blue-bg) text-(--status-blue-text)",
15+
PUT: "bg-(--status-yellow-bg) text-(--status-yellow-text)",
16+
PATCH: "bg-(--status-orange-bg) text-(--status-orange-text)",
17+
DELETE: "bg-(--status-red-bg) text-(--status-red-text)",
1818
};
1919
2020
// Get example response from first successful response
@@ -32,13 +32,11 @@ const exampleResponse =
3232
<!-- Method and Path -->
3333
<div class="flex items-center gap-3">
3434
<span
35-
class={`rounded px-2 py-1 text-xs font-bold ${methodColors[endpoint.method] || "bg-navy-100 text-navy-800"}`}
35+
class={`rounded px-2 py-1 text-xs font-bold ${methodColors[endpoint.method] || "bg-(--surface-subtle) text-(--text)"}`}
3636
>
3737
{endpoint.method}
3838
</span>
39-
<span class="font-mono text-sm text-navy-900"
40-
>{API_HOST}{endpoint.path}</span
41-
>
39+
<span class="font-mono text-sm">{API_HOST}{endpoint.path}</span>
4240
</div>
4341

4442
<!-- Summary and Description -->
@@ -52,7 +50,7 @@ const exampleResponse =
5250
<h4 class="mb-0 text-lg">Parameters</h4>
5351
<div class="overflow-x-auto">
5452
<table class="w-full text-sm">
55-
<thead class="bg-navy-50">
53+
<thead class="bg-(--surface-subtle)">
5654
<tr>
5755
<th class="w-32 px-3 py-2 text-left">Name</th>
5856
<th class="w-20 px-3 py-2 text-left">Location</th>
@@ -61,12 +59,12 @@ const exampleResponse =
6159
<th class="px-3 py-2 text-left">Description</th>
6260
</tr>
6361
</thead>
64-
<tbody class="divide-y divide-navy-100">
62+
<tbody class="divide-y divide-(--border-subtle)">
6563
{endpoint.parameters.map((param) => (
6664
<tr>
6765
<td class="px-3 py-2 font-mono">{param.name}</td>
6866
<td class="px-3 py-2">
69-
<span class="rounded bg-navy-100 px-2 py-1 text-xs">
67+
<span class="rounded bg-(--surface-subtle) px-2 py-1 text-xs">
7068
{param.in}
7169
</span>
7270
</td>
@@ -82,7 +80,9 @@ const exampleResponse =
8280
<span class="text-navy-400">—</span>
8381
)}
8482
</td>
85-
<td class="px-3 py-2 text-navy-600">{param.description}</td>
83+
<td class="px-3 py-2 text-(--text-secondary)">
84+
{param.description}
85+
</td>
8686
</tr>
8787
))}
8888
</tbody>
@@ -97,7 +97,7 @@ const exampleResponse =
9797
exampleResponse && (
9898
<div>
9999
<h4>Example Response</h4>
100-
<div class="overflow-x-auto rounded-lg bg-navy-900 p-4 text-white">
100+
<div class="bg-navy-900 overflow-x-auto rounded-lg p-4 text-white">
101101
<pre class="text-sm">
102102
<code>{JSON.stringify(exampleResponse, null, 2)}</code>
103103
</pre>

website/src/components/layout/Header.astro

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const currentPath = Astro.url.pathname;
1515
<!-- Logo -->
1616
<a
1717
href="/"
18-
class="flex items-center gap-2 text-2xl font-bold text-navy-900 transition-colors hover:text-ocean-600"
18+
class="flex items-center gap-2 text-2xl font-bold transition-colors"
19+
style="color: var(--text);"
1920
>
2021
<svg
2122
class="h-8 w-8"
@@ -44,9 +45,14 @@ const currentPath = Astro.url.pathname;
4445
href={item.href}
4546
class={`font-medium transition-colors ${
4647
currentPath.startsWith(item.href)
47-
? "text-ocean-600"
48-
: "text-navy-700 hover:text-ocean-600"
48+
? ""
49+
: "hover:text-(--accent)"
4950
}`}
51+
style={
52+
currentPath.startsWith(item.href)
53+
? `color: var(--accent)`
54+
: `color: var(--text-secondary)`
55+
}
5056
>
5157
{item.name}
5258
</a>
@@ -58,7 +64,8 @@ const currentPath = Astro.url.pathname;
5864
<!-- Mobile Menu Button -->
5965
<button
6066
id="mobile-menu-button"
61-
class="rounded p-2 text-navy-700 hover:text-ocean-600 focus:outline-none focus:ring-2 focus:ring-ocean-500 md:hidden"
67+
class="rounded p-2 hover:text-(--accent) focus:ring-2 focus:outline-hidden md:hidden"
68+
style="color: var(--text-secondary);"
6269
aria-label="Toggle menu"
6370
aria-expanded="false"
6471
>
@@ -87,8 +94,8 @@ const currentPath = Astro.url.pathname;
8794
href={item.href}
8895
class={`block rounded-lg px-4 py-2 font-medium transition-colors ${
8996
currentPath.startsWith(item.href)
90-
? "bg-ocean-50 text-ocean-600"
91-
: "text-navy-700 hover:bg-navy-50"
97+
? "bg-(--accent-bg) text-(--accent)"
98+
: "text-(--text-secondary) hover:bg-(--surface-subtle)"
9299
}`}
93100
>
94101
{item.name}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { useRef, useCallback, useMemo } from "react";
2+
import {
3+
NeapsProvider,
4+
StationsMap,
5+
NearbyStations,
6+
createQueryClient,
7+
type StationSummary,
8+
} from "@neaps/react";
9+
import { hydrate, type DehydratedState } from "@tanstack/react-query";
10+
import type { MapRef } from "react-map-gl/maplibre";
11+
import "@neaps/react/styles.css";
12+
import { API_HOST } from "../../utils/constants";
13+
import { useMapStyle } from "../../utils/useMapStyle";
14+
15+
interface Props {
16+
stationId: string;
17+
latitude: number;
18+
longitude: number;
19+
dehydratedState?: DehydratedState;
20+
}
21+
22+
export function NearbyStationsIsland({
23+
stationId,
24+
latitude,
25+
longitude,
26+
dehydratedState,
27+
}: Props) {
28+
const queryClient = useMemo(() => {
29+
const client = createQueryClient();
30+
if (dehydratedState) {
31+
hydrate(client, dehydratedState);
32+
}
33+
return client;
34+
}, [dehydratedState]);
35+
36+
const mapStyle = useMapStyle();
37+
const mapRef = useRef<MapRef>(null);
38+
39+
const handleStationSelect = useCallback((station: StationSummary) => {
40+
window.location.href = `/tides/stations/${station.id}`;
41+
}, []);
42+
43+
const handleHover = useCallback((station: StationSummary) => {
44+
mapRef.current?.panTo([station.longitude, station.latitude]);
45+
}, []);
46+
47+
const handleHoverEnd = useCallback(() => {
48+
mapRef.current?.panTo([longitude, latitude]);
49+
}, [longitude, latitude]);
50+
51+
return (
52+
<NeapsProvider baseUrl={API_HOST} queryClient={queryClient}>
53+
<div className="flex flex-col gap-4">
54+
<StationsMap
55+
ref={mapRef}
56+
mapStyle={mapStyle}
57+
initialViewState={{
58+
longitude,
59+
latitude,
60+
zoom: 11,
61+
}}
62+
focusStation={stationId}
63+
clustering={false}
64+
showGeolocation={false}
65+
popupContent="simple"
66+
onStationSelect={handleStationSelect}
67+
className="aspect-video overflow-hidden rounded-lg border border-(--border)"
68+
/>
69+
<NearbyStations
70+
stationId={stationId}
71+
onStationSelect={handleStationSelect}
72+
onHover={handleHover}
73+
onHoverEnd={handleHoverEnd}
74+
/>
75+
</div>
76+
</NeapsProvider>
77+
);
78+
}

0 commit comments

Comments
 (0)