signalk-siparu 0.2.20 → 0.2.23
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/package.json +1 -1
- package/plugin/dist/bounded.d.ts +7 -0
- package/plugin/dist/bounded.js +41 -0
- package/plugin/dist/keysync.js +6 -2
- package/plugin/dist/live.d.ts +1 -0
- package/plugin/dist/live.js +5 -2
- package/plugin/dist/pairing.js +10 -4
- package/plugin/dist/phases.d.ts +1 -0
- package/plugin/dist/phases.js +24 -11
- package/plugin/dist/query.js +16 -12
- package/plugin/dist/voyage.d.ts +2 -0
- package/plugin/dist/voyage.js +10 -4
- package/plugin/dist/voyagelog.js +1 -1
- package/public/assets/{Logbook-D4bd0BKi.js → Logbook-BynviqKK.js} +1 -1
- package/public/assets/Map-j1JeE-OI.js +111 -0
- package/public/assets/{Remote-CroZb8E-.js → Remote-CfDSrk82.js} +1 -1
- package/public/assets/{SecurityHelp-BkZTE2S_.js → SecurityHelp-CpxLhvL1.js} +1 -1
- package/public/assets/Voyage-mM53xUG_.js +1 -0
- package/public/assets/index-DPNvHdqr.js +20 -0
- package/public/assets/index-Djj1q7Ea.css +1 -0
- package/public/assets/maplibre-gl-worker-CY0-DIEi.js +11 -0
- package/public/assets/style-BRg0vyat.js +828 -0
- package/public/index.html +2 -2
- package/public/assets/Map-v6TtxzKF.js +0 -111
- package/public/assets/Voyage-CVqU1kQ3.js +0 -1
- package/public/assets/index-BgEguoa4.css +0 -1
- package/public/assets/index-BtvisMV4.js +0 -20
- package/public/assets/style-D6ViMmrL.js +0 -762
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signalk-siparu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "Kept aboard, proven ashore. Position, wind, depth and voyage history, recorded on the boat and readable from anywhere: sealed to the devices you name, signed on the way out. A read-only Signal K plugin with a built-in dashboard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"signalk-node-server-plugin",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const RELAY_ANSWER_MAX_BYTES: number;
|
|
2
|
+
export declare class AnswerTooLarge extends Error {
|
|
3
|
+
readonly bytes: number;
|
|
4
|
+
readonly limit: number;
|
|
5
|
+
constructor(bytes: number, limit: number);
|
|
6
|
+
}
|
|
7
|
+
export declare function readBounded(res: Response, max?: number): Promise<string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnswerTooLarge = exports.RELAY_ANSWER_MAX_BYTES = void 0;
|
|
4
|
+
exports.readBounded = readBounded;
|
|
5
|
+
exports.RELAY_ANSWER_MAX_BYTES = 64 * 1024;
|
|
6
|
+
class AnswerTooLarge extends Error {
|
|
7
|
+
bytes;
|
|
8
|
+
limit;
|
|
9
|
+
constructor(bytes, limit) {
|
|
10
|
+
super(`relay answer exceeds ${limit} bytes (${bytes} seen)`);
|
|
11
|
+
this.bytes = bytes;
|
|
12
|
+
this.limit = limit;
|
|
13
|
+
this.name = 'AnswerTooLarge';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.AnswerTooLarge = AnswerTooLarge;
|
|
17
|
+
async function readBounded(res, max = exports.RELAY_ANSWER_MAX_BYTES) {
|
|
18
|
+
const declared = res.headers.get('content-length');
|
|
19
|
+
if (declared !== null) {
|
|
20
|
+
const n = Number(declared);
|
|
21
|
+
if (Number.isFinite(n) && n > max)
|
|
22
|
+
throw new AnswerTooLarge(n, max);
|
|
23
|
+
}
|
|
24
|
+
if (!res.body)
|
|
25
|
+
return '';
|
|
26
|
+
const reader = res.body.getReader();
|
|
27
|
+
const chunks = [];
|
|
28
|
+
let total = 0;
|
|
29
|
+
for (;;) {
|
|
30
|
+
const { done, value } = await reader.read();
|
|
31
|
+
if (done)
|
|
32
|
+
break;
|
|
33
|
+
total += value.byteLength;
|
|
34
|
+
if (total > max) {
|
|
35
|
+
await reader.cancel().catch(() => { });
|
|
36
|
+
throw new AnswerTooLarge(total, max);
|
|
37
|
+
}
|
|
38
|
+
chunks.push(value);
|
|
39
|
+
}
|
|
40
|
+
return new TextDecoder().decode(Buffer.concat(chunks));
|
|
41
|
+
}
|
package/plugin/dist/keysync.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KeySync = exports.MAX_APPROVALS = exports.PROMPTED_FLOOR_MS = void 0;
|
|
4
|
+
const bounded_1 = require("./bounded");
|
|
4
5
|
const sealing_1 = require("./sealing");
|
|
5
6
|
const DEFAULT_INTERVAL_MS = 5 * 60_000;
|
|
6
7
|
const REQUEST_TIMEOUT_MS = 20_000;
|
|
@@ -159,7 +160,7 @@ class KeySync {
|
|
|
159
160
|
this.deps.debug(`keysync: ${this.lastError}`);
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
162
|
-
const answer = (await
|
|
163
|
+
const answer = JSON.parse(await (0, bounded_1.readBounded)(res));
|
|
163
164
|
if (generation !== this.generation)
|
|
164
165
|
return;
|
|
165
166
|
if (answer?.keys === 'mismatch') {
|
|
@@ -194,7 +195,10 @@ class KeySync {
|
|
|
194
195
|
this.failures++;
|
|
195
196
|
if (this.state !== 'mismatch') {
|
|
196
197
|
this.state = 'failing';
|
|
197
|
-
this.lastError =
|
|
198
|
+
this.lastError =
|
|
199
|
+
e instanceof bounded_1.AnswerTooLarge
|
|
200
|
+
? 'Siparu answered with more than this boat will read. If it persists, contact support.'
|
|
201
|
+
: 'Cannot reach Siparu. Is the boat online?';
|
|
198
202
|
}
|
|
199
203
|
this.deps.debug(`keysync unreachable: ${String(e)}`);
|
|
200
204
|
}
|
package/plugin/dist/live.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare const STILL_FRAME_EVERY_MS = 60000;
|
|
|
5
5
|
export declare const PROMPTED_FRAME_FLOOR_MS = 5000;
|
|
6
6
|
export declare const REPORTING_STALE_MS: number;
|
|
7
7
|
export declare const PING_EVERY_MS = 25000;
|
|
8
|
+
export declare const SHORE_MESSAGE_MAX_BYTES: number;
|
|
8
9
|
export interface LiveSocket {
|
|
9
10
|
send(data: string): void;
|
|
10
11
|
close(code?: number, reason?: string): void;
|
package/plugin/dist/live.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LiveUplink = exports.PING_EVERY_MS = exports.REPORTING_STALE_MS = exports.PROMPTED_FRAME_FLOOR_MS = exports.STILL_FRAME_EVERY_MS = exports.FRAME_EVERY_MS = void 0;
|
|
3
|
+
exports.LiveUplink = exports.SHORE_MESSAGE_MAX_BYTES = exports.PING_EVERY_MS = exports.REPORTING_STALE_MS = exports.PROMPTED_FRAME_FLOOR_MS = exports.STILL_FRAME_EVERY_MS = exports.FRAME_EVERY_MS = void 0;
|
|
4
4
|
exports.rpcEnvelope = rpcEnvelope;
|
|
5
5
|
exports.isWatchingNote = isWatchingNote;
|
|
6
6
|
exports.FRAME_EVERY_MS = 2_000;
|
|
@@ -22,6 +22,7 @@ const CLOSE_PLAN_REQUIRED = 4403;
|
|
|
22
22
|
const REFUSED_UNKNOWN_TOKEN = 401;
|
|
23
23
|
const REFUSED_PLAN_REQUIRED = 403;
|
|
24
24
|
const HANDSHAKE_TIMEOUT_MS = 15_000;
|
|
25
|
+
exports.SHORE_MESSAGE_MAX_BYTES = 64 * 1024;
|
|
25
26
|
class LiveUplink {
|
|
26
27
|
deps;
|
|
27
28
|
sock = null;
|
|
@@ -629,7 +630,9 @@ function wsConnect(url, token) {
|
|
|
629
630
|
const WS = require('ws');
|
|
630
631
|
const sock = new WS(url, {
|
|
631
632
|
headers: { authorization: `Bearer ${token}` },
|
|
632
|
-
handshakeTimeout: HANDSHAKE_TIMEOUT_MS
|
|
633
|
+
handshakeTimeout: HANDSHAKE_TIMEOUT_MS,
|
|
634
|
+
maxPayload: exports.SHORE_MESSAGE_MAX_BYTES,
|
|
635
|
+
perMessageDeflate: false
|
|
633
636
|
});
|
|
634
637
|
return {
|
|
635
638
|
send: (data) => sock.send(data),
|
package/plugin/dist/pairing.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.registerPairRoutes = registerPairRoutes;
|
|
|
11
11
|
exports.retryPendingUnlinks = retryPendingUnlinks;
|
|
12
12
|
exports.__resetPairingState = __resetPairingState;
|
|
13
13
|
const access_1 = require("./access");
|
|
14
|
+
const bounded_1 = require("./bounded");
|
|
14
15
|
const fingerprint_1 = require("./fingerprint");
|
|
15
16
|
const origin_guard_1 = require("./origin-guard");
|
|
16
17
|
function securityOff(app, req) {
|
|
@@ -87,7 +88,7 @@ async function relay(url, path, body, boatToken) {
|
|
|
87
88
|
throw new Error(`relay ${path} unreachable${cause}`);
|
|
88
89
|
}
|
|
89
90
|
if (!res.ok) {
|
|
90
|
-
const text = await
|
|
91
|
+
const text = await (0, bounded_1.readBounded)(res).catch(() => '');
|
|
91
92
|
let code = null;
|
|
92
93
|
try {
|
|
93
94
|
code = JSON.parse(text).error ?? null;
|
|
@@ -96,7 +97,7 @@ async function relay(url, path, body, boatToken) {
|
|
|
96
97
|
}
|
|
97
98
|
throw new RelayRefused(res.status, code, `relay ${path} -> ${res.status} ${text.slice(0, 120)}`);
|
|
98
99
|
}
|
|
99
|
-
return (await
|
|
100
|
+
return JSON.parse(await (0, bounded_1.readBounded)(res));
|
|
100
101
|
}
|
|
101
102
|
finally {
|
|
102
103
|
clearTimeout(timeout);
|
|
@@ -193,7 +194,9 @@ function registerPairRoutes(router, deps) {
|
|
|
193
194
|
catch (e) {
|
|
194
195
|
json({
|
|
195
196
|
state: 'error',
|
|
196
|
-
message:
|
|
197
|
+
message: e instanceof bounded_1.AnswerTooLarge
|
|
198
|
+
? 'Siparu answered with more than this boat will read. Try again later.'
|
|
199
|
+
: 'Cannot reach Siparu. Is the boat online?'
|
|
197
200
|
});
|
|
198
201
|
app.debug(`pair status: ${String(e)}`);
|
|
199
202
|
}
|
|
@@ -219,7 +222,10 @@ function registerPairRoutes(router, deps) {
|
|
|
219
222
|
e instanceof RelayRefused && e.status === 429
|
|
220
223
|
?
|
|
221
224
|
'Too many pairing attempts from this network. Wait an hour and try again.'
|
|
222
|
-
:
|
|
225
|
+
: e instanceof bounded_1.AnswerTooLarge
|
|
226
|
+
?
|
|
227
|
+
'Siparu answered with more than this boat will read. Try again later.'
|
|
228
|
+
: 'Cannot reach Siparu. Check the boat is online (DNS, port 443, captive portal).';
|
|
223
229
|
app.error(`pair start failed: ${String(e)}`);
|
|
224
230
|
res.status(502).json({ state: 'error', message: lastError });
|
|
225
231
|
}
|
package/plugin/dist/phases.d.ts
CHANGED
package/plugin/dist/phases.js
CHANGED
|
@@ -47,12 +47,22 @@ class PhaseStateMachine {
|
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
const dt = this.lastTs !== null ? row.ts - this.lastTs : 0;
|
|
50
|
+
const before = this.last;
|
|
50
51
|
this.lastTs = row.ts;
|
|
51
52
|
this.last = pt;
|
|
52
53
|
if (dt < 0 || dt > MAX_GAP_MS) {
|
|
54
|
+
if (dt < 0 || raw === this.curKind) {
|
|
55
|
+
this.candKind = null;
|
|
56
|
+
this.candStreakMs = 0;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const boundary = raw === this.candKind && this.candStart ? this.candStart : null;
|
|
60
|
+
const closed = this.close(boundary ?? before);
|
|
61
|
+
this.curKind = raw;
|
|
62
|
+
this.curStart = boundary ?? pt;
|
|
53
63
|
this.candKind = null;
|
|
54
64
|
this.candStreakMs = 0;
|
|
55
|
-
return
|
|
65
|
+
return closed;
|
|
56
66
|
}
|
|
57
67
|
if (raw === this.curKind) {
|
|
58
68
|
this.candKind = null;
|
|
@@ -69,16 +79,7 @@ class PhaseStateMachine {
|
|
|
69
79
|
}
|
|
70
80
|
if (this.candStreakMs >= this.opts.phaseMinMinutes * 60_000) {
|
|
71
81
|
const start = this.candStart;
|
|
72
|
-
const
|
|
73
|
-
const closed = {
|
|
74
|
-
kind: this.curKind,
|
|
75
|
-
start_ts: cur.ts,
|
|
76
|
-
end_ts: start.ts,
|
|
77
|
-
start_lat: cur.lat,
|
|
78
|
-
start_lon: cur.lon,
|
|
79
|
-
end_lat: start.lat,
|
|
80
|
-
end_lon: start.lon
|
|
81
|
-
};
|
|
82
|
+
const closed = this.close(start);
|
|
82
83
|
this.curKind = this.candKind;
|
|
83
84
|
this.curStart = start;
|
|
84
85
|
this.candKind = null;
|
|
@@ -87,6 +88,18 @@ class PhaseStateMachine {
|
|
|
87
88
|
}
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
91
|
+
close(end) {
|
|
92
|
+
const cur = this.curStart;
|
|
93
|
+
return {
|
|
94
|
+
kind: this.curKind,
|
|
95
|
+
start_ts: cur.ts,
|
|
96
|
+
end_ts: end.ts,
|
|
97
|
+
start_lat: cur.lat,
|
|
98
|
+
start_lon: cur.lon,
|
|
99
|
+
end_lat: end.lat,
|
|
100
|
+
end_lon: end.lon
|
|
101
|
+
};
|
|
102
|
+
}
|
|
90
103
|
current() {
|
|
91
104
|
if (this.curKind === null || this.curStart === null)
|
|
92
105
|
return null;
|
package/plugin/dist/query.js
CHANGED
|
@@ -2,9 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.QueryError = exports.QueryService = exports.RAW_WINDOW_DAYS = exports.LIMIT_MAX = exports.LIMIT_DEFAULT = void 0;
|
|
4
4
|
const contract_1 = require("./contract");
|
|
5
|
+
const aggregate_1 = require("./aggregate");
|
|
5
6
|
const time_1 = require("./time");
|
|
6
7
|
const units_1 = require("./units");
|
|
7
8
|
const ROLLUP_FIELDS = (0, contract_1.metricFields)('linear', 'angular', 'text');
|
|
9
|
+
const SIX_HOURS_MS = 6 * 3_600_000;
|
|
10
|
+
function sixHourWindows(hours) {
|
|
11
|
+
const byWindow = new Map();
|
|
12
|
+
for (const h of hours) {
|
|
13
|
+
const win = Math.floor((0, time_1.hourStartOf)(h.hour) / SIX_HOURS_MS);
|
|
14
|
+
const list = byWindow.get(win);
|
|
15
|
+
if (list)
|
|
16
|
+
list.push(h);
|
|
17
|
+
else
|
|
18
|
+
byWindow.set(win, [h]);
|
|
19
|
+
}
|
|
20
|
+
return [...byWindow.entries()].map(([win, hs]) => [win * SIX_HOURS_MS, (0, aggregate_1.mergeHours)(hs)]);
|
|
21
|
+
}
|
|
8
22
|
exports.LIMIT_DEFAULT = 200;
|
|
9
23
|
exports.LIMIT_MAX = 5000;
|
|
10
24
|
exports.RAW_WINDOW_DAYS = 7;
|
|
@@ -66,13 +80,7 @@ class QueryService {
|
|
|
66
80
|
}
|
|
67
81
|
else if (q.bucket === 360) {
|
|
68
82
|
const from = q.from ?? 0;
|
|
69
|
-
|
|
70
|
-
const byWindow = new Map();
|
|
71
|
-
for (const h of hours) {
|
|
72
|
-
const win = Math.floor((0, time_1.hourStartOf)(h.hour) / (6 * 3_600_000));
|
|
73
|
-
byWindow.set(win, h);
|
|
74
|
-
}
|
|
75
|
-
rows = [...byWindow.entries()].map(([win, h]) => rollupToRow(h, win * 6 * 3_600_000));
|
|
83
|
+
rows = sixHourWindows(await this.rollups.readHourly(from, to)).map(([ts, w]) => rollupToRow(w, ts));
|
|
76
84
|
}
|
|
77
85
|
else if (q.bucket === 1440) {
|
|
78
86
|
const from = q.from ?? 0;
|
|
@@ -116,11 +124,7 @@ class QueryService {
|
|
|
116
124
|
}
|
|
117
125
|
else if (q.bucket === 360) {
|
|
118
126
|
const from = q.from ?? 0;
|
|
119
|
-
|
|
120
|
-
for (const h of await this.rollups.readHourly(from, to)) {
|
|
121
|
-
byWindow.set(Math.floor((0, time_1.hourStartOf)(h.hour) / (6 * 3_600_000)), h);
|
|
122
|
-
}
|
|
123
|
-
points = [...byWindow.entries()].flatMap(([win, h]) => aggToPoint(win * 6 * 3_600_000, aggFor(h, coreField, pathName)));
|
|
127
|
+
points = sixHourWindows(await this.rollups.readHourly(from, to)).flatMap(([ts, w]) => aggToPoint(ts, aggFor(w, coreField, pathName)));
|
|
124
128
|
}
|
|
125
129
|
else if (q.bucket === 1440) {
|
|
126
130
|
const from = q.from ?? 0;
|
package/plugin/dist/voyage.d.ts
CHANGED
|
@@ -19,12 +19,14 @@ export declare class VoyageStateMachine {
|
|
|
19
19
|
private movingStreakMs;
|
|
20
20
|
private stationaryStreakMs;
|
|
21
21
|
private lastTs;
|
|
22
|
+
private endBeforeGap;
|
|
22
23
|
constructor(opts: VoyageOptions, open: boolean);
|
|
23
24
|
feed(row: VoyageRow): {
|
|
24
25
|
type: 'open';
|
|
25
26
|
startTs: number;
|
|
26
27
|
} | {
|
|
27
28
|
type: 'close';
|
|
29
|
+
endTs: number;
|
|
28
30
|
} | null;
|
|
29
31
|
}
|
|
30
32
|
export declare function mergeContiguousVoyages(voyages: Voyage[], opts: VoyageOptions, reintegrate: (v: Voyage) => Promise<void>, manual?: ReadonlySet<number>): Promise<Voyage[]>;
|
package/plugin/dist/voyage.js
CHANGED
|
@@ -112,6 +112,7 @@ class VoyageStateMachine {
|
|
|
112
112
|
movingStreakMs = 0;
|
|
113
113
|
stationaryStreakMs = 0;
|
|
114
114
|
lastTs = null;
|
|
115
|
+
endBeforeGap = null;
|
|
115
116
|
constructor(opts, open) {
|
|
116
117
|
this.opts = opts;
|
|
117
118
|
this.open = open;
|
|
@@ -125,6 +126,9 @@ class VoyageStateMachine {
|
|
|
125
126
|
(isStationaryState(row.nav_state) && sogValid === null);
|
|
126
127
|
const dtMs = this.lastTs !== null ? ts - this.lastTs : 0;
|
|
127
128
|
if (dtMs < 0 || dtMs > MAX_GAP_MS) {
|
|
129
|
+
if (dtMs > MAX_GAP_MS && this.open && this.lastTs !== null && this.stationaryStreakMs > 0) {
|
|
130
|
+
this.endBeforeGap ??= this.lastTs;
|
|
131
|
+
}
|
|
128
132
|
this.movingStreakMs = 0;
|
|
129
133
|
this.stationaryStreakMs = 0;
|
|
130
134
|
this.lastTs = ts;
|
|
@@ -144,11 +148,15 @@ class VoyageStateMachine {
|
|
|
144
148
|
}
|
|
145
149
|
else {
|
|
146
150
|
this.stationaryStreakMs = stationary ? this.stationaryStreakMs + dtMs : 0;
|
|
151
|
+
if (!stationary)
|
|
152
|
+
this.endBeforeGap = null;
|
|
147
153
|
if (this.stationaryStreakMs >= this.opts.closeMinutes * 60_000) {
|
|
154
|
+
const endTs = this.endBeforeGap ?? ts;
|
|
148
155
|
this.open = false;
|
|
149
156
|
this.movingStreakMs = 0;
|
|
150
157
|
this.stationaryStreakMs = 0;
|
|
151
|
-
|
|
158
|
+
this.endBeforeGap = null;
|
|
159
|
+
return { type: 'close', endTs };
|
|
152
160
|
}
|
|
153
161
|
}
|
|
154
162
|
return null;
|
|
@@ -215,9 +223,7 @@ async function reconcile(state, rows, opts, ports, readRange, now, fuelRatePaths
|
|
|
215
223
|
state.voyages.push(openVoyage);
|
|
216
224
|
}
|
|
217
225
|
else if (event.type === 'close' && openVoyage) {
|
|
218
|
-
openVoyage.end_ts =
|
|
219
|
-
openVoyage.end_lat = row.lat;
|
|
220
|
-
openVoyage.end_lon = row.lon;
|
|
226
|
+
openVoyage.end_ts = event.endTs;
|
|
221
227
|
openVoyage.status = 'closed';
|
|
222
228
|
await applyMetrics(openVoyage, readRange, now, fuelRatePaths);
|
|
223
229
|
openVoyage.end_port = nearestPort(openVoyage.end_lat, openVoyage.end_lon, ports);
|
package/plugin/dist/voyagelog.js
CHANGED
|
@@ -156,7 +156,7 @@ class VoyageLog {
|
|
|
156
156
|
let hours = 0;
|
|
157
157
|
for (const v of this.state.voyages) {
|
|
158
158
|
const vStart = v.start_ts;
|
|
159
|
-
const vEnd = v.end_ts ??
|
|
159
|
+
const vEnd = v.end_ts ?? now;
|
|
160
160
|
const s = Math.max(vStart, winStart);
|
|
161
161
|
const e = Math.min(vEnd, winEnd);
|
|
162
162
|
if (e <= s)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./tz-DxphYhHy.js","./rolldown-runtime-CNC7AqOf.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-CaR_m4Xc.js";import{t as r}from"./visibleInterval-CFxPzgzx.js";import{A as i,C as a,D as o,E as s,F as c,N as l,O as u,P as d,S as f,T as p,_ as m,b as h,c as g,d as _,g as v,k as y,l as b,o as x,p as S,s as C,v as w,w as T}from"./index-BtvisMV4.js";import{a as E,d as D,i as O,l as k,n as A,o as j,r as M,t as N,u as P}from"./export-CGdOfqNp.js";var F=e(t(),1),I={key:`ts`,head:`UTC`,book:`bridge`,cell:()=>``};function L(e,t,n,r){if(e===null)return`·`;let i=Math.abs(e),a=Math.floor(i),o=(i-a)*60;return`${String(a).padStart(t,`0`)}°${o.toFixed(3).padStart(6,`0`)}' ${e<0?r:n}`}function R(e){return[{col:{key:`lat`,head:`LAT`,book:`bridge`,lanes:2,cell:e=>L(e.lat,2,`N`,`S`)},has:e=>e.lat!==null},{col:{key:`lon`,head:`LON`,book:`bridge`,lanes:2,cell:e=>L(e.lon,3,`E`,`W`)},has:e=>e.lon!==null},{col:{key:`sog`,head:`SOG`,book:`bridge`,unit:`kn`,cell:e=>h(o(e.sog),1)},has:e=>e.sog!==null},{col:{key:`cog`,head:`COG`,book:`bridge`,cell:e=>{let t=s(e.cog);return t===null?`·`:Math.round(t)+`°`}},has:e=>e.cog!==null},{col:{key:`hdg`,head:`HDG`,book:`bridge`,cell:e=>{let t=s(e.heading_true??e.heading_mag);return t===null?`·`:Math.round(t)+`°`}},has:e=>(e.heading_true??e.heading_mag)!==null},{col:{key:`wind`,head:e===`kn`?`TWS`:`BFT`,book:`bridge`,unit:e===`kn`?`kn`:void 0,tappable:!0,cell:t=>{let n=T(t.wind_speed_true);return n===null?`·`:String(e===`kn`?Math.round(n):a(n)??`·`)}},has:e=>e.wind_speed_true!==null},{col:{key:`awa`,head:`AWA`,book:`bridge`,cell:e=>{let t=s(e.wind_angle_apparent);if(t===null)return`·`;let n=(t+180)%360-180;return`${Math.abs(Math.round(n))}°${n<0?`P`:`S`}`}},has:e=>e.wind_angle_apparent!==null},{col:{key:`baro`,head:`BARO`,book:`bridge`,unit:`hPa`,dim:!0,cell:e=>{let t=p(e.air_pressure_pa);return t===null?`·`:String(Math.round(t))}},has:e=>e.air_pressure_pa!==null},{col:{key:`air`,head:`AIR`,book:`bridge`,unit:`°C`,cell:e=>h(f(e.air_temp_k),1)},has:e=>e.air_temp_k!==null},{col:{key:`sea`,head:`SEA`,book:`bridge`,unit:`°C`,cell:e=>h(f(e.water_temp_k),1)},has:e=>e.water_temp_k!==null},{col:{key:`depth`,head:`DEP`,book:`bridge`,unit:`m`,cell:e=>e.depth===null?`·`:e.depth.toFixed(1)},has:e=>e.depth!==null}]}var z={Revolutions:`RPM`,Temperature:`TEMP`,"Oil pressure":`OIL`,"Oil temperature":`OILT`,"Coolant temperature":`COOL`,"Coolant pressure":`COOLP`,"Exhaust temperature":`EXH`,"Intake manifold temperature":`INTK`,"Boost pressure":`BOOST`,"Engine load":`LOAD`,"Engine torque":`TORQ`,"Run time":`HRS`,"Fuel rate":`FUEL`,"Fuel per mile":`L/NM`,"Fuel used (since reset)":`USED`,"Fuel pressure":`FUELP`,"Alternator voltage":`ALT`,"Gearbox oil temperature":`GBOXT`,"Gearbox oil pressure":`GBOXP`,"Current level":`LEVEL`,Voltage:`VOLT`,Current:`AMP`};function B(e){return z[e]??e.split(` `)[0].toUpperCase()}function V(e){return e.sub===null?e.tab===`tanks`?`Current level`:null:e.sub}function H(e){let t=/^(Engine|Generator|Fuel|Fresh water|Black water|Grey water|Lubrication)\s+(\S+)$/.exec(e);return t?`${t[1].split(` `).map(e=>e[0]).join(``)}${t[2]}`.toUpperCase():e.slice(0,1).toUpperCase()}function U(e){let t=[];for(let n of e)for(let e of Object.keys(n.path_values??{}))t.includes(e)||t.push(e);let n=[];for(let e of t){let t=u(e);if(!t)continue;let r=V(t);r!==null&&n.push({path:e,d:{...t,sub:r}})}let r=new Map;for(let{d:e}of n)r.has(e.tab)||r.set(e.tab,new Set),r.get(e.tab).add(e.label);let a=[];for(let{path:e,d:t}of n){let n=B(t.sub);a.push({col:{key:`p:${e}`,head:r.get(t.tab).size>1?`${H(t.label)} ${n}`:n,book:`engine`,tab:t.tab,unit:i(e),cell:t=>{let n=t.path_values?.[e];if(typeof n!=`number`)return`·`;let r=y(e,n).value;return Number.isFinite(r)?Number.isInteger(r)?String(r):r.toFixed(1):`·`}},has:t=>typeof t.path_values?.[e]==`number`})}return a}function W(e,t){return[I,...[...R(t),...U(e)].filter(t=>e.some(t.has)).map(e=>e.col)]}function G(e,t){return e.filter(e=>e.key===`ts`||e.book===t)}var ee={engine:`ENGINES`,generator:`GENERATORS`,tanks:`TANKS`};function K(e){let t=[],n=new Map,r=new Map;for(let i of e)for(let e of Object.keys(i.path_values??{})){let i=u(e);if(!i)continue;let a=V(i);if(a===null)continue;n.has(i.tab)||(t.push(i.tab),n.set(i.tab,new Map),r.set(i.tab,[]));let o=n.get(i.tab);o.has(i.label)||o.set(i.label,new Map),o.get(i.label).set(a,e);let s=r.get(i.tab);s.includes(a)||s.push(a)}return t.map(e=>{let t=[...n.get(e)].map(([e,t])=>({key:e,head:e.toUpperCase(),paths:Object.fromEntries(t)})),a=r.get(e).map(e=>{let n=t.map(t=>t.paths[e]).find(e=>e!==void 0);return{key:e,head:B(e),unit:n===void 0?``:i(n)}});return{tab:e,head:ee[e]??e.toUpperCase(),units:t,metrics:a}})}function te(e,t,n){let r=t.paths[n.key];if(r===void 0)return`·`;let i=e.path_values?.[r];if(typeof i!=`number`)return`·`;let a=y(r,i).value;return Number.isFinite(a)?Number.isInteger(a)?String(a):a.toFixed(1):`·`}function ne(e,t){let[n,r]=(0,F.useState)(e),[i,a]=(0,F.useState)(!1);return(0,F.useEffect)(()=>{if(e===n)return;a(!0);let i=setTimeout(()=>{r(e),a(!1)},t);return()=>clearTimeout(i)},[e,n,t]),[n,i]}var q=new Map;function J(e,t,n){let r=`${t}|${e}`,i=q.get(r);if(i===void 0){try{i=new Intl.DateTimeFormat(`en-GB`,{...n,timeZone:e})}catch{i=null}q.set(r,i)}return i}var re={hour:`2-digit`,minute:`2-digit`,hourCycle:`h23`},Y={hour:`2-digit`,timeZoneName:`shortOffset`},X={weekday:`short`,day:`2-digit`,month:`short`,year:`numeric`},Z=e=>e!==null&&J(e,`clock`,re)&&J(e,`offset`,Y)&&J(e,`day`,X)?e:`UTC`;function ie(e,t){return J(Z(t),`clock`,re).format(e)}function ae(e,t){let n=J(Z(t),`offset`,Y);if(!n)return`UTC`;let r=(n.formatToParts(e).find(e=>e.type===`timeZoneName`)?.value??``).replace(/^(GMT|UTC)/,``);return/[1-9]/.test(r)?`UTC${r}`:`UTC`}function oe(e,t){return J(Z(t),`day`,X).format(e).replace(/,\s*/,` · `).toUpperCase()}function se(e,t){let n=new Map,r=new Map,i=(e,n)=>{let i=`${Math.round(e*10)},${Math.round(n*10)}`,a=r.get(i);if(a===void 0){try{a=t(e,n)}catch{a=null}r.set(i,a)}return a},a=[...e].sort((e,t)=>e.ts-t.ts),o=a.map(e=>t!==null&&e.lat!==null&&e.lon!==null?i(e.lat,e.lon):null),s=a.flatMap((e,t)=>o[t]===null?[]:[{ts:e.ts,zone:o[t]}]),c=0;return a.forEach((e,t)=>{if(o[t]!==null||s.length===0){n.set(e.ts,o[t]);return}for(;c+1<s.length&&Math.abs(s[c+1].ts-e.ts)<Math.abs(s[c].ts-e.ts);)c++;n.set(e.ts,s[c].zone)}),n}function ce(e,t){let n=se(e,t),r=e=>n.get(e)??null,i=new Set(e.map(e=>ae(e.ts,r(e.ts)))),a=i.size>1;return{head:a?`SHIP`:i.values().next().value??`UTC`,mixed:a,clock:e=>ie(e,r(e)),day:e=>oe(e,r(e)),offset:e=>ae(e,r(e)),dayLine:e=>`${oe(e,r(e))} · ${ae(e,r(e))}`}}var le=null;function ue(t){let[n,r]=(0,F.useState)(()=>le);return(0,F.useEffect)(()=>{let t=!0;return c(()=>import(`./tz-DxphYhHy.js`).then(t=>e(t.default,1)).then(e=>{le=e.default,t&&r(()=>e.default)}),__vite__mapDeps([0,1]),import.meta.url).catch(()=>{}),()=>{t=!1}},[]),(0,F.useMemo)(()=>ce(t,n),[t,n])}var de=e=>`lb:columns:${e}`,fe={off:[]};function pe(e){return e.key===`ts`}function Q(e,t){return pe(e)||!t.off.includes(e.key)}function me(e,t){return e.filter(e=>Q(e,t))}function he(e){return e.filter(e=>!pe(e))}function ge(e,t){return pe(t)?e:{off:Q(t,e)?[...e.off,t.key]:e.off.filter(e=>e!==t.key)}}function _e(e,t){return{off:t?[]:he(e).map(e=>e.key)}}function ve(e,t){return xe(e.off)===xe(t.off)}function ye(e){try{let t=globalThis.localStorage?.getItem(de(e));if(!t)return fe;let n=JSON.parse(t);return{off:Array.isArray(n.off)?n.off.filter(e=>typeof e==`string`):[]}}catch{return fe}}function be(e,t){try{globalThis.localStorage?.setItem(de(e),JSON.stringify(t))}catch{}}function xe(e){return[...new Set(e)].sort().join(` `)}var $=n();function Se({cols:e,applied:t,onApply:n,onCancel:r}){let[i,a]=(0,F.useState)(t),o=ve(i,t),s=he(e),c=s.filter(e=>Q(e,i)).length;return(0,$.jsxs)(`div`,{className:`lb-pick`,children:[(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Columns`}),(0,$.jsxs)(`span`,{className:`lbp-s`,children:[c,` of `,s.length]}),(0,$.jsxs)(`span`,{className:`lbp-all`,children:[(0,$.jsx)(`button`,{onClick:()=>a(_e(e,!0)),children:`All`}),(0,$.jsx)(`button`,{onClick:()=>a(_e(e,!1)),children:`None`})]})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:s.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${Q(e,i)?` on`:``}`,"aria-pressed":Q(e,i),onClick:()=>a(ge(i,e)),children:e.head},e.key))})]}),(0,$.jsxs)(`div`,{className:`lbp-act`,children:[(0,$.jsx)(`button`,{onClick:r,children:`Cancel`}),(0,$.jsx)(`button`,{className:`lbp-go`,disabled:o,onClick:()=>n(i),children:`Show these columns`})]})]})}var Ce={"1m":1,"1h":60,"6h":360,"1d":1440},we={"1m":`Every minute`,"1h":`Hourly`,"6h":`Six-hourly`,"1d":`Daily`},Te={"1m":60,"1h":48,"6h":40,"1d":30},Ee=15e3;function De(e){let t=l(),[n,i]=(0,F.useState)(0),[a,o]=(0,F.useState)(!1),[s,c]=(0,F.useState)([]),[u,d]=(0,F.useState)(null),[f,p]=(0,F.useState)(!1),[m,h]=(0,F.useState)(e);m!==e&&(h(e),i(0),o(!1));let g=Ce[e],_=Te[e]+n*Te[e],v=(0,F.useCallback)(async()=>{p(!0),d(null);try{let e=_+1,n=g===1?(await t.logbook.minutes({limit:e,order:`desc`})).rows:await t.logbook.snapshots({bucket:g,limit:e,order:`desc`});o(n.length>_),c(n.slice(0,_))}catch(e){d(e.message)}finally{p(!1)}},[g,_]);return(0,F.useEffect)(()=>{v();let e=r(v,Ee);return()=>e()},[v]),{snaps:s,err:u,busy:f,hasMore:a,loadMore:(0,F.useCallback)(()=>i(e=>e+1),[])}}function Oe(){let e=l(),[t,n]=(0,F.useState)(w()),[i,a]=(0,F.useState)([]),[o,s]=(0,F.useState)(null),[c,u]=(0,F.useState)(!1),d=(0,F.useRef)(!0),f=S(6e4),p=w(new Date(f)),h=(0,F.useMemo)(()=>m(t),[t]),g=h+24*36e5,_=t===p;(0,F.useEffect)(()=>{d.current&&t!==p&&n(p)},[p,t]);let v=(0,F.useCallback)(e=>{d.current=e===w(),n(e)},[]),y=(0,F.useCallback)(async()=>{u(!0),s(null);try{let t=await e.logbook.snapshots({from:h,to:g,limit:5e3,order:`desc`,bucket:60});a(t)}catch(e){s(e.message)}finally{u(!1)}},[h,g]);return(0,F.useEffect)(()=>{if(y(),!_)return;let e=r(y,Ee);return()=>e()},[y,_]),{dateStr:t,setDateStr:v,dayStart:h,isToday:_,snaps:i,err:o,busy:c,prevDay:(0,F.useCallback)(()=>v(w(new Date(h-864e5))),[h,v]),nextDay:(0,F.useCallback)(()=>v(w(new Date(h+864e5))),[h,v]),goToday:(0,F.useCallback)(()=>v(w()),[v])}}var ke=5e3;async function Ae(e,t,n){let r=await e({from:t,to:n,limit:5001,order:`desc`});return{rows:r.rows.slice(0,ke),truncated:r.clamped||r.rows.length>5e3,minutesFrom:r.minutesFrom}}function je(e,t,n,r=`last`){let i=l(),[a,o]=(0,F.useState)([]),[s,c]=(0,F.useState)(null),[u,d]=(0,F.useState)(!1),[f,p]=(0,F.useState)(!1),[h,g]=(0,F.useState)(!1),[_,v]=(0,F.useState)(null),[y,b]=(0,F.useState)([]),x=(0,F.useMemo)(()=>m(e),[e]),S=(0,F.useMemo)(()=>m(t)+864e5-1,[t]),C=Ce[n],w=(0,F.useCallback)(async()=>{if(Number.isNaN(x)||Number.isNaN(S)||S<x){o([]),b([]),p(!1),c(null),g(!0);return}g(!1),d(!0),c(null);try{if(b([]),C===1){let e=await Ae(e=>i.logbook.minutes(e),x,S);v(e.minutesFrom),p(e.truncated),o(e.rows);return}let e=await i.logbook.rollupHours(x,S);v(null);let t=P(e,n),a=t.map(e=>D(e,r)),s=e=>e.slice(Math.max(0,e.length-ke));p(a.length>ke),o(s(a)),r!==`last`&&b(s(t.map(e=>D(e,`last`))))}catch(e){c(e.message)}finally{d(!1),g(!0)}},[x,S,C,n,r]);return(0,F.useEffect)(()=>{w()},[w]),{snaps:a,err:s,busy:u,truncated:f,loaded:h,minutesFrom:_,plain:y}}var Me=[`1m`,`1h`,`6h`,`1d`],Ne=[{v:`csv`,name:`CSV`,note:`a file for a spreadsheet`},{v:`pdf`,name:`PDF`,note:`the page, through your printer`}],Pe=[{v:`screen`,name:`Screen`},{v:`paper`,name:`Paper`}],Fe=[`last`,`avg`,`min`,`max`];function Ie(e,t,n){return e===`pdf`?[n]:t.includes(n)?t.filter(e=>e!==n):[...t,n]}function Le(e,t){return e===`pdf`?[t[0]??`last`]:t}function Re(){return w(new Date(Date.now()-7*864e5))}function ze({initial:e,onView:t,onSave:n}){let[r,i]=(0,F.useState)(e?.from??Re()),[a,o]=(0,F.useState)(e?.to??w()),[s,c]=(0,F.useState)(e?.gran??`1h`),[l,u]=(0,F.useState)(e?.format??`csv`),[d,f]=(0,F.useState)(e?.stats??[`last`]),[p,m]=(0,F.useState)(e?.distance??!1),[h,g]=(0,F.useState)(e?.samples??!1),[_,v]=(0,F.useState)(e?.style??`screen`),y=a<r,b={from:r,to:a,gran:s,format:l,stats:Le(l,d),distance:p,samples:h,style:_},x=s!==`1m`,S=l===`pdf`,C=x&&!S&&d.length===0&&!p&&!h,T=e=>f(t=>Ie(l,t,e)),E=Le(l,d),D=e=>E.includes(e);return(0,$.jsxs)(`div`,{className:`lb-pick lb-exp`,children:[(0,$.jsxs)(`div`,{className:`lbp-books`,children:[(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Window`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:`UTC days, both ends included`})]}),(0,$.jsxs)(`div`,{className:`lbe-dates`,children:[(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`From`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:r,max:w(),onChange:e=>i(e.target.value)})]}),(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`To`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:a,max:w(),onChange:e=>o(e.target.value)})]})]})]}),(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Interval`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:`one row per`})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Me.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${s===e?` on`:``}`,onClick:()=>c(e),children:we[e]},e))})]}),(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Save as`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:Ne.find(e=>e.v===l)?.note})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Ne.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${l===e.v?` on`:``}`,onClick:()=>u(e.v),children:e.name},e.v))})]}),(0,$.jsxs)(`div`,{className:`lbp-book${S?``:` off`}`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Style`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:S?_===`screen`?`the app's own dark ink`:`white, for a printer`:`the page's ink; a file carries none`})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Pe.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${_===e.v?` on`:``}`,disabled:!S,onClick:()=>v(e.v),children:e.name},e.v))})]})]}),x&&(0,$.jsxs)(`div`,{className:`lbp-book lbp-figs`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Figures`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:S?`one: a table cell holds one number`:`one or more: a column each`})]}),(0,$.jsxs)(`div`,{className:`lbp-chips`,children:[Fe.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${D(e)?` on`:``}`,onClick:()=>T(e),children:k[e]},e)),(0,$.jsx)(`button`,{className:`lbp-c${p?` on`:``}`,disabled:S,onClick:()=>m(!p),children:`Distance`}),(0,$.jsx)(`button`,{className:`lbp-c${h?` on`:``}`,disabled:S,onClick:()=>g(!h),children:`Samples`})]})]}),y&&(0,$.jsx)(`div`,{className:`lbe-warn`,children:`That window ends before it begins.`}),C&&(0,$.jsx)(`div`,{className:`lbe-warn`,children:`Choose at least one figure to put in the file.`}),(0,$.jsxs)(`div`,{className:`lbp-act`,children:[S&&(0,$.jsx)(`button`,{disabled:y,onClick:()=>t(b),children:`View`}),(0,$.jsxs)(`button`,{className:`lbp-go`,disabled:y||C,onClick:()=>n(b),children:[`Save `,l.toUpperCase()]})]})]})}function Be({open:e,style:t,cls:n,children:r}){let[i,a]=(0,F.useState)(e);return e&&!i&&a(!0),i?(0,$.jsx)(`div`,{className:`lb-open${e?``:` shut`}${n??``}`,style:t,onAnimationEnd:t=>{t.target===t.currentTarget&&!e&&a(!1)},children:(0,$.jsx)(`div`,{className:`lb-open-in`,children:r})}):null}function Ve(e){let t=e-32-58;return Math.max(1,Math.floor(t/52))}function He(e){return e.reduce((e,t)=>e+(t.lanes??1),0)}function Ue(e,t){if(t===null||e.length===0)return e;let n=Ve(t),r=e.slice(0,1);for(let t of e.slice(1)){let e=t.lanes??1;if(e>n)break;n-=e,r.push(t)}return r}function We(e,t,n){return t===null?e:e.slice(0,Ve(t-(n?108:0)))}var Ge=180,Ke=[`1m`,`1h`,`6h`,`1d`],qe={"1m":`Last hour`,"1h":`Last 2 days`,"6h":`Last 10 days`,"1d":`Last month`};function Je({book:e}){let t=l(),[n,r]=(0,F.useState)(`live`),[i,a]=(0,F.useState)(`1h`),[o,s]=(0,F.useState)(null),[c,u]=ne((0,F.useMemo)(()=>({book:e,mode:n,gran:i,family:o}),[e,n,i,o]),Ge),{book:d,mode:f,gran:p,family:h}=c,g=n!==f,[v,y]=(0,F.useState)(()=>localStorage.getItem(`lb:windUnit`)||`kn`),b=()=>y(e=>{let t=e===`kn`?`bft`:`kn`;return localStorage.setItem(`lb:windUnit`,t),t}),x=(0,F.useRef)([]),S=(0,F.useRef)(0),[C,w]=(0,F.useState)(()=>ye(d)),[T,E]=(0,F.useState)(d);T!==d&&(E(d),w(ye(d)),x.current=[],S.current=0);let[O,k]=(0,F.useState)(!1),I=e=>{w(e),be(d,e),k(!1)},[L,R]=_(),z=(0,F.useRef)(null),B=(0,F.useRef)(null),V=(0,F.useCallback)(e=>{B.current=e,L(e)},[L]),H=(0,F.useRef)(null);(0,F.useLayoutEffect)(()=>{let e=B.current;if(!e)return;let t=()=>e.querySelectorAll(`.lb-ctrl, .lb-pick, .lb-frame`);if(u){let e=new Map;t().forEach(t=>e.set(t,t.getBoundingClientRect().width)),H.current=e;return}let n=H.current;if(H.current=null,!n||window.matchMedia(`(prefers-reduced-motion: reduce)`).matches)return;let r=parseFloat(getComputedStyle(e).getPropertyValue(`--lb-fade-in`))||0;t().forEach(e=>{let t=n.get(e);if(t===void 0||typeof e.animate!=`function`)return;let i=e.getBoundingClientRect().width;Math.abs(i-t)<1||e.animate([{maxWidth:`${t}px`},{maxWidth:`${i}px`}],{duration:r,easing:`cubic-bezier(0.32, 0.72, 0, 1)`})})},[u,c]);let[U,ee]=(0,F.useState)(!1),[K,te]=(0,F.useState)(null),[q,J]=(0,F.useState)(!1),[re,Y]=(0,F.useState)(null),[X,Z]=(0,F.useState)(null),ie={book:d,mode:n,setMode:r,gran:i,setGran:a,shownGran:p,family:o,setFamily:s,shownFamily:h,leaving:u,modeLeaving:g,lanesHold:z,groupsHold:x,chosenHold:S,windUnit:v,toggleWind:b,selection:C,picking:O,setPicking:k,applySelection:I,width:R,exporting:U,setExporting:ee,request:K,onView:e=>{te(e),r(`range`),Y(null)},onSave:async e=>{if(ee(!1),Y(null),Z(null),e.format===`pdf`){te(e),r(`range`),J(!0);return}try{let n=m(e.from),r=m(e.to)+864e5-1;if(e.gran===`1m`){let{rows:e,truncated:i}=await Ae(e=>t.logbook.minutes(e),n,r),a=me(G(W(e,v),d),C);A(M(`logbook-${d}`,n,`csv`,i?`-partial`:``),`text/csv`,j(e,a)),i&&Z(`That window holds more than ${ke} minutes, so the file stops at the most recent ${ke} and its name ends in -partial. A longer interval covers the same days in fewer rows.`);return}let i=P(await t.logbook.rollupHours(n,r),e.gran),a=e.stats.map(e=>({stat:e,cols:me(G(W(i.map(t=>D(t,e)),v),d),C)})).filter(e=>e.cols.length>1);A(M(`logbook-${d}`,n,`csv`),`text/csv`,N(i,a,{distance:e.distance,samples:e.samples}))}catch(e){Y(e.message)}},saveErr:re,saveNote:X};return(0,$.jsxs)(`div`,{className:`lb`,ref:V,children:[(0,$.jsx)(`style`,{children:`@media print { @page { size: A4 landscape; } }`}),f===`live`?(0,$.jsx)(_t,{...ie}):f===`day`?(0,$.jsx)(vt,{...ie}):(0,$.jsx)(wt,{...ie,req:K,printing:q,donePrinting:()=>J(!1)})]})}function Ye({mode:e,setMode:t}){return(0,$.jsxs)(`div`,{className:`seg`,children:[(0,$.jsx)(`button`,{className:e===`live`?`on`:``,onClick:()=>t(`live`),children:`Live`}),(0,$.jsx)(`button`,{className:e===`day`?`on`:``,onClick:()=>t(`day`),children:`Day`})]})}function Xe({leaving:e,children:t}){return(0,$.jsx)(`div`,{className:`lb-win${e?` leaving`:``}`,children:t})}function Ze({groups:e,family:t,setFamily:n}){if(e.length<2)return null;let r=e.find(e=>e.tab===t)??e[0];return(0,$.jsx)(`div`,{className:`seg`,children:e.map(e=>(0,$.jsx)(`button`,{className:e.tab===r.tab?`on`:``,onClick:()=>n(e.tab),children:e.head},e.tab))})}function Qe(e,t,n){if(e===null||m(t.from)>=e)return null;let r=new Date(e).toLocaleDateString(void 0,{day:`numeric`,month:`short`}),i=n[n.length-1];return`Minutes reach back to ${r}.${i!==void 0&&i.ts<e?` Earlier days in this window read one row per hour.`:``}`}function $e(e,t,n){let r=k[e].toLowerCase(),i=t.length===1?t[0]:`${t.slice(0,-1).join(`, `)} and ${t[t.length-1]}`,a=n.some(e=>e.lat!==null&&e.lon!==null),o=t.length===1;return`${i} ${o?`has`:`have`} no ${r}, so on each row ${o?`it carries`:`they carry`} the reading that window closed on${a?`, as the position does`:``}.`}function et(e,t){if(t.length===0)return e;let n=new Map(t.map(e=>[e.ts,e]));return e.map(e=>{let t=n.get(e.ts);if(!t)return e;let r={...e};for(let[e,n]of Object.entries(t))e!==`path_values`&&(r[e]===null||r[e]===void 0)&&n!=null&&(r[e]=n);if(t.path_values){let n={...e.path_values??{}};for(let[e,r]of Object.entries(t.path_values))(n[e]===void 0||n[e]===null)&&(n[e]=r);r.path_values=n}return r})}function tt(e){return m(e.to)+864e5-1>=Date.now()&&e.gran!==`1m`?`No row has closed at this interval yet. A shorter interval shows today's.`:`Nothing was logged between these dates.`}function nt(e,t,n){return e.length>1||t===null?lt(e):{"--lb-cols":n.current??Ve(t)}}function rt({what:e}){return(0,$.jsxs)(`div`,{className:`sp-empty`,children:[(0,$.jsx)(`div`,{className:`em-t`,children:`No snapshots`}),(0,$.jsx)(`div`,{className:`em-s`,children:e})]})}var it=(e,t)=>`u:${e}:${t}`;function at(e,t,n,r,i,a,o,s,c,l=!0){let u=st(e,t,n,r,i,a,o,s,c,l);if(t!==`engine`||u.groups.length<2)return u;let d=u,f=ot(u);for(let o of u.groups){if(o===u.group||o.tab===a)continue;let s=st(e,t,n,r,i,o.tab,{current:null},{current:[]},{current:0},l),c=ot(s);c>f&&(d=s,f=c)}return d===u?u:{...u,block:d.block,cls:d.cls}}function ot(e){let t=Math.max(1,Number(e.block[`--lb-cols`]??1));return 58+(e.cls.includes(`u`)?108:0)+t*164}function st(e,t,n,r,i,a,o,s,c,l){let u=t===`engine`?K(e):[];u.length>0&&(s.current=u);let d=u.length===0&&e.length===0?s.current:u,f=u.find(e=>e.tab===a)??u[0];if(f&&f.units.length>1){let e=f.metrics.map(e=>({key:it(f.tab,e.key),head:e.head})),t=f.metrics.filter(e=>Q({key:it(f.tab,e.key)},r)),n=l?We(t,i,!0):t,a={...f,metrics:n};return o.current=Math.max(1,n.length),t.length>0&&(c.current=t.length),{groups:d,group:a,drawn:[],pick:e,btn:{shown:n.length,chosen:t.length,kept:c.current,offered:e.length},block:{"--lb-cols":Math.max(1,n.length)},cls:` u`}}let p=G(W(e,n),t),m=f?p.filter(e=>e.key===`ts`||e.tab===f.tab):p,h=me(m,r),g=l?Ue(h,i):h;return g.length>1&&(o.current=He(g.slice(1))),h.length>1&&(c.current=h.length-1),{groups:d,group:null,drawn:g,pick:m,btn:{shown:g.length-1,chosen:h.length-1,kept:c.current,offered:m.length-1},block:nt(g,i,o),cls:``}}function ct(e){return{"--lb-cols":Math.max(1,e.metrics.length)}}function lt(e){return{"--lb-cols":He(e.slice(1))}}function ut(e){return(e.lanes??1)>1?` w${e.lanes}`:``}function dt(e,t){return t===`last`?we[e]:`${we[e]} · ${k[t]}`}function ft(e,t,n,r){return r===0?String(n):e<t?`${e} of ${t}`:String(t)}function pt({shown:e,chosen:t,kept:n,offered:r,open:i,onOpen:a}){let o=r===0;return(0,$.jsxs)(`button`,{className:`lb-colbtn${i?` on`:``}${o?` quiet`:``}`,onClick:a,disabled:o,children:[`Columns · `,(0,$.jsx)(`b`,{children:ft(e,t,n,r)})]})}function mt({open:e,onOpen:t}){return(0,$.jsx)(`button`,{className:`lb-colbtn${e?` on`:``}`,onClick:t,children:`View`})}function ht({cols:e,group:t,times:n,toggleWind:r}){if(t){let e=t.units.length>1;return(0,$.jsxs)(`div`,{className:`lb-cols${e?` u`:``}`,style:ct(t),children:[(0,$.jsx)(`span`,{children:n.head}),e&&(0,$.jsx)(`span`,{className:`un`,children:`Unit`}),t.metrics.map(e=>(0,$.jsxs)(`span`,{children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))]})}return(0,$.jsx)(`div`,{className:`lb-cols`,style:lt(e),children:e.map(e=>e.tappable?(0,$.jsxs)(`span`,{className:`tap${ut(e)}`,onClick:r,title:`Tap: knots ⇄ Beaufort`,children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key):(0,$.jsxs)(`span`,{className:ut(e).trim(),children:[e.key===`ts`?n.head:e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))})}function gt({of:e}){return(0,$.jsx)(`b`,{className:`lb-u`,children:e===void 0||e===``?`\xA0`:e})}function _t({book:e,mode:t,setMode:n,gran:r,setGran:i,shownGran:a,family:o,setFamily:s,shownFamily:c,leaving:l,modeLeaving:u,lanesHold:d,groupsHold:f,chosenHold:p,windUnit:m,toggleWind:h,selection:g,picking:_,setPicking:v,applySelection:y,width:b,exporting:x,setExporting:S,request:C,onView:w,onSave:T,saveErr:E,saveNote:D}){let{snaps:O,err:k,busy:A,hasMore:j,loadMore:M}=De(a),N=ue(O),P=(0,F.useMemo)(()=>Tt(O,N,!1),[O,N]),{groups:I,group:L,drawn:R,pick:z,btn:B,block:V,cls:H}=at(O,e,m,g,b,c,d,f,p);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${H}`,style:V,children:[(0,$.jsx)(Ye,{mode:t,setMode:n}),(0,$.jsx)(Xe,{leaving:u,children:(0,$.jsx)(`div`,{className:`seg`,children:Ke.map(e=>(0,$.jsx)(`button`,{className:r===e?`on`:``,onClick:()=>i(e),children:e},e))})}),(0,$.jsx)(Ze,{groups:I,family:o,setFamily:s}),(0,$.jsxs)(`div`,{className:`lb-acts`,children:[(0,$.jsx)(pt,{shown:B.shown,chosen:B.chosen,kept:B.kept,offered:B.offered,open:_,onOpen:()=>v(!_)}),(0,$.jsx)(mt,{open:x,onOpen:()=>S(!x)})]})]}),(0,$.jsx)(Be,{open:_,style:V,cls:H,children:(0,$.jsx)(Se,{cols:z,applied:g,onApply:y,onCancel:()=>v(!1)})}),(0,$.jsx)(Be,{open:x,style:V,cls:H,children:(0,$.jsx)(ze,{initial:C??void 0,onView:w,onSave:T})}),E&&(0,$.jsx)(`div`,{className:`lb-err`,children:E}),D&&(0,$.jsx)(`div`,{className:`lb-note`,children:D}),(0,$.jsxs)(`div`,{className:`lb-frame${P?` dated`:``}${N.mixed?` mixed`:``}${H}${l?` leaving`:``}`,style:V,children:[(0,$.jsx)(xt,{book:e,window:qe[a],interval:we[a],times:N}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(R),children:[(0,$.jsx)(`span`,{children:qe[a]}),(0,$.jsx)(`b`,{children:O.length})]}),(0,$.jsx)(ht,{cols:R,group:L,times:N,toggleWind:h}),k&&(0,$.jsx)(`div`,{className:`lb-err`,children:k}),!A&&!k&&O.length===0?(0,$.jsx)(rt,{what:`Nothing was logged in this window (${qe[a].toLowerCase()}).`}):(0,$.jsx)(Et,{snaps:O,cols:R,group:L,times:N,lined:P,footer:j?(0,$.jsx)(`button`,{className:`lb-more`,onClick:M,disabled:A,children:A?`Loading…`:`Load ${Te[a]} more`}):null}),(0,$.jsx)(St,{})]})]})}function vt({book:e,mode:t,setMode:n,family:r,setFamily:i,shownFamily:a,leaving:o,modeLeaving:s,lanesHold:c,groupsHold:l,chosenHold:u,windUnit:d,toggleWind:f,selection:p,picking:m,setPicking:h,applySelection:g,width:_,exporting:v,setExporting:y,request:b,onView:x,onSave:S,saveErr:C,saveNote:T}){let{dateStr:E,setDateStr:D,isToday:O,snaps:k,err:A,busy:j,prevDay:M,nextDay:N,goToday:P}=Oe(),I=ue(k),L=(0,F.useMemo)(()=>Tt(k,I,`turns`),[k,I]),{groups:R,group:z,drawn:B,pick:V,btn:H,block:U,cls:W}=at(k,e,d,p,_,a,c,l,u),G=`${O?`Today · ${new Date(E).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,timeZone:`UTC`})}`:new Date(E).toLocaleDateString(`en-GB`,{weekday:`short`,day:`2-digit`,month:`short`,timeZone:`UTC`}).replace(/,/g,``)} · UTC day`;return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${W}`,style:U,children:[(0,$.jsx)(Ye,{mode:t,setMode:n}),(0,$.jsx)(Xe,{leaving:s,children:(0,$.jsxs)(`div`,{className:`lb-date`,children:[(0,$.jsx)(`button`,{className:`lb-step`,onClick:M,"aria-label":`Previous day`,children:`‹`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:E,max:w(),onChange:e=>D(e.target.value)}),(0,$.jsx)(`button`,{className:`lb-step`,onClick:N,disabled:O,"aria-label":`Next day`,children:`›`}),(0,$.jsx)(`button`,{onClick:P,disabled:O,children:`Now`})]})}),(0,$.jsx)(Ze,{groups:R,family:r,setFamily:i}),(0,$.jsxs)(`div`,{className:`lb-acts`,children:[(0,$.jsx)(pt,{shown:H.shown,chosen:H.chosen,kept:H.kept,offered:H.offered,open:m,onOpen:()=>h(!m)}),(0,$.jsx)(mt,{open:v,onOpen:()=>y(!v)})]})]}),(0,$.jsx)(Be,{open:m,style:U,cls:W,children:(0,$.jsx)(Se,{cols:V,applied:p,onApply:g,onCancel:()=>h(!1)})}),(0,$.jsx)(Be,{open:v,style:U,cls:W,children:(0,$.jsx)(ze,{initial:b??void 0,onView:x,onSave:S})}),C&&(0,$.jsx)(`div`,{className:`lb-err`,children:C}),T&&(0,$.jsx)(`div`,{className:`lb-note`,children:T}),(0,$.jsxs)(`div`,{className:`lb-frame${L?` dated`:``}${I.mixed?` mixed`:``}${W}${o?` leaving`:``}`,style:U,children:[(0,$.jsx)(xt,{book:e,window:G,interval:we[`1h`],times:I}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(B),children:[(0,$.jsx)(`span`,{children:G}),(0,$.jsx)(`b`,{children:k.length})]}),(0,$.jsx)(ht,{cols:B,group:z,times:I,toggleWind:f}),A&&(0,$.jsx)(`div`,{className:`lb-err`,children:A}),!j&&k.length===0?(0,$.jsx)(rt,{what:`No telemetry was logged for this day.`}):(0,$.jsx)(Et,{snaps:k,cols:B,group:z,times:I,footer:null,lined:L}),(0,$.jsx)(St,{})]})]})}function yt(){let e=new Date,t=e.toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,year:`numeric`,timeZone:`UTC`}),n=e=>String(e).padStart(2,`0`);return`${t.toUpperCase()} · ${n(e.getUTCHours())}:${n(e.getUTCMinutes())} UTC`}var bt={bridge:`CHIEF OFFICER`,engine:`CHIEF ENGINEER`};function xt({book:e,window:t,interval:n,times:r}){let i=r.mixed?`SHIP'S TIME · OFFSET ON EACH DATED LINE`:r.head===`UTC`?`UTC`:`SHIP'S TIME · ${r.head}`;return(0,$.jsxs)(`div`,{className:`lb-print-hd`,children:[(0,$.jsxs)(`div`,{className:`ph-id`,children:[(0,$.jsxs)(`span`,{className:`sp-lockup`,children:[(0,$.jsx)(C,{className:`sp-glyph`}),(0,$.jsx)(`span`,{className:`ph-wm`,children:`Siparu`})]}),(0,$.jsxs)(`span`,{className:`ph-book`,children:[`LOGBOOK · `,(0,$.jsx)(`b`,{children:e.toUpperCase()}),` · `,bt[e]]})]}),(0,$.jsxs)(`div`,{className:`ph-meta`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`GENERATED`}),(0,$.jsx)(`b`,{children:yt()})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`WINDOW`}),(0,$.jsx)(`b`,{children:`${t} · ${n}`.toUpperCase()})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`CLOCK`}),(0,$.jsx)(`b`,{children:i})]})]})]})}function St(){return(0,$.jsx)(`div`,{className:`lb-print-ft`,children:(0,$.jsx)(`span`,{children:`siparu.app`})})}function Ct(e,t){let n=(e,t)=>new Date(e).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,...t?{year:`numeric`}:{},timeZone:`UTC`});return e===t?`${n(t,!0)} · UTC day`:`${n(e,!1)} - ${n(t,!0)} · UTC days`}function wt({book:e,req:t,setMode:n,family:r,setFamily:i,shownFamily:a,leaving:o,modeLeaving:s,lanesHold:c,groupsHold:l,chosenHold:u,windUnit:d,toggleWind:f,selection:p,picking:m,setPicking:h,applySelection:g,width:_,exporting:v,setExporting:y,request:b,onView:x,onSave:S,saveErr:C,saveNote:T,printing:D,donePrinting:k}){let A={from:w(),to:w(),gran:`1h`,format:`csv`,stats:[`last`],distance:!1,samples:!1,style:`screen`},j=t??A,M=j.stats[0]??`last`,{snaps:N,err:P,busy:I,truncated:L,loaded:R,minutesFrom:z,plain:B}=je(j.from,j.to,j.gran,M),V=(0,F.useMemo)(()=>et([...N].sort((e,t)=>e.ts-t.ts),B),[N,B]),H=ue(V),{groups:U,group:ee,drawn:K,pick:te,btn:ne,block:q,cls:J}=at(V,e,d,p,_,a,c,l,u,!1),re=(0,F.useCallback)(()=>k(),[k]);(0,F.useEffect)(()=>{!D||!R||I||(re(),O(E(`Siparu-Logbook`,Date.now()),j.style))},[D,R,I,re,j.style]);let Y=Ct(j.from,j.to),X=dt(j.gran,M),Z=(0,F.useMemo)(()=>{if(B.length===0)return[];let t=t=>me(G(W(t,d),e),p).map(e=>e.head),n=new Set(t(N));return t(B).filter(e=>!n.has(e))},[B,N,d,e,p]);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${J}`,style:q,children:[(0,$.jsx)(Ye,{mode:`range`,setMode:n}),(0,$.jsx)(Xe,{leaving:s,children:(0,$.jsxs)(`button`,{className:`lb-colbtn on`,onClick:()=>y(!v),children:[Y,` · `,(0,$.jsx)(`b`,{children:X})]})}),(0,$.jsx)(Ze,{groups:U,family:r,setFamily:i}),(0,$.jsx)(`div`,{className:`lb-acts`,children:(0,$.jsx)(pt,{shown:ne.shown,chosen:ne.chosen,kept:ne.kept,offered:ne.offered,open:m,onOpen:()=>h(!m)})})]}),(0,$.jsx)(Be,{open:m,style:q,cls:J,children:(0,$.jsx)(Se,{cols:te,applied:p,onApply:g,onCancel:()=>h(!1)})}),(0,$.jsx)(Be,{open:v,style:q,cls:J,children:(0,$.jsx)(ze,{initial:b??void 0,onView:x,onSave:S})}),C&&(0,$.jsx)(`div`,{className:`lb-err`,children:C}),T&&(0,$.jsx)(`div`,{className:`lb-note`,children:T}),(0,$.jsxs)(`div`,{className:`lb-frame dated${H.mixed?` mixed`:``}${J}${o?` leaving`:``}`,style:q,children:[(0,$.jsx)(xt,{book:e,window:Y,interval:X,times:H}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(K),children:[(0,$.jsxs)(`span`,{children:[Y,` · `,X]}),(0,$.jsx)(`b`,{children:L?`${N.length} of more`:N.length})]}),(0,$.jsx)(ht,{cols:K,group:ee,times:H,toggleWind:f}),P&&(0,$.jsx)(`div`,{className:`lb-err`,children:P}),Z.length>0&&(0,$.jsx)(`div`,{className:`lb-note`,children:$e(M,Z,N)}),L&&(0,$.jsxs)(`div`,{className:`lb-note`,children:[`This window holds more than `,5e3,` rows. The most recent `,5e3,` are here; a longer interval covers the same days in fewer.`]}),Qe(z,j,N)&&(0,$.jsx)(`div`,{className:`lb-note`,children:Qe(z,j,N)}),!I&&V.length===0?(0,$.jsx)(rt,{what:tt(j)}):(0,$.jsx)(Et,{snaps:V,cols:K,group:ee,times:H,footer:null,lined:!0}),(0,$.jsx)(St,{})]})]})}function Tt(e,t,n){return n===!0?!0:n===!1&&!t.mixed?!1:new Set(e.map(e=>t.dayLine(e.ts))).size>1}function Et({snaps:e,cols:t,group:n,times:r,footer:i,lined:a}){let o=[],s=null;for(let i of e){if(a){let e=r.dayLine(i.ts);e!==s&&(o.push((0,$.jsx)(Dt,{day:r.day(i.ts),offset:r.offset(i.ts),cols:t,group:n},`sep-${i.ts}`)),s=e)}o.push(n?(0,$.jsx)(Ot,{s:i,group:n,times:r},i.ts):(0,$.jsx)(kt,{s:i,cols:t,times:r},i.ts))}return(0,$.jsxs)(`div`,{className:`lb-rows`,style:n?ct(n):lt(t),children:[o,i]})}function Dt({day:e,offset:t,cols:n,group:r}){let i=r!==null&&r.units.length>1,a=r?r.metrics.map(e=>({key:e.key,head:e.head,unit:e.unit,cls:``})):n.slice(1).map(e=>({key:e.key,head:e.head,unit:e.unit,cls:ut(e).trim()}));return(0,$.jsxs)(`div`,{className:`lb-sep${i?` u`:``}`,children:[(0,$.jsxs)(`span`,{className:`sd`,children:[e,t&&(0,$.jsxs)(`span`,{className:`so`,children:[` · `,t]})]}),i&&(0,$.jsx)(`span`,{className:`sh`}),a.map(e=>(0,$.jsxs)(`span`,{className:e.cls?`sh ${e.cls}`:`sh`,children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))]})}function Ot({s:e,group:t,times:n}){let r=t.units.length>1;return(0,$.jsx)($.Fragment,{children:t.units.map((i,a)=>(0,$.jsxs)(`div`,{className:`lb-row${r?` u`:``}${a>0?` cont`:``}`,children:[(0,$.jsx)(`span`,{className:`tm`,children:n.clock(e.ts)}),r&&(0,$.jsx)(`span`,{className:`un`,children:i.head}),t.metrics.map(t=>(0,$.jsx)(`span`,{className:`v`,children:te(e,i,t)},t.key))]},i.key))})}function kt({s:e,cols:t,times:n}){return(0,$.jsx)(`div`,{className:`lb-row`,children:t.map((t,r)=>(0,$.jsx)(`span`,{className:r===0?`tm`:`${t.dim?`v dim`:`v`}${ut(t)}`,children:t.key===`ts`?n.clock(e.ts):t.cell(e)},t.key))})}var At=[{to:`/logbook/bridge`,name:`Bridge`,keeper:`Chief officer`,holds:`Position, course and speed, the weather she ran in and the water under her.`,Icon:g},{to:`/logbook/engine`,name:`Engine`,keeper:`Chief engineer`,holds:`Engines, generators and tanks, as she reported them.`,Icon:b}];function jt(){let e=v();return(0,$.jsx)(`div`,{className:`lb-door`,children:(0,$.jsx)(`div`,{className:`lbd-cards`,children:At.map(({to:t,name:n,keeper:r,holds:i,Icon:a})=>(0,$.jsxs)(d,{to:e(t),replace:!0,className:`lbd-card`,children:[(0,$.jsx)(a,{size:42}),(0,$.jsx)(`span`,{className:`lbd-n`,children:n}),(0,$.jsx)(`span`,{className:`lbd-k`,children:r}),(0,$.jsx)(`span`,{className:`lbd-h`,children:i}),(0,$.jsxs)(`span`,{className:`lbd-go`,children:[`Open `,(0,$.jsx)(x,{size:15})]})]},t))})})}function Mt({book:e}){return e?(0,$.jsx)(Je,{book:e}):(0,$.jsx)(jt,{})}export{Mt as default};
|
|
2
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-CaR_m4Xc.js";import{t as r}from"./visibleInterval-CFxPzgzx.js";import{A as i,C as a,D as o,E as s,F as c,I as l,O as u,P as d,T as f,_ as p,c as m,d as h,j as g,k as _,l as v,o as y,p as b,s as x,v as S,w as C,x as w,y as T}from"./index-DPNvHdqr.js";import{a as E,d as D,i as O,l as k,n as A,o as j,r as M,t as N,u as P}from"./export-CGdOfqNp.js";var F=e(t(),1),I={key:`ts`,head:`UTC`,book:`bridge`,cell:()=>``};function L(e,t,n,r){if(e===null)return`·`;let i=Math.abs(e),a=Math.floor(i),o=(i-a)*60;return`${String(a).padStart(t,`0`)}°${o.toFixed(3).padStart(6,`0`)}' ${e<0?r:n}`}function R(e){return[{col:{key:`lat`,head:`LAT`,book:`bridge`,lanes:2,cell:e=>L(e.lat,2,`N`,`S`)},has:e=>e.lat!==null},{col:{key:`lon`,head:`LON`,book:`bridge`,lanes:2,cell:e=>L(e.lon,3,`E`,`W`)},has:e=>e.lon!==null},{col:{key:`sog`,head:`SOG`,book:`bridge`,unit:`kn`,cell:e=>w(u(e.sog),1)},has:e=>e.sog!==null},{col:{key:`cog`,head:`COG`,book:`bridge`,cell:e=>{let t=o(e.cog);return t===null?`·`:Math.round(t)+`°`}},has:e=>e.cog!==null},{col:{key:`hdg`,head:`HDG`,book:`bridge`,cell:e=>{let t=o(e.heading_true??e.heading_mag);return t===null?`·`:Math.round(t)+`°`}},has:e=>(e.heading_true??e.heading_mag)!==null},{col:{key:`wind`,head:e===`kn`?`TWS`:`BFT`,book:`bridge`,unit:e===`kn`?`kn`:void 0,tappable:!0,cell:t=>{let n=f(t.wind_speed_true);return n===null?`·`:String(e===`kn`?Math.round(n):C(n)??`·`)}},has:e=>e.wind_speed_true!==null},{col:{key:`awa`,head:`AWA`,book:`bridge`,cell:e=>{let t=o(e.wind_angle_apparent);if(t===null)return`·`;let n=(t+180)%360-180;return`${Math.abs(Math.round(n))}°${n<0?`P`:`S`}`}},has:e=>e.wind_angle_apparent!==null},{col:{key:`baro`,head:`BARO`,book:`bridge`,unit:`hPa`,dim:!0,cell:e=>{let t=s(e.air_pressure_pa);return t===null?`·`:String(Math.round(t))}},has:e=>e.air_pressure_pa!==null},{col:{key:`air`,head:`AIR`,book:`bridge`,unit:`°C`,cell:e=>w(a(e.air_temp_k),1)},has:e=>e.air_temp_k!==null},{col:{key:`sea`,head:`SEA`,book:`bridge`,unit:`°C`,cell:e=>w(a(e.water_temp_k),1)},has:e=>e.water_temp_k!==null},{col:{key:`depth`,head:`DEP`,book:`bridge`,unit:`m`,cell:e=>e.depth===null?`·`:e.depth.toFixed(1)},has:e=>e.depth!==null}]}var z={Revolutions:`RPM`,Temperature:`TEMP`,"Oil pressure":`OIL`,"Oil temperature":`OILT`,"Coolant temperature":`COOL`,"Coolant pressure":`COOLP`,"Exhaust temperature":`EXH`,"Intake manifold temperature":`INTK`,"Boost pressure":`BOOST`,"Engine load":`LOAD`,"Engine torque":`TORQ`,"Run time":`HRS`,"Fuel rate":`FUEL`,"Fuel per mile":`L/NM`,"Fuel used (since reset)":`USED`,"Fuel pressure":`FUELP`,"Alternator voltage":`ALT`,"Gearbox oil temperature":`GBOXT`,"Gearbox oil pressure":`GBOXP`,"Current level":`LEVEL`,Voltage:`VOLT`,Current:`AMP`};function B(e){return z[e]??e.split(` `)[0].toUpperCase()}function V(e){return e.sub===null?e.tab===`tanks`?`Current level`:null:e.sub}function H(e){let t=/^(Engine|Generator|Fuel|Fresh water|Black water|Grey water|Lubrication)\s+(\S+)$/.exec(e);return t?`${t[1].split(` `).map(e=>e[0]).join(``)}${t[2]}`.toUpperCase():e.slice(0,1).toUpperCase()}function U(e){let t=[];for(let n of e)for(let e of Object.keys(n.path_values??{}))t.includes(e)||t.push(e);let n=[];for(let e of t){let t=_(e);if(!t)continue;let r=V(t);r!==null&&n.push({path:e,d:{...t,sub:r}})}let r=new Map;for(let{d:e}of n)r.has(e.tab)||r.set(e.tab,new Set),r.get(e.tab).add(e.label);let a=[];for(let{path:e,d:t}of n){let n=B(t.sub);a.push({col:{key:`p:${e}`,head:r.get(t.tab).size>1?`${H(t.label)} ${n}`:n,book:`engine`,tab:t.tab,unit:g(e),cell:t=>{let n=t.path_values?.[e];if(typeof n!=`number`)return`·`;let r=i(e,n).value;return Number.isFinite(r)?Number.isInteger(r)?String(r):r.toFixed(1):`·`}},has:t=>typeof t.path_values?.[e]==`number`})}return a}function W(e,t){return[I,...[...R(t),...U(e)].filter(t=>e.some(t.has)).map(e=>e.col)]}function G(e,t){return e.filter(e=>e.key===`ts`||e.book===t)}var ee={engine:`ENGINES`,generator:`GENERATORS`,tanks:`TANKS`};function K(e){let t=[],n=new Map,r=new Map;for(let i of e)for(let e of Object.keys(i.path_values??{})){let i=_(e);if(!i)continue;let a=V(i);if(a===null)continue;n.has(i.tab)||(t.push(i.tab),n.set(i.tab,new Map),r.set(i.tab,[]));let o=n.get(i.tab);o.has(i.label)||o.set(i.label,new Map),o.get(i.label).set(a,e);let s=r.get(i.tab);s.includes(a)||s.push(a)}return t.map(e=>{let t=[...n.get(e)].map(([e,t])=>({key:e,head:e.toUpperCase(),paths:Object.fromEntries(t)})),i=r.get(e).map(e=>{let n=t.map(t=>t.paths[e]).find(e=>e!==void 0);return{key:e,head:B(e),unit:n===void 0?``:g(n)}});return{tab:e,head:ee[e]??e.toUpperCase(),units:t,metrics:i}})}function te(e,t,n){let r=t.paths[n.key];if(r===void 0)return`·`;let a=e.path_values?.[r];if(typeof a!=`number`)return`·`;let o=i(r,a).value;return Number.isFinite(o)?Number.isInteger(o)?String(o):o.toFixed(1):`·`}function ne(e,t){let[n,r]=(0,F.useState)(e),[i,a]=(0,F.useState)(!1);return(0,F.useEffect)(()=>{if(e===n)return;a(!0);let i=setTimeout(()=>{r(e),a(!1)},t);return()=>clearTimeout(i)},[e,n,t]),[n,i]}var q=new Map;function J(e,t,n){let r=`${t}|${e}`,i=q.get(r);if(i===void 0){try{i=new Intl.DateTimeFormat(`en-GB`,{...n,timeZone:e})}catch{i=null}q.set(r,i)}return i}var re={hour:`2-digit`,minute:`2-digit`,hourCycle:`h23`},Y={hour:`2-digit`,timeZoneName:`shortOffset`},X={weekday:`short`,day:`2-digit`,month:`short`,year:`numeric`},Z=e=>e!==null&&J(e,`clock`,re)&&J(e,`offset`,Y)&&J(e,`day`,X)?e:`UTC`;function ie(e,t){return J(Z(t),`clock`,re).format(e)}function ae(e,t){let n=J(Z(t),`offset`,Y);if(!n)return`UTC`;let r=(n.formatToParts(e).find(e=>e.type===`timeZoneName`)?.value??``).replace(/^(GMT|UTC)/,``);return/[1-9]/.test(r)?`UTC${r}`:`UTC`}function oe(e,t){return J(Z(t),`day`,X).format(e).replace(/,\s*/,` · `).toUpperCase()}function se(e,t){let n=new Map,r=new Map,i=(e,n)=>{let i=`${Math.round(e*10)},${Math.round(n*10)}`,a=r.get(i);if(a===void 0){try{a=t(e,n)}catch{a=null}r.set(i,a)}return a},a=[...e].sort((e,t)=>e.ts-t.ts),o=a.map(e=>t!==null&&e.lat!==null&&e.lon!==null?i(e.lat,e.lon):null),s=a.flatMap((e,t)=>o[t]===null?[]:[{ts:e.ts,zone:o[t]}]),c=0;return a.forEach((e,t)=>{if(o[t]!==null||s.length===0){n.set(e.ts,o[t]);return}for(;c+1<s.length&&Math.abs(s[c+1].ts-e.ts)<Math.abs(s[c].ts-e.ts);)c++;n.set(e.ts,s[c].zone)}),n}function ce(e,t){let n=se(e,t),r=e=>n.get(e)??null,i=new Set(e.map(e=>ae(e.ts,r(e.ts)))),a=i.size>1;return{head:a?`SHIP`:i.values().next().value??`UTC`,mixed:a,clock:e=>ie(e,r(e)),day:e=>oe(e,r(e)),offset:e=>ae(e,r(e)),dayLine:e=>`${oe(e,r(e))} · ${ae(e,r(e))}`}}var le=null;function ue(t){let[n,r]=(0,F.useState)(()=>le);return(0,F.useEffect)(()=>{let t=!0;return l(()=>import(`./tz-DxphYhHy.js`).then(t=>e(t.default,1)).then(e=>{le=e.default,t&&r(()=>e.default)}),__vite__mapDeps([0,1]),import.meta.url).catch(()=>{}),()=>{t=!1}},[]),(0,F.useMemo)(()=>ce(t,n),[t,n])}var de=e=>`lb:columns:${e}`,fe={off:[]};function pe(e){return e.key===`ts`}function Q(e,t){return pe(e)||!t.off.includes(e.key)}function me(e,t){return e.filter(e=>Q(e,t))}function he(e){return e.filter(e=>!pe(e))}function ge(e,t){return pe(t)?e:{off:Q(t,e)?[...e.off,t.key]:e.off.filter(e=>e!==t.key)}}function _e(e,t){return{off:t?[]:he(e).map(e=>e.key)}}function ve(e,t){return xe(e.off)===xe(t.off)}function ye(e){try{let t=globalThis.localStorage?.getItem(de(e));if(!t)return fe;let n=JSON.parse(t);return{off:Array.isArray(n.off)?n.off.filter(e=>typeof e==`string`):[]}}catch{return fe}}function be(e,t){try{globalThis.localStorage?.setItem(de(e),JSON.stringify(t))}catch{}}function xe(e){return[...new Set(e)].sort().join(` `)}var $=n();function Se({cols:e,applied:t,onApply:n,onCancel:r}){let[i,a]=(0,F.useState)(t),o=ve(i,t),s=he(e),c=s.filter(e=>Q(e,i)).length;return(0,$.jsxs)(`div`,{className:`lb-pick`,children:[(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Columns`}),(0,$.jsxs)(`span`,{className:`lbp-s`,children:[c,` of `,s.length]}),(0,$.jsxs)(`span`,{className:`lbp-all`,children:[(0,$.jsx)(`button`,{onClick:()=>a(_e(e,!0)),children:`All`}),(0,$.jsx)(`button`,{onClick:()=>a(_e(e,!1)),children:`None`})]})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:s.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${Q(e,i)?` on`:``}`,"aria-pressed":Q(e,i),onClick:()=>a(ge(i,e)),children:e.head},e.key))})]}),(0,$.jsxs)(`div`,{className:`lbp-act`,children:[(0,$.jsx)(`button`,{onClick:r,children:`Cancel`}),(0,$.jsx)(`button`,{className:`lbp-go`,disabled:o,onClick:()=>n(i),children:`Show these columns`})]})]})}var Ce={"1m":1,"1h":60,"6h":360,"1d":1440},we={"1m":`Every minute`,"1h":`Hourly`,"6h":`Six-hourly`,"1d":`Daily`},Te={"1m":60,"1h":48,"6h":40,"1d":30},Ee=15e3;function De(e){let t=d(),[n,i]=(0,F.useState)(0),[a,o]=(0,F.useState)(!1),[s,c]=(0,F.useState)([]),[l,u]=(0,F.useState)(null),[f,p]=(0,F.useState)(!1),[m,h]=(0,F.useState)(e);m!==e&&(h(e),i(0),o(!1));let g=Ce[e],_=Te[e]+n*Te[e],v=(0,F.useCallback)(async()=>{p(!0),u(null);try{let e=_+1,n=g===1?(await t.logbook.minutes({limit:e,order:`desc`})).rows:await t.logbook.snapshots({bucket:g,limit:e,order:`desc`});o(n.length>_),c(n.slice(0,_))}catch(e){u(e.message)}finally{p(!1)}},[g,_]);return(0,F.useEffect)(()=>{v();let e=r(v,Ee);return()=>e()},[v]),{snaps:s,err:l,busy:f,hasMore:a,loadMore:(0,F.useCallback)(()=>i(e=>e+1),[])}}function Oe(){let e=d(),[t,n]=(0,F.useState)(T()),[i,a]=(0,F.useState)([]),[o,s]=(0,F.useState)(null),[c,l]=(0,F.useState)(!1),u=(0,F.useRef)(!0),f=b(6e4),p=T(new Date(f)),m=(0,F.useMemo)(()=>S(t),[t]),h=m+24*36e5,g=t===p;(0,F.useEffect)(()=>{u.current&&t!==p&&n(p)},[p,t]);let _=(0,F.useCallback)(e=>{u.current=e===T(),n(e)},[]),v=(0,F.useCallback)(async()=>{l(!0),s(null);try{let t=await e.logbook.snapshots({from:m,to:h,limit:5e3,order:`desc`,bucket:60});a(t)}catch(e){s(e.message)}finally{l(!1)}},[m,h]);return(0,F.useEffect)(()=>{if(v(),!g)return;let e=r(v,Ee);return()=>e()},[v,g]),{dateStr:t,setDateStr:_,dayStart:m,isToday:g,snaps:i,err:o,busy:c,prevDay:(0,F.useCallback)(()=>_(T(new Date(m-864e5))),[m,_]),nextDay:(0,F.useCallback)(()=>_(T(new Date(m+864e5))),[m,_]),goToday:(0,F.useCallback)(()=>_(T()),[_])}}var ke=2e3;async function Ae(e,t,n){let r=await e({from:t,to:n,limit:2001,order:`desc`});return{rows:r.rows.slice(0,ke),truncated:r.clamped||r.rows.length>2e3,minutesFrom:r.minutesFrom}}function je(e,t,n,r=`last`){let i=d(),[a,o]=(0,F.useState)([]),[s,c]=(0,F.useState)(null),[l,u]=(0,F.useState)(!1),[f,p]=(0,F.useState)(!1),[m,h]=(0,F.useState)(!1),[g,_]=(0,F.useState)(null),[v,y]=(0,F.useState)([]),b=(0,F.useMemo)(()=>S(e),[e]),x=(0,F.useMemo)(()=>S(t)+864e5-1,[t]),C=Ce[n],w=(0,F.useCallback)(async()=>{if(Number.isNaN(b)||Number.isNaN(x)||x<b){o([]),y([]),p(!1),c(null),h(!0);return}h(!1),u(!0),c(null);try{if(y([]),C===1){let e=await Ae(e=>i.logbook.minutes(e),b,x);_(e.minutesFrom),p(e.truncated),o(e.rows);return}let e=await i.logbook.rollupHours(b,x);_(null);let t=P(e,n),a=t.map(e=>D(e,r)),s=e=>e.slice(Math.max(0,e.length-ke));p(a.length>ke),o(s(a)),r!==`last`&&y(s(t.map(e=>D(e,`last`))))}catch(e){c(e.message)}finally{u(!1),h(!0)}},[b,x,C,n,r]);return(0,F.useEffect)(()=>{w()},[w]),{snaps:a,err:s,busy:l,truncated:f,loaded:m,minutesFrom:g,plain:v}}var Me=[`1m`,`1h`,`6h`,`1d`],Ne=[{v:`csv`,name:`CSV`,note:`a file for a spreadsheet`},{v:`pdf`,name:`PDF`,note:`the page, through your printer`}],Pe=[{v:`screen`,name:`Screen`},{v:`paper`,name:`Paper`}],Fe=[`last`,`avg`,`min`,`max`];function Ie(e,t,n){return e===`pdf`?[n]:t.includes(n)?t.filter(e=>e!==n):[...t,n]}function Le(e,t){return e===`pdf`?[t[0]??`last`]:t}function Re(){return T(new Date(Date.now()-7*864e5))}function ze({initial:e,onView:t,onSave:n}){let[r,i]=(0,F.useState)(e?.from??Re()),[a,o]=(0,F.useState)(e?.to??T()),[s,c]=(0,F.useState)(e?.gran??`1h`),[l,u]=(0,F.useState)(e?.format??`csv`),[d,f]=(0,F.useState)(e?.stats??[`last`]),[p,m]=(0,F.useState)(e?.distance??!1),[h,g]=(0,F.useState)(e?.samples??!1),[_,v]=(0,F.useState)(e?.style??`screen`),y=a<r,b={from:r,to:a,gran:s,format:l,stats:Le(l,d),distance:p,samples:h,style:_},x=s!==`1m`,S=l===`pdf`,C=x&&!S&&d.length===0&&!p&&!h,w=e=>f(t=>Ie(l,t,e)),E=Le(l,d),D=e=>E.includes(e);return(0,$.jsxs)(`div`,{className:`lb-pick lb-exp`,children:[(0,$.jsxs)(`div`,{className:`lbp-books`,children:[(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Window`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:`UTC days, both ends included`})]}),(0,$.jsxs)(`div`,{className:`lbe-dates`,children:[(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`From`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:r,max:T(),onChange:e=>i(e.target.value)})]}),(0,$.jsxs)(`label`,{children:[(0,$.jsx)(`span`,{children:`To`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:a,max:T(),onChange:e=>o(e.target.value)})]})]})]}),(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Interval`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:`one row per`})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Me.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${s===e?` on`:``}`,onClick:()=>c(e),children:we[e]},e))})]}),(0,$.jsxs)(`div`,{className:`lbp-book`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Save as`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:Ne.find(e=>e.v===l)?.note})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Ne.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${l===e.v?` on`:``}`,onClick:()=>u(e.v),children:e.name},e.v))})]}),(0,$.jsxs)(`div`,{className:`lbp-book${S?``:` off`}`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Style`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:S?_===`screen`?`the app's own dark ink`:`white, for a printer`:`the page's ink; a file carries none`})]}),(0,$.jsx)(`div`,{className:`lbp-chips`,children:Pe.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${_===e.v?` on`:``}`,disabled:!S,onClick:()=>v(e.v),children:e.name},e.v))})]})]}),x&&(0,$.jsxs)(`div`,{className:`lbp-book lbp-figs`,children:[(0,$.jsxs)(`div`,{className:`lbp-h`,children:[(0,$.jsx)(`span`,{className:`lbp-n`,children:`Figures`}),(0,$.jsx)(`span`,{className:`lbp-s`,children:S?`one: a table cell holds one number`:`one or more: a column each`})]}),(0,$.jsxs)(`div`,{className:`lbp-chips`,children:[Fe.map(e=>(0,$.jsx)(`button`,{className:`lbp-c${D(e)?` on`:``}`,onClick:()=>w(e),children:k[e]},e)),(0,$.jsx)(`button`,{className:`lbp-c${p?` on`:``}`,disabled:S,onClick:()=>m(!p),children:`Distance`}),(0,$.jsx)(`button`,{className:`lbp-c${h?` on`:``}`,disabled:S,onClick:()=>g(!h),children:`Samples`})]})]}),y&&(0,$.jsx)(`div`,{className:`lbe-warn`,children:`That window ends before it begins.`}),C&&(0,$.jsx)(`div`,{className:`lbe-warn`,children:`Choose at least one figure to put in the file.`}),(0,$.jsxs)(`div`,{className:`lbp-act`,children:[S&&(0,$.jsx)(`button`,{disabled:y,onClick:()=>t(b),children:`View`}),(0,$.jsxs)(`button`,{className:`lbp-go`,disabled:y||C,onClick:()=>n(b),children:[`Save `,l.toUpperCase()]})]})]})}function Be({open:e,style:t,cls:n,children:r}){let[i,a]=(0,F.useState)(e);return e&&!i&&a(!0),i?(0,$.jsx)(`div`,{className:`lb-open${e?``:` shut`}${n??``}`,style:t,onAnimationEnd:t=>{t.target===t.currentTarget&&!e&&a(!1)},children:(0,$.jsx)(`div`,{className:`lb-open-in`,children:r})}):null}function Ve(e){let t=e-32-58;return Math.max(1,Math.floor(t/52))}function He(e){return e.reduce((e,t)=>e+(t.lanes??1),0)}function Ue(e,t){if(t===null||e.length===0)return e;let n=Ve(t),r=e.slice(0,1);for(let t of e.slice(1)){let e=t.lanes??1;if(e>n)break;n-=e,r.push(t)}return r}function We(e,t,n){return t===null?e:e.slice(0,Ve(t-(n?108:0)))}var Ge=180,Ke=[`1m`,`1h`,`6h`,`1d`],qe={"1m":`Last hour`,"1h":`Last 2 days`,"6h":`Last 10 days`,"1d":`Last month`};function Je({book:e}){let t=d(),[n,r]=(0,F.useState)(`live`),[i,a]=(0,F.useState)(`1h`),[o,s]=(0,F.useState)(null),[c,l]=ne((0,F.useMemo)(()=>({book:e,mode:n,gran:i,family:o}),[e,n,i,o]),Ge),{book:u,mode:f,gran:p,family:m}=c,g=n!==f,[_,v]=(0,F.useState)(()=>localStorage.getItem(`lb:windUnit`)||`kn`),y=()=>v(e=>{let t=e===`kn`?`bft`:`kn`;return localStorage.setItem(`lb:windUnit`,t),t}),b=(0,F.useRef)([]),x=(0,F.useRef)(0),[C,w]=(0,F.useState)(()=>ye(u)),[T,E]=(0,F.useState)(u);T!==u&&(E(u),w(ye(u)),b.current=[],x.current=0);let[O,k]=(0,F.useState)(!1),I=e=>{w(e),be(u,e),k(!1)},[L,R]=h(),z=(0,F.useRef)(null),B=(0,F.useRef)(null),V=(0,F.useCallback)(e=>{B.current=e,L(e)},[L]),H=(0,F.useRef)(null);(0,F.useLayoutEffect)(()=>{let e=B.current;if(!e)return;let t=()=>e.querySelectorAll(`.lb-ctrl, .lb-pick, .lb-frame`);if(l){let e=new Map;t().forEach(t=>e.set(t,t.getBoundingClientRect().width)),H.current=e;return}let n=H.current;if(H.current=null,!n||window.matchMedia(`(prefers-reduced-motion: reduce)`).matches)return;let r=parseFloat(getComputedStyle(e).getPropertyValue(`--lb-fade-in`))||0;t().forEach(e=>{let t=n.get(e);if(t===void 0||typeof e.animate!=`function`)return;let i=e.getBoundingClientRect().width;Math.abs(i-t)<1||e.animate([{maxWidth:`${t}px`},{maxWidth:`${i}px`}],{duration:r,easing:`cubic-bezier(0.32, 0.72, 0, 1)`})})},[l,c]);let[U,ee]=(0,F.useState)(!1),[K,te]=(0,F.useState)(null),[q,J]=(0,F.useState)(!1),[re,Y]=(0,F.useState)(null),[X,Z]=(0,F.useState)(null),ie={book:u,mode:n,setMode:r,gran:i,setGran:a,shownGran:p,family:o,setFamily:s,shownFamily:m,leaving:l,modeLeaving:g,lanesHold:z,groupsHold:b,chosenHold:x,windUnit:_,toggleWind:y,selection:C,picking:O,setPicking:k,applySelection:I,width:R,exporting:U,setExporting:ee,request:K,onView:e=>{te(e),r(`range`),Y(null)},onSave:async e=>{if(ee(!1),Y(null),Z(null),e.format===`pdf`){te(e),r(`range`),J(!0);return}try{let n=S(e.from),r=S(e.to)+864e5-1;if(e.gran===`1m`){let{rows:e,truncated:i}=await Ae(e=>t.logbook.minutes(e),n,r),a=me(G(W(e,_),u),C);A(M(`logbook-${u}`,n,`csv`,i?`-partial`:``),`text/csv`,j(e,a)),i&&Z(`That window holds more than ${ke} minutes, so the file stops at the most recent ${ke} and its name ends in -partial. A longer interval covers the same days in fewer rows.`);return}let i=P(await t.logbook.rollupHours(n,r),e.gran),a=e.stats.map(e=>({stat:e,cols:me(G(W(i.map(t=>D(t,e)),_),u),C)})).filter(e=>e.cols.length>1);A(M(`logbook-${u}`,n,`csv`),`text/csv`,N(i,a,{distance:e.distance,samples:e.samples}))}catch(e){Y(e.message)}},saveErr:re,saveNote:X};return(0,$.jsxs)(`div`,{className:`lb`,ref:V,children:[(0,$.jsx)(`style`,{children:`@media print { @page { size: A4 landscape; } }`}),f===`live`?(0,$.jsx)(_t,{...ie}):f===`day`?(0,$.jsx)(vt,{...ie}):(0,$.jsx)(wt,{...ie,req:K,printing:q,donePrinting:()=>J(!1)})]})}function Ye({mode:e,setMode:t}){return(0,$.jsxs)(`div`,{className:`seg`,children:[(0,$.jsx)(`button`,{className:e===`live`?`on`:``,onClick:()=>t(`live`),children:`Live`}),(0,$.jsx)(`button`,{className:e===`day`?`on`:``,onClick:()=>t(`day`),children:`Day`})]})}function Xe({leaving:e,children:t}){return(0,$.jsx)(`div`,{className:`lb-win${e?` leaving`:``}`,children:t})}function Ze({groups:e,family:t,setFamily:n}){if(e.length<2)return null;let r=e.find(e=>e.tab===t)??e[0];return(0,$.jsx)(`div`,{className:`seg`,children:e.map(e=>(0,$.jsx)(`button`,{className:e.tab===r.tab?`on`:``,onClick:()=>n(e.tab),children:e.head},e.tab))})}function Qe(e,t,n){if(e===null||S(t.from)>=e)return null;let r=new Date(e).toLocaleDateString(void 0,{day:`numeric`,month:`short`}),i=n[n.length-1];return`Minutes reach back to ${r}.${i!==void 0&&i.ts<e?` Earlier days in this window read one row per hour.`:``}`}function $e(e,t,n){let r=k[e].toLowerCase(),i=t.length===1?t[0]:`${t.slice(0,-1).join(`, `)} and ${t[t.length-1]}`,a=n.some(e=>e.lat!==null&&e.lon!==null),o=t.length===1;return`${i} ${o?`has`:`have`} no ${r}, so on each row ${o?`it carries`:`they carry`} the reading that window closed on${a?`, as the position does`:``}.`}function et(e,t){if(t.length===0)return e;let n=new Map(t.map(e=>[e.ts,e]));return e.map(e=>{let t=n.get(e.ts);if(!t)return e;let r={...e};for(let[e,n]of Object.entries(t))e!==`path_values`&&(r[e]===null||r[e]===void 0)&&n!=null&&(r[e]=n);if(t.path_values){let n={...e.path_values??{}};for(let[e,r]of Object.entries(t.path_values))(n[e]===void 0||n[e]===null)&&(n[e]=r);r.path_values=n}return r})}function tt(e){return S(e.to)+864e5-1>=Date.now()&&e.gran!==`1m`?`No row has closed at this interval yet. A shorter interval shows today's.`:`Nothing was logged between these dates.`}function nt(e,t,n){return e.length>1||t===null?lt(e):{"--lb-cols":n.current??Ve(t)}}function rt({what:e}){return(0,$.jsxs)(`div`,{className:`sp-empty`,children:[(0,$.jsx)(`div`,{className:`em-t`,children:`No snapshots`}),(0,$.jsx)(`div`,{className:`em-s`,children:e})]})}var it=(e,t)=>`u:${e}:${t}`;function at(e,t,n,r,i,a,o,s,c,l=!0){let u=st(e,t,n,r,i,a,o,s,c,l);if(t!==`engine`||u.groups.length<2)return u;let d=u,f=ot(u);for(let o of u.groups){if(o===u.group||o.tab===a)continue;let s=st(e,t,n,r,i,o.tab,{current:null},{current:[]},{current:0},l),c=ot(s);c>f&&(d=s,f=c)}return d===u?u:{...u,block:d.block,cls:d.cls}}function ot(e){let t=Math.max(1,Number(e.block[`--lb-cols`]??1));return 58+(e.cls.includes(`u`)?108:0)+t*164}function st(e,t,n,r,i,a,o,s,c,l){let u=t===`engine`?K(e):[];u.length>0&&(s.current=u);let d=u.length===0&&e.length===0?s.current:u,f=u.find(e=>e.tab===a)??u[0];if(f&&f.units.length>1){let e=f.metrics.map(e=>({key:it(f.tab,e.key),head:e.head})),t=f.metrics.filter(e=>Q({key:it(f.tab,e.key)},r)),n=l?We(t,i,!0):t,a={...f,metrics:n};return o.current=Math.max(1,n.length),t.length>0&&(c.current=t.length),{groups:d,group:a,drawn:[],pick:e,btn:{shown:n.length,chosen:t.length,kept:c.current,offered:e.length},block:{"--lb-cols":Math.max(1,n.length)},cls:` u`}}let p=G(W(e,n),t),m=f?p.filter(e=>e.key===`ts`||e.tab===f.tab):p,h=me(m,r),g=l?Ue(h,i):h;return g.length>1&&(o.current=He(g.slice(1))),h.length>1&&(c.current=h.length-1),{groups:d,group:null,drawn:g,pick:m,btn:{shown:g.length-1,chosen:h.length-1,kept:c.current,offered:m.length-1},block:nt(g,i,o),cls:``}}function ct(e){return{"--lb-cols":Math.max(1,e.metrics.length)}}function lt(e){return{"--lb-cols":He(e.slice(1))}}function ut(e){return(e.lanes??1)>1?` w${e.lanes}`:``}function dt(e,t){return t===`last`?we[e]:`${we[e]} · ${k[t]}`}function ft(e,t,n,r){return r===0?String(n):e<t?`${e} of ${t}`:String(t)}function pt({shown:e,chosen:t,kept:n,offered:r,open:i,onOpen:a}){let o=r===0;return(0,$.jsxs)(`button`,{className:`lb-colbtn${i?` on`:``}${o?` quiet`:``}`,onClick:a,disabled:o,children:[`Columns · `,(0,$.jsx)(`b`,{children:ft(e,t,n,r)})]})}function mt({open:e,onOpen:t}){return(0,$.jsx)(`button`,{className:`lb-colbtn${e?` on`:``}`,onClick:t,children:`View`})}function ht({cols:e,group:t,times:n,toggleWind:r}){if(t){let e=t.units.length>1;return(0,$.jsxs)(`div`,{className:`lb-cols${e?` u`:``}`,style:ct(t),children:[(0,$.jsx)(`span`,{children:n.head}),e&&(0,$.jsx)(`span`,{className:`un`,children:`Unit`}),t.metrics.map(e=>(0,$.jsxs)(`span`,{children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))]})}return(0,$.jsx)(`div`,{className:`lb-cols`,style:lt(e),children:e.map(e=>e.tappable?(0,$.jsxs)(`span`,{className:`tap${ut(e)}`,onClick:r,title:`Tap: knots ⇄ Beaufort`,children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key):(0,$.jsxs)(`span`,{className:ut(e).trim(),children:[e.key===`ts`?n.head:e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))})}function gt({of:e}){return(0,$.jsx)(`b`,{className:`lb-u`,children:e===void 0||e===``?`\xA0`:e})}function _t({book:e,mode:t,setMode:n,gran:r,setGran:i,shownGran:a,family:o,setFamily:s,shownFamily:c,leaving:l,modeLeaving:u,lanesHold:d,groupsHold:f,chosenHold:p,windUnit:m,toggleWind:h,selection:g,picking:_,setPicking:v,applySelection:y,width:b,exporting:x,setExporting:S,request:C,onView:w,onSave:T,saveErr:E,saveNote:D}){let{snaps:O,err:k,busy:A,hasMore:j,loadMore:M}=De(a),N=ue(O),P=(0,F.useMemo)(()=>Tt(O,N,!1),[O,N]),{groups:I,group:L,drawn:R,pick:z,btn:B,block:V,cls:H}=at(O,e,m,g,b,c,d,f,p);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${H}`,style:V,children:[(0,$.jsx)(Ye,{mode:t,setMode:n}),(0,$.jsx)(Xe,{leaving:u,children:(0,$.jsx)(`div`,{className:`seg`,children:Ke.map(e=>(0,$.jsx)(`button`,{className:r===e?`on`:``,onClick:()=>i(e),children:e},e))})}),(0,$.jsx)(Ze,{groups:I,family:o,setFamily:s}),(0,$.jsxs)(`div`,{className:`lb-acts`,children:[(0,$.jsx)(pt,{shown:B.shown,chosen:B.chosen,kept:B.kept,offered:B.offered,open:_,onOpen:()=>v(!_)}),(0,$.jsx)(mt,{open:x,onOpen:()=>S(!x)})]})]}),(0,$.jsx)(Be,{open:_,style:V,cls:H,children:(0,$.jsx)(Se,{cols:z,applied:g,onApply:y,onCancel:()=>v(!1)})}),(0,$.jsx)(Be,{open:x,style:V,cls:H,children:(0,$.jsx)(ze,{initial:C??void 0,onView:w,onSave:T})}),E&&(0,$.jsx)(`div`,{className:`lb-err`,children:E}),D&&(0,$.jsx)(`div`,{className:`lb-note`,children:D}),(0,$.jsxs)(`div`,{className:`lb-frame${P?` dated`:``}${N.mixed?` mixed`:``}${H}${l?` leaving`:``}`,style:V,children:[(0,$.jsx)(xt,{book:e,window:qe[a],interval:we[a],times:N}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(R),children:[(0,$.jsx)(`span`,{children:qe[a]}),(0,$.jsx)(`b`,{children:O.length})]}),(0,$.jsx)(ht,{cols:R,group:L,times:N,toggleWind:h}),k&&(0,$.jsx)(`div`,{className:`lb-err`,children:k}),!A&&!k&&O.length===0?(0,$.jsx)(rt,{what:`Nothing was logged in this window (${qe[a].toLowerCase()}).`}):(0,$.jsx)(Et,{snaps:O,cols:R,group:L,times:N,lined:P,footer:j?(0,$.jsx)(`button`,{className:`lb-more`,onClick:M,disabled:A,children:A?`Loading…`:`Load ${Te[a]} more`}):null}),(0,$.jsx)(St,{})]})]})}function vt({book:e,mode:t,setMode:n,family:r,setFamily:i,shownFamily:a,leaving:o,modeLeaving:s,lanesHold:c,groupsHold:l,chosenHold:u,windUnit:d,toggleWind:f,selection:p,picking:m,setPicking:h,applySelection:g,width:_,exporting:v,setExporting:y,request:b,onView:x,onSave:S,saveErr:C,saveNote:w}){let{dateStr:E,setDateStr:D,isToday:O,snaps:k,err:A,busy:j,prevDay:M,nextDay:N,goToday:P}=Oe(),I=ue(k),L=(0,F.useMemo)(()=>Tt(k,I,`turns`),[k,I]),{groups:R,group:z,drawn:B,pick:V,btn:H,block:U,cls:W}=at(k,e,d,p,_,a,c,l,u),G=`${O?`Today · ${new Date(E).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,timeZone:`UTC`})}`:new Date(E).toLocaleDateString(`en-GB`,{weekday:`short`,day:`2-digit`,month:`short`,timeZone:`UTC`}).replace(/,/g,``)} · UTC day`;return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${W}`,style:U,children:[(0,$.jsx)(Ye,{mode:t,setMode:n}),(0,$.jsx)(Xe,{leaving:s,children:(0,$.jsxs)(`div`,{className:`lb-date`,children:[(0,$.jsx)(`button`,{className:`lb-step`,onClick:M,"aria-label":`Previous day`,children:`‹`}),(0,$.jsx)(`input`,{type:`date`,className:`dt`,value:E,max:T(),onChange:e=>D(e.target.value)}),(0,$.jsx)(`button`,{className:`lb-step`,onClick:N,disabled:O,"aria-label":`Next day`,children:`›`}),(0,$.jsx)(`button`,{onClick:P,disabled:O,children:`Now`})]})}),(0,$.jsx)(Ze,{groups:R,family:r,setFamily:i}),(0,$.jsxs)(`div`,{className:`lb-acts`,children:[(0,$.jsx)(pt,{shown:H.shown,chosen:H.chosen,kept:H.kept,offered:H.offered,open:m,onOpen:()=>h(!m)}),(0,$.jsx)(mt,{open:v,onOpen:()=>y(!v)})]})]}),(0,$.jsx)(Be,{open:m,style:U,cls:W,children:(0,$.jsx)(Se,{cols:V,applied:p,onApply:g,onCancel:()=>h(!1)})}),(0,$.jsx)(Be,{open:v,style:U,cls:W,children:(0,$.jsx)(ze,{initial:b??void 0,onView:x,onSave:S})}),C&&(0,$.jsx)(`div`,{className:`lb-err`,children:C}),w&&(0,$.jsx)(`div`,{className:`lb-note`,children:w}),(0,$.jsxs)(`div`,{className:`lb-frame${L?` dated`:``}${I.mixed?` mixed`:``}${W}${o?` leaving`:``}`,style:U,children:[(0,$.jsx)(xt,{book:e,window:G,interval:we[`1h`],times:I}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(B),children:[(0,$.jsx)(`span`,{children:G}),(0,$.jsx)(`b`,{children:k.length})]}),(0,$.jsx)(ht,{cols:B,group:z,times:I,toggleWind:f}),A&&(0,$.jsx)(`div`,{className:`lb-err`,children:A}),!j&&k.length===0?(0,$.jsx)(rt,{what:`No telemetry was logged for this day.`}):(0,$.jsx)(Et,{snaps:k,cols:B,group:z,times:I,footer:null,lined:L}),(0,$.jsx)(St,{})]})]})}function yt(){let e=new Date,t=e.toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,year:`numeric`,timeZone:`UTC`}),n=e=>String(e).padStart(2,`0`);return`${t.toUpperCase()} · ${n(e.getUTCHours())}:${n(e.getUTCMinutes())} UTC`}var bt={bridge:`CHIEF OFFICER`,engine:`CHIEF ENGINEER`};function xt({book:e,window:t,interval:n,times:r}){let i=r.mixed?`SHIP'S TIME · OFFSET ON EACH DATED LINE`:r.head===`UTC`?`UTC`:`SHIP'S TIME · ${r.head}`;return(0,$.jsxs)(`div`,{className:`lb-print-hd`,children:[(0,$.jsxs)(`div`,{className:`ph-id`,children:[(0,$.jsxs)(`span`,{className:`sp-lockup`,children:[(0,$.jsx)(x,{className:`sp-glyph`}),(0,$.jsx)(`span`,{className:`ph-wm`,children:`Siparu`})]}),(0,$.jsxs)(`span`,{className:`ph-book`,children:[`LOGBOOK · `,(0,$.jsx)(`b`,{children:e.toUpperCase()}),` · `,bt[e]]})]}),(0,$.jsxs)(`div`,{className:`ph-meta`,children:[(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`GENERATED`}),(0,$.jsx)(`b`,{children:yt()})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`WINDOW`}),(0,$.jsx)(`b`,{children:`${t} · ${n}`.toUpperCase()})]}),(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`span`,{className:`l`,children:`CLOCK`}),(0,$.jsx)(`b`,{children:i})]})]})]})}function St(){return(0,$.jsx)(`div`,{className:`lb-print-ft`,children:(0,$.jsx)(`span`,{children:`siparu.app`})})}function Ct(e,t){let n=(e,t)=>new Date(e).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,...t?{year:`numeric`}:{},timeZone:`UTC`});return e===t?`${n(t,!0)} · UTC day`:`${n(e,!1)} - ${n(t,!0)} · UTC days`}function wt({book:e,req:t,setMode:n,family:r,setFamily:i,shownFamily:a,leaving:o,modeLeaving:s,lanesHold:c,groupsHold:l,chosenHold:u,windUnit:d,toggleWind:f,selection:p,picking:m,setPicking:h,applySelection:g,width:_,exporting:v,setExporting:y,request:b,onView:x,onSave:S,saveErr:C,saveNote:w,printing:D,donePrinting:k}){let A={from:T(),to:T(),gran:`1h`,format:`csv`,stats:[`last`],distance:!1,samples:!1,style:`screen`},j=t??A,M=j.stats[0]??`last`,{snaps:N,err:P,busy:I,truncated:L,loaded:R,minutesFrom:z,plain:B}=je(j.from,j.to,j.gran,M),V=(0,F.useMemo)(()=>et([...N].sort((e,t)=>e.ts-t.ts),B),[N,B]),H=ue(V),{groups:U,group:ee,drawn:K,pick:te,btn:ne,block:q,cls:J}=at(V,e,d,p,_,a,c,l,u,!1),re=(0,F.useCallback)(()=>k(),[k]);(0,F.useEffect)(()=>{!D||!R||I||(re(),O(E(`Siparu-Logbook`,Date.now()),j.style))},[D,R,I,re,j.style]);let Y=Ct(j.from,j.to),X=dt(j.gran,M),Z=(0,F.useMemo)(()=>{if(B.length===0)return[];let t=t=>me(G(W(t,d),e),p).map(e=>e.head),n=new Set(t(N));return t(B).filter(e=>!n.has(e))},[B,N,d,e,p]);return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(`div`,{className:`lb-ctrl${J}`,style:q,children:[(0,$.jsx)(Ye,{mode:`range`,setMode:n}),(0,$.jsx)(Xe,{leaving:s,children:(0,$.jsxs)(`button`,{className:`lb-colbtn on`,onClick:()=>y(!v),children:[Y,` · `,(0,$.jsx)(`b`,{children:X})]})}),(0,$.jsx)(Ze,{groups:U,family:r,setFamily:i}),(0,$.jsx)(`div`,{className:`lb-acts`,children:(0,$.jsx)(pt,{shown:ne.shown,chosen:ne.chosen,kept:ne.kept,offered:ne.offered,open:m,onOpen:()=>h(!m)})})]}),(0,$.jsx)(Be,{open:m,style:q,cls:J,children:(0,$.jsx)(Se,{cols:te,applied:p,onApply:g,onCancel:()=>h(!1)})}),(0,$.jsx)(Be,{open:v,style:q,cls:J,children:(0,$.jsx)(ze,{initial:b??void 0,onView:x,onSave:S})}),C&&(0,$.jsx)(`div`,{className:`lb-err`,children:C}),w&&(0,$.jsx)(`div`,{className:`lb-note`,children:w}),(0,$.jsxs)(`div`,{className:`lb-frame dated${H.mixed?` mixed`:``}${J}${o?` leaving`:``}`,style:q,children:[(0,$.jsx)(xt,{book:e,window:Y,interval:X,times:H}),(0,$.jsxs)(`div`,{className:`lb-day`,style:lt(K),children:[(0,$.jsxs)(`span`,{children:[Y,` · `,X]}),(0,$.jsx)(`b`,{children:L?`${N.length} of more`:N.length})]}),(0,$.jsx)(ht,{cols:K,group:ee,times:H,toggleWind:f}),P&&(0,$.jsx)(`div`,{className:`lb-err`,children:P}),Z.length>0&&(0,$.jsx)(`div`,{className:`lb-note`,children:$e(M,Z,N)}),L&&(0,$.jsxs)(`div`,{className:`lb-note`,children:[`This window holds more than `,2e3,` rows. The most recent `,2e3,` are here; a longer interval covers the same days in fewer.`]}),Qe(z,j,N)&&(0,$.jsx)(`div`,{className:`lb-note`,children:Qe(z,j,N)}),!I&&V.length===0?(0,$.jsx)(rt,{what:tt(j)}):(0,$.jsx)(Et,{snaps:V,cols:K,group:ee,times:H,footer:null,lined:!0}),(0,$.jsx)(St,{})]})]})}function Tt(e,t,n){return n===!0?!0:n===!1&&!t.mixed?!1:new Set(e.map(e=>t.dayLine(e.ts))).size>1}function Et({snaps:e,cols:t,group:n,times:r,footer:i,lined:a}){let o=[],s=null;for(let i of e){if(a){let e=r.dayLine(i.ts);e!==s&&(o.push((0,$.jsx)(Dt,{day:r.day(i.ts),offset:r.offset(i.ts),cols:t,group:n},`sep-${i.ts}`)),s=e)}o.push(n?(0,$.jsx)(Ot,{s:i,group:n,times:r},i.ts):(0,$.jsx)(kt,{s:i,cols:t,times:r},i.ts))}return(0,$.jsxs)(`div`,{className:`lb-rows`,style:n?ct(n):lt(t),children:[o,i]})}function Dt({day:e,offset:t,cols:n,group:r}){let i=r!==null&&r.units.length>1,a=r?r.metrics.map(e=>({key:e.key,head:e.head,unit:e.unit,cls:``})):n.slice(1).map(e=>({key:e.key,head:e.head,unit:e.unit,cls:ut(e).trim()}));return(0,$.jsxs)(`div`,{className:`lb-sep${i?` u`:``}`,children:[(0,$.jsxs)(`span`,{className:`sd`,children:[e,t&&(0,$.jsxs)(`span`,{className:`so`,children:[` · `,t]})]}),i&&(0,$.jsx)(`span`,{className:`sh`}),a.map(e=>(0,$.jsxs)(`span`,{className:e.cls?`sh ${e.cls}`:`sh`,children:[e.head,(0,$.jsx)(gt,{of:e.unit})]},e.key))]})}function Ot({s:e,group:t,times:n}){let r=t.units.length>1;return(0,$.jsx)($.Fragment,{children:t.units.map((i,a)=>(0,$.jsxs)(`div`,{className:`lb-row${r?` u`:``}${a>0?` cont`:``}`,children:[(0,$.jsx)(`span`,{className:`tm`,children:n.clock(e.ts)}),r&&(0,$.jsx)(`span`,{className:`un`,children:i.head}),t.metrics.map(t=>(0,$.jsx)(`span`,{className:`v`,children:te(e,i,t)},t.key))]},i.key))})}function kt({s:e,cols:t,times:n}){return(0,$.jsx)(`div`,{className:`lb-row`,children:t.map((t,r)=>(0,$.jsx)(`span`,{className:r===0?`tm`:`${t.dim?`v dim`:`v`}${ut(t)}`,children:t.key===`ts`?n.clock(e.ts):t.cell(e)},t.key))})}var At=[{to:`/logbook/bridge`,name:`Bridge`,keeper:`Chief officer`,holds:`Position, course and speed, the weather she ran in and the water under her.`,Icon:m},{to:`/logbook/engine`,name:`Engine`,keeper:`Chief engineer`,holds:`Engines, generators and tanks, as she reported them.`,Icon:v}];function jt(){let e=p();return(0,$.jsx)(`div`,{className:`lb-door`,children:(0,$.jsx)(`div`,{className:`lbd-cards`,children:At.map(({to:t,name:n,keeper:r,holds:i,Icon:a})=>(0,$.jsxs)(c,{to:e(t),replace:!0,className:`lbd-card`,children:[(0,$.jsx)(a,{size:42}),(0,$.jsx)(`span`,{className:`lbd-n`,children:n}),(0,$.jsx)(`span`,{className:`lbd-k`,children:r}),(0,$.jsx)(`span`,{className:`lbd-h`,children:i}),(0,$.jsxs)(`span`,{className:`lbd-go`,children:[`Open `,(0,$.jsx)(y,{size:15})]})]},t))})})}function Mt({book:e}){return e?(0,$.jsx)(Je,{book:e}):(0,$.jsx)(jt,{})}export{Mt as default};
|