@sailingrotevista/rotevista-dash 2.0.22 → 2.0.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.
Files changed (3) hide show
  1. package/app.js +30 -5
  2. package/package.json +1 -1
  3. package/style.css +66 -45
package/app.js CHANGED
@@ -429,11 +429,36 @@ function toggleFocusMode(type, element) {
429
429
  let lastTapTime = 0, tapTimeout, isLongPressActive = false;
430
430
  el.addEventListener('pointerdown', (e) => { isLongPressActive = false; pressTimer = setTimeout(() => { if (!isFocusActive) { isLongPressActive = true; toggleFocusMode(type, el); lastTapTime = 0; } }, 1000); });
431
431
  el.addEventListener('pointerup', (e) => {
432
- clearTimeout(pressTimer); if (isLongPressActive) return;
433
- const currentTime = new Date().getTime(), tapDelay = currentTime - lastTapTime;
434
- if (tapDelay < 300 && tapDelay > 0) { clearTimeout(tapTimeout); if (!isFocusActive) { graphModes[type] = graphModes[type] === 'standard' ? 'hercules' : 'standard'; localStorage.setItem('mode_' + type, graphModes[type]); } lastTapTime = 0; }
435
- else { lastTapTime = currentTime; tapTimeout = setTimeout(() => { if (isFocusActive && el.classList.contains('is-focused')) toggleFocusMode(type, el); else if (!isFocusActive && type === 'sog') { displayModeSog = (displayModeSog === 'SOG') ? 'VMG' : 'SOG'; el.style.backgroundColor = "rgba(0, 0, 0, 0.05)"; setTimeout(() => el.style.backgroundColor = "", 150); } }, 250); }
436
- });
432
+ clearTimeout(pressTimer); if (isLongPressActive) return;
433
+ const currentTime = new Date().getTime(), tapDelay = currentTime - lastTapTime;
434
+
435
+ // RILEVAMENTO DOPPIO TAP (HERCULES)
436
+ if (tapDelay < 300 && tapDelay > 0) {
437
+ clearTimeout(tapTimeout); // Cancella l'azione del tap singolo (uscita dal focus)
438
+
439
+ // Permette il toggle Hercules sempre, sia in vista normale che in Focus
440
+ graphModes[type] = graphModes[type] === 'standard' ? 'hercules' : 'standard';
441
+ localStorage.setItem('mode_' + type, graphModes[type]);
442
+
443
+ lastTapTime = 0;
444
+ }
445
+ // RILEVAMENTO TAP SINGOLO (ESCI DA FOCUS o CAMBIA SOG/VMG)
446
+ else {
447
+ lastTapTime = currentTime;
448
+ tapTimeout = setTimeout(() => {
449
+ // Se siamo in focus e clicchiamo il box ingrandito, usciamo
450
+ if (isFocusActive && el.classList.contains('is-focused')) {
451
+ toggleFocusMode(type, el);
452
+ }
453
+ // Se siamo in vista normale e clicchiamo SOG, cambiamo in VMG
454
+ else if (!isFocusActive && type === 'sog') {
455
+ displayModeSog = (displayModeSog === 'SOG') ? 'VMG' : 'SOG';
456
+ el.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
457
+ setTimeout(() => el.style.backgroundColor = "", 150);
458
+ }
459
+ }, 250);
460
+ }
461
+ });
437
462
  el.addEventListener('pointerleave', () => clearTimeout(pressTimer));
438
463
  });
439
464
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailingrotevista/rotevista-dash",
3
- "version": "2.0.22",
3
+ "version": "2.0.23",
4
4
  "description": "Public Wind Dashboard with navigation and course aids",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
package/style.css CHANGED
@@ -1,15 +1,16 @@
1
1
  /* ==========================================================================
2
- 1. BASE E RESET DI SISTEMA (GIORNO: SFONDO CHIARO)
2
+ 1. BASE E RESET DI SISTEMA
3
3
  ========================================================================== */
4
4
  body {
5
- background-color: #fff;
6
- color: #000;
5
+ background-color: #fff; /* Day Mode Default */
6
+ color: #000; /* Day Mode Default */
7
7
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
8
8
  margin: 0;
9
9
  padding: 0;
10
10
  height: 100vh;
11
11
  width: 100vw;
12
12
  overflow: hidden;
13
+ /* Inibisce i gesti di sistema per favorire Long Press e Swipe della dashboard */
13
14
  -webkit-touch-callout: none;
14
15
  -webkit-user-select: none;
15
16
  user-select: none;
@@ -26,6 +27,7 @@ body {
26
27
  padding: 5px;
27
28
  box-sizing: border-box;
28
29
  gap: 8px;
30
+ /* Rapporto Standard: Lati flessibili, Centro bilanciato a 1.5fr */
29
31
  grid-template-columns: minmax(180px, 1fr) minmax(auto, 1.5fr) minmax(180px, 1fr);
30
32
  grid-template-rows: 100%;
31
33
  transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
@@ -35,18 +37,19 @@ body {
35
37
  .side-panel {
36
38
  display: flex;
37
39
  flex-direction: column;
38
- background: rgba(0, 0, 0, 0.03);
40
+ background: rgba(0, 0, 0, 0.03); /* Sfondo Day Mode */
39
41
  border-radius: 12px;
40
42
  height: 100%;
41
43
  overflow: hidden;
42
- gap: 2px;
44
+ gap: 2px; /* Massimizza lo spazio per i 5 box verticali */
43
45
  }
44
46
 
45
- .left-panel { grid-column: 1; }
47
+ .left-panel { grid-column: 1; align-items: flex-start; }
48
+ .right-panel { grid-column: 3; align-items: flex-end; } /* Forza i box a destra */
46
49
 
47
50
  .center-panel {
48
51
  grid-column: 2;
49
- position: relative;
52
+ position: relative; /* Indispensabile per posizionare l'etichetta STATUS in alto a dx */
50
53
  display: flex;
51
54
  flex-direction: column;
52
55
  align-items: center;
@@ -55,37 +58,40 @@ body {
55
58
  overflow: hidden;
56
59
  }
57
60
 
58
- .right-panel {
59
- grid-column: 3;
60
- align-items: flex-end;
61
- text-align: right;
62
- }
63
-
64
61
  /* ==========================================================================
65
- 3. DATA-BOX E TIPOGRAFIA
62
+ 3. DATA-BOX E TIPOGRAFIA (UNITA' ELASTICHE E NUOVE PROPORZIONI)
66
63
  ========================================================================== */
67
64
  .data-box {
68
65
  position: relative;
69
- border-bottom: 1px solid #eee;
70
- padding: 2px 4px;
66
+ border-bottom: 1px solid #eee; /* Day Mode Border */
67
+ padding: 2px 8px;
71
68
  display: flex;
72
69
  flex-direction: column;
73
70
  width: 100%;
74
71
  box-sizing: border-box;
75
- container-type: size;
76
- flex: 1 1 0px;
72
+ container-type: size; /* Permette l'uso di cqh per i font */
77
73
  min-height: 0;
78
74
  overflow: hidden;
79
75
  transition: background-color 0.2s ease;
80
76
  }
81
77
 
82
- .left-panel .data-box { align-items: flex-start; text-align: left; }
83
- .right-panel .data-box { align-items: flex-end; text-align: right; }
78
+ /* RIPRISTINO ALLINEAMENTO SPECULARE RIGIDO */
79
+ .left-panel .data-box { align-items: flex-start !important; text-align: left !important; }
80
+ .right-panel .data-box { align-items: flex-end !important; text-align: right !important; }
81
+
82
+ /* Inversione etichette colonna destra per aderenza al bordo schermo */
83
+ .right-panel .label-row { flex-direction: row-reverse !important; }
84
+
85
+ /* NUOVE PROPORZIONI VERTICALI 1.75 / 0.75 / 1.25 */
86
+ .data-box:nth-child(1), .data-box:nth-child(2) { flex: 1.75 1 0px; }
87
+ .data-box:nth-child(3), .data-box:nth-child(4) { flex: 0.75 0.75 0px; }
88
+ .data-box:nth-child(5) { flex: 1.25 1 0px; border-bottom: none; }
84
89
 
85
90
  .label-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2px; width: 100%; }
86
91
  .label { color: #888; font-size: 0.65rem; font-weight: bold; text-transform: uppercase; }
87
92
  .unit { color: #aaa; font-size: 0.6rem; font-weight: bold; }
88
93
 
94
+ /* Font dinamico per i valori: massimo 22% dell'altezza del box */
89
95
  .value {
90
96
  color: #000;
91
97
  font-size: clamp(1.2rem, 22cqh, 3rem);
@@ -95,6 +101,7 @@ body {
95
101
  padding-bottom: 5px;
96
102
  }
97
103
 
104
+ /* Centratura verticale automatica per i box senza grafico */
98
105
  .value-large, .dual-value-container, .value-with-compass {
99
106
  margin-top: auto;
100
107
  margin-bottom: auto;
@@ -102,31 +109,37 @@ body {
102
109
 
103
110
  .value-large { font-size: clamp(1.5rem, 35cqh, 4.5rem); line-height: 0.85; }
104
111
 
112
+ /* --- BUSSOLA TWD (FIX ALLINEAMENTO) --- */
105
113
  .value-with-compass {
106
114
  display: flex;
107
- justify-content: space-between;
115
+ justify-content: space-between; /* Bussola a SX, Valore a DX */
108
116
  align-items: center;
109
117
  width: 100%;
110
- align-self: stretch;
118
+ align-self: stretch; /* Impedisce al pannello DX di schiacciare il widget a destra */
111
119
  gap: 5px;
112
120
  }
113
121
 
122
+ /* TACK (Mure opposte) Layout */
114
123
  .dual-value-container { display: flex; justify-content: space-between; width: 100%; }
115
124
  .dual-value-col { display: flex; flex-direction: column; width: 48%; }
116
125
  .dual-label { color: #888; font-size: 0.55rem; font-weight: bold; text-transform: uppercase; margin-bottom: 2px; }
117
126
  .value.dual-val { font-size: clamp(1rem, 22cqh, 2rem); padding-bottom: 0; line-height: 0.9; }
118
127
 
119
128
  /* ==========================================================================
120
- 4. TACTICAL FOCUS MODE
129
+ 4. TACTICAL FOCUS MODE (DUAL SCREEN 60/40)
121
130
  ========================================================================== */
122
131
  .focus-active .side-panel:not(.has-focus) { display: none !important; }
132
+
133
+ /* Split: 60% per il grafico scelto, 40% per il vento centrale */
123
134
  .focus-active.focus-side-left { grid-template-columns: 3fr 2fr !important; }
124
135
  .focus-active.focus-side-left .side-panel.has-focus { grid-column: 1 !important; }
125
136
  .focus-active.focus-side-left .center-panel { grid-column: 2 !important; justify-content: center !important; align-items: center !important; }
137
+
126
138
  .focus-active.focus-side-right { grid-template-columns: 2fr 3fr !important; }
127
139
  .focus-active.focus-side-right .center-panel { grid-column: 1 !important; justify-content: center !important; align-items: center !important; }
128
140
  .focus-active.focus-side-right .side-panel.has-focus { grid-column: 2 !important; }
129
141
 
142
+ /* Espansione box e tipografia massiccia in Focus Mode */
130
143
  .focus-active .has-focus .data-box:not(.is-focused) { display: none !important; }
131
144
  .focus-active .has-focus .data-box.is-focused {
132
145
  height: 100vh !important;
@@ -142,11 +155,12 @@ body {
142
155
  .focus-active .is-focused .label-row .label { font-size: 2rem !important; }
143
156
  .focus-active .is-focused .label-row .unit { font-size: 2rem !important; }
144
157
  .focus-active .is-focused .sparkline path { stroke-width: 2.5px !important; }
158
+
145
159
  .focus-active .center-panel svg#wind-gauge { max-width: 95% !important; max-height: 85vh !important; }
146
160
 
147
161
  /* ==========================================================================
148
162
  5. GRAFICI, SCALE E HERCULES MODE
149
- ========================================================================= */
163
+ ========================================================================== */
150
164
  .graph-wrapper {
151
165
  position: relative; width: 100%; flex-grow: 1; min-height: 0; margin-top: 4px;
152
166
  display: flex; align-items: stretch; background: rgba(0, 0, 0, 0.04);
@@ -170,6 +184,7 @@ body {
170
184
  .right-panel .scale-labels { order: 1; text-align: right; padding-right: 4px; }
171
185
  .right-panel .sparkline { order: 2; }
172
186
 
187
+ /* Hercules Mode Visuals */
173
188
  .line-hercules { filter: drop-shadow(0 0 5px #ff0000); stroke-width: 1.8px !important; }
174
189
  .box-hercules { background: rgba(255, 0, 0, 0.05) !important; }
175
190
  .box-hercules .scale-labels { color: #ff5555; }
@@ -180,13 +195,14 @@ body {
180
195
  .right-panel .box-hercules .unit::after { content: " HERCULES"; }
181
196
  .right-panel .box-hercules .label:only-child::after { content: " HERCULES"; }
182
197
 
198
+ /* Colori standard grafici */
183
199
  #stw-graph { stroke: #2ecc71; fill: rgba(46, 204, 113, 0.12); }
184
200
  #sog-graph { stroke: #f39c12; fill: rgba(243, 156, 18, 0.12); }
185
201
  #depth-graph { stroke: #3498db; fill: rgba(52, 152, 219, 0.12); }
186
202
  #tws-graph { stroke: #000000; fill: rgba(0, 0, 0, 0.08); }
187
203
 
188
204
  /* ==========================================================================
189
- 6. WIDGETS E STATUS (GIORNO)
205
+ 6. WIDGETS E STATUS
190
206
  ========================================================================== */
191
207
  #status {
192
208
  position: absolute; top: 10px; right: 10px;
@@ -200,15 +216,13 @@ body {
200
216
 
201
217
  .mini-compass {
202
218
  width: min(80cqh, 42cqw); height: min(80cqh, 42cqw); aspect-ratio: 1 / 1;
203
- flex-shrink: 0; background: #f0f0f0;
204
- border-radius: 50%; border: 1.5px solid #ddd;
219
+ flex-shrink: 0; background: #f0f0f0; border-radius: 50%; border: 1.5px solid #ddd;
205
220
  box-shadow: inset 0 0 10px rgba(0,0,0,0.05); transition: all 0.4s ease;
206
221
  }
207
222
 
208
- /* Inversione elementi Mini Bussola TWD - Giorno */
209
- .mini-compass text:last-of-type { fill: #000 !important; opacity: 0.4; } /* La "S" nera */
210
- #twd-boat-wrap path { fill: #000 !important; opacity: 0.3; } /* Barca interna nera */
211
- #twd-wind-chevron { stroke: #000 !important; } /* Forza il triangolino vento a nero in giorno */
223
+ .mini-compass text:last-of-type { fill: #000 !important; opacity: 0.4; }
224
+ #twd-boat-wrap path { fill: #000 !important; opacity: 0.3; }
225
+ #twd-wind-chevron { stroke: #000 !important; }
212
226
 
213
227
  #awa-pointer, #twa-pointer, #track-pointer, #twd-arrow, #twd-boat-wrap {
214
228
  transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
@@ -232,7 +246,7 @@ rect[fill="#222"] { fill: #eee !important; }
232
246
  #leeway-val { color: #000 !important; }
233
247
 
234
248
  /* ==========================================================================
235
- 7. STATI DI ALLARME
249
+ 7. STATI DI ALLARME E INSTABILITÀ
236
250
  ========================================================================== */
237
251
  .unstable-data { animation: blink-unstable 1.5s infinite ease-in-out; color: #e67e22 !important; }
238
252
  .alarm-warning { color: #f39c12 !important; }
@@ -240,7 +254,7 @@ rect[fill="#222"] { fill: #eee !important; }
240
254
  @keyframes blink-unstable { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
241
255
 
242
256
  /* ==========================================================================
243
- 8. RESPONSIVE
257
+ 8. RESPONSIVE (PORTRAIT MODE)
244
258
  ========================================================================== */
245
259
  @media (max-aspect-ratio: 0.9 / 1) {
246
260
  .main-container { grid-template-columns: 1fr 1fr !important; grid-template-rows: 45vh calc(55vh - 8px) !important; }
@@ -250,7 +264,7 @@ rect[fill="#222"] { fill: #eee !important; }
250
264
  .main-container.focus-active { display: flex !important; flex-direction: column !important; }
251
265
  .focus-active .center-panel { flex: 0 0 45vh !important; }
252
266
  .focus-active .side-panel.has-focus { flex: 0 0 calc(55vh - 8px) !important; display: flex !important; }
253
- .data-box { height: auto !important; flex: 1 !important; }
267
+ .data-box { height: auto !important; }
254
268
  }
255
269
 
256
270
  /* ==========================================================================
@@ -262,10 +276,12 @@ body.night-mode { background-color: #000 !important; color: #ff0000 !important;
262
276
  .night-mode .label, .night-mode .unit, .night-mode .dual-label { color: #800000 !important; }
263
277
  .night-mode .value, .night-mode .value-large { color: #ff3333 !important; text-shadow: 0 0 8px rgba(255, 0, 0, 0.4); }
264
278
 
279
+ /* Grafici Night Mode: Solo linea, no riempimento */
265
280
  .night-mode .graph-wrapper { background: rgba(30, 0, 0, 0.3) !important; }
266
281
  .night-mode .sparkline path:first-of-type { display: none !important; }
267
282
  .night-mode .sparkline path { fill: none !important; stroke: #ff3333 !important; stroke-width: 1.8px !important; opacity: 1 !important; filter: drop-shadow(0 0 2px rgba(255, 0, 0, 0.4)); }
268
283
 
284
+ /* Sovrascrittura griglia per Night Mode: Rosso scuro trasparente */
269
285
  .night-mode .sparkline line { stroke: rgba(255, 0, 0, 0.15) !important; stroke-width: 0.7px !important; }
270
286
  .night-mode #tws-graph line:not([stroke*="rgba"]) { stroke: #ff3333 !important; stroke-width: 1.8px !important; }
271
287
  .night-mode .scale-labels { color: #660000 !important; }
@@ -273,7 +289,7 @@ body.night-mode { background-color: #000 !important; color: #ff0000 !important;
273
289
  .night-mode .box-hercules { background: rgba(60, 0, 0, 0.2) !important; }
274
290
  .night-mode .line-hercules { filter: drop-shadow(0 0 6px #ff0000) !important; }
275
291
 
276
- /* Fix Bussola Centrale Night */
292
+ /* Wind Gauge Night */
277
293
  .night-mode #wind-gauge circle { stroke: #330000; }
278
294
  .night-mode #wind-gauge circle[fill="#050505"] { fill: #050505 !important; }
279
295
  .night-mode #wind-gauge circle[fill="#121212"] { fill: #121212 !important; }
@@ -286,42 +302,47 @@ body.night-mode { background-color: #000 !important; color: #ff0000 !important;
286
302
  .night-mode #aws-display-group text { fill: #ff3333 !important; }
287
303
  .night-mode #center-glow feDropShadow { flood-color: #ff0000 !important; flood-opacity: 0.6 !important; }
288
304
 
289
- /* Bussola TWD Night */
290
- .night-mode .mini-compass { border-color: #330000; background: #000; }
291
- .night-mode .mini-compass text { fill: #800000 !important; }
292
- .night-mode .mini-compass text:last-of-type { fill: #800000 !important; opacity: 1; } /* La "S" torna rossa */
293
- .night-mode #twd-boat-wrap path { fill: #ff3333 !important; opacity: 0.4 !important; } /* Barca torna rossa */
294
- .night-mode #twd-arrow #twd-wind-chevron { stroke: #ff3333 !important; stroke-width: 3px !important; opacity: 1 !important; filter: drop-shadow(0 0 4px #ff0000); transform-origin: center; }
295
-
296
- /* Vento e Leeway Night */
305
+ /* Settori Vento Night */
297
306
  .night-mode #wind-gauge path[stroke="#ff0000"] { stroke: #660000 !important; opacity: 0.8; }
298
307
  .night-mode #wind-gauge path[stroke="#00ff00"] { stroke: #660000 !important; stroke-dasharray: 4, 3; opacity: 0.8; }
299
308
  .night-mode #wind-gauge path[stroke="#ff8800"] { stroke: #330000 !important; stroke-width: 8; }
309
+
310
+ /* Leeway & Pointer Night */
300
311
  .night-mode rect[fill="url(#leeway-grad)"] { fill: url(#leeway-night-grad) !important; }
301
312
  .night-mode #leeway-val { fill: #ff3333 !important; }
302
313
  .night-mode g[stroke="#555"] line { stroke: #4d0000 !important; }
303
314
  .night-mode g[fill="#555"] text { fill: #660000 !important; }
304
- .night-mode rect[fill="#222"] { fill: #0a0000 !important; stroke: #200000; }
315
+ .night-mode rect[fill="#222"], .night-mode rect[fill="#eee"] { fill: #0a0000 !important; stroke: #200000; }
305
316
 
306
317
  .night-mode #awa-pointer path { fill: #ff0000; stroke: #000; }
307
318
  .night-mode #twa-pointer path { fill: #800000; stroke: #000; }
308
319
  .night-mode #track-pointer path { fill: #ff0000; stroke: #fff; stroke-width: 0.5; }
309
320
 
321
+ /* Bussola TWD Night */
322
+ .night-mode .mini-compass { border-color: #330000; background: #000; }
323
+ .night-mode .mini-compass text { fill: #800000 !important; }
324
+ .night-mode .mini-compass text:last-of-type { fill: #800000 !important; opacity: 1; }
325
+ .night-mode #twd-boat-wrap path { fill: #ff3333 !important; opacity: 0.4 !important; }
326
+ .night-mode #twd-arrow #twd-wind-chevron { stroke: #ff3333 !important; filter: drop-shadow(0 0 4px #ff0000); }
327
+
310
328
  /* ==========================================================================
311
- 10. TREND VENTO E ALLARME STRAMBATA
329
+ 11. TREND VENTO E ALLARME STRAMBATA (GYBE)
312
330
  ========================================================================== */
313
331
  @keyframes blink-trend { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
314
332
 
333
+ /* Stato base dei pallini di trend: discreti al 30% */
315
334
  #trend-dot-cw, #trend-dot-ccw, #trend-gauge-cw, #trend-gauge-ccw {
316
335
  opacity: 0.3;
317
336
  transition: opacity 0.3s ease;
318
337
  }
319
338
 
339
+ /* Quando attivi: brillano al 100% e lampeggiano */
320
340
  .is-trending {
321
341
  opacity: 1 !important;
322
342
  animation: blink-trend 1s infinite !important;
323
343
  }
324
344
 
345
+ /* Allarme Strambata: Rosso fisso con bagliore neon massimo */
325
346
  .is-gybing {
326
347
  opacity: 1 !important;
327
348
  animation: none !important;