Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16,641 changes: 9,002 additions & 7,639 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
"concurrently": "^9.2.1"
},
"dependencies": {
"@neaps/api": "^0.4.0",
"@neaps/tide-database": "^0.6.20260220",
"@neaps/tide-predictor": "^0.8.0",
"neaps": "^0.6.0"
"@neaps/api": "https://pkg.pr.new/openwatersio/neaps/@neaps/api@638b20d",
"@neaps/react": "https://pkg.pr.new/openwatersio/neaps/@neaps/react@638b20d",
"@neaps/tide-database": "^0.7.20260304",
"@neaps/tide-predictor": "https://pkg.pr.new/openwatersio/neaps/@neaps/tide-predictor@638b20d",
"neaps": "https://pkg.pr.new/openwatersio/neaps@638b20d"
}
}
48 changes: 39 additions & 9 deletions website/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,23 +1,53 @@
import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind";
import tailwindcss from "@tailwindcss/vite";
import react from "@astrojs/react";
import vercel from "@astrojs/vercel";

import icon from "astro-icon";

// Derive API URL for Vercel preview deployments
if (
!process.env.PUBLIC_TIDES_API_URL &&
process.env.VERCEL_ENV === "preview" &&
process.env.VERCEL_BRANCH_URL
) {
process.env.PUBLIC_TIDES_API_URL = `https://api-${process.env.VERCEL_BRANCH_URL}`;
}

// https://astro.build/config
export default defineConfig({
site: "https://openwaters.io",
integrations: [
tailwind({
applyBaseStyles: false,
}),
react(),
icon(),
],
integrations: [react(), icon()],
vite: {
plugins: [tailwindcss()],
optimizeDeps: {
include: ["maplibre-gl"],
esbuildOptions: {
target: "es2022",
},
},
resolve: {
// Deduplicate React to ensure a single instance across the file: symlink boundary.
dedupe: ["react", "react-dom", "react/jsx-runtime"],
},
ssr: {
noExternal: ["maplibre-gl"],
// Process these through Vite's bundler for SSR (instead of externalizing to Node)
// so that resolve.dedupe applies to React, and browser-only packages don't fail.
// Includes @neaps/react and all its dependencies (which live in the neaps workspace
// and have ESM extensionless imports that Node.js can't resolve natively).
noExternal: [
"@neaps/react",
// @neaps/react dependencies (and their transitive deps that use ESM
// extensionless imports, which Node.js can't resolve natively)
/^@visx\//,
"@tanstack/react-query",
"astronomy-engine",
"d3-array",
"date-fns",
// map dependencies
"maplibre-gl",
"react-map-gl",
],
},
},
adapter: vercel({}),
Expand Down
21 changes: 9 additions & 12 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,30 @@
"dependencies": {
"@astrojs/check": "^0.9.6",
"@astrojs/react": "^4.4.2",
"@astrojs/tailwind": "^6.0.2",
"@astrojs/vercel": "^9.0.4",
"@iconify-json/mdi": "^1.2.3",
"@js-temporal/polyfill": "^0.5.1",
"@neaps/api": "*",
"@neaps/react": "*",
"@neaps/tide-predictor": "*",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.1",
"@tanstack/react-query": "^5.90.21",
"astro": "^5.17.1",
"astro-icon": "^1.1.5",
"chart.js": "^4.4.0",
"chartjs-adapter-date-fns": "^3.0.0",
"clsx": "^2.1.1",
"coordinate-format": "^1.0.0",
"date-fns": "^3.0.0",
"maplibre-gl": "^4.7.0",
"maplibre-gl": "^5.19.0",
"neaps": "*",
"react": "^18.3.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.3.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-map-gl": "^8.1.0",
"tailwind-merge": "^2.5.0",
"tailwindcss": "^3.4.1",
"tailwindcss": "^4.2.1",
"typescript": "^5.6.0"
},
"devDependencies": {
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"prettier": "^3.8.1",
Expand Down
56 changes: 0 additions & 56 deletions website/src/components/TideHeight.tsx

This file was deleted.

28 changes: 14 additions & 14 deletions website/src/components/api/ApiEndpoint.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ interface Props {
const { endpoint } = Astro.props;

const methodColors: Record<string, string> = {
GET: "bg-green-100 text-green-800",
POST: "bg-blue-100 text-blue-800",
PUT: "bg-yellow-100 text-yellow-800",
PATCH: "bg-orange-100 text-orange-800",
DELETE: "bg-red-100 text-red-800",
GET: "bg-(--status-green-bg) text-(--status-green-text)",
POST: "bg-(--status-blue-bg) text-(--status-blue-text)",
PUT: "bg-(--status-yellow-bg) text-(--status-yellow-text)",
PATCH: "bg-(--status-orange-bg) text-(--status-orange-text)",
DELETE: "bg-(--status-red-bg) text-(--status-red-text)",
};

// Get example response from first successful response
Expand All @@ -32,13 +32,11 @@ const exampleResponse =
<!-- Method and Path -->
<div class="flex items-center gap-3">
<span
class={`rounded px-2 py-1 text-xs font-bold ${methodColors[endpoint.method] || "bg-navy-100 text-navy-800"}`}
class={`rounded px-2 py-1 text-xs font-bold ${methodColors[endpoint.method] || "bg-(--surface-subtle) text-(--text)"}`}
>
{endpoint.method}
</span>
<span class="font-mono text-sm text-navy-900"
>{API_HOST}{endpoint.path}</span
>
<span class="font-mono text-sm">{API_HOST}{endpoint.path}</span>
</div>

<!-- Summary and Description -->
Expand All @@ -52,7 +50,7 @@ const exampleResponse =
<h4 class="mb-0 text-lg">Parameters</h4>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-navy-50">
<thead class="bg-(--surface-subtle)">
<tr>
<th class="w-32 px-3 py-2 text-left">Name</th>
<th class="w-20 px-3 py-2 text-left">Location</th>
Expand All @@ -61,12 +59,12 @@ const exampleResponse =
<th class="px-3 py-2 text-left">Description</th>
</tr>
</thead>
<tbody class="divide-y divide-navy-100">
<tbody class="divide-y divide-(--border-subtle)">
{endpoint.parameters.map((param) => (
<tr>
<td class="px-3 py-2 font-mono">{param.name}</td>
<td class="px-3 py-2">
<span class="rounded bg-navy-100 px-2 py-1 text-xs">
<span class="rounded bg-(--surface-subtle) px-2 py-1 text-xs">
{param.in}
</span>
</td>
Expand All @@ -82,7 +80,9 @@ const exampleResponse =
<span class="text-navy-400">—</span>
)}
</td>
<td class="px-3 py-2 text-navy-600">{param.description}</td>
<td class="px-3 py-2 text-(--text-secondary)">
{param.description}
</td>
</tr>
))}
</tbody>
Expand All @@ -97,7 +97,7 @@ const exampleResponse =
exampleResponse && (
<div>
<h4>Example Response</h4>
<div class="overflow-x-auto rounded-lg bg-navy-900 p-4 text-white">
<div class="bg-navy-900 overflow-x-auto rounded-lg p-4 text-white">
<pre class="text-sm">
<code>{JSON.stringify(exampleResponse, null, 2)}</code>
</pre>
Expand Down
19 changes: 13 additions & 6 deletions website/src/components/layout/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const currentPath = Astro.url.pathname;
<!-- Logo -->
<a
href="/"
class="flex items-center gap-2 text-2xl font-bold text-navy-900 transition-colors hover:text-ocean-600"
class="flex items-center gap-2 text-2xl font-bold transition-colors"
style="color: var(--text);"
>
<svg
class="h-8 w-8"
Expand Down Expand Up @@ -44,9 +45,14 @@ const currentPath = Astro.url.pathname;
href={item.href}
class={`font-medium transition-colors ${
currentPath.startsWith(item.href)
? "text-ocean-600"
: "text-navy-700 hover:text-ocean-600"
? ""
: "hover:text-(--accent)"
}`}
style={
currentPath.startsWith(item.href)
? `color: var(--accent)`
: `color: var(--text-secondary)`
}
>
{item.name}
</a>
Expand All @@ -58,7 +64,8 @@ const currentPath = Astro.url.pathname;
<!-- Mobile Menu Button -->
<button
id="mobile-menu-button"
class="rounded p-2 text-navy-700 hover:text-ocean-600 focus:outline-none focus:ring-2 focus:ring-ocean-500 md:hidden"
class="rounded p-2 hover:text-(--accent) focus:ring-2 focus:outline-hidden md:hidden"
style="color: var(--text-secondary);"
aria-label="Toggle menu"
aria-expanded="false"
>
Expand Down Expand Up @@ -87,8 +94,8 @@ const currentPath = Astro.url.pathname;
href={item.href}
class={`block rounded-lg px-4 py-2 font-medium transition-colors ${
currentPath.startsWith(item.href)
? "bg-ocean-50 text-ocean-600"
: "text-navy-700 hover:bg-navy-50"
? "bg-(--accent-bg) text-(--accent)"
: "text-(--text-secondary) hover:bg-(--surface-subtle)"
}`}
>
{item.name}
Expand Down
78 changes: 78 additions & 0 deletions website/src/components/tides/NearbyStations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useRef, useCallback, useMemo } from "react";
import {
NeapsProvider,
StationsMap,
NearbyStations,
createQueryClient,
type StationSummary,
} from "@neaps/react";
import { hydrate, type DehydratedState } from "@tanstack/react-query";
import type { MapRef } from "react-map-gl/maplibre";
import "@neaps/react/styles.css";
import { API_HOST } from "../../utils/constants";
import { useMapStyle } from "../../utils/useMapStyle";

interface Props {
stationId: string;
latitude: number;
longitude: number;
dehydratedState?: DehydratedState;
}

export function NearbyStationsIsland({
stationId,
latitude,
longitude,
dehydratedState,
}: Props) {
const queryClient = useMemo(() => {
const client = createQueryClient();
if (dehydratedState) {
hydrate(client, dehydratedState);
}
return client;
}, [dehydratedState]);

const mapStyle = useMapStyle();
const mapRef = useRef<MapRef>(null);

const handleStationSelect = useCallback((station: StationSummary) => {
window.location.href = `/tides/stations/${station.id}`;
}, []);

const handleHover = useCallback((station: StationSummary) => {
mapRef.current?.panTo([station.longitude, station.latitude]);
}, []);

const handleHoverEnd = useCallback(() => {
mapRef.current?.panTo([longitude, latitude]);
}, [longitude, latitude]);

return (
<NeapsProvider baseUrl={API_HOST} queryClient={queryClient}>
<div className="flex flex-col gap-4">
<StationsMap
ref={mapRef}
mapStyle={mapStyle}
initialViewState={{
longitude,
latitude,
zoom: 11,
}}
focusStation={stationId}
clustering={false}
showGeolocation={false}
popupContent="simple"
onStationSelect={handleStationSelect}
className="aspect-video overflow-hidden rounded-lg border border-(--border)"
/>
<NearbyStations
stationId={stationId}
onStationSelect={handleStationSelect}
onHover={handleHover}
onHoverEnd={handleHoverEnd}
/>
</div>
</NeapsProvider>
);
}
Loading