Implement front end location/time/weather etc

This commit is contained in:
Dale Davies
2022-02-08 23:05:56 +00:00
parent 36f44fb266
commit 6d5366147f
19 changed files with 275 additions and 150 deletions

View File

@@ -26,6 +26,10 @@ body {
bottom: 0;
}
.hidden {
opacity: 0;
}
.background {
filter: brightness(0.65) blur(13px);
background-repeat: no-repeat;
@@ -43,7 +47,7 @@ body::after {
right:0;
bottom:0;
background-image: url(../images/overlay.png);
opacity: 0.4;
opacity: 0.3;
z-index: 2;
}
@@ -62,13 +66,14 @@ body::after {
font-size: 2.3em;
font-weight: 200;
text-transform: capitalize;
text-shadow: 1px 2px 14px #000000;
text-shadow: 1px 2px 10px #000000;
margin-bottom: 13px;
}
.time-weather {
font-family: 'Quicksand', sans-serif;
font-weight: 200;
user-select: none;
display: block;
position: absolute;
z-index: 100;
@@ -77,7 +82,7 @@ body::after {
color: inherit;
text-decoration: none;
padding:5px 10px;
border-radius: 7px;
border-radius: 6px;
}
.time-weather:hover {
background-color: #ffffff15;
@@ -95,11 +100,38 @@ body::after {
top: -1px;
}
.useclientlocation {
font-size: 13px;
user-select: none;
cursor: pointer;
display: none;
position: absolute;
bottom: 10px;
left: 15px;
z-index: 10;
border-radius: 6px;
height: 58px;
line-height:58px;
padding: 0 10px 0 45px;
background-size: 35px;
background-position: top 50% left 5px;
background-repeat: no-repeat;
background-image: url(../images/map-pin.svg);
}
.useclientlocation:hover {
background-color: #ffffff15;
transition: background-color .1s;
}
.useclientlocation.enable {
display: block;
}
.sites, .sites li {
padding: 0;
margin: 0;
list-style-type: none;
font-weight: 300;
font-size: 14px;
}
@@ -112,7 +144,7 @@ body::after {
text-decoration: none;
display: inline-block;
padding: 15px;
border-radius: 7px
border-radius: 6px
}
.sites li a:hover {
@@ -125,7 +157,7 @@ body::after {
background-color: #fff;
width: 80px;
height: 80px;
border-radius: 8px;
border-radius: 6px;
border: .2em solid #fff;
box-shadow: 0 1px 5px rgba(0,0,0,.3);
padding: 15px;
@@ -142,8 +174,7 @@ body::after {
max-height: 3.3em;
overflow: hidden;
word-wrap: break-word;
text-shadow: 1px 1px 2px #000000;
overflow: hidden;
text-shadow: 1px 1px 2px #00000070;
text-overflow: ellipsis;
white-space: nowrap;
}
}

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-map-pin-off" width="44" height="44" viewBox="0 0 24 24" stroke-width="1" stroke="#ffffff" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<line x1="3" y1="3" x2="21" y2="21" />
<path d="M9.44 9.435a3 3 0 0 0 4.126 4.124m1.434 -2.559a3 3 0 0 0 -3 -3" />
<path d="M8.048 4.042a8 8 0 0 1 10.912 10.908m-1.8 2.206l-3.745 3.744a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 0 1 -.48 -10.79" />
</svg>

After

Width:  |  Height:  |  Size: 536 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-map-pin" width="44" height="44" viewBox="0 0 24 24" stroke-width="1" stroke="#ffffff" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<circle cx="12" cy="11" r="3" />
<path d="M17.657 16.657l-4.243 4.243a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 1 1 11.314 0z" />
</svg>

After

Width:  |  Height:  |  Size: 413 B

View File

@@ -0,0 +1 @@
(()=>{"use strict";class t{constructor(t=0){this.utcshift=1e3*t,this.shiftedtimestamp=(new Date).getTime()+this.utcshift,this.shifteddate=new Date(this.shiftedtimestamp)}get_formatted_time(){return String(this.shifteddate.getHours()).padStart(2,"0")+":"+String(this.shifteddate.getMinutes()).padStart(2,"0")}get_hour(){return this.shifteddate.getHours()}}class e{constructor(t){this.hour=t.get_hour(),this.greetings={0:"morning",12:"afternoon",16:"evening",19:"night"}}get_greeting(){let t=Object.keys(this.greetings).reverse();for(let e of t)if(this.hour>=e)return this.greetings[e]}}class i{constructor(t,e){this.owmapiurlbase="https://api.openweathermap.org/data/2.5/weather",this.owmapikey=t,this.latlong=e}async fetch_owm_data(){const t=this.owmapiurlbase+"?lat="+this.latlong[0]+"&lon="+this.latlong[1]+"&appid="+this.owmapikey;return await fetch(t).then((t=>t.json())).then((t=>{401===t.cod&&alert("The OWM API key is invalid, check config.php");var e="night";return t.dt>t.sys.sunrise&&t.dt<t.sys.sunset&&(e="day"),{locationcode:t.id,locationname:t.name,iconclass:"wi-owm-"+e+"-"+t.weather[0].id,timezoneshift:t.timezone}}))}}(new class{constructor(){this.owmapikey=null,this.latlong=[],this.storage=window.localStorage,this.updatefrequency=1e4,this.contentintervalid=null,this.timezoneshift=0,this.greetingelm=document.querySelector(".greeting .chosen"),this.holderelm=document.querySelector(".time-weather"),this.timeelm=this.holderelm.querySelector(".time"),this.weatherelm=this.holderelm.querySelector(".weather"),this.clientlocationelm=document.querySelector(".useclientlocation"),JUMP.latlong&&JUMP.owmapikey&&(this.owmapikey=JUMP.owmapikey,this.latlong=JUMP.latlong.split(",")),(this.lastrequestedlocation=this.storage.getItem("lastrequestedlocation"))&&(this.latlong=JSON.parse(this.lastrequestedlocation))}init(){if(!this.owmapikey)return this.refresh_basic_content(),void this.show_content();new i(this.owmapikey,this.latlong).fetch_owm_data().then((t=>{this.timezoneshift=t.timezoneshift,this.refresh_basic_content(),this.holderelm.href+="city/"+t.locationcode,this.weatherelm.classList.add(t.iconclass),this.clientlocationelm.innerHTML=t.locationname,this.clientlocationelm.addEventListener("click",(t=>{navigator.geolocation.getCurrentPosition((t=>{this.latlong=[t.coords.latitude,t.coords.longitude],this.storage.setItem("lastrequestedlocation",JSON.stringify(this.latlong)),this.init()}),null,{enableHighAccuracy:!0})}),{once:!0}),this.clientlocationelm.classList.add("enable"),this.show_content()}))}show_content(){document.querySelectorAll(".hidden").forEach((function(t){t.classList.remove("hidden")}))}update_basic_content(){let i=new t(this.timezoneshift),s=new e(i);this.timeelm.innerHTML=i.get_formatted_time(),this.greetingelm.innerHTML=s.get_greeting()}refresh_basic_content(){this.contentintervalid&&clearInterval(this.contentintervalid),this.update_basic_content(),this.contentintervalid=setInterval((()=>{this.update_basic_content()}),this.updatefrequency)}}).init()})();

View File

@@ -1,40 +0,0 @@
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!****************************************!*\
!*** ./jumpapp/assets/js/src/index.js ***!
\****************************************/
/**
* Do some fancy UI stuff in a rather unfancy way.
*
* @author Dale Davies <dale@daledavies.co.uk>
* @license MIT
*/
if (JUMP.latlong && JUMP.owmapikey) {
var latlong = JUMP.latlong.split(',');
// Get some data from the open weather map api...
fetch('https://api.openweathermap.org/data/2.5/weather?lat='+latlong[0]+'&lon='+latlong[1]+'&appid='+JUMP.owmapikey)
.then(function(resp) {
// Attempt to convert the response into a json object.
return resp.json();
})
.then(function(data) {
// Determine if we should use the ay or night variant of our weather icon.
var datnightvariant = 'night';
if (data.dt > data.sys.sunrise && data.dt < data.sys.sunset) {
datnightvariant = 'day'
}
// Link to the correct city in openweathermap and display the appropriate weather icon.
var holderelm = document.querySelector('.time-weather');
holderelm.href += 'city/' + data.sys.id;
holderelm.querySelector('.weather').classList.add('wi-owm-'+datnightvariant+'-'+data.weather[0].id);
});
}
/******/ })()
;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9qdW1wLy4vanVtcGFwcC9hc3NldHMvanMvc3JjL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRG8gc29tZSBmYW5jeSBVSSBzdHVmZiBpbiBhIHJhdGhlciB1bmZhbmN5IHdheS5cbiAqXG4gKiBAYXV0aG9yIERhbGUgRGF2aWVzIDxkYWxlQGRhbGVkYXZpZXMuY28udWs+XG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG5pZiAoSlVNUC5sYXRsb25nICYmIEpVTVAub3dtYXBpa2V5KSB7XG4gICAgdmFyIGxhdGxvbmcgPSBKVU1QLmxhdGxvbmcuc3BsaXQoJywnKTtcbiAgICAvLyBHZXQgc29tZSBkYXRhIGZyb20gdGhlIG9wZW4gd2VhdGhlciBtYXAgYXBpLi4uXG4gICAgZmV0Y2goJ2h0dHBzOi8vYXBpLm9wZW53ZWF0aGVybWFwLm9yZy9kYXRhLzIuNS93ZWF0aGVyP2xhdD0nK2xhdGxvbmdbMF0rJyZsb249JytsYXRsb25nWzFdKycmYXBwaWQ9JytKVU1QLm93bWFwaWtleSlcbiAgICAudGhlbihmdW5jdGlvbihyZXNwKSB7XG4gICAgICAgIC8vIEF0dGVtcHQgdG8gY29udmVydCB0aGUgcmVzcG9uc2UgaW50byBhIGpzb24gb2JqZWN0LlxuICAgICAgICByZXR1cm4gcmVzcC5qc29uKCk7XG4gICAgfSlcbiAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgIC8vIERldGVybWluZSBpZiB3ZSBzaG91bGQgdXNlIHRoZSBheSBvciBuaWdodCB2YXJpYW50IG9mIG91ciB3ZWF0aGVyIGljb24uXG4gICAgICAgIHZhciBkYXRuaWdodHZhcmlhbnQgPSAnbmlnaHQnO1xuICAgICAgICBpZiAoZGF0YS5kdCA+IGRhdGEuc3lzLnN1bnJpc2UgJiYgZGF0YS5kdCA8IGRhdGEuc3lzLnN1bnNldCkge1xuICAgICAgICAgICAgZGF0bmlnaHR2YXJpYW50ID0gJ2RheSdcbiAgICAgICAgfVxuICAgICAgICAvLyBMaW5rIHRvIHRoZSBjb3JyZWN0IGNpdHkgaW4gb3BlbndlYXRoZXJtYXAgYW5kIGRpc3BsYXkgdGhlIGFwcHJvcHJpYXRlIHdlYXRoZXIgaWNvbi5cbiAgICAgICAgdmFyIGhvbGRlcmVsbSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy50aW1lLXdlYXRoZXInKTtcbiAgICAgICAgaG9sZGVyZWxtLmhyZWYgKz0gJ2NpdHkvJyArIGRhdGEuc3lzLmlkO1xuICAgICAgICBob2xkZXJlbG0ucXVlcnlTZWxlY3RvcignLndlYXRoZXInKS5jbGFzc0xpc3QuYWRkKCd3aS1vd20tJytkYXRuaWdodHZhcmlhbnQrJy0nK2RhdGEud2VhdGhlclswXS5pZCk7XG4gICAgfSk7XG59XG5cblxuXG5cbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==

View File

@@ -1,6 +0,0 @@
/**
* Do some fancy UI stuff in a rather unfancy way.
*
* @author Dale Davies <dale@daledavies.co.uk>
* @license MIT
*/

View File

@@ -0,0 +1,18 @@
export default class Clock {
constructor(utcshift = 0) {
this.utcshift = utcshift*1000;
this.shiftedtimestamp = new Date().getTime()+this.utcshift;
this.shifteddate = new Date(this.shiftedtimestamp);
}
get_formatted_time() {
const hour = String(this.shifteddate.getHours()).padStart(2, "0");
const minutes = String(this.shifteddate.getMinutes()).padStart(2, "0");
return hour + ":" + minutes;
}
get_hour() {
return this.shifteddate.getHours();
}
}

View File

@@ -0,0 +1,24 @@
import Clock from "./Clock";
export default class Greeting {
constructor(clock) {
this.hour = clock.get_hour();
this.greetings = {
0 : 'morning',
12 : 'afternoon',
16 : 'evening',
19 : 'night'
};
}
get_greeting() {
let keys = Object.keys(this.greetings).reverse();
for (let element of keys) {
if (this.hour >= element) {
return this.greetings[element];
}
};
}
}

View File

@@ -0,0 +1,121 @@
import Clock from './Clock';
import Greeting from './Greeting';
import Weather from './Weather';
export default class Main {
constructor() {
this.owmapikey = null;
this.latlong = [];
this.storage = window.localStorage;
this.updatefrequency = 10000;
this.contentintervalid = null;
this.timezoneshift = 0;
// Cache some DOM elements that we will access frequently.
this.greetingelm = document.querySelector('.greeting .chosen');
this.holderelm = document.querySelector('.time-weather');
this.timeelm = this.holderelm.querySelector('.time');
this.weatherelm = this.holderelm.querySelector('.weather');
this.clientlocationelm = document.querySelector('.useclientlocation');
// See if we were provided a latlong and api key via the apps config.php.
if (JUMP.latlong && JUMP.owmapikey) {
this.owmapikey = JUMP.owmapikey;
this.latlong = JUMP.latlong.split(',');
}
// If the user has previously asked for geolocation we will have stored the latlong.
if (this.lastrequestedlocation = this.storage.getItem('lastrequestedlocation')){
this.latlong = JSON.parse(this.lastrequestedlocation);
}
}
/**
* Get data from OWM and do stuff with it.
*/
init() {
// If there is no OWM API key provided then just update the greeting
// and clock, otherwise we can go get the weather data and set everything
// up properly.
if (!this.owmapikey) {
this.refresh_basic_content();
this.show_content();
return;
}
// Retrieve weather and timezone data from Open Weather Map API.
new Weather(this.owmapikey, this.latlong).fetch_owm_data().then(owmdata => {
// Update the timezone shift from UTC to whatever it should be for the
// requested location, then tell the greeting and clock to update.
this.timezoneshift = owmdata.timezoneshift;
this.refresh_basic_content();
// Display the weather icon, link to the requested location in OWM
// and update location name element.
this.holderelm.href += 'city/' + owmdata.locationcode;
this.weatherelm.classList.add(owmdata.iconclass);
this.clientlocationelm.innerHTML = owmdata.locationname;
// Should someone click on the location button then request their location
// from the client and store it, then re run init() to update the page.
this.clientlocationelm.addEventListener('click', e => {
navigator.geolocation.getCurrentPosition(position => {
this.latlong = [position.coords.latitude, position.coords.longitude];
this.storage.setItem('lastrequestedlocation', JSON.stringify(this.latlong));
this.init();
}, null, {enableHighAccuracy: true});
}, {once: true});
this.clientlocationelm.classList.add('enable');
// Finally we can make everything visible.
this.show_content();
});
}
/**
* Once everything is set up we can remove the .hidden class to display content
* on the page to stop things jumping around between the initial page load
* and JS rendering.
*/
show_content() {
document.querySelectorAll('.hidden').forEach(function(element){
element.classList.remove('hidden');
});
}
/**
* Calculate the correct time for the requested location and display it,
* along with an appropriate greeting.
*/
update_basic_content() {
let clock = new Clock(this.timezoneshift);
let greeting = new Greeting(clock);
this.timeelm.innerHTML = clock.get_formatted_time();
this.greetingelm.innerHTML = greeting.get_greeting();
}
/**
* Update the greeting message and clock initially, then continue to update
* them at the frequency set in this.updatefrequency.
*/
refresh_basic_content() {
// Clear any previously set intervals for updating content.
if (this.contentintervalid) {
clearInterval(this.contentintervalid);
}
// Set the clock and greeting text appropriately for the requested location.
this.update_basic_content();
// Update the content periodically, we don't need to be too frequent as we are
// not displaying seconds on the clock.
this.contentintervalid = setInterval(() => {
this.update_basic_content();
}, this.updatefrequency);
}
}

View File

@@ -0,0 +1,37 @@
export default class Weather {
constructor(owmapikey, latlong) {
this.owmapiurlbase = 'https://api.openweathermap.org/data/2.5/weather';
this.owmapikey = owmapikey;
this.latlong = latlong;
}
async fetch_owm_data() {
const url = this.owmapiurlbase
+'?lat='+this.latlong[0]
+'&lon='+this.latlong[1]
+'&appid='+this.owmapikey;
// Get some data from the open weather map api...
const promise = await fetch(url)
.then(response => response.json())
.then(data => {
if (data.cod === 401) {
alert('The OWM API key is invalid, check config.php');
}
// Determine if we should use the ay or night variant of our weather icon.
var datnightvariant = 'night';
if (data.dt > data.sys.sunrise && data.dt < data.sys.sunset) {
datnightvariant = 'day'
}
return {
locationcode: data.id,
locationname: data.name,
iconclass: 'wi-owm-'+datnightvariant+'-'+data.weather[0].id,
timezoneshift: data.timezone
};
})
return promise;
}
}

View File

@@ -5,27 +5,7 @@
* @license MIT
*/
if (JUMP.latlong && JUMP.owmapikey) {
var latlong = JUMP.latlong.split(',');
// Get some data from the open weather map api...
fetch('https://api.openweathermap.org/data/2.5/weather?lat='+latlong[0]+'&lon='+latlong[1]+'&appid='+JUMP.owmapikey)
.then(function(resp) {
// Attempt to convert the response into a json object.
return resp.json();
})
.then(function(data) {
// Determine if we should use the ay or night variant of our weather icon.
var datnightvariant = 'night';
if (data.dt > data.sys.sunrise && data.dt < data.sys.sunset) {
datnightvariant = 'day'
}
// Link to the correct city in openweathermap and display the appropriate weather icon.
var holderelm = document.querySelector('.time-weather');
holderelm.href += 'city/' + data.sys.id;
holderelm.querySelector('.weather').classList.add('wi-owm-'+datnightvariant+'-'+data.weather[0].id);
});
}
import Main from './classes/Main';
let jumpapp = new Main();
jumpapp.init();

View File

@@ -35,9 +35,7 @@ class Config {
'wwwroot',
'cachebypass',
'cachedir',
'noindex',
'latlong',
'owmapikey'
'noindex'
];
public function __construct() {
@@ -69,22 +67,24 @@ class Config {
*/
private function config_params_missing(): bool {
return !!array_diff(
array_keys($this->config->toArray()),
array_merge(
array_keys(self::BASE_APPLICATION_PATHS),
self::CONFIG_PARAMS
));
),
array_keys($this->config->toArray()),
);
}
/**
* Retrieves the config parameter provided in $key, first checks for its
* existence.
*
* @param string $key The config parameter required.
* @param string $key The requested config parameter key.
* @param bool $strict Throw exception if requested param is not found, or return null.
* @return mixed The selected value from the configuration array.
*/
public function get(string $key): mixed {
if (!$this->config->has($key)) {
public function get(string $key, $strict = true): mixed {
if (!$this->config->has($key) && $strict === true) {
throw new Exception('Config key does not exist... ('.$key.')');
}
return $this->config->get($key);

View File

@@ -1,38 +0,0 @@
<?php
namespace Jump;
/**
* Choose the appropriate greeting word for the time of day, so if the current
* hour is 04:00 this will return "morning" etc.
*
* @author Dale Davies <dale@daledavies.co.uk>
* @license MIT
*/
class Greeting {
private array $greetings;
public function __construct() {
$this->greetings = [
0 => 'morning',
12 => 'afternoon',
16 => 'evening',
19 => 'night'
];
}
/**
* Select the appropriate greeting word based on the time of day and
* what has been defined in $this->greetings.
*
* @return string The greeting word selected.
*/
public function get_greeting(): string {
krsort($this->greetings);
foreach ($this->greetings as $key => $value) {
if (date('H', time()) >= $key) {
return $value;
}
}
}
}

View File

@@ -5,14 +5,12 @@ namespace Jump;
class Main {
private Cache $cache;
private Greeting $greeting;
private \Mustache_Engine $mustache;
private array $outputarray;
private Sites $sites;
public function __construct() {
$this->config = new Config();
$this->greeting = new Greeting();
$this->mustache = new \Mustache_Engine([
'loader' => new \Mustache_Loader_FilesystemLoader($this->config->get('templatedir'))
]);
@@ -25,15 +23,8 @@ class Main {
return $template->render([
'noindex' => $this->config->parse_bool($this->config->get('noindex')),
'sitename' => $this->config->get('sitename'),
'latlong' => $this->config->get('latlong'),
'owmapikey' => $this->config->get('owmapikey')
]);
}
private function render_greeting(): string {
$template = $this->mustache->loadTemplate('greeting');
return $template->render([
'greeting' => $this->greeting->get_greeting(),
'latlong' => $this->config->get('latlong', false),
'owmapikey' => $this->config->get('owmapikey', false)
]);
}
@@ -55,7 +46,6 @@ class Main {
public function build_index_page(): void {
$this->outputarray = [
$this->render_header(),
$this->render_greeting(),
$this->render_sites(),
$this->render_footer(),
];

View File

@@ -17,8 +17,8 @@ return [
'cachedir' => getenv('CACHEDIR') ?: '/var/www/cache',
// Include the robots noindex meta tag in site header.
'noindex' => getenv('NOINDEX') ?: true,
// Coordinates for weather location.
'latlong' => getenv('LATLONG') ?: '51.509865,-0.118092',
// Coordinates for weather location. E.g. 51.509865,-0.118092
'latlong' => getenv('LATLONG') ?: '',
// Open Weather Map API key.
'owmapikey' => getenv('OWMAPIKEY') ?: '01234567890ABCDEFG',
'owmapikey' => getenv('OWMAPIKEY') ?: '',
];

View File

@@ -1,9 +1,10 @@
</div>
<a href="https://openweathermap.org/" class="time-weather">
<span class="time">21:44</span>
<a href="https://openweathermap.org/" class="time-weather hidden">
<span class="time"></span>
<i class="weather wi"></i>
</a>
<span class="useclientlocation"></span>
<div class="background fixed"></div>
<script src="/assets/js/index.js"></script>
<script src="/assets/js/index.bundle.js"></script>
</body>
</html>

View File

@@ -1 +0,0 @@
<div class="greeting">Good {{greeting}}</div>

View File

@@ -1,19 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{# noindex}}<meta name="robots" content="noindex">{{/ noindex}}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/assets/css/styles.css">
<link rel="stylesheet" href="background-css.php">
<link rel="stylesheet" href="/assets/css/weather-icons.min.css">
<title>{{sitename}}</title>
<script>
const JUMP = {
@@ -22,6 +18,6 @@
};
</script>
</head>
<body>
<div class="content fixed">
<div class="content fixed hidden">
<div class="greeting">Good <span class="chosen"></span></div>

View File

@@ -4,7 +4,7 @@ module.exports = {
mode: 'production',
entry: './jumpapp/assets/js/src/index.js',
output: {
filename: 'index.js',
filename: 'index.bundle.js',
path: path.resolve(__dirname, './jumpapp/assets/js/'),
},
};