signalk-tides 2.1.2 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +7 -0
- package/.github/mise.node24.toml +3 -0
- package/.github/workflows/ci.yml +9 -3
- package/.github/workflows/lockfile.yml +31 -0
- package/.github/workflows/release.yml +2 -2
- package/.oxlintrc.json +8 -0
- package/CONTRIBUTING.md +11 -0
- package/README.md +8 -2
- package/dist/index.js +61 -6
- package/dist/middleware.js +2 -2
- package/dist/plotter-extension.js +35 -0
- package/mise.toml +2 -0
- package/package.json +32 -29
- package/public/assets/main-BvKlaM8p.js +1 -0
- package/public/assets/maplibre-CXEYa9hE.js +814 -0
- package/public/assets/maplibre-gl-worker-BWso-Bu4.js +10 -0
- package/public/assets/useUnitPreferences-Bnl2Hfv0.js +12 -0
- package/public/assets/useUnitPreferences-D6HIp3mv.css +1 -0
- package/public/assets/widget-DrHqs948.js +1 -0
- package/public/index.html +3 -2
- package/public/widget.html +17 -0
- package/tides-dev-server.ts +5 -5
- package/tsconfig.node.json +1 -0
- package/tsconfig.test.json +1 -0
- package/vitest.config.browser.ts +5 -0
- package/widget.html +15 -0
- package/public/assets/index-BYJ4l3Sy.js +0 -12
- package/public/assets/index-CityHj4f.css +0 -1
- package/public/assets/maplibre-gl-BOnKX8T3.js +0 -748
package/.github/dependabot.yml
CHANGED
|
@@ -5,6 +5,13 @@ updates:
|
|
|
5
5
|
schedule:
|
|
6
6
|
interval: "weekly"
|
|
7
7
|
open-pull-requests-limit: 100
|
|
8
|
+
# vitest and every @vitest/* package pin each other's exact version, so a
|
|
9
|
+
# bump to one alone fails `npm ci` with ERESOLVE before a test runs.
|
|
10
|
+
groups:
|
|
11
|
+
vitest:
|
|
12
|
+
patterns:
|
|
13
|
+
- "vitest"
|
|
14
|
+
- "@vitest/*"
|
|
8
15
|
- package-ecosystem: "github-actions"
|
|
9
16
|
directory: "/"
|
|
10
17
|
schedule:
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -12,7 +12,9 @@ jobs:
|
|
|
12
12
|
uses: actions/checkout@v7
|
|
13
13
|
|
|
14
14
|
- name: Setup Node.js
|
|
15
|
-
uses: actions/setup-node@
|
|
15
|
+
uses: actions/setup-node@v7
|
|
16
|
+
with:
|
|
17
|
+
node-version-file: mise.toml
|
|
16
18
|
|
|
17
19
|
- name: Install dependencies
|
|
18
20
|
run: npm install
|
|
@@ -30,7 +32,9 @@ jobs:
|
|
|
30
32
|
uses: actions/checkout@v7
|
|
31
33
|
|
|
32
34
|
- name: Setup Node.js
|
|
33
|
-
uses: actions/setup-node@
|
|
35
|
+
uses: actions/setup-node@v7
|
|
36
|
+
with:
|
|
37
|
+
node-version-file: mise.toml
|
|
34
38
|
|
|
35
39
|
- name: Install dependencies
|
|
36
40
|
run: npm install
|
|
@@ -53,7 +57,9 @@ jobs:
|
|
|
53
57
|
steps:
|
|
54
58
|
- uses: actions/checkout@v7
|
|
55
59
|
|
|
56
|
-
- uses: actions/setup-node@
|
|
60
|
+
- uses: actions/setup-node@v7
|
|
61
|
+
with:
|
|
62
|
+
node-version-file: mise.toml
|
|
57
63
|
|
|
58
64
|
- name: Install modules
|
|
59
65
|
run: npm install
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Lockfile
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
# A pull request can slip a package in through package-lock.json, which
|
|
13
|
+
# reviewers rarely read. npm keeps existing resolved URLs when it regenerates,
|
|
14
|
+
# so the diff alone misses a swapped tarball; lockfile-lint catches that.
|
|
15
|
+
lockfile:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
|
+
- uses: actions/setup-node@v7
|
|
20
|
+
with:
|
|
21
|
+
node-version-file: .github/mise.node24.toml
|
|
22
|
+
- name: Check the lockfile regenerates from package.json
|
|
23
|
+
run: |
|
|
24
|
+
git ls-files --error-unmatch package-lock.json
|
|
25
|
+
npm install --package-lock-only --ignore-scripts
|
|
26
|
+
git diff --exit-code -- package-lock.json
|
|
27
|
+
- name: Check every package resolves from the npm registry
|
|
28
|
+
# @isaacs/cliui installs CommonJS releases of these packages under -cjs aliases.
|
|
29
|
+
run: |
|
|
30
|
+
npx -y lockfile-lint@5.0.1 --path package-lock.json --allowed-hosts npm --validate-https --validate-integrity --validate-package-names \
|
|
31
|
+
--allowed-package-name-aliases string-width-cjs:string-width strip-ansi-cjs:strip-ansi wrap-ansi-cjs:wrap-ansi
|
|
@@ -15,9 +15,9 @@ jobs:
|
|
|
15
15
|
with:
|
|
16
16
|
ref: ${{ github.event.release.target_commitish }}
|
|
17
17
|
|
|
18
|
-
- uses: actions/setup-node@
|
|
18
|
+
- uses: actions/setup-node@v7
|
|
19
19
|
with:
|
|
20
|
-
node-version:
|
|
20
|
+
node-version-file: .github/mise.node24.toml # npm >= 11.5.1 for trusted publishing
|
|
21
21
|
registry-url: https://registry.npmjs.org
|
|
22
22
|
|
|
23
23
|
- name: Install dependencies
|
package/.oxlintrc.json
ADDED
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Releasing
|
|
4
|
+
|
|
5
|
+
Publishing to npm runs from [release.yml](.github/workflows/release.yml) when a GitHub release is created. A person creates the release by hand: choose or create a `vX.Y.Z` tag, then fill in the title and notes.
|
|
6
|
+
|
|
7
|
+
Title and notes follow the Open Waters [release notes guidance](https://github.com/openwatersio/.github/blob/main/docs/agents/releases.md#release-notes). Write them for boaters running Signal K, not for developers reading commit subjects:
|
|
8
|
+
|
|
9
|
+
- Title the release with a short headline of what changed, in sentence case with no period and no version. Patch releases get a headline too. Put a new requirement in the headline, such as "requires Node 24".
|
|
10
|
+
- Open the notes with what is new and who it is for. Put breaking changes and upgrade steps first.
|
|
11
|
+
- List the changes users will notice, one per bullet, each linking its pull request. Leave out chores, CI changes, and bot dependency bumps unless a runtime dependency change matters to users.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# signalk-tides
|
|
2
2
|
|
|
3
|
-
A SignalK plugin that provides offline tidal predictions for the vessel's position, powered by [
|
|
3
|
+
A SignalK plugin that provides offline tidal predictions for the vessel's position, powered by [Slackwater](https://openwaters.io/tides/slackwater/).
|
|
4
4
|
|
|
5
5
|
Since 2.0, predictions are computed locally from harmonic constituents — no network access or API keys required.
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ It publishes the following [tide data](https://signalk.org/specification/1.7.0/d
|
|
|
26
26
|
|
|
27
27
|
### Tides API
|
|
28
28
|
|
|
29
|
-
The plugin mounts the [
|
|
29
|
+
The plugin mounts the [Slackwater API](https://openwaters.io/api/tides/) at `/signalk/v2/api/tides`, which serves station search, extremes, and timeline predictions. The synthetic station `vessel/default` resolves to the configured default station, or the nearest station to the vessel when none is set:
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
$ curl http://localhost:3000/signalk/v2/api/tides/stations/vessel/default/extremes
|
|
@@ -59,6 +59,12 @@ $ curl http://localhost:3000/signalk/v2/api/resources/tides
|
|
|
59
59
|
}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
### Chart plotter widget
|
|
63
|
+
|
|
64
|
+
The plugin offers a tide widget to chart plotters that support Signal K [Plotter Extensions](https://github.com/SignalK/freeboard-sk/blob/master/docs/api/plotter-extensions-api.md), such as [Freeboard-SK](https://github.com/SignalK/freeboard-sk). It shows the tide at the vessel's position: the level now with its trend, and the next high or low water, on the predicted curve. Tapping it opens the full Tides app in a panel beside the chart.
|
|
65
|
+
|
|
66
|
+
In Freeboard-SK, press and hold an empty spot in a corner of the chart (or right-click it and choose *Add widget here*) and pick *Tides*.
|
|
67
|
+
|
|
62
68
|
## License
|
|
63
69
|
|
|
64
70
|
This plugin is a fork of the [signalk-tides-api](https://github.com/joabakk/signalk-tides-api) plugin (which is no longer working) and is licensed under the [Apache License 2.0](LICENSE). Kudos to @joabakk and @sbender9 for the original work.
|
package/dist/index.js
CHANGED
|
@@ -13,15 +13,24 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { createRoutes } from "@
|
|
17
|
-
import { findStation, nearestStation, stationsNear } from "
|
|
16
|
+
import { createRoutes } from "@slackwater/api";
|
|
17
|
+
import { findStation, nearestStation, stationsNear } from "slackwater";
|
|
18
18
|
import { tideStateAt, timeToNextExtreme } from "./calculations.js";
|
|
19
19
|
import FileCache from "./cache.js";
|
|
20
20
|
import { withVesselPosition } from "./middleware.js";
|
|
21
|
+
import { PLOTTER_EXTENSION_ID, plotterExtensionManifest, } from "./plotter-extension.js";
|
|
21
22
|
// Recompute and republish on a fixed interval. Predictions are computed locally
|
|
22
|
-
// by
|
|
23
|
+
// by slackwater, so this is cheap and needs no configuration.
|
|
23
24
|
const UPDATE_INTERVAL = 60 * 1000; // 1 minute
|
|
24
25
|
const API_PATH = "/signalk/v2/api/tides";
|
|
26
|
+
// Tide heights are water levels, so clients should show them in the user's
|
|
27
|
+
// depth unit. Without a category the server picks one from the unit alone, and
|
|
28
|
+
// for meters that is distance: kilometers or miles, depending on the preset.
|
|
29
|
+
const TIDE_HEIGHT_PATHS = [
|
|
30
|
+
"environment.tide.heightHigh",
|
|
31
|
+
"environment.tide.heightNow",
|
|
32
|
+
"environment.tide.heightLow",
|
|
33
|
+
];
|
|
25
34
|
export default function (app) {
|
|
26
35
|
let unsubscribes = [];
|
|
27
36
|
let activeRouter = null;
|
|
@@ -40,7 +49,7 @@ export default function (app) {
|
|
|
40
49
|
const plugin = {
|
|
41
50
|
id: "tides",
|
|
42
51
|
name: "Tides",
|
|
43
|
-
description: "Offline tidal predictions for the vessel's position, powered by
|
|
52
|
+
description: "Offline tidal predictions for the vessel's position, powered by Slackwater.",
|
|
44
53
|
schema: () => ({
|
|
45
54
|
title: "Tides",
|
|
46
55
|
type: "object",
|
|
@@ -84,6 +93,25 @@ export default function (app) {
|
|
|
84
93
|
}
|
|
85
94
|
return options;
|
|
86
95
|
}
|
|
96
|
+
// The server keeps display units the user chose for a path, and stores the
|
|
97
|
+
// suggestion, so later starts leave a path alone while it has display units.
|
|
98
|
+
async function suggestDepthUnits() {
|
|
99
|
+
// Signal K server 2.30 added setDefaultMetadata
|
|
100
|
+
if (typeof app.setDefaultMetadata !== "function")
|
|
101
|
+
return;
|
|
102
|
+
for (const path of TIDE_HEIGHT_PATHS) {
|
|
103
|
+
try {
|
|
104
|
+
// MetaValue types displayUnits as the server resolves it; a suggestion
|
|
105
|
+
// needs only the category.
|
|
106
|
+
await app.setDefaultMetadata(path, {
|
|
107
|
+
displayUnits: { category: "depth" },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
app.error(`Could not suggest display units for ${path}: ${e}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
87
115
|
function savedDefaultStation() {
|
|
88
116
|
try {
|
|
89
117
|
const saved = app.readPluginOptions();
|
|
@@ -96,14 +124,20 @@ export default function (app) {
|
|
|
96
124
|
async function start(options) {
|
|
97
125
|
app.debug("Starting tides");
|
|
98
126
|
config = (options ?? {});
|
|
127
|
+
void suggestDepthUnits();
|
|
99
128
|
// Keep the forecast and the predictor that produced it together, so the
|
|
100
129
|
// extremes and the current height are always read from the same station.
|
|
101
130
|
let lastForecast = null;
|
|
102
131
|
let lastPredictor = null;
|
|
103
132
|
const cache = new FileCache(app.getDataDirPath());
|
|
104
|
-
// Mount the
|
|
133
|
+
// Mount the Slackwater API, with vessel/default resolved to the configured
|
|
105
134
|
// default station (or the nearest one).
|
|
106
|
-
activeRouter = withVesselPosition(
|
|
135
|
+
activeRouter = withVesselPosition(
|
|
136
|
+
// @slackwater/api bundles its own Express declarations, so its Router is
|
|
137
|
+
// callable at runtime but not structurally compatible with ours.
|
|
138
|
+
// The OpenAPI server URL comes from req.baseUrl, set by the
|
|
139
|
+
// app.use(API_PATH, ...) mount above.
|
|
140
|
+
createRoutes(), () => lastPosition, () => config.defaultStation ?? null);
|
|
107
141
|
// Register tide predictions as a resource provider
|
|
108
142
|
app.registerResourceProvider({
|
|
109
143
|
type: "tides",
|
|
@@ -126,6 +160,27 @@ export default function (app) {
|
|
|
126
160
|
},
|
|
127
161
|
},
|
|
128
162
|
});
|
|
163
|
+
// Offer the tide widget to chart plotters (src/plotter-extension.ts)
|
|
164
|
+
app.registerResourceProvider({
|
|
165
|
+
type: "plotterExtensions",
|
|
166
|
+
methods: {
|
|
167
|
+
async listResources() {
|
|
168
|
+
return { [PLOTTER_EXTENSION_ID]: plotterExtensionManifest };
|
|
169
|
+
},
|
|
170
|
+
async getResource(id) {
|
|
171
|
+
if (id !== PLOTTER_EXTENSION_ID) {
|
|
172
|
+
throw new Error(`No such plotterExtensions resource: ${id}`);
|
|
173
|
+
}
|
|
174
|
+
return plotterExtensionManifest;
|
|
175
|
+
},
|
|
176
|
+
setResource() {
|
|
177
|
+
throw new Error("Read-only resource");
|
|
178
|
+
},
|
|
179
|
+
deleteResource() {
|
|
180
|
+
throw new Error("Read-only resource");
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
129
184
|
app.subscriptionmanager.subscribe({
|
|
130
185
|
context: ("vessels." + app.selfId),
|
|
131
186
|
subscribe: [
|
package/dist/middleware.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findStation, nearestStation } from "
|
|
1
|
+
import { findStation, nearestStation } from "slackwater";
|
|
2
2
|
/**
|
|
3
3
|
* Middleware that resolves the vessel/default station alias and bare
|
|
4
4
|
* location-based queries (/extremes, /timeline) against the configured default
|
|
@@ -49,7 +49,7 @@ export function withVesselPosition(router, getPosition, getDefaultStationId) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
// Bare location-based queries: redirect to the configured station when set,
|
|
52
|
-
// otherwise inject the vessel position so
|
|
52
|
+
// otherwise inject the vessel position so slackwater uses the nearest station.
|
|
53
53
|
const isLocationQueryPath = req.path === "/extremes" || req.path === "/timeline";
|
|
54
54
|
if (isLocationQueryPath && !req.query.latitude && !req.query.longitude) {
|
|
55
55
|
const station = defaultStation();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tide widget this plugin offers to chart plotters that implement the
|
|
3
|
+
* Signal K Plotter Extensions API, such as Freeboard-SK, where the user places
|
|
4
|
+
* it on the chart. Both pages are part of the webapp, which the server serves
|
|
5
|
+
* at /signalk-tides/.
|
|
6
|
+
*/
|
|
7
|
+
const WEBAPP_PATH = "/signalk-tides/";
|
|
8
|
+
export const PLOTTER_EXTENSION_ID = "signalk-tides";
|
|
9
|
+
export const plotterExtensionManifest = {
|
|
10
|
+
name: "Tides",
|
|
11
|
+
description: "The tide at the vessel's position: the level now and the next high or low water.",
|
|
12
|
+
apiVersion: "1",
|
|
13
|
+
requires: ["widgets"],
|
|
14
|
+
// Without them the widget still shows the tide; tapping it opens the panel.
|
|
15
|
+
optional: ["panels.iframe", "ui"],
|
|
16
|
+
widgets: [
|
|
17
|
+
{
|
|
18
|
+
id: "tides",
|
|
19
|
+
title: "Tides",
|
|
20
|
+
type: "iframe",
|
|
21
|
+
url: `${WEBAPP_PATH}widget.html`,
|
|
22
|
+
size: "2x1",
|
|
23
|
+
lifecycle: "whileEnabled",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
panels: [
|
|
27
|
+
{
|
|
28
|
+
id: "tides",
|
|
29
|
+
title: "Tides",
|
|
30
|
+
type: "iframe",
|
|
31
|
+
url: WEBAPP_PATH,
|
|
32
|
+
lifecycle: "onOpen",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
package/mise.toml
ADDED
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signalk-tides",
|
|
3
|
-
"version": "2.1
|
|
4
|
-
"description": "Tidal predictions for the vessel's position, powered by
|
|
3
|
+
"version": "2.2.1",
|
|
4
|
+
"description": "Tidal predictions for the vessel's position, powered by Slackwater.",
|
|
5
|
+
"homepage": "https://openwaters.io/tides/slackwater/",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"exports": "./dist/index.js",
|
|
8
9
|
"scripts": {
|
|
9
10
|
"build": "tsc -b && vite build",
|
|
10
11
|
"dev": "vite",
|
|
11
|
-
"lint": "
|
|
12
|
+
"lint": "oxlint",
|
|
12
13
|
"prepack": "npm run build",
|
|
13
14
|
"preview": "vite preview",
|
|
14
15
|
"test": "npm run test:node && npm run test:browser",
|
|
@@ -34,45 +35,47 @@
|
|
|
34
35
|
],
|
|
35
36
|
"license": "Apache-2.0",
|
|
36
37
|
"dependencies": {
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@
|
|
40
|
-
"express": "^5.
|
|
41
|
-
"neaps": "^0.7.0",
|
|
38
|
+
"@signalk/server-api": "^2.35.0",
|
|
39
|
+
"@slackwater/api": "^1.0.0-beta.0",
|
|
40
|
+
"@slackwater/react": "^1.0.0-beta.2",
|
|
41
|
+
"express": "^5.3.0",
|
|
42
42
|
"react": "^19.1.0",
|
|
43
|
-
"react-dom": "^19.1
|
|
43
|
+
"react-dom": "^19.3.1",
|
|
44
|
+
"signalk-plotterext-bus": "^0.24.0",
|
|
45
|
+
"slackwater": "^1.0.0-beta.3"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
48
|
"@eslint/js": "^9.21.0",
|
|
47
49
|
"@tailwindcss/vite": "^4.1.3",
|
|
48
50
|
"@testing-library/dom": "^10.4.1",
|
|
49
51
|
"@testing-library/react": "^16.3.2",
|
|
50
|
-
"@testing-library/user-event": "^14.6.
|
|
52
|
+
"@testing-library/user-event": "^14.6.8",
|
|
51
53
|
"@types/express": "^5.0.6",
|
|
52
|
-
"@types/node": "^26.
|
|
54
|
+
"@types/node": "^26.6.5",
|
|
53
55
|
"@types/react": "^19.0.12",
|
|
54
56
|
"@types/react-dom": "^19.0.4",
|
|
55
57
|
"@types/supertest": "^7.2.0",
|
|
56
|
-
"@vitejs/plugin-react": "^6.
|
|
57
|
-
"@vitest/browser": "
|
|
58
|
-
"@vitest/browser-playwright": "
|
|
59
|
-
"@vitest/ui": "
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"maplibre-gl": "^5.19.0",
|
|
66
|
-
"pkg-pr-new": "^0.0.75",
|
|
67
|
-
"playwright": "^1.58.2",
|
|
58
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
59
|
+
"@vitest/browser": "5.0.5",
|
|
60
|
+
"@vitest/browser-playwright": "5.0.5",
|
|
61
|
+
"@vitest/ui": "5.0.5",
|
|
62
|
+
"jsdom": "^30.1.3",
|
|
63
|
+
"maplibre-gl": "^6.15.0",
|
|
64
|
+
"oxlint": "^1.89.0",
|
|
65
|
+
"pkg-pr-new": "^0.0.92",
|
|
66
|
+
"playwright": "^1.64.1",
|
|
68
67
|
"react-map-gl": "^8.1.0",
|
|
69
|
-
"signalk-server": "^2.
|
|
70
|
-
"supertest": "^7.
|
|
68
|
+
"signalk-server": "^2.35.1",
|
|
69
|
+
"supertest": "^7.3.1",
|
|
71
70
|
"tailwindcss": "^4.1.3",
|
|
72
|
-
"typescript": "^
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
71
|
+
"typescript": "^7.0.2",
|
|
72
|
+
"vite": "^8.3.5",
|
|
73
|
+
"vitest": "5.0.5"
|
|
74
|
+
},
|
|
75
|
+
"overrides": {
|
|
76
|
+
"vite-plus": {
|
|
77
|
+
"@vitest/browser-playwright": "4.1.11"
|
|
78
|
+
}
|
|
76
79
|
},
|
|
77
80
|
"repository": {
|
|
78
81
|
"type": "git",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,c as t,d as n,f as r,i,l as a,n as o,r as s,s as c,t as l,u}from"./useUnitPreferences-Bnl2Hfv0.js";var d=u(),f=r(n(),1),p=()=>new URLSearchParams(window.location.search).get(`station`)||`vessel/default`;function m(){let[e,t]=(0,f.useState)(p);return(0,f.useEffect)(()=>{let e=()=>t(p());return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[]),[e,(0,f.useCallback)(e=>{let n=e.trim()||`vessel/default`,r=new URL(window.location.href);n===`vessel/default`?r.searchParams.delete(`station`):r.searchParams.set(`station`,n),window.history.pushState(window.history.state,``,r),t(n)},[])]}var h=a(),g={version:8,sources:{osm:{type:`raster`,tiles:[`https://tile.openstreetmap.org/{z}/{x}/{y}.png`],tileSize:256,attribution:`© OpenStreetMap contributors`}},layers:[{id:`osm`,type:`raster`,source:`osm`}]};function _({stationId:n,onSelect:r}){let a=(0,f.useRef)(null),[s,c]=(0,f.useState)(!1),[l,u]=(0,f.useState)(!1),[d,p]=(0,f.useState)(`list`),{data:m}=t(n),_=()=>{u(window.matchMedia(`(min-width: 1024px)`).matches),p(`list`),c(!0),a.current?.showModal()},v=e=>{r(e.id),a.current?.close()};return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`button`,{type:`button`,onClick:_,"aria-label":`Browse stations`,className:`absolute hidden min-[20rem]:block right-2 top-2 sm:right-4 sm:top-4 md:right-6 md:top-6 lg:right-8 lg:top-8 xl:right-20 xl:top-20 z-10 rounded-md border border-(--slackwater-border) bg-(--slackwater-bg-subtle) p-2 text-(--slackwater-text) hover:bg-(--slackwater-bg)`,children:(0,h.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,"aria-hidden":`true`,children:[(0,h.jsx)(`line`,{x1:`3`,y1:`6`,x2:`21`,y2:`6`}),(0,h.jsx)(`line`,{x1:`3`,y1:`12`,x2:`21`,y2:`12`}),(0,h.jsx)(`line`,{x1:`3`,y1:`18`,x2:`21`,y2:`18`})]})}),(0,h.jsx)(`dialog`,{ref:a,onClose:()=>c(!1),onClick:e=>{e.target===e.currentTarget&&e.currentTarget.close()},className:`m-auto w-[min(92vw,900px)] max-h-[85vh] rounded-lg border border-(--slackwater-border) bg-(--slackwater-bg) p-0 text-(--slackwater-text) backdrop:bg-black/50`,children:s&&(0,h.jsxs)(`div`,{className:`flex max-h-[85vh] flex-col`,children:[(0,h.jsxs)(`div`,{className:`flex items-center justify-between border-b border-(--slackwater-border) p-3`,children:[(0,h.jsx)(`button`,{type:`button`,onClick:()=>a.current?.close(),"aria-label":`Close`,className:`grid size-11 place-items-center rounded-md text-(--slackwater-text-muted) hover:text-(--slackwater-text)`,children:`✕`}),(0,h.jsx)(`h2`,{className:`text-base font-semibold`,children:`Stations`}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>p(d===`map`?`list`:`map`),"aria-label":d===`map`?`Show list`:`Show map`,className:`grid size-11 place-items-center rounded-md text-(--slackwater-text-muted) hover:text-(--slackwater-text) lg:invisible`,children:d===`map`?(0,h.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,h.jsx)(`line`,{x1:`8`,y1:`6`,x2:`21`,y2:`6`}),(0,h.jsx)(`line`,{x1:`8`,y1:`12`,x2:`21`,y2:`12`}),(0,h.jsx)(`line`,{x1:`8`,y1:`18`,x2:`21`,y2:`18`}),(0,h.jsx)(`line`,{x1:`3`,y1:`6`,x2:`3.01`,y2:`6`}),(0,h.jsx)(`line`,{x1:`3`,y1:`12`,x2:`3.01`,y2:`12`}),(0,h.jsx)(`line`,{x1:`3`,y1:`18`,x2:`3.01`,y2:`18`})]}):(0,h.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[(0,h.jsx)(`polygon`,{points:`3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21 3 6`}),(0,h.jsx)(`line`,{x1:`9`,y1:`3`,x2:`9`,y2:`18`}),(0,h.jsx)(`line`,{x1:`15`,y1:`6`,x2:`15`,y2:`21`})]})})]}),(0,h.jsxs)(`div`,{className:`flex min-h-0 flex-col gap-4 p-3 lg:flex-row`,children:[(0,h.jsxs)(`div`,{className:`w-full flex-col gap-3 overflow-y-auto lg:flex lg:w-80 ${d===`map`?`hidden`:`flex`}`,children:[(0,h.jsx)(i,{onSelect:v}),(0,h.jsx)(`button`,{type:`button`,onClick:()=>v({id:`vessel/default`}),className:`rounded-md border border-(--slackwater-border) px-3 py-2 text-left text-sm hover:bg-(--slackwater-bg-subtle)`,children:`📍 Vessel position`}),(0,h.jsx)(o,{stationId:n,onStationSelect:v})]}),(l||d===`map`)&&m&&(0,h.jsx)(`div`,{className:`h-[60vh] overflow-hidden rounded-md border border-(--slackwater-border) lg:h-auto lg:min-h-100 lg:flex-1`,children:(0,h.jsx)(e,{mapStyle:g,initialViewState:{longitude:m.longitude,latitude:m.latitude,zoom:10},focusStation:m.id,onStationSelect:v})})]})]})})]})}var{VITE_SIGNALK_URL:v=window.location.toString()}={BASE_URL:`./`,DEV:!1,MODE:`production`,PROD:!0,SSR:!1},y=new URL(`/signalk/v2/api`,v).toString();function b(){let{units:e,ready:t}=l(),[n,r]=m();return t?(0,h.jsx)(s,{baseUrl:y,units:e,children:(0,h.jsxs)(`div`,{className:`relative`,children:[(0,h.jsx)(_,{stationId:n,onSelect:r}),(0,h.jsx)(c,{id:n,className:`overflow-y-auto p-2 sm:p-4 md:p-6 lg:p-8 xl:p-20`})]})}):null}(0,d.createRoot)(document.getElementById(`app`)).render((0,h.jsx)(b,{}));
|