General Development
3
LICENSE
@ -1,3 +1,6 @@
|
||||
** This license applies to all files in this repository/website unless a separate license *
|
||||
** is provided in a folder, in which case that license will apply to the folder contents **
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
|
@ -9,3 +9,7 @@ Whilst the application is open source, the webservice (owlboard.fb-infra.uk) is
|
||||
## Default Settings
|
||||
|
||||
webPort: 8460
|
||||
|
||||
## WebApp Colours:
|
||||
|
||||
- To be updated
|
18
app.js
@ -1,12 +1,13 @@
|
||||
// OwlBoard - © Fred Boniface 2022
|
||||
// Licensed under GPLv3 (or later)
|
||||
// Please see the included LICENSE file
|
||||
// OwlBoard - © Fred Boniface 2022 - Licensed under GPLv3 (or later)
|
||||
|
||||
// Please see the included LICENSE file statically served fonts are
|
||||
// licensed separately, each folder contains a license file
|
||||
|
||||
// Version Number:
|
||||
var version = "0.0.1"
|
||||
console.log(`Starting OwlBoard version ${version}`)
|
||||
|
||||
// Load Modules:
|
||||
// Load & prepare modules:
|
||||
const fs = require('fs');
|
||||
const ldb = require('ldbs-json');
|
||||
const express = require('express');
|
||||
@ -44,7 +45,7 @@ app.listen(settings.webPort, (error) =>{
|
||||
);
|
||||
|
||||
|
||||
// Check Athena API Key:
|
||||
// Create/Connect to database:
|
||||
|
||||
// Routes:
|
||||
|
||||
@ -54,7 +55,7 @@ app.get('/api', (req, res)=>{
|
||||
res.send(JSON.stringify({"OwlBoard_Status":"ready","OwlBoard_Version":version}));
|
||||
});
|
||||
|
||||
app.post('/api/test', (req, res)=>{
|
||||
app.post('/api/test', (req, res)=>{ //Check auth and return status
|
||||
const {test} = req.body;
|
||||
res.status(200);
|
||||
res.set('Content-Type', 'application/json');
|
||||
@ -78,10 +79,13 @@ app.post('/api/arrdep', (req, res)=>{
|
||||
|
||||
})
|
||||
|
||||
app.post('/stations', (req, res)=>{
|
||||
app.post('/api/stations', (req, res)=>{
|
||||
//Return JSON of all available stations - No Auth Required
|
||||
})
|
||||
|
||||
app.post('/api/send-issue', (req, res)=>{
|
||||
//Submit issue to Gitea (based on existing PHP Athena function)
|
||||
})
|
||||
|
||||
// General Functions
|
||||
function checkValid(input){
|
||||
|
1983
package-lock.json
generated
@ -1,13 +1,13 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"ldbs-json": "^1.2.1"
|
||||
"ldbs-json": "^1.2.1",
|
||||
"sqlite3": "^5.1.2"
|
||||
},
|
||||
"name": "owlboard",
|
||||
"description": "OwlBoard is the backend API that powers the Athena web application at athena.fb-infra.uk.",
|
||||
"description": "OwlBoard is an API and PWA for live rail departure board in the UK.",
|
||||
"version": "0.0.1",
|
||||
"main": "express.js",
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
|
0
routes/api.js
Normal file
0
routes/api.list.js
Normal file
0
routes/api.test.js
Normal file
BIN
static/images/.app-icon.xcf
Normal file
BIN
static/images/.full-logo.xcf
Normal file
94
static/images/.mono-logo.inkscape.svg
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg1081"
|
||||
xml:space="preserve"
|
||||
width="880"
|
||||
height="880"
|
||||
viewBox="0 0 880 880"
|
||||
sodipodi:docname="mono-logo.inkscape.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
inkscape:export-filename="mono-logo.svg"
|
||||
inkscape:export-xdpi="100"
|
||||
inkscape:export-ydpi="100"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||
id="metadata1087"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs1085"><rect
|
||||
x="425.4978"
|
||||
y="106.37445"
|
||||
width="394.47193"
|
||||
height="272.58453"
|
||||
id="rect947" /><clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath1097"><path
|
||||
d="M 0,660 H 660 V 0 H 0 Z"
|
||||
id="path1095"
|
||||
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="727"
|
||||
id="namedview1083"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.45123617"
|
||||
inkscape:cx="-38.782352"
|
||||
inkscape:cy="467.60436"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g1089"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showguides="true"><sodipodi:guide
|
||||
position="768.99864,381.36976"
|
||||
orientation="1,0"
|
||||
id="guide1739"
|
||||
inkscape:locked="false" /><sodipodi:guide
|
||||
position="-409.98486,802.4353"
|
||||
orientation="0,-1"
|
||||
id="guide1741"
|
||||
inkscape:locked="false" /></sodipodi:namedview><g
|
||||
id="g1089"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="owl-silhouette-freesvg.org"
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,880)"><g
|
||||
id="g1337"
|
||||
style="fill:#00b7b7;fill-opacity:1"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path1191"
|
||||
style="fill:#00b7b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 112.253,369.323 c 12.988,-10.101 30.989,0.076 39.875,15.722 9.969,-34.512 37.501,-53.367 57.648,-37.596 -6.503,-20.085 -34.373,-34.554 -61.522,13.215 -15.947,-14.598 -28.559,-14.416 -36.001,8.659 m 14.302,-81.369 c 15.405,-6.791 28.15,7.974 30.66,25.885 21.351,-31.973 53.097,-43.81 65.802,-22.905 1.237,-21.743 -18.954,-43.315 -60.644,-2.464 -9.305,-18.663 -20.837,-21.694 -35.818,-0.516 m 33.549,175.931 24.381,-9.342 24.382,9.342 -24.382,-24.381 z m -14.899,47.955 c 1.574,0 3.075,-0.31 4.448,-0.869 -1.973,-1.1 -3.309,-3.206 -3.309,-5.626 0,-3.554 2.883,-6.436 6.437,-6.436 1.608,0 3.079,0.59 4.208,1.566 0.005,-0.143 0.008,-0.284 0.008,-0.428 0,-6.512 -5.28,-11.791 -11.792,-11.791 -6.512,0 -11.791,5.279 -11.791,11.791 0,6.513 5.279,11.793 11.791,11.793 m 77.642,0 c 1.573,0 3.075,-0.31 4.447,-0.869 -1.973,-1.1 -3.308,-3.206 -3.308,-5.626 0,-3.554 2.882,-6.436 6.437,-6.436 1.608,0 3.079,0.59 4.207,1.566 0.006,-0.143 0.009,-0.284 0.009,-0.428 0,-6.512 -5.28,-11.791 -11.792,-11.791 -6.513,0 -11.792,5.279 -11.792,11.791 0,6.513 5.279,11.793 11.792,11.793 m 0,8.887 c 11.421,0 20.677,-9.259 20.677,-20.68 0,-11.42 -9.256,-20.677 -20.677,-20.677 -11.42,0 -20.678,9.257 -20.678,20.677 0,11.421 9.258,20.68 20.678,20.68 m -77.642,0 c 11.42,0 20.679,-9.259 20.679,-20.68 0,-11.42 -9.259,-20.677 -20.679,-20.677 -11.42,0 -20.678,9.257 -20.678,20.677 0,11.421 9.258,20.68 20.678,20.68 M 367.82,249.402 c -5.257,-16.303 -14.169,-16.431 -25.436,-6.118 -19.182,-33.751 -38.872,-23.527 -43.468,-9.336 14.236,-11.143 33.688,2.178 40.73,26.562 6.28,-11.055 18.998,-18.245 28.174,-11.108 m -7.657,101.75 c -5.26,-16.304 -14.169,-16.433 -25.436,-6.118 -19.182,-33.751 -38.873,-23.529 -43.469,-9.338 14.236,-11.142 33.688,2.179 40.731,26.564 6.279,-11.055 18.997,-18.247 28.174,-11.108 m 3.828,-50.877 c -5.259,-16.302 -14.168,-16.429 -25.435,-6.117 -19.182,-33.752 -38.873,-23.528 -43.469,-9.338 14.236,-11.14 33.687,2.181 40.731,26.564 6.279,-11.055 18.996,-18.243 28.173,-11.109 m -184.999,-126.56 8.456,14.687 -2.481,14.064 c 8.24,-6.441 16.897,-12.257 25.895,-17.419 l -13.787,-20.682 c -5.163,5.163 -11.523,8.215 -18.083,9.35 m 214.435,47.276 -16.013,24.214 v 93.753 c 0,40.019 -32.441,72.459 -72.458,72.459 -37.742,0 -68.739,-28.855 -72.144,-65.707 -0.563,6.626 -0.974,13.336 -1.228,20.135 0,36.412 26.858,66.546 61.843,71.684 15.118,42.436 3.44,91.058 -31.815,121.878 -0.332,0.288 -0.668,0.569 -1.002,0.854 -14.934,-8.987 -28.921,-18.756 -41.766,-29.467 14.159,17.506 30.102,32.253 47.212,45.198 -47.368,32.008 -116.692,32.008 -164.058,0 17.11,-12.946 33.054,-27.694 47.212,-45.201 -11.522,9.609 -23.965,18.462 -37.188,26.67 -40.329,-37.119 -47.937,-98.2 -17.545,-144.158 4.83,-7.304 7.155,-15.981 6.624,-24.722 -3.808,-62.683 19.436,-123.991 63.84,-168.396 3.505,-3.505 7.116,-6.877 10.824,-10.115 l -15.66,-23.489 c -18.988,18.987 -54.154,9.494 -56.053,-19.369 4.94,7.294 12.965,10.334 21.93,10.306 4.624,3.683 10.595,5.668 18.277,5.498 -14.197,-2.669 -23.71,-11.684 -25.256,-26.007 9.826,11.065 21.246,13.643 34.785,11.262 -7.045,-4.94 -12.081,-12.841 -12.767,-23.274 4.941,7.293 12.965,10.335 21.932,10.303 1.457,1.162 3.047,2.155 4.783,2.963 0.557,-0.597 1.095,-1.202 1.614,-1.819 -7.504,-4.493 -12.316,-11.823 -13.378,-21.652 5.924,6.673 12.428,10.259 19.627,11.533 1.471,-3.662 2.152,-7.45 1.823,-11.24 4.057,2.964 6.698,7.077 8.006,11.651 2.475,-0.187 5.026,-0.574 7.654,-1.132 12.8,-8.149 22.377,-20.41 21.31,-32.736 11.849,8.659 11.621,27.116 1.367,38.28 l 8.659,15.04 -2.26,12.808 c 15.693,-7.825 32.28,-13.746 49.402,-17.626 -7.313,17.831 -12.59,36.793 -15.633,56.995 19.737,-52.989 51.201,-99.462 92.224,-140.627 3.548,-6.147 10.784,-9.143 17.64,-7.305 6.856,1.837 11.623,8.048 11.623,15.147 v 65.793 c 33.793,-9.913 62.771,-33.463 79.074,-66.13 l 119.851,29.509 c -14.567,69.186 -99.576,110.135 -175.589,96.362 z" /></g><text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.75000002,0,0,-0.75000002,-16.621008,676.62103)"
|
||||
id="text945"
|
||||
style="font-size:106.667px;line-height:0.8;white-space:pre;shape-inside:url(#rect947);display:inline;fill:#00b7b7;fill-opacity:1"><tspan
|
||||
x="425.49805"
|
||||
y="179.42858"
|
||||
id="tspan1419"><tspan
|
||||
style="font-weight:600;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic Semi-Bold'"
|
||||
id="tspan1417">OWL
|
||||
</tspan></tspan><tspan
|
||||
x="425.49805"
|
||||
y="269.65554"
|
||||
id="tspan1425"><tspan
|
||||
style="font-weight:600;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic Semi-Bold'"
|
||||
id="tspan1421"> </tspan><tspan
|
||||
style="font-size:96px;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic'"
|
||||
id="tspan1423">BOARD</tspan></tspan></text></g></svg>
|
After Width: | Height: | Size: 7.3 KiB |
48
static/images/.mono-logo.svg
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg1081"
|
||||
xml:space="preserve"
|
||||
width="880"
|
||||
height="880"
|
||||
viewBox="0 0 880 880"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||
id="metadata1087"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs1085"><rect
|
||||
x="425.4978"
|
||||
y="106.37445"
|
||||
width="394.47192"
|
||||
height="272.58453"
|
||||
id="rect947" /></defs><g
|
||||
id="g1089"
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,0,880)"><g
|
||||
id="g1337"
|
||||
style="fill:#00b7b7;fill-opacity:1"><path
|
||||
id="path1191"
|
||||
style="fill:#00b7b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||
d="m 112.253,369.323 c 12.988,-10.101 30.989,0.076 39.875,15.722 9.969,-34.512 37.501,-53.367 57.648,-37.596 -6.503,-20.085 -34.373,-34.554 -61.522,13.215 -15.947,-14.598 -28.559,-14.416 -36.001,8.659 m 14.302,-81.369 c 15.405,-6.791 28.15,7.974 30.66,25.885 21.351,-31.973 53.097,-43.81 65.802,-22.905 1.237,-21.743 -18.954,-43.315 -60.644,-2.464 -9.305,-18.663 -20.837,-21.694 -35.818,-0.516 m 33.549,175.931 24.381,-9.342 24.382,9.342 -24.382,-24.381 z m -14.899,47.955 c 1.574,0 3.075,-0.31 4.448,-0.869 -1.973,-1.1 -3.309,-3.206 -3.309,-5.626 0,-3.554 2.883,-6.436 6.437,-6.436 1.608,0 3.079,0.59 4.208,1.566 0.005,-0.143 0.008,-0.284 0.008,-0.428 0,-6.512 -5.28,-11.791 -11.792,-11.791 -6.512,0 -11.791,5.279 -11.791,11.791 0,6.513 5.279,11.793 11.791,11.793 m 77.642,0 c 1.573,0 3.075,-0.31 4.447,-0.869 -1.973,-1.1 -3.308,-3.206 -3.308,-5.626 0,-3.554 2.882,-6.436 6.437,-6.436 1.608,0 3.079,0.59 4.207,1.566 0.006,-0.143 0.009,-0.284 0.009,-0.428 0,-6.512 -5.28,-11.791 -11.792,-11.791 -6.513,0 -11.792,5.279 -11.792,11.791 0,6.513 5.279,11.793 11.792,11.793 m 0,8.887 c 11.421,0 20.677,-9.259 20.677,-20.68 0,-11.42 -9.256,-20.677 -20.677,-20.677 -11.42,0 -20.678,9.257 -20.678,20.677 0,11.421 9.258,20.68 20.678,20.68 m -77.642,0 c 11.42,0 20.679,-9.259 20.679,-20.68 0,-11.42 -9.259,-20.677 -20.679,-20.677 -11.42,0 -20.678,9.257 -20.678,20.677 0,11.421 9.258,20.68 20.678,20.68 M 367.82,249.402 c -5.257,-16.303 -14.169,-16.431 -25.436,-6.118 -19.182,-33.751 -38.872,-23.527 -43.468,-9.336 14.236,-11.143 33.688,2.178 40.73,26.562 6.28,-11.055 18.998,-18.245 28.174,-11.108 m -7.657,101.75 c -5.26,-16.304 -14.169,-16.433 -25.436,-6.118 -19.182,-33.751 -38.873,-23.529 -43.469,-9.338 14.236,-11.142 33.688,2.179 40.731,26.564 6.279,-11.055 18.997,-18.247 28.174,-11.108 m 3.828,-50.877 c -5.259,-16.302 -14.168,-16.429 -25.435,-6.117 -19.182,-33.752 -38.873,-23.528 -43.469,-9.338 14.236,-11.14 33.687,2.181 40.731,26.564 6.279,-11.055 18.996,-18.243 28.173,-11.109 m -184.999,-126.56 8.456,14.687 -2.481,14.064 c 8.24,-6.441 16.897,-12.257 25.895,-17.419 l -13.787,-20.682 c -5.163,5.163 -11.523,8.215 -18.083,9.35 m 214.435,47.276 -16.013,24.214 v 93.753 c 0,40.019 -32.441,72.459 -72.458,72.459 -37.742,0 -68.739,-28.855 -72.144,-65.707 -0.563,6.626 -0.974,13.336 -1.228,20.135 0,36.412 26.858,66.546 61.843,71.684 15.118,42.436 3.44,91.058 -31.815,121.878 -0.332,0.288 -0.668,0.569 -1.002,0.854 -14.934,-8.987 -28.921,-18.756 -41.766,-29.467 14.159,17.506 30.102,32.253 47.212,45.198 -47.368,32.008 -116.692,32.008 -164.058,0 17.11,-12.946 33.054,-27.694 47.212,-45.201 -11.522,9.609 -23.965,18.462 -37.188,26.67 -40.329,-37.119 -47.937,-98.2 -17.545,-144.158 4.83,-7.304 7.155,-15.981 6.624,-24.722 -3.808,-62.683 19.436,-123.991 63.84,-168.396 3.505,-3.505 7.116,-6.877 10.824,-10.115 l -15.66,-23.489 c -18.988,18.987 -54.154,9.494 -56.053,-19.369 4.94,7.294 12.965,10.334 21.93,10.306 4.624,3.683 10.595,5.668 18.277,5.498 -14.197,-2.669 -23.71,-11.684 -25.256,-26.007 9.826,11.065 21.246,13.643 34.785,11.262 -7.045,-4.94 -12.081,-12.841 -12.767,-23.274 4.941,7.293 12.965,10.335 21.932,10.303 1.457,1.162 3.047,2.155 4.783,2.963 0.557,-0.597 1.095,-1.202 1.614,-1.819 -7.504,-4.493 -12.316,-11.823 -13.378,-21.652 5.924,6.673 12.428,10.259 19.627,11.533 1.471,-3.662 2.152,-7.45 1.823,-11.24 4.057,2.964 6.698,7.077 8.006,11.651 2.475,-0.187 5.026,-0.574 7.654,-1.132 12.8,-8.149 22.377,-20.41 21.31,-32.736 11.849,8.659 11.621,27.116 1.367,38.28 l 8.659,15.04 -2.26,12.808 c 15.693,-7.825 32.28,-13.746 49.402,-17.626 -7.313,17.831 -12.59,36.793 -15.633,56.995 19.737,-52.989 51.201,-99.462 92.224,-140.627 3.548,-6.147 10.784,-9.143 17.64,-7.305 6.856,1.837 11.623,8.048 11.623,15.147 v 65.793 c 33.793,-9.913 62.771,-33.463 79.074,-66.13 l 119.851,29.509 c -14.567,69.186 -99.576,110.135 -175.589,96.362 z" /></g><text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.75000002,0,0,-0.75000002,-16.621008,676.62103)"
|
||||
id="text945"
|
||||
style="font-size:106.667px;line-height:0.8;white-space:pre;shape-inside:url(#rect947);display:inline;fill:#00b7b7;fill-opacity:1"><tspan
|
||||
x="425.49805"
|
||||
y="179.42858"
|
||||
id="tspan1391"><tspan
|
||||
style="font-weight:600;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic Semi-Bold'"
|
||||
id="tspan1389">OWL
|
||||
</tspan></tspan><tspan
|
||||
x="425.49805"
|
||||
y="269.65554"
|
||||
id="tspan1397"><tspan
|
||||
style="font-weight:600;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic Semi-Bold'"
|
||||
id="tspan1393"> </tspan><tspan
|
||||
style="font-size:96px;font-family:'URW Gothic';-inkscape-font-specification:'URW Gothic'"
|
||||
id="tspan1395">BOARD</tspan></tspan></text></g></svg>
|
After Width: | Height: | Size: 5.7 KiB |
BIN
static/images/.square-logo.xcf
Normal file
BIN
static/images/app-icons/app-1200.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
static/images/app-icons/app-128.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/images/app-icons/app-256.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
static/images/app-icons/app-384.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
static/images/app-icons/app-512.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
static/images/app-icons/app-76.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/images/app-icons/app-768.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/images/logo/logo-full-128.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/images/logo/logo-full-256.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
static/images/logo/logo-full-512.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
static/images/logo/logo-full-715.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
static/images/logo/logo-full-76.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
static/images/logo/logo-sq-128.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
static/images/logo/logo-sq-256.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
static/images/logo/logo-sq-512.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
static/images/logo/logo-sq-64.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
static/images/logo/logo-sq-745.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
static/images/logo/logo-sq-76.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
static/images/mono-logo.png
Normal file
After Width: | Height: | Size: 59 KiB |
@ -1,9 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>OwlBoard</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="Athena - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="Athena">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<link rel="stylesheet" type="text/css" href="/styles/style.css"/>
|
||||
<link rel="icon" type="image/png" href="/assets/icons/favicon.ico"/>
|
||||
<link rel="manifest" type="application/json" href="/manifest.json"/>
|
||||
|
||||
<script src="/js/nav.js"></script> <title>Athena</title>
|
||||
|
||||
<script src="/js/tiploc-finder.js" async></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>OwlBoard</h1>
|
||||
|
||||
<!-- Popup Menu -->
|
||||
<div id="menubar_hamburger" class="hide_micro">
|
||||
<button class="sidebar_control" id="sidebar_open_short" onclick="sidebarOpen()">☰</button>
|
||||
<button class="sidebar_control" id="sidebar_close_short" onclick="sidebarClose()">×</button>
|
||||
</div>
|
||||
<div id="sidebar">
|
||||
<a href="/">Home</a>
|
||||
<a href="/help.php">Help</a>
|
||||
<a href="/issue.php">Report Issue</a>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Begins -->
|
||||
<picture>
|
||||
<source media="(min-width:1500px)" srcset="/images/logo/logo-full-715.png" type="image/png">
|
||||
<source media="(min-width:1000px)" srcset="/images/logo/logo-full-512.png" type="image/png">
|
||||
<source media="(min-width:600px)" srcset="/images/logo/logo-full-256.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-512.png" alt="OwlBoards Logo">
|
||||
</picture>
|
||||
<br>
|
||||
<input class="lookup-box" type="text" id="crs-lookup" name="crs-lookup" placeholder="Enter CRS/TIPLOC"/>
|
||||
<br>
|
||||
<button class="lookup-button" onclick="getTextEntry()">Lookup Departure Board</button>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h2 hidden>Server Maintenance</h2>
|
||||
<p hidden>Athena may be completely or partially unavailable between 1900-2300 on 07/10/2022,
|
||||
apologies for any inconvinience caused to you.</p>
|
||||
|
||||
<h2>Quick Links</h2>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('bathspa')">BTH</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('brstltm')">BRI</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('brstpwy')">BPW</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('crdfcen')">CDF</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('gloster')">GCR</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('oldfldp')">OLF</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('soton')">SOU</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('wstbryw')">WSB</button>
|
||||
<button class="actionbutton" onclick="gotoInfoBoard('wsmare')">WSM</button>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<div class="text-description">
|
||||
<p>This is an Alpha release and is under testing.</p>
|
||||
<p>Some features may not work and some stations may not be available.</p>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
<p>Created by <a href="https://fredboniface.co.uk" target="_blank" rel="noreferrer noopener">Fred Boniface</a> - v1.0.0-devel</p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
11
static/js/nav.js
Normal file
@ -0,0 +1,11 @@
|
||||
function sidebarOpen() {
|
||||
document.getElementById("sidebar").style.width = "50%";
|
||||
document.getElementById("sidebar_open_short").style.display = "none";
|
||||
document.getElementById("sidebar_close_short").style.display = "block";
|
||||
}
|
||||
|
||||
function sidebarClose() {
|
||||
document.getElementById("sidebar").style.width = "0%"
|
||||
document.getElementById("sidebar_open_short").style.display = "block";
|
||||
document.getElementById("sidebar_close_short").style.display = "none";
|
||||
}
|
0
static/js/sw.js
Normal file
90
static/js/tiploc-finder.js
Normal file
@ -0,0 +1,90 @@
|
||||
const url = "https://tiger.worldline.global/";
|
||||
const view = "/staff;scrollbar=true";
|
||||
|
||||
console.group("Athena - Departure Boards")
|
||||
console.info("Initialising");
|
||||
|
||||
|
||||
/* Get lookup data from JSON file */
|
||||
let dataGlobal;
|
||||
|
||||
const getData = async () => {
|
||||
console.info("Loading Tiger lookup file");
|
||||
// Probably put a loading wheel here!
|
||||
const response = await fetch("./assets/tiger_codes.json");
|
||||
const data = await response.json();
|
||||
dataGlobal = data;
|
||||
return data;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
await getData();
|
||||
console.info("Lookup file loaded");
|
||||
console.info(dataGlobal);
|
||||
console.info("Initialisation complete");
|
||||
// Probably end the loading wheel here.
|
||||
console.groupEnd();
|
||||
})();
|
||||
|
||||
/* Read Lookup textbox entry and call the gotoInfoBoard() function */
|
||||
function getTextEntry() {
|
||||
console.group("Athena: function: getTextEntry()");
|
||||
console.info("Getting contents of textbox 'crs-lookup'");
|
||||
let forLookup = document.getElementById("crs-lookup").value;
|
||||
console.info("You have entered: " + forLookup.toUpperCase());
|
||||
console.info("Calling gotoInfoBoard(" + forLookup.toLowerCase() + ")");
|
||||
console.groupEnd()
|
||||
gotoInfoBoard(forLookup);
|
||||
};
|
||||
|
||||
/* Runs basic validation of data type and then process that and finally
|
||||
redirects to Tiger using a built URL */
|
||||
function gotoInfoBoard(station) {
|
||||
// Firstly start a console group for the function
|
||||
console.group("Athena: function: gotoInfoBoard(" + station.toLowerCase() + ")");
|
||||
|
||||
//Determins if code is TIPLOC and if so redirects immediately
|
||||
if (station.length > 3 && station.length < 8) {
|
||||
console.info(station.length + "characters, presumed to be tiploc.");
|
||||
console.info("Redirecting to " + station + " departure board");
|
||||
window.location = url + station.toUpperCase() + view;
|
||||
|
||||
//If code is CRS then process further to determine the TIPLOC then redirect
|
||||
} else if (station.length == 3) {
|
||||
console.info("CRS entered: " + station.toUpperCase() + ", required lookup");
|
||||
console.info("Finding object");
|
||||
let crs_to_find = station.toLowerCase();
|
||||
console.debug("Converted string to lower case:" + crs_to_find);
|
||||
//Check if the entered CRS exists in the lookup file
|
||||
console.info("Checking if CRS code exists in lookup data")
|
||||
let hasKey = dataGlobal.hasOwnProperty(crs_to_find);
|
||||
if (hasKey) { //If key exists then log and continue
|
||||
console.info(crs_to_find.toUpperCase() + " does exist in lookup file");
|
||||
} else { //If key does not exist then stop further processing
|
||||
console.warn(crs_to_find.toUpperCase() + "does not exist in lookup file");
|
||||
console.error(crs_to_find.toUpperCase() + " is an incorrect code or not supported.");
|
||||
alert(crs_to_find.toUpperCase() + " is not a valid or supported CRS, " +
|
||||
"please see the help section for more information");
|
||||
console.groupEnd();
|
||||
return 0;
|
||||
}
|
||||
let crs_obj = dataGlobal[crs_to_find];
|
||||
console.info("Isolating TIPLOC from Object");
|
||||
let tiploc = crs_obj['tiploc']; // crs_obj['tiploc']??
|
||||
console.info("TIPLOC: " + tiploc);
|
||||
console.info("Redirecting to " + tiploc + " departure board");
|
||||
window.location = url + tiploc.toUpperCase() + view;
|
||||
|
||||
//If the code cannot be validated as CRS or TIPLOC then throw an alert and log
|
||||
} else {
|
||||
console.error("Please only enter:\n - A 3 character CRS code,\n - A 4-7 " +
|
||||
"character TIPLOC code.\n\nPartial codes or station names cannot be looked "+
|
||||
"up.");
|
||||
alert("Please only enter:\n - A 3 character CRS code,\n - A 4-7 " +
|
||||
"character TIPLOC code.\n\nPartial codes or station names cannot be looked "+
|
||||
"up.");
|
||||
}
|
||||
// Lastly close the log group at the end of the Function and return.
|
||||
console.groupEnd();
|
||||
return 0;
|
||||
}
|
57
static/manifest.json
Normal file
@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "OwlBoards",
|
||||
"short_name": "OwlBoards",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"description": "Live station departures - aimed at train-crew.",
|
||||
"categories": "travel,utilities",
|
||||
"lang": "en",
|
||||
"orientation": "portrait",
|
||||
"theme_color": "#155bb7",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/app-icons/app-1200.png",
|
||||
"sizes": "1200x1200",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-768.png",
|
||||
"sizes": "768x768",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/app-76.png",
|
||||
"sizes": "76x76",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
95
static/styles/fonts/firamono/LICENSE
Normal file
@ -0,0 +1,95 @@
|
||||
** This license applies only to fonts within the same folder *
|
||||
|
||||
Copyright (c) 2012-2013, The Mozilla Corporation and Telefonica S.A.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
BIN
static/styles/fonts/firamono/firamono-500.ttf
Normal file
BIN
static/styles/fonts/firamono/firamono-500.woff
Normal file
BIN
static/styles/fonts/firamono/firamono-500.woff2
Normal file
BIN
static/styles/fonts/firamono/firamono-regular.ttf
Normal file
BIN
static/styles/fonts/firamono/firamono-regular.woff
Normal file
BIN
static/styles/fonts/firamono/firamono-regular.woff2
Normal file
188
static/styles/style.css
Normal file
@ -0,0 +1,188 @@
|
||||
/* FONTS */
|
||||
@font-face {
|
||||
font-family: 'firamono';
|
||||
src: url('/styles/fonts/firamono/firamono-regular.woff2') format('woff2'),
|
||||
url('/styles/fonts/firamono/firamono-regular.woff') format('woff'),
|
||||
url('/styles/fonts/firamono/firamono-regular.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'firamono';
|
||||
src: url('/styles/fonts/firamono/firamono-500.woff2') format('woff2'),
|
||||
url('/styles/fonts/firamono/firamono-500.woff') format('woff'),
|
||||
url('/styles/fonts/firamono/firamono-500.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* COLOR VARS */
|
||||
:root {
|
||||
--main-bg-color: #5d5d74;
|
||||
--accent-color: #007979;
|
||||
--overlay-color: #7fa6e6de;
|
||||
--main-text-color: #00b7b7;
|
||||
--link-color: azure;
|
||||
--link-visited-color: azure;
|
||||
}
|
||||
body {
|
||||
background-color: var(--main-bg-color);
|
||||
color: var(--main-text-color);
|
||||
font-family: firamono, monospace;
|
||||
text-align: center;
|
||||
padding-bottom: 60px; /*Footer height*/
|
||||
}
|
||||
.titleimg {
|
||||
width: 80%;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
max-width: 500px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.lookup-box {
|
||||
text-align: center;
|
||||
border: black;
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.form-text-small {
|
||||
text-align: center;
|
||||
border: black;
|
||||
width: 80%;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
@media only screen and (min-width: 600px) {.form-text-small{width: 50%}}
|
||||
.form-text-large {
|
||||
text-align: left;
|
||||
border: black;
|
||||
width: 80%;
|
||||
height: 90px;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
@media only screen and (min-width: 600px) {.form-text-large{width: 50%}}
|
||||
.form-info {
|
||||
color: var(--main-text-color);
|
||||
font-size: 17px;
|
||||
font-weight: bolder;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.text-description {
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
font-family: sans-serif;
|
||||
color: var(--main-text-color);
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
transition: 0.2s;
|
||||
}
|
||||
@media only screen and (min-width: 600px) {.text-description{width: 50%}}
|
||||
.lookup-button {
|
||||
background-color: var(--accent-color);
|
||||
color: var(--link-color);
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.actionbutton {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
font-family: firamono, monospace;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
background-color: var(--accent-color);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
color: var(--link-color);
|
||||
padding: 7px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.inlinelink {
|
||||
text-decoration: underline;
|
||||
color: var(--link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
/* START MENU STYLE */
|
||||
#menubar_hamburger {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
.sidebar_control {
|
||||
background-color: transparent;
|
||||
color: var(--accent-color);
|
||||
border: none;
|
||||
font-family: sans-serif;
|
||||
font-size: larger;
|
||||
}
|
||||
#sidebar_open_short {display: block;}
|
||||
#sidebar_close_short {
|
||||
display: none;
|
||||
font-size: x-large;
|
||||
}
|
||||
#sidebar {
|
||||
position: fixed;
|
||||
top: 40px;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
display: block;
|
||||
max-width: 250px;
|
||||
width: 0;
|
||||
border-top-left-radius: 45px;
|
||||
border-bottom-left-radius: 45px;
|
||||
background-color: var(--overlay-color);
|
||||
transition: 0.4s;
|
||||
}
|
||||
#sidebar a {
|
||||
padding: 8px 8px 8px 8px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-family: firamono, monospace;
|
||||
font-weight: 300;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 25px;
|
||||
color: var(--link-color);
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
transition: 0.5s;
|
||||
}
|
||||
/* Footer Styles */
|
||||
footer {
|
||||
background-color: var(--accent-color);
|
||||
font-family: firamono, monospace;
|
||||
color: white;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
footer a {
|
||||
text-decoration: underline;
|
||||
color: white;
|
||||
}
|
||||
footer a:visited {
|
||||
color: white;
|
||||
}
|
||||
footer a:hover {
|
||||
color: beige;
|
||||
}
|