From f26fce1e58c755d72135c881d418379c4bda444d Mon Sep 17 00:00:00 2001 From: Matt Walsh Date: Fri, 29 Jul 2022 16:12:42 -0500 Subject: [PATCH] more html --- .vscode/settings.json | 18 +- package-lock.json | 374 +++++++++++++++++++++++ package.json | 83 ++--- server/scripts/modules/currentweather.js | 20 +- server/scripts/modules/hourly.js | 109 ++----- server/scripts/modules/icons.js | 2 + server/scripts/modules/progress.js | 6 +- server/scripts/modules/utilities.js | 7 + server/scripts/modules/weatherdisplay.js | 118 +++---- server/styles/compiled.css | 237 ++++++++++++++ server/styles/compiled.css.map | 1 + server/styles/scss/_colors.scss | 8 + server/styles/scss/_current-weather.scss | 97 ++++++ server/styles/scss/_hourly.scss | 95 ++++++ server/styles/scss/_utils.scss | 17 ++ server/styles/scss/_weatherdisplay.scss | 103 +++++++ server/styles/scss/compiled.scss | 3 + server/styles/weatherdisplay.css | 61 ---- views/index.ejs | 230 +++++++------- views/partials/current-weather.ejs | 37 +++ views/partials/header.ejs | 28 +- views/partials/hourly.ejs | 23 +- 22 files changed, 1305 insertions(+), 372 deletions(-) create mode 100644 server/styles/compiled.css create mode 100644 server/styles/compiled.css.map create mode 100644 server/styles/scss/_colors.scss create mode 100644 server/styles/scss/_current-weather.scss create mode 100644 server/styles/scss/_hourly.scss create mode 100644 server/styles/scss/_utils.scss create mode 100644 server/styles/scss/_weatherdisplay.scss create mode 100644 server/styles/scss/compiled.scss delete mode 100644 server/styles/weatherdisplay.css create mode 100644 views/partials/current-weather.ejs diff --git a/.vscode/settings.json b/.vscode/settings.json index 84b57c5..ebca767 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,21 @@ { "cSpell.enableFiletypes": [ "javascript" - ] + ], + "liveSassCompile.settings.formats": [ + { + "format": "expanded", + "extensionName": ".css", + "savePath": "/server/styles", + "savePathSegmentKeys": null, + "savePathReplaceSegmentsWith": null + } + ], + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/*.code-search": true, + "**/compiled.css": true, + "**/*.min.js": true, + }, } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a6e82d6..3f042da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,11 +22,13 @@ "gulp-htmlmin": "^5.0.1", "gulp-rename": "^2.0.0", "gulp-s3-upload": "^1.7.3", + "gulp-sass": "^5.1.0", "gulp-terser": "^2.0.0", "jquery": "^3.6.0", "jquery-touchswipe": "^1.6.19", "luxon": "^2.3.1", "nosleep.js": "^0.12.0", + "sass": "^1.54.0", "suncalc": "^1.8.0", "swiped-events": "^1.1.4" } @@ -3162,6 +3164,32 @@ "node": ">=6" } }, + "node_modules/gulp-sass": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-5.1.0.tgz", + "integrity": "sha512-7VT0uaF+VZCmkNBglfe1b34bxn/AfcssquLKVDYnCDJ3xNBaW7cUuI3p3BQmoKcoKFrs9jdzUxyb+u+NGfL4OQ==", + "dev": true, + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "picocolors": "^1.0.0", + "plugin-error": "^1.0.1", + "replace-ext": "^2.0.0", + "strip-ansi": "^6.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gulp-sass/node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/gulp-terser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/gulp-terser/-/gulp-terser-2.1.0.tgz", @@ -3445,6 +3473,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4209,6 +4243,12 @@ "node": ">=4" } }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5293,6 +5333,12 @@ "through": "~2.3" } }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -6086,6 +6132,167 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sass": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz", + "integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass/node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/sass/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sass/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/sass/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sass/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", @@ -6405,6 +6612,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -10215,6 +10431,28 @@ } } }, + "gulp-sass": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-5.1.0.tgz", + "integrity": "sha512-7VT0uaF+VZCmkNBglfe1b34bxn/AfcssquLKVDYnCDJ3xNBaW7cUuI3p3BQmoKcoKFrs9jdzUxyb+u+NGfL4OQ==", + "dev": true, + "requires": { + "lodash.clonedeep": "^4.5.0", + "picocolors": "^1.0.0", + "plugin-error": "^1.0.1", + "replace-ext": "^2.0.0", + "strip-ansi": "^6.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true + } + } + }, "gulp-terser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/gulp-terser/-/gulp-terser-2.1.0.tgz", @@ -10435,6 +10673,12 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -11008,6 +11252,12 @@ "path-exists": "^3.0.0" } }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11856,6 +12106,12 @@ "through": "~2.3" } }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -12444,6 +12700,118 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sass": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz", + "integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", @@ -12712,6 +13080,12 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", diff --git a/package.json b/package.json index 71a16a9..ad91172 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,44 @@ { - "name": "ws4kp", - "version": "4.1.3", - "description": "Welcome to the WeatherStar 4000+ project page!", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/netbymatt/ws4kp.git" - }, - "author": "Matt Walsh", - "license": "MIT", - "bugs": { - "url": "https://github.com/netbymatt/ws4kp/issues" - }, - "homepage": "https://github.com/netbymatt/ws4kp#readme", - "devDependencies": { - "del": "^6.0.0", - "ejs": "^3.1.5", - "eslint": "^8.10.0", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-plugin-import": "^2.22.1", - "express": "^4.17.1", - "gulp": "^4.0.2", - "gulp-clean-css": "^4.3.0", - "gulp-concat": "^2.6.1", - "gulp-ejs": "^5.1.0", - "gulp-htmlmin": "^5.0.1", - "gulp-rename": "^2.0.0", - "gulp-s3-upload": "^1.7.3", - "gulp-terser": "^2.0.0", - "jquery": "^3.6.0", - "jquery-touchswipe": "^1.6.19", - "luxon": "^2.3.1", - "nosleep.js": "^0.12.0", - "suncalc": "^1.8.0", - "swiped-events": "^1.1.4" - } -} + "name": "ws4kp", + "version": "4.1.3", + "description": "Welcome to the WeatherStar 4000+ project page!", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build:css": "sass ./server/styles/scss/style.scss ./server/styles/compiled.css" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/netbymatt/ws4kp.git" + }, + "author": "Matt Walsh", + "license": "MIT", + "bugs": { + "url": "https://github.com/netbymatt/ws4kp/issues" + }, + "homepage": "https://github.com/netbymatt/ws4kp#readme", + "devDependencies": { + "del": "^6.0.0", + "ejs": "^3.1.5", + "eslint": "^8.10.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.22.1", + "express": "^4.17.1", + "gulp": "^4.0.2", + "gulp-clean-css": "^4.3.0", + "gulp-concat": "^2.6.1", + "gulp-ejs": "^5.1.0", + "gulp-htmlmin": "^5.0.1", + "gulp-rename": "^2.0.0", + "gulp-s3-upload": "^1.7.3", + "gulp-sass": "^5.1.0", + "gulp-terser": "^2.0.0", + "jquery": "^3.6.0", + "jquery-touchswipe": "^1.6.19", + "luxon": "^2.3.1", + "nosleep.js": "^0.12.0", + "sass": "^1.54.0", + "suncalc": "^1.8.0", + "swiped-events": "^1.1.4" + } +} \ No newline at end of file diff --git a/server/scripts/modules/currentweather.js b/server/scripts/modules/currentweather.js index b47351e..d1def95 100644 --- a/server/scripts/modules/currentweather.js +++ b/server/scripts/modules/currentweather.js @@ -69,7 +69,7 @@ class CurrentWeather extends WeatherDisplay { data.Temperature = Math.round(observations.temperature.value); data.TemperatureUnit = 'C'; data.DewPoint = Math.round(observations.dewpoint.value); - data.Ceiling = Math.round(observations.cloudLayers[0].base.value); + data.Ceiling = Math.round(observations.cloudLayers[0]?.base?.value ?? 0); data.CeilingUnit = 'm.'; data.Visibility = Math.round(observations.visibility.value / 1000); data.VisibilityUnit = ' km.'; @@ -190,15 +190,17 @@ class CurrentWeather extends WeatherDisplay { draw.text(this.context, 'Star4000 Large', 'bold 16pt', '#FFFFFF', 560, 365, data.WindChill + String.fromCharCode(176), 2, 'right'); } + if (data.Icon) { // get main icon - this.gifs.push(await utils.image.superGifAsync({ - src: data.Icon, - auto_play: true, - canvas: this.canvas, - x: 140, - y: 175, - max_width: 126, - })); + this.gifs.push(await utils.image.superGifAsync({ + src: data.Icon, + auto_play: true, + canvas: this.canvas, + x: 140, + y: 175, + max_width: 126, + })); + } this.finishDraw(); } diff --git a/server/scripts/modules/hourly.js b/server/scripts/modules/hourly.js index 1f4c85c..9fd5876 100644 --- a/server/scripts/modules/hourly.js +++ b/server/scripts/modules/hourly.js @@ -1,22 +1,17 @@ // hourly forecast list -/* globals WeatherDisplay, utils, STATUS, UNITS, draw, navigation, icons, luxon */ +/* globals WeatherDisplay, utils, STATUS, UNITS, navigation, icons, luxon */ // eslint-disable-next-line no-unused-vars class Hourly extends WeatherDisplay { constructor(navId, elemId, defaultActive) { // special height and width for scrolling - super(navId, elemId, 'Hourly Forecast', defaultActive); - // pre-load background image (returns promise) - this.backgroundImage = utils.image.load('images/BackGround6_1.png'); - - // height of one hour in the forecast - this.hourHeight = 72; + super(navId, elemId, 'Hourly Forecast', defaultActive, true); // set up the timing this.timing.baseDelay = 20; // 24 hours = 6 pages const pages = 4; // first page is already displayed, last page doesn't happen - const timingStep = this.hourHeight * 4; + const timingStep = 75 * 4; this.timing.delay = [150 + timingStep]; // add additional pages for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep); @@ -114,52 +109,25 @@ class Hourly extends WeatherDisplay { } async drawLongCanvas() { - // create the "long" canvas if necessary - if (!this.longCanvas) { - this.longCanvas = document.createElement('canvas'); - this.longCanvas.width = 640; - this.longCanvas.height = 24 * this.hourHeight; - this.longContext = this.longCanvas.getContext('2d'); - this.longCanvasGifs = []; - } - - // stop all gifs - this.longCanvasGifs.forEach((gif) => gif.pause()); - // delete the gifs - this.longCanvasGifs.length = 0; - - // clean up existing gifs - this.gifs.forEach((gif) => gif.pause()); - // delete the gifs - this.gifs.length = 0; - - this.longContext.clearRect(0, 0, this.longCanvas.width, this.longCanvas.height); - - // draw the "long" canvas with all cities - draw.box(this.longContext, 'rgb(35, 50, 112)', 0, 0, 640, 24 * this.hourHeight); - - for (let i = 0; i <= 4; i += 1) { - const y = i * 346; - draw.horizontalGradient(this.longContext, 0, y, 640, y + 346, '#102080', '#001040'); - } + // get the list element and populate + const list = this.elem.querySelector('.hourly-lines'); + list.innerHTML = ''; const startingHour = luxon.DateTime.local(); - await Promise.all(this.data.map(async (data, index) => { - // calculate base y value - const y = 50 + this.hourHeight * index; - + const lines = this.data.map((data, index) => { + const line = this.templates['hourly-row'].cloneNode(true); // hour const hour = startingHour.plus({ hours: index }); const formattedHour = hour.toLocaleString({ weekday: 'short', hour: 'numeric' }); - draw.text(this.longContext, 'Star4000 Large Compressed', '24pt', '#FFFF00', 80, y, formattedHour, 2); + line.querySelector('.hour').innerHTML = formattedHour; // temperatures, convert to strings with no decimal const temperature = Math.round(data.temperature).toString().padStart(3); const feelsLike = Math.round(data.apparentTemperature).toString().padStart(3); - draw.text(this.longContext, 'Star4000 Large', '24pt', '#FFFF00', 390, y, temperature, 2, 'center'); + line.querySelector('.temp').innerHTML = temperature; // only plot apparent temperature if there is a difference - if (temperature !== feelsLike) draw.text(this.longContext, 'Star4000 Large', '24pt', '#FFFF00', 470, y, feelsLike, 2, 'center'); + if (temperature !== feelsLike) line.querySelector('.like').innerHTML = feelsLike; // wind let wind = 'Calm'; @@ -167,44 +135,25 @@ class Hourly extends WeatherDisplay { const windSpeed = Math.round(data.windSpeed).toString(); wind = data.windDirection + (Array(6 - data.windDirection.length - windSpeed.length).join(' ')) + windSpeed; } - draw.text(this.longContext, 'Star4000 Large', '24pt', '#FFFF00', 580, y, wind, 2, 'center'); + line.querySelector('.wind').innerHTML = wind; - this.longCanvasGifs.push(await utils.image.superGifAsync({ - src: data.icon, - auto_play: true, - canvas: this.longCanvas, - x: 290, - y: y - 35, - max_width: 47, - })); - })); + // image + line.querySelector('.icon img').src = data.icon; + + return line; + }); + + list.append(...lines); } - async drawCanvas() { - // there are technically 2 canvases: the standard canvas and the extra-long canvas that contains the complete - // list of cities. The second canvas is copied into the standard canvas to create the scroll + drawCanvas() { super.drawCanvas(); - - // draw the standard context - this.context.drawImage(await this.backgroundImage, 0, 0); - draw.horizontalGradientSingle(this.context, 0, 30, 500, 90, draw.topColor1, draw.topColor2); - draw.triangle(this.context, 'rgb(28, 10, 87)', 500, 30, 450, 90, 500, 90); - - draw.titleText(this.context, 'Hourly Forecast'); - - draw.text(this.context, 'Star4000 Small', '24pt', '#FFFF00', 390, 105, 'TEMP', 2, 'center'); - draw.text(this.context, 'Star4000 Small', '24pt', '#FFFF00', 470, 105, 'LIKE', 2, 'center'); - draw.text(this.context, 'Star4000 Small', '24pt', '#FFFF00', 580, 105, 'WIND', 2, 'center'); - - // copy the scrolled portion of the canvas for the initial run before the scrolling starts - this.context.drawImage(this.longCanvas, 0, 0, 640, 289, 0, 110, 640, 289); - this.finishDraw(); } - async showCanvas() { - // special to travel forecast to draw the remainder of the canvas - await this.drawCanvas(); + showCanvas() { + // special to hourly to draw the remainder of the canvas + this.drawCanvas(); super.showCanvas(); } @@ -215,17 +164,14 @@ class Hourly extends WeatherDisplay { // base count change callback baseCountChange(count) { - // get a fresh canvas - const longCanvas = this.getLongCanvas(); - // calculate scroll offset and don't go past end - let offsetY = Math.min(longCanvas.height - 289, (count - 150)); + let offsetY = Math.min(this.elem.querySelector('.hourly-lines').getBoundingClientRect().height - 289, (count - 150)); // don't let offset go negative if (offsetY < 0) offsetY = 0; // copy the scrolled portion of the canvas - this.context.drawImage(longCanvas, 0, offsetY, 640, 289, 0, 110, 640, 289); + this.elem.querySelector('.main').scrollTo(0, offsetY); } static getTravelCitiesDayName(cities) { @@ -241,9 +187,4 @@ class Hourly extends WeatherDisplay { return dayName; }, ''); } - - // necessary to get the lastest long canvas when scrolling - getLongCanvas() { - return this.longCanvas; - } } diff --git a/server/scripts/modules/icons.js b/server/scripts/modules/icons.js index c0c6c87..2b80349 100644 --- a/server/scripts/modules/icons.js +++ b/server/scripts/modules/icons.js @@ -142,6 +142,8 @@ const icons = (() => { }; const getWeatherIconFromIconLink = (link, _isNightTime) => { + if (!link) return; + // internal function to add path to returned icon const addPath = (icon) => `images/${icon}`; // extract day or night if not provided diff --git a/server/scripts/modules/progress.js b/server/scripts/modules/progress.js index 6e3ca23..0c8dcb4 100644 --- a/server/scripts/modules/progress.js +++ b/server/scripts/modules/progress.js @@ -94,8 +94,10 @@ class Progress extends WeatherDisplay { } canvasClick(e) { - const x = e.offsetX; - const y = e.offsetY; + // un-scale + const scale = e.target.getBoundingClientRect().width / e.target.width; + const x = e.offsetX / scale; + const y = e.offsetY / scale; // eliminate off canvas and outside area clicks if (!this.isActive()) return; if (y < 100 || y > 410) return; diff --git a/server/scripts/modules/utilities.js b/server/scripts/modules/utilities.js index 2a1ede2..01294c7 100644 --- a/server/scripts/modules/utilities.js +++ b/server/scripts/modules/utilities.js @@ -286,8 +286,15 @@ const utils = (() => { } }; + const elemForEach = (selector, callback) => { + [...document.querySelectorAll(selector)].forEach(callback); + }; + // return an orderly object return { + elem: { + forEach: elemForEach, + }, image: { load: loadImg, superGifAsync, diff --git a/server/scripts/modules/weatherdisplay.js b/server/scripts/modules/weatherdisplay.js index 874212c..e19133b 100644 --- a/server/scripts/modules/weatherdisplay.js +++ b/server/scripts/modules/weatherdisplay.js @@ -1,6 +1,6 @@ // base weather display class -/* globals navigation, utils, draw, UNITS, luxon, currentWeatherScroll */ +/* globals navigation, utils, luxon, currentWeatherScroll */ const STATUS = { loading: Symbol('loading'), @@ -12,7 +12,7 @@ const STATUS = { // eslint-disable-next-line no-unused-vars class WeatherDisplay { - constructor(navId, elemId, name, defaultEnabled) { + constructor(navId, elemId, name, defaultEnabled, isHtml) { // navId is used in messaging this.navId = navId; this.elemId = undefined; @@ -21,6 +21,7 @@ class WeatherDisplay { this.loadingStatus = STATUS.loading; this.name = name ?? elemId; this.getDataCallbacks = []; + this.isHtml = isHtml; // default navigation timing this.timing = { @@ -41,6 +42,9 @@ class WeatherDisplay { this.setStatus(STATUS.disabled); } this.startNavCount(); + + // get any templates + this.loadTemplates(); } addCheckbox(defaultEnabled = true) { @@ -97,6 +101,9 @@ class WeatherDisplay { if (this.elemId) return; this.elemId = elemId; + // no additional work if this is HTML + if (this.isHtml) return; + // create a canvas const canvas = document.createElement('template'); canvas.innerHTML = `