mirror of
https://github.com/netbymatt/ws4kp.git
synced 2026-04-17 09:09:30 -07:00
Compare commits
13 Commits
marine-for
...
v5.9.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4840909098 | ||
|
|
03dfbc462b | ||
|
|
25291efff5 | ||
|
|
dc77ba835c | ||
|
|
a440990696 | ||
|
|
fc4cbc1415 | ||
|
|
20ba3ddaac | ||
|
|
4205155f96 | ||
|
|
f4101f06cc | ||
|
|
4c3fcfc358 | ||
|
|
366f527aee | ||
|
|
797b4d32fa | ||
|
|
5092076050 |
2
dist/index.html
vendored
2
dist/index.html
vendored
File diff suppressed because one or more lines are too long
2
dist/resources/ws.min.css
vendored
2
dist/resources/ws.min.css
vendored
File diff suppressed because one or more lines are too long
2
dist/resources/ws.min.js
vendored
2
dist/resources/ws.min.js
vendored
File diff suppressed because one or more lines are too long
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ws4kp",
|
||||
"version": "5.9.1",
|
||||
"version": "5.9.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ws4kp",
|
||||
"version": "5.9.1",
|
||||
"version": "5.9.5",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"del": "^6.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ws4kp",
|
||||
"version": "5.9.1",
|
||||
"version": "5.9.5",
|
||||
"description": "Welcome to the WeatherStar 4000+ project page!",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -44,10 +44,13 @@ const init = () => {
|
||||
if (document.fullscreenElement) updateFullScreenNavigate();
|
||||
});
|
||||
|
||||
document.getElementById('txtAddress').addEventListener('keydown', (key) => { if (key.code === 'Enter') formSubmit(); });
|
||||
document.getElementById('btnGetLatLng').addEventListener('click', () => formSubmit());
|
||||
|
||||
document.addEventListener('keydown', documentKeydown);
|
||||
document.addEventListener('touchmove', (e) => { if (fullScreenOverride) e.preventDefault(); });
|
||||
|
||||
$('#frmGetLatLng #txtAddress').devbridgeAutocomplete({
|
||||
$('#txtAddress').devbridgeAutocomplete({
|
||||
serviceUrl: 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest',
|
||||
deferRequestBy: 300,
|
||||
paramName: 'text',
|
||||
@@ -71,11 +74,11 @@ const init = () => {
|
||||
width: 490,
|
||||
});
|
||||
|
||||
$('#frmGetLatLng').on('submit', () => {
|
||||
const ac = $('#frmGetLatLng #txtAddress').devbridgeAutocomplete();
|
||||
const formSubmit = () => {
|
||||
const ac = $('#txtAddress').devbridgeAutocomplete();
|
||||
if (ac.suggestions[0]) $(ac.suggestionsContainer.children[0]).trigger('click');
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
// Auto load the previous query
|
||||
const query = localStorage.getItem('latLonQuery');
|
||||
|
||||
@@ -43,7 +43,7 @@ const incrementInterval = () => {
|
||||
|
||||
const drawScreen = async () => {
|
||||
// get the conditions
|
||||
const data = await getCurrentWeather(() => this.stillWaiting());
|
||||
const data = await getCurrentWeather();
|
||||
|
||||
// nothing to do if there's no data yet
|
||||
if (!data) return;
|
||||
|
||||
@@ -85,15 +85,15 @@ class Hazards extends WeatherDisplay {
|
||||
// set up the timing
|
||||
this.timing.baseDelay = 20;
|
||||
// 24 hours = 6 pages
|
||||
const pages = Math.ceil(list.scrollHeight / 390); // first page is already displayed, last page doesn't happen
|
||||
const timingStep = 75 * 4;
|
||||
const pages = Math.max(Math.ceil(list.scrollHeight / 400) - 3, 1);
|
||||
const timingStep = 400;
|
||||
this.timing.delay = [150 + timingStep];
|
||||
// add additional pages
|
||||
for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep);
|
||||
// add the final 3 second delay
|
||||
this.timing.delay.push(150);
|
||||
this.setStatus(STATUS.loaded);
|
||||
this.timing.delay.push(250);
|
||||
this.calcNavTiming();
|
||||
this.setStatus(STATUS.loaded);
|
||||
}
|
||||
|
||||
drawCanvas() {
|
||||
|
||||
@@ -141,7 +141,6 @@ const parseForecast = async (data) => {
|
||||
const iceAccumulation = expand(data.iceAccumulation.values); // ice icon
|
||||
const probabilityOfPrecipitation = expand(data.probabilityOfPrecipitation.values); // rain icon
|
||||
const snowfallAmount = expand(data.snowfallAmount.values); // snow icon
|
||||
const waveHeight = expand(data.waveHeight.values);
|
||||
|
||||
const icons = await determineIcon(skyCover, weather, iceAccumulation, probabilityOfPrecipitation, snowfallAmount, windSpeed);
|
||||
|
||||
@@ -153,7 +152,6 @@ const parseForecast = async (data) => {
|
||||
probabilityOfPrecipitation: probabilityOfPrecipitation[idx],
|
||||
skyCover: skyCover[idx],
|
||||
icon: icons[idx],
|
||||
waveHeight: waveHeight[idx],
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@@ -32,26 +32,20 @@ class LatestObservations extends WeatherDisplay {
|
||||
const regionalStations = sortedStations.slice(0, 30);
|
||||
|
||||
// get data for regional stations
|
||||
const allConditions = await Promise.all(regionalStations.map(async (station) => {
|
||||
try {
|
||||
const data = await json(`https://api.weather.gov/stations/${station.id}/observations/latest`, { retryCount: 3, stillWaiting: () => this.stillWaiting() });
|
||||
// test for temperature, weather and wind values present
|
||||
if (data.properties.temperature.value === null
|
||||
|| data.properties.textDescription === ''
|
||||
|| data.properties.windSpeed.value === null) return false;
|
||||
// format the return values
|
||||
return {
|
||||
...data.properties,
|
||||
StationId: station.id,
|
||||
city: station.city,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(`Unable to get latest observations for ${station.id}`);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
// remove and stations that did not return data
|
||||
const actualConditions = allConditions.filter((condition) => condition);
|
||||
// get first 7 stations
|
||||
const actualConditions = [];
|
||||
let lastStation = Math.min(regionalStations.length, 7);
|
||||
let firstStation = 0;
|
||||
while (actualConditions.length < 7 && (lastStation) <= regionalStations.length) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const someStations = await getStations(regionalStations.slice(firstStation, lastStation));
|
||||
|
||||
actualConditions.push(...someStations);
|
||||
// update counters
|
||||
firstStation += lastStation;
|
||||
lastStation = Math.min(regionalStations.length + 1, firstStation + 7 - actualConditions.length);
|
||||
}
|
||||
|
||||
// cut down to the maximum of 7
|
||||
this.data = actualConditions.slice(0, this.MaximumRegionalStations);
|
||||
|
||||
@@ -119,5 +113,28 @@ const shortenCurrentConditions = (_condition) => {
|
||||
condition = condition.replace(/ with /, '/');
|
||||
return condition;
|
||||
};
|
||||
|
||||
const getStations = async (stations) => {
|
||||
const stationData = await Promise.all(stations.map(async (station) => {
|
||||
try {
|
||||
const data = await json(`https://api.weather.gov/stations/${station.id}/observations/latest`, { retryCount: 1, stillWaiting: () => this.stillWaiting() });
|
||||
// test for temperature, weather and wind values present
|
||||
if (data.properties.temperature.value === null
|
||||
|| data.properties.textDescription === ''
|
||||
|| data.properties.windSpeed.value === null) return false;
|
||||
// format the return values
|
||||
return {
|
||||
...data.properties,
|
||||
StationId: station.id,
|
||||
city: station.city,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(`Unable to get latest observations for ${station.id}`);
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
// filter false (no data or other error)
|
||||
return stationData.filter((d) => d);
|
||||
};
|
||||
// register display
|
||||
registerDisplay(new LatestObservations(2, 'latest-observations'));
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
// display extended forecast graphically
|
||||
// technically uses the same data as the local forecast, we'll let the browser do the caching of that
|
||||
|
||||
import STATUS from './status.mjs';
|
||||
import WeatherDisplay from './weatherdisplay.mjs';
|
||||
import { registerDisplay } from './navigation.mjs';
|
||||
import getHourlyForecast from './hourly.mjs';
|
||||
|
||||
class MarineForecast extends WeatherDisplay {
|
||||
constructor(navId, elemId) {
|
||||
super(navId, elemId, 'Marine Forecast', false);
|
||||
// this.showOnProgress = false;
|
||||
|
||||
// set timings
|
||||
this.timing.totalScreens = 1;
|
||||
}
|
||||
|
||||
async getData() {
|
||||
if (!super.getData()) return;
|
||||
|
||||
const hourlyForecast = await getHourlyForecast(() => this.stillWaiting());
|
||||
if (hourlyForecast === undefined) {
|
||||
this.setStatus(STATUS.failed);
|
||||
return;
|
||||
}
|
||||
|
||||
// test for all wave heights = 0, no data for wave heights
|
||||
if (hourlyForecast.every((value) => !value.waveHeight)) {
|
||||
// total screens = 0 to skip this display
|
||||
this.totalScreens = 0;
|
||||
this.setStatus(STATUS.noData);
|
||||
return;
|
||||
}
|
||||
|
||||
this.data = hourlyForecast;
|
||||
this.screenIndex = 0;
|
||||
this.setStatus(STATUS.loaded);
|
||||
}
|
||||
|
||||
async drawCanvas() {
|
||||
super.drawCanvas();
|
||||
|
||||
// determine bounds
|
||||
// grab the first three or second set of three array elements
|
||||
const forecast = this.data.slice(0, 2);
|
||||
|
||||
// create each day template
|
||||
const days = forecast.map((Day) => {
|
||||
const fill = {};
|
||||
const waveHeight = Math.round(Day.waveHeight * 3.281);
|
||||
fill.date = Day.dayName;
|
||||
fill['wind-dir'] = Day.windDirection;
|
||||
fill['wind-speed'] = '10 - 15kts';
|
||||
fill['wave-height'] = `${waveHeight}'`;
|
||||
fill['wave-desc'] = waveDesc(waveHeight);
|
||||
|
||||
const { low } = Day;
|
||||
if (low !== undefined) {
|
||||
fill['value-lo'] = Math.round(low);
|
||||
}
|
||||
const { high } = Day;
|
||||
fill['value-hi'] = Math.round(high);
|
||||
fill.condition = Day.text;
|
||||
|
||||
// draw the icon
|
||||
fill['wave-icon'] = { type: 'img', src: waveImage('') };
|
||||
|
||||
// return the filled template
|
||||
return this.fillTemplate('day', fill);
|
||||
});
|
||||
|
||||
// empty and update the container
|
||||
const dayContainer = this.elem.querySelector('.day-container');
|
||||
dayContainer.innerHTML = '';
|
||||
dayContainer.append(...days);
|
||||
this.finishDraw();
|
||||
}
|
||||
}
|
||||
|
||||
const waveImage = (conditions) => {
|
||||
const color = 'rgb(172, 165, 251)';
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 150;
|
||||
canvas.height = 20;
|
||||
const context = canvas.getContext('2d');
|
||||
context.imageSmoothingEnabled = false;
|
||||
|
||||
let y = 0;
|
||||
let r = 35;
|
||||
let arc1 = Math.PI * 0.3;
|
||||
let arc2 = Math.PI * 0.7;
|
||||
|
||||
switch (conditions) {
|
||||
case 'CHOPPY':
|
||||
y = -10;
|
||||
arc1 = Math.PI * 0.2;
|
||||
arc2 = Math.PI * 0.8;
|
||||
r = 25;
|
||||
break;
|
||||
|
||||
case 'ROUGH':
|
||||
y = -5;
|
||||
arc1 = Math.PI * 0.1;
|
||||
arc2 = Math.PI * 0.9;
|
||||
r = 20;
|
||||
break;
|
||||
|
||||
case 'LIGHT':
|
||||
default:
|
||||
y = -20;
|
||||
arc1 = Math.PI * 0.3;
|
||||
arc2 = Math.PI * 0.7;
|
||||
r = 35;
|
||||
break;
|
||||
}
|
||||
|
||||
context.beginPath();
|
||||
context.arc(35, y, r, arc1, arc2);
|
||||
context.strokeStyle = color;
|
||||
context.lineWidth = 4;
|
||||
context.stroke();
|
||||
context.beginPath();
|
||||
context.arc(75, y, r, arc1, arc2);
|
||||
context.stroke();
|
||||
context.beginPath();
|
||||
context.arc(115, y, r, arc1, arc2);
|
||||
context.stroke();
|
||||
|
||||
return canvas.toDataURL();
|
||||
};
|
||||
|
||||
const waveDesc = (waveHeight) => {
|
||||
if (waveHeight > 7) return 'ROUGH';
|
||||
if (waveHeight > 4) return 'CHOPPY';
|
||||
return 'LIGHT';
|
||||
};
|
||||
|
||||
// register display
|
||||
registerDisplay(new MarineForecast(11, 'marine-forecast'));
|
||||
@@ -77,7 +77,7 @@ const getWeather = async (latLon, haveDataCallback) => {
|
||||
weatherParameters.weatherOffice = point.properties.cwa;
|
||||
weatherParameters.city = city;
|
||||
weatherParameters.state = point.properties.relativeLocation.properties.state;
|
||||
weatherParameters.timeZone = point.properties.relativeLocation.properties.timeZone;
|
||||
weatherParameters.timeZone = point.properties.timeZone;
|
||||
weatherParameters.forecast = point.properties.forecast;
|
||||
weatherParameters.forecastGridData = point.properties.forecastGridData;
|
||||
weatherParameters.stations = stations.features;
|
||||
@@ -109,6 +109,13 @@ const updateStatus = (value) => {
|
||||
// calculate first enabled display
|
||||
const firstDisplayIndex = displays.findIndex((display) => display.enabled && display.timing.totalScreens > 0);
|
||||
|
||||
// value.id = 0 is hazards, if they fail to load hot-wire a new value.id to the current display to see if it needs to be loaded
|
||||
// typically this plays out as current conditions loads, then hazards fails.
|
||||
if (value.id === 0 && (value.status === STATUS.failed || value.status === STATUS.retrying)) {
|
||||
value.id = firstDisplayIndex;
|
||||
value.status = displays[firstDisplayIndex].status;
|
||||
}
|
||||
|
||||
// if this is the first display and we're playing, load it up so it starts playing
|
||||
if (isPlaying() && value.id === firstDisplayIndex && value.status === STATUS.loaded) {
|
||||
navTo(msg.command.firstFrame);
|
||||
@@ -393,6 +400,8 @@ const registerRefreshData = (callback) => {
|
||||
loadTwcData.callback = callback;
|
||||
};
|
||||
|
||||
const timeZone = () => weatherParameters.timeZone;
|
||||
|
||||
export {
|
||||
updateStatus,
|
||||
displayNavMessage,
|
||||
@@ -408,4 +417,5 @@ export {
|
||||
latLonReceived,
|
||||
stopAutoRefreshTimer,
|
||||
registerRefreshData,
|
||||
timeZone,
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ import { loadImg } from './utils/image.mjs';
|
||||
import { text } from './utils/fetch.mjs';
|
||||
import { rewriteUrl } from './utils/cors.mjs';
|
||||
import WeatherDisplay from './weatherdisplay.mjs';
|
||||
import { registerDisplay } from './navigation.mjs';
|
||||
import { registerDisplay, timeZone } from './navigation.mjs';
|
||||
import * as utils from './radar-utils.mjs';
|
||||
|
||||
class Radar extends WeatherDisplay {
|
||||
@@ -159,7 +159,7 @@ class Radar extends WeatherDisplay {
|
||||
zone: 'UTC',
|
||||
}).setZone();
|
||||
} else {
|
||||
time = DateTime.fromHTTP(response.headers.get('last-modified')).setZone();
|
||||
time = DateTime.fromHTTP(response.headers.get('last-modified')).setZone(timeZone());
|
||||
}
|
||||
|
||||
// assign to an html image element
|
||||
|
||||
@@ -23,7 +23,9 @@ const getRegionalObservation = async (point, city) => {
|
||||
const observation = await json(`${station}/observations/latest`);
|
||||
// preload the image
|
||||
if (!observation.properties.icon) return false;
|
||||
preloadImg(getWeatherRegionalIconFromIconLink(observation.properties.icon, !observation.properties.daytime));
|
||||
const icon = getWeatherRegionalIconFromIconLink(observation.properties.icon, !observation.properties.daytime);
|
||||
if (!icon) return false;
|
||||
preloadImg(icon);
|
||||
// return the observation
|
||||
return observation.properties;
|
||||
} catch (e) {
|
||||
|
||||
@@ -87,6 +87,9 @@ class RegionalForecast extends WeatherDisplay {
|
||||
|
||||
// wait for the regional observation if it's not done yet
|
||||
const observation = await observationPromise;
|
||||
|
||||
if (!observation) return false;
|
||||
|
||||
// format the observation the same as the forecast
|
||||
const regionalObservation = {
|
||||
daytime: !!observation.icon.match(/\/day\//),
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
import STATUS, { calcStatusClass, statusClasses } from './status.mjs';
|
||||
import { DateTime } from '../vendor/auto/luxon.mjs';
|
||||
import { elemForEach } from './utils/elem.mjs';
|
||||
import {
|
||||
msg, displayNavMessage, isPlaying, updateStatus,
|
||||
msg, displayNavMessage, isPlaying, updateStatus, timeZone,
|
||||
} from './navigation.mjs';
|
||||
|
||||
class WeatherDisplay {
|
||||
@@ -173,20 +172,22 @@ class WeatherDisplay {
|
||||
// only draw if canvas is active to conserve battery
|
||||
if (!this.active) return;
|
||||
// Get the current date and time.
|
||||
const now = DateTime.local();
|
||||
const now = DateTime.local().setZone(timeZone());
|
||||
|
||||
// time = "11:35:08 PM";
|
||||
const time = now.toLocaleString(DateTime.TIME_WITH_SECONDS).padStart(11, ' ');
|
||||
const date = now.toFormat(' ccc LLL ') + now.day.toString().padStart(2, ' ');
|
||||
|
||||
if (this.lastTime !== time) {
|
||||
elemForEach('.date-time.time', (elem) => { elem.innerHTML = time.toUpperCase(); });
|
||||
const dateElem = this.elem.querySelector('.date-time.date');
|
||||
const timeElem = this.elem.querySelector('.date-time.time');
|
||||
|
||||
if (timeElem && this.lastTime !== time) {
|
||||
timeElem.innerHTML = time.toUpperCase();
|
||||
}
|
||||
this.lastTime = time;
|
||||
|
||||
const date = now.toFormat(' ccc LLL ') + now.day.toString().padStart(2, ' ');
|
||||
|
||||
if (this.lastDate !== date) {
|
||||
elemForEach('.date-time.date', (elem) => { elem.innerHTML = date.toUpperCase(); });
|
||||
if (dateElem && this.lastDate !== date) {
|
||||
dateElem.innerHTML = date.toUpperCase();
|
||||
}
|
||||
this.lastDate = date;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,98 +0,0 @@
|
||||
@use 'shared/_colors'as c;
|
||||
@use 'shared/_utils'as u;
|
||||
|
||||
#marine-forecast-html.weather-display {
|
||||
background-image: url('../images/BackGround8_1.png');
|
||||
}
|
||||
|
||||
.weather-display .main.marine-forecast {
|
||||
font-family: 'Star4000';
|
||||
font-size: 24pt;
|
||||
@include u.text-shadow();
|
||||
|
||||
.advisory {
|
||||
width: 100%;
|
||||
height: 90px;
|
||||
overflow: hidden;
|
||||
|
||||
.advisory-text {
|
||||
border: 4px solid black;
|
||||
width: 75%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
.headers {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.winds {
|
||||
text-align: right;
|
||||
width: 150px;
|
||||
margin-top: 42px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.day-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.day {
|
||||
padding: 5px;
|
||||
width: 165px;
|
||||
display: inline-block;
|
||||
margin: 0px 15px;
|
||||
text-align: center;
|
||||
|
||||
.date {
|
||||
color: c.$title-color;
|
||||
}
|
||||
|
||||
.wave {
|
||||
border: 4px solid #b09ffb;
|
||||
|
||||
.wave-icon {
|
||||
height: 20px;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.temperatures {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
|
||||
.temperature-block {
|
||||
display: inline-block;
|
||||
width: 44%;
|
||||
vertical-align: top;
|
||||
|
||||
>div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-family: 'Star4000 Large';
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&.lo .label {
|
||||
color: c.$extended-low;
|
||||
}
|
||||
|
||||
&.hi .label {
|
||||
color: c.$title-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,72 +20,83 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
font-family: "Star4000";
|
||||
}
|
||||
#divQuery {
|
||||
max-width: 640px;
|
||||
|
||||
#imgGetGps {
|
||||
height: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.buttons {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
text-align: right;
|
||||
|
||||
#txtAddress {
|
||||
width: 490px;
|
||||
font-size: 16pt;
|
||||
max-width: calc(100% - 8px);
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
border: 1px solid darkgray;
|
||||
}
|
||||
}
|
||||
|
||||
#btnGetGps,
|
||||
#btnGetLatLng,
|
||||
#btnClearQuery {
|
||||
font-size: 16pt;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
}
|
||||
|
||||
border: 1px solid darkgray;
|
||||
}
|
||||
|
||||
#btnGetGps {
|
||||
img {
|
||||
|
||||
&.dark {
|
||||
display: none;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
display: inline-block;
|
||||
}
|
||||
#imgGetGps {
|
||||
height: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.light {
|
||||
button {
|
||||
font-size: 16pt;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
display: none;
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
}
|
||||
|
||||
border: 1px solid darkgray;
|
||||
}
|
||||
|
||||
#btnGetGps {
|
||||
img {
|
||||
|
||||
&.dark {
|
||||
display: none;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: black;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: black;
|
||||
input,
|
||||
button {
|
||||
font-family: "Star4000";
|
||||
}
|
||||
|
||||
#txtAddress {
|
||||
width: calc(100% - 170px);
|
||||
max-width: 490px;
|
||||
font-size: 16pt;
|
||||
min-width: 200px;
|
||||
display: inline-block;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(1);
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
border: 1px solid darkgray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.autocomplete-suggestions {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #000000;
|
||||
@@ -93,19 +104,19 @@ button {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
.autocomplete-suggestion {
|
||||
/*padding: 2px 5px;*/
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 16pt;
|
||||
}
|
||||
.autocomplete-suggestion {
|
||||
/*padding: 2px 5px;*/
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
.autocomplete-selected {
|
||||
background-color: #0000ff;
|
||||
color: #ffffff;
|
||||
.autocomplete-selected {
|
||||
background-color: #0000ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
#divTwc {
|
||||
|
||||
@@ -11,5 +11,4 @@
|
||||
@import 'radar';
|
||||
@import 'regional-forecast';
|
||||
@import 'almanac';
|
||||
@import 'hazards';
|
||||
@import 'marine-forecast';
|
||||
@import 'hazards';
|
||||
@@ -42,7 +42,7 @@
|
||||
<script type="module" src="scripts/modules/regionalforecast.mjs"></script>
|
||||
<script type="module" src="scripts/modules/travelforecast.mjs"></script>
|
||||
<script type="module" src="scripts/modules/progress.mjs"></script>
|
||||
<script type="module" src="scripts/modules/marineforecast.mjs"></script>
|
||||
<script type="module" src="scripts/modules/radar.mjs"></script>
|
||||
<script type="module" src="scripts/index.mjs"></script>
|
||||
|
||||
<!-- data -->
|
||||
@@ -60,13 +60,14 @@
|
||||
|
||||
|
||||
<div id="divQuery">
|
||||
<form id="frmGetLatLng">
|
||||
<input id="txtAddress" type="text" value="" placeholder="Zip or City, State" /><button id="btnGetGps" type="button" title="Get GPS Location"><img src="images/nav/ic_gps_fixed_black_18dp_1x.png" class="light"/><img src="images/nav/ic_gps_fixed_white_18dp_1x.png" class="dark"/></button>
|
||||
<input id="btnGetLatLng" type="submit" value="GO" />
|
||||
<input id="btnClearQuery" type="reset" value="Reset" />
|
||||
</form>
|
||||
<div id="divLat"></div>
|
||||
<div id="divLng"></div>
|
||||
<input id="txtAddress" type="text" value="" placeholder="Zip or City, State" />
|
||||
<div class="buttons">
|
||||
<button id="btnGetGps" type="button" title="Get GPS Location"><img src="images/nav/ic_gps_fixed_black_18dp_1x.png" class="light"/>
|
||||
<img src="images/nav/ic_gps_fixed_white_18dp_1x.png" class="dark"/>
|
||||
</button>
|
||||
<button id="btnGetLatLng" type="submit">GO</button>
|
||||
<button id="btnClearQuery" type="reset">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="version" style="display:none">
|
||||
<%- version %>
|
||||
@@ -107,9 +108,6 @@
|
||||
</div>
|
||||
<div id="almanac-html" class="weather-display">
|
||||
<%- include('partials/almanac.ejs') %>
|
||||
</div>
|
||||
<div id="marine-forecast-html" class="weather-display">
|
||||
<%- include('partials/marine-forecast.ejs') %>
|
||||
</div>
|
||||
<div id="extended-forecast-html" class="weather-display">
|
||||
<%- include('partials/extended-forecast.ejs') %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%- include('header.ejs', {titleDual:{ top: 'Current' , bottom: 'Conditions' }, noaaLogo: true}) %>
|
||||
<%- include('header.ejs', {titleDual:{ top: 'Current' , bottom: 'Conditions' }, noaaLogo: true, hasTime: true}) %>
|
||||
<div class="main has-scroll has-box current-weather">
|
||||
<div class="weather template">
|
||||
<div class="left col">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%- include('header.ejs', {titleDual:{ top: 'Latest' , bottom: 'Observations' }, noaaLogo: true }) %>
|
||||
<%- include('header.ejs', {titleDual:{ top: 'Latest' , bottom: 'Observations' }, noaaLogo: true, hasTime: true }) %>
|
||||
<div class="main has-scroll latest-observations has-box">
|
||||
<div class="container">
|
||||
<div class="column-headers">
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<%- include('header.ejs', { title: 'Marine Forecast' , hasTime: true }) %>
|
||||
<div class="main has-scroll marine-forecast">
|
||||
<div class="advisory">
|
||||
<div class="advisory-text">Small Craft Advisory</div>
|
||||
</div>
|
||||
<div class="headers">
|
||||
<div class="winds">WINDS:</div>
|
||||
<div class="winds">WAVES:</div>
|
||||
</div>
|
||||
<div class="day-container">
|
||||
<div class="day template">
|
||||
<div class="date"></div>
|
||||
<div class="wind-dir"></div>
|
||||
<div class="wind-speed"></div>
|
||||
<div class="wave">
|
||||
<div class="wave-height"></div>
|
||||
<div class="wave-icon"><img src="" /></div>
|
||||
<div class="wave-desc"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('scroll.ejs') %>
|
||||
@@ -51,9 +51,5 @@
|
||||
"editor.defaultFormatter": "j69.ejs-beautify"
|
||||
},
|
||||
"files.exclude": {},
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
}
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user