Initial Push (v0.0.3)
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
34
404.html
Normal file
@ -0,0 +1,34 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<!-- NO SCRIPTS LOADED - NOT REQUIRED AT PRESENT -->
|
||||
<title>OwlBoard - Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top_button" class="hide_micro">
|
||||
<picture aria-label="Back" class="sidebar_control" onclick="history.back()">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Back">
|
||||
</picture>
|
||||
</div>
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Oh no!</h2>
|
||||
<p>That page cannot be found</p>
|
||||
<p>Try going to the <a href="/">homepage</a></p>
|
||||
<p>Error number: 404</p>
|
||||
</body>
|
||||
</html>
|
12
Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM fedora:latest as compressor
|
||||
RUN dnf install brotli nodejs npm jq -y
|
||||
RUN npm i uglifyjs-folder uglifycss html-minifier-terser -g
|
||||
COPY . /data/in
|
||||
RUN bash /data/in/conf/deploy.sh
|
||||
|
||||
FROM fholzer/nginx-brotli:latest
|
||||
RUN rm /etc/nginx/nginx.conf
|
||||
RUN apk update
|
||||
RUN apk add --upgrade libxml2 libxslt
|
||||
COPY ./conf/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=compressor /data/out/ /site-static/
|
129
board.html
Normal file
@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<title>OwlBoard - Loading</title>
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./styles/boards.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<script src="./js/lib.main.js" defer></script>
|
||||
<script src="./js/lib.board.js" defer></script>
|
||||
<script src="./js/simple-board.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading">
|
||||
<div class="spinner">
|
||||
</div>
|
||||
<p id="loading_desc">\nLoading</p>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div id="header">
|
||||
<div id="station_name">
|
||||
<h1 id="stn_name" class="header-large"></h1>
|
||||
</div>
|
||||
<div id="header-right">
|
||||
<p class="header-small">Data from:</p>
|
||||
<p id="fetch_time" class="header-small">Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="alerts" onclick="">
|
||||
<div id="alerts_bar" onclick="inflateAlerts()">
|
||||
<picture>
|
||||
<source srcset="./images/nav/alert_icon.svg" type="image/svg+xml">
|
||||
<img id="alert_icon" src="./images/nav/alert_icon.svg" alt="">
|
||||
</picture>
|
||||
<p id="alert_bar_note"></p>
|
||||
<button id="alert_expand_arrow">⋁</button>
|
||||
<div id="alerts_msg" onclick="NULL">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="output">
|
||||
<table>
|
||||
<caption>Train Services</caption>
|
||||
<tr>
|
||||
<th class="name">Origin</th>
|
||||
<th class="name">Dest.</th>
|
||||
<th class="plat">Plat.</th>
|
||||
<th class="time">Sch Arr.</th>
|
||||
<th class="time">Exp Arr.</th>
|
||||
<th class="time">Sch Dep.</th>
|
||||
<th class="time">Exp Dep.</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="no_services" class="main-notice hidden-whille-loading">
|
||||
<p>There are no scheduled train services from this station</p>
|
||||
</div>
|
||||
|
||||
<div id="ferry" class="hide-when-loading secondary-table">
|
||||
<table>
|
||||
<caption>Ferry Services</caption>
|
||||
<tr>
|
||||
<th class="name">Origin</th>
|
||||
<th class="name">Dest.</th>
|
||||
<th class="plat"></th>
|
||||
<th class="time">Sch Arr.</th>
|
||||
<th class="time">Exp Arr.</th>
|
||||
<th class="time">Sch Dep.</th>
|
||||
<th class="time">Exp Dep.</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="bus" class="hide-when-loading secondary-table">
|
||||
<table>
|
||||
<caption>Bus Services</caption>
|
||||
<tr>
|
||||
<th class="name">Origin</th>
|
||||
<th class="name">Dest.</th>
|
||||
<th class="plat"></th>
|
||||
<th class="time">Sch Arr.</th>
|
||||
<th class="time">Exp Arr.</th>
|
||||
<th class="time">Sch Dep.</th>
|
||||
<th class="time">Exp Dep.</th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="error_notice" class="main-notice hide-when-loading">
|
||||
<h1 class="error">Oops</h1>
|
||||
<p class="error">There was an error with your request</p>
|
||||
<p id="err_not_found" class="notices-hidden">The station you are searching for cannot be found</p>
|
||||
<p id="err_no_data" class="notices-hidden">The station has no data. It may not be in operation yet/anymore.</p>
|
||||
<p id="err_conn" class="notices-hidden">Connection Error, check your data connection. Retrying.</p>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<a href="https://nationalrail.co.uk" target="_blank" rel="nofollow external noreferrer noopener">
|
||||
<picture id="nre_logo">
|
||||
<source srcset="./images/nre/nre-powered_400w.jxl" type="image/jxl">
|
||||
<source srcset="./images/nre/nre-powered_400w.webp" type="image/webp">
|
||||
<img src="./images/nre/nre-powered_400w.png" alt="Powered by National Rail Enquiries">
|
||||
</picture>
|
||||
</a>
|
||||
<a href="/">
|
||||
<picture id="owlboard_logo">
|
||||
<source srcset="./images/logo/mono-logo.svg" type="image/svg+xml">
|
||||
<img src="./images/logo/mono-logo-33.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<picture id="home_icon">
|
||||
<source srcset="./images/nav/home_icon.svg" type="image/svg+xml">
|
||||
<img src="./images/nav/home_icon-40.png" alt="Home">
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
38
conf/deploy.sh
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOTIN="/data/in"
|
||||
ROOTOUT="/data/out"
|
||||
|
||||
echo "Running UglifyJS on /data/in folder"
|
||||
uglifyjs-folder "$ROOTIN" -x ".js" -eo "$ROOTOUT"
|
||||
|
||||
echo "Running UglifyCSS"
|
||||
CSSIN="/data/in/styles/"
|
||||
CSSOUT="/data/out/styles"
|
||||
|
||||
cd $CSSIN
|
||||
echo "Changed directory"
|
||||
pwd
|
||||
for f in *
|
||||
do
|
||||
if [ -f "$f" ]; then
|
||||
uglifycss "$f" --output "$f";
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Moving 'styles' to 'out'"
|
||||
cp -r /data/in/styles /data/out/styles
|
||||
|
||||
echo "Running html-minifier-terser on /folder"
|
||||
HTMLIN="/data/in/"
|
||||
HTMLOUT="/data/out"
|
||||
html-minifier-terser --collapse-whitespace --remove-comments --file-ext html --input-dir /data/in/ --output-dir /data/out/
|
||||
|
||||
echo "Moving JSON Manifest file from root to output"
|
||||
cat /data/in/manifest.json | jq -c > /data/out/manifest.json
|
||||
|
||||
echo "Moving images folder from in/ to out/"
|
||||
cp -r /data/in/images /data/out/images
|
||||
|
||||
echo "Running GZIP & Brotli on all HTML, JS, CSS, JSON & SVG files"
|
||||
find /data/out -type f -name \*.html -or -name \*.js -or -name \*.css -or -name \*.json -or -name \*.svg -or -name \*.ttf | while read file; do gzip -k -9 $file; brotli -k -q 11 $file; done
|
60
conf/nginx.conf
Normal file
@ -0,0 +1,60 @@
|
||||
user nginx;
|
||||
worker_processes 1;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
proxy_cache_path /var/cache/nginx keys_zone=owl_cache:20m inactive=24h;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
proxy_cache owl_cache;
|
||||
|
||||
add_header Content-Security-Policy "default-src 'self'";
|
||||
|
||||
location / {
|
||||
root /site-static/;
|
||||
index index.html;
|
||||
gzip_static on;
|
||||
brotli_static on;
|
||||
error_page 404 /404.html;
|
||||
expires 3600;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8460;
|
||||
proxy_cache_key $scheme://$host$uri$is_args$query_string;
|
||||
proxy_ignore_headers Cache-Control;
|
||||
proxy_cache_valid 200 2m; # Evaluate whether 2m or 1m is more appropriate
|
||||
expires 2m;
|
||||
add_header Cache-Control "private, no-transform";
|
||||
}
|
||||
|
||||
location /api/v1/list/ {
|
||||
proxy_pass http://localhost:8460;
|
||||
proxy_cache_key $scheme://$host$uri$is_args$query_string;
|
||||
proxy_ignore_headers Cache-Control;
|
||||
proxy_cache_valid 200 10080m;
|
||||
expires 3d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
}
|
||||
}
|
36
conn-err.html
Normal file
@ -0,0 +1,36 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<!-- NO SCRIPTS LOADED - NOT REQUIRED AT PRESENT -->
|
||||
<title>OwlBoard - Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="top_button" class="hide_micro">
|
||||
<picture aria-label="Close Menu" class="sidebar_control" onclick="history.back()">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Close menu">
|
||||
</picture>
|
||||
</div>
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Oh no!</h2>
|
||||
<p>OwlBoard has encountered a Connection Error</p>
|
||||
<p>Check your data connection and try again</p>
|
||||
<p>Go to the <a href="/">homepage</a></p>
|
||||
<br>
|
||||
<p>Error Code: CERR</p>
|
||||
</body>
|
||||
</html>
|
64
find-code.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./styles/find-code.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<title>OwlBoard - Code Lookup</title>
|
||||
<script src="./js/lib.main.js" defer></script>
|
||||
<script src="./js/find-code.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="top_button" class="hide_micro">
|
||||
<a href="/">
|
||||
<picture aria-label="Home" class="sidebar_control">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Home">
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Code Lookup</h2>
|
||||
<p>Enter one known code in the relevant box below and hit submit.
|
||||
Where they exist, the other code types will be filled in.</p>
|
||||
<p>You cannot yet lookup by location name as the values are not unique.</p>
|
||||
<p>Location name search will be added in the future.</p>
|
||||
|
||||
<div id="loading">
|
||||
<div class="spinner">
|
||||
</div>
|
||||
<p id="loading_desc">Searching</p>
|
||||
</div>
|
||||
|
||||
<label for="name">Location name:</label><br>
|
||||
<input type="text" class="small-lookup-box" id="name" name="name" readonly=""><br>
|
||||
<label for="3alpha">CRS/3ALPHA:</label><br>
|
||||
<input type="text" class="small-lookup-box" id="3alpha" name="3alpha" maxlength="3"><br>
|
||||
<label for="nlc">NLC:</label><br>
|
||||
<input type="number" class="small-lookup-box" id="nlc" name="nlc" min="100000" max="999999"><br>
|
||||
<label for="tiploc">TIPLOC:</label><br>
|
||||
<input type="text" class="small-lookup-box" id="tiploc" name="tiploc" maxlength="7"><br>
|
||||
<label for="stanox">STANOX:</label><br>
|
||||
<input type="number" class="small-lookup-box" id="stanox" name="stanox"><br>
|
||||
<label for="stanme" hidden>STANME:</label><br>
|
||||
<input type="test" class="small-lookup-box" id="stanme" name="stanme" readonly="" hidden><br>
|
||||
<input type="submit" value="Find" class="lookup-button" onclick="fetchEntry()">
|
||||
<input type="submit" value="Clear" class="lookup-button" onclick="clearForm()">
|
||||
</body>
|
||||
</html>
|
93
help.html
Normal file
@ -0,0 +1,93 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./styles/help.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<!-- NO SCRIPTS LOADED - NOT REQUIRED AT PRESENT -->
|
||||
<title>OwlBoard</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="top_button" class="hide_micro">
|
||||
<a href="/">
|
||||
<picture aria-label="Home" class="sidebar_control">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Home">
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Help</h2>
|
||||
<p>OwlBoard gives you quick and easy access to departure boards for
|
||||
all National Rail stations in the UK.</p>
|
||||
<p>Just type a CRS, TIPLOC or STANOX into the textbox on the homepage and tap
|
||||
enter on the screen or your keypad. You can also select a differnt board type,
|
||||
more details on your choices below.</p>
|
||||
<p>For example, Portway Park &
|
||||
Ride's CRS is 'PRI', and its TIPLOC is 'PTWYPR'; Portsmouth Harbour's
|
||||
CRS is 'PMH', and its TIPLOC is 'PHBR'.</p>
|
||||
<p>A CRS is always three letters,
|
||||
a TIPLOC can be between 4-7 letters.</p>
|
||||
<br>
|
||||
<h3>Don't know the CRS or TIPLOC?</h3>
|
||||
<p>Sorry, you can't search by name but you can use our <a href="find-code.html">
|
||||
Code Lookup</a> page to help.</p>
|
||||
<h3>Board Types</h3>
|
||||
<h4>Basic Board - Default</h4>
|
||||
<p>The basic board shows the next 10 train arrival and departures, as well as
|
||||
bus and ferry departures where available.</p>
|
||||
<p>You can tap on a trains origin or destination to see service details.</p>
|
||||
<br>
|
||||
<h3>Glossary</h3>
|
||||
<p>Some of the terms may be new to you or different from those commonly used.</p>
|
||||
<table id="table">
|
||||
<tr>
|
||||
<th>Term</th>
|
||||
<th>Definition</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CAN</td>
|
||||
<td>Cancelled</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CRS</td>
|
||||
<td>Computer Reservation System Code - correctly termed as '3ALPHA'</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>NLC</td>
|
||||
<td>National Location Code - Used for finance & accounting</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RT</td>
|
||||
<td>Right rime (On time)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>STANOX</td>
|
||||
<td>Station Number</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TIPLOC</td>
|
||||
<td>Timing Point Location (Name)</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<h3>Spotted an issue with the site?</h3>
|
||||
<p>Let me know by <a href="./report.html">reporting an issue</a>.</p>
|
||||
</body>
|
||||
</html>
|
BIN
images/app-icons/any/apple-192.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
images/app-icons/any/plain-logo-512.png
Normal file
After Width: | Height: | Size: 33 KiB |
2
images/app-icons/any/plain-logo.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 667.26 706.8" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><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><g transform="translate(-111.19 -90.003)"><rect x="213.88" y="260.42" width="81.997" height="48.755" fill="#fcfc09"/><rect x="167.35" y="187.29" width="181.72" height="68.7" fill="#f0ffff"/></g><g transform="matrix(1.3333 0 0 -1.3333 -111.19 790)" fill="#00b7b7"><g transform="translate(7.5,-7.5)"><path d="m112.25 369.32c12.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.659m14.302-81.369c15.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.516m33.549 175.93 24.381-9.342 24.382 9.342-24.382-24.381zm-14.899 47.955c1.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 5e-3 -0.143 8e-3 -0.284 8e-3 -0.428 0-6.512-5.28-11.791-11.792-11.791s-11.791 5.279-11.791 11.791c0 6.513 5.279 11.793 11.791 11.793m77.642 0c1.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 6e-3 -0.143 9e-3 -0.284 9e-3 -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.793m0 8.887c11.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.68m-77.642 0c11.42 0 20.679-9.259 20.679-20.68 0-11.42-9.259-20.677-20.679-20.677s-20.678 9.257-20.678 20.677c0 11.421 9.258 20.68 20.678 20.68m222.62-271.32c-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.108m-7.657 101.75c-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.108m3.828-50.877c-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.109m-185-126.56 8.456 14.687-2.481 14.064c8.24-6.441 16.897-12.257 25.895-17.419l-13.787-20.682c-5.163 5.163-11.523 8.215-18.083 9.35m214.44 47.276-16.013 24.214v93.753c0 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.88-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.69 32.008-164.06 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.16 4.83-7.304 7.155-15.981 6.624-24.722-3.808-62.683 19.436-123.99 63.84-168.4 3.505-3.505 7.116-6.877 10.824-10.115l-15.66-23.489c-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.28l8.659 15.04-2.26 12.808c15.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.63 3.548-6.147 10.784-9.143 17.64-7.305 6.856 1.837 11.623 8.048 11.623 15.147v65.793c33.793-9.913 62.771-33.463 79.074-66.13l119.85 29.509c-14.567 69.186-99.576 110.14-175.59 96.362z" fill="#00b7b7" fill-rule="evenodd"/></g><path transform="scale(1,-1)" d="m426.75-584.57h11.635v242.67h-11.635z" fill-rule="evenodd" stroke-width=".80733"/><path transform="scale(1,-1)" d="m533.35-584.09h11.635v242.67h-11.635z" fill-rule="evenodd" stroke-width=".80733"/><path transform="scale(1,-1)" d="m404.98-554.66h159.56v34.904h-159.56z" fill-rule="evenodd" stroke-width=".75"/><path transform="scale(1,-1)" d="m404.98-481.16h159.56v34.904h-159.56z" fill-rule="evenodd" stroke-width=".75"/><path transform="scale(1,-1)" d="m404.98-404.66h159.56v34.904h-159.56z" fill-rule="evenodd" stroke-width=".75"/></g></svg>
|
After Width: | Height: | Size: 4.7 KiB |
2
images/app-icons/maskable/mask-icon.svg
Normal file
After Width: | Height: | Size: 5.1 KiB |
2
images/icon.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 667.26 706.8" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><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><g transform="translate(-101.19 -80.003)"><rect transform="matrix(1.3333 0 0 1.3333 0 880)" x="152.91" y="-472.18" width="61.498" height="36.566" fill="#fcfc09" stroke-width=".75"/><rect x="157.35" y="177.29" width="181.72" height="68.7" fill="#f0ffff"/></g><g transform="matrix(1.3333 0 0 -1.3333 -101.19 800)"><g fill="#00b7b7"><path d="m112.25 369.32c12.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.659m14.302-81.369c15.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.516m33.549 175.93 24.381-9.342 24.382 9.342-24.382-24.381zm-14.899 47.955c1.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 5e-3 -0.143 8e-3 -0.284 8e-3 -0.428 0-6.512-5.28-11.791-11.792-11.791s-11.791 5.279-11.791 11.791c0 6.513 5.279 11.793 11.791 11.793m77.642 0c1.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 6e-3 -0.143 9e-3 -0.284 9e-3 -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.793m0 8.887c11.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.68m-77.642 0c11.42 0 20.679-9.259 20.679-20.68 0-11.42-9.259-20.677-20.679-20.677s-20.678 9.257-20.678 20.677c0 11.421 9.258 20.68 20.678 20.68m222.62-271.32c-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.108m-7.657 101.75c-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.108m3.828-50.877c-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.109m-185-126.56 8.456 14.687-2.481 14.064c8.24-6.441 16.897-12.257 25.895-17.419l-13.787-20.682c-5.163 5.163-11.523 8.215-18.083 9.35m214.44 47.276-16.013 24.214v93.753c0 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.88-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.69 32.008-164.06 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.16 4.83-7.304 7.155-15.981 6.624-24.722-3.808-62.683 19.436-123.99 63.84-168.4 3.505-3.505 7.116-6.877 10.824-10.115l-15.66-23.489c-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.28l8.659 15.04-2.26 12.808c15.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.63 3.548-6.147 10.784-9.143 17.64-7.305 6.856 1.837 11.623 8.048 11.623 15.147v65.793c33.793-9.913 62.771-33.463 79.074-66.13l119.85 29.509c-14.567 69.186-99.576 110.14-175.59 96.362z" fill="#00b7b7" fill-rule="evenodd"/></g></g></svg>
|
After Width: | Height: | Size: 4.2 KiB |
BIN
images/logo/mono-logo-33.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
2
images/logo/mono-logo.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 667.26 706.8" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><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><g transform="matrix(1.3333 0 0 -1.3333 -101.19 800)"><g fill="#fff"><path d="m112.25 369.32c12.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.659m14.302-81.369c15.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.516m33.549 175.93 24.381-9.342 24.382 9.342-24.382-24.381zm-14.899 47.955c1.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 5e-3 -0.143 8e-3 -0.284 8e-3 -0.428 0-6.512-5.28-11.791-11.792-11.791s-11.791 5.279-11.791 11.791c0 6.513 5.279 11.793 11.791 11.793m77.642 0c1.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 6e-3 -0.143 9e-3 -0.284 9e-3 -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.793m0 8.887c11.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.68m-77.642 0c11.42 0 20.679-9.259 20.679-20.68 0-11.42-9.259-20.677-20.679-20.677s-20.678 9.257-20.678 20.677c0 11.421 9.258 20.68 20.678 20.68m222.62-271.32c-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.108m-7.657 101.75c-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.108m3.828-50.877c-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.109m-185-126.56 8.456 14.687-2.481 14.064c8.24-6.441 16.897-12.257 25.895-17.419l-13.787-20.682c-5.163 5.163-11.523 8.215-18.083 9.35m214.44 47.276-16.013 24.214v93.753c0 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.88-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.69 32.008-164.06 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.16 4.83-7.304 7.155-15.981 6.624-24.722-3.808-62.683 19.436-123.99 63.84-168.4 3.505-3.505 7.116-6.877 10.824-10.115l-15.66-23.489c-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.28l8.659 15.04-2.26 12.808c15.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.63 3.548-6.147 10.784-9.143 17.64-7.305 6.856 1.837 11.623 8.048 11.623 15.147v65.793c33.793-9.913 62.771-33.463 79.074-66.13l119.85 29.509c-14.567 69.186-99.576 110.14-175.59 96.362z" fill="#fff" fill-rule="evenodd"/></g></g></svg>
|
After Width: | Height: | Size: 4.0 KiB |
BIN
images/logo/square-logo-100.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
2
images/logo/square-logo.svg
Normal file
After Width: | Height: | Size: 6.8 KiB |
2
images/logo/wide_logo.svg
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
images/logo/wide_logo_200.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
images/logo/wide_logo_250.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
images/nav/alert_icon-50.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
10
images/nav/alert_icon.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg enable-background="new 0 0 448 433" version="1.1" viewBox="0 0 448 433" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<radialGradient id="a" cx="216.7" cy="393.79" r="296.7" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#F4D708" offset="0"/>
|
||||
<stop stop-color="#FCB400" offset="1"/>
|
||||
</radialGradient>
|
||||
<path d="m8.551 390.5 184.85-368.8s26.409-31.504 52.815 0c26.41 31.501 180.19 370.65 180.19 370.65s3.105 18.534-27.961 18.534-361.94 0-361.94 0-23.299 0-27.959-20.38z" fill="url(#a)"/>
|
||||
<path d="m8.551 390.5 184.85-368.8s26.409-31.504 52.815 0c26.41 31.501 180.19 370.65 180.19 370.65s3.105 18.534-27.961 18.534-361.94 0-361.94 0-23.299 0-27.959-20.38z" fill="none" stroke="#E2A713" stroke-width="5"/>
|
||||
<path d="m212.5 292.63c-13.168-79.969-19.75-123.12-19.75-129.45 0-7.703 2.551-13.926 7.66-18.676 5.105-4.746 10.871-7.121 17.293-7.121 6.949 0 12.82 2.535 17.609 7.598s7.188 11.023 7.188 17.883c0 6.543-6.668 49.801-20 129.77h-10zm27 38.17c0 6.098-2.156 11.301-6.469 15.613-4.313 4.309-9.461 6.465-15.453 6.465-6.098 0-11.301-2.156-15.613-6.465-4.313-4.313-6.465-9.516-6.465-15.613 0-5.992 2.152-11.141 6.465-15.453s9.516-6.469 15.613-6.469c5.992 0 11.141 2.156 15.453 6.469s6.48 9.45 6.48 15.44z"/>
|
||||
<metadata><rdf:RDF><cc:Work><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/><dc:publisher><cc:Agent rdf:about="http://openclipart.org/"><dc:title>Openclipart</dc:title></cc:Agent></dc:publisher><dc:title>Warning Notification</dc:title><dc:date>2007-02-08T17:08:47</dc:date><dc:description>Beveled yellow caution sign</dc:description><dc:source>http://openclipart.org/detail/3130/warning-notification-by-eastshores</dc:source><dc:creator><cc:Agent><dc:title>eastshores</dc:title></cc:Agent></dc:creator><dc:subject><rdf:Bag><rdf:li>alert</rdf:li><rdf:li>caution</rdf:li><rdf:li>clip art</rdf:li><rdf:li>clipart</rdf:li><rdf:li>icon</rdf:li><rdf:li>image</rdf:li><rdf:li>media</rdf:li><rdf:li>public domain</rdf:li><rdf:li>svg</rdf:li><rdf:li>warning</rdf:li></rdf:Bag></dc:subject></cc:Work><cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/"><cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/><cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/><cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/></cc:License></rdf:RDF></metadata></svg>
|
After Width: | Height: | Size: 2.6 KiB |
BIN
images/nav/back-40.png
Normal file
After Width: | Height: | Size: 195 B |
6
images/nav/back.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="4.191mm" height="4.191mm" version="1.1" viewBox="0 0 4.191 4.191" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-91.032 -156.47)">
|
||||
<path d="m95.223 158.3v0.52916h-3.175c0.48507 0.48507 0.97014 0.97014 1.4552 1.4552-0.12524 0.12524-0.25047 0.25047-0.37571 0.37571l-2.0955-2.0955 2.0955-2.0955c0.12524 0.12524 0.25047 0.25047 0.37571 0.37571-0.48507 0.48507-0.97014 0.97014-1.4552 1.4552h3.175z" fill="#f9f9f9" stroke-width=".26458"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 510 B |
BIN
images/nav/close-40.png
Normal file
After Width: | Height: | Size: 468 B |
6
images/nav/close.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="3.7042mm" height="3.7042mm" version="1.1" viewBox="0 0 3.7042 3.7042" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-20.8 -106.38)">
|
||||
<path d="m24.505 106.75-0.37306-0.37306-1.479 1.479-1.479-1.479-0.37306 0.37306 1.479 1.479-1.479 1.479 0.37306 0.37306 1.479-1.479 1.479 1.479 0.37306-0.37306-1.479-1.479z" fill="#f9f9f9" stroke-width=".26458"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 422 B |
6
images/nav/hamburger.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="4.7625mm" height="3.175mm" version="1.1" viewBox="0 0 4.7625 3.175" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-54.25 -207.32)">
|
||||
<path d="m54.25 207.32h4.7625v0.52917h-4.7625v-0.52917m0 1.3229h4.7625v0.52916h-4.7625v-0.52916m0 1.3229h4.7625v0.52917h-4.7625z" fill="#f9f9f9" stroke-width=".26458"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 378 B |
BIN
images/nav/home_icon-25.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
15
images/nav/home_icon.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 97.74 85.154" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(-51.081 -910.49)">
|
||||
<path d="m100.72 910.49-24.82 23.287-24.82 23.285 16.678 0.084v38.498h23.467v-32.783h17.453v32.783h23.467v-38.174l16.676 0.084-48.1-47.064z" color="#000000" color-rendering="auto" fill="#fff" fill-rule="evenodd" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="isolation:auto;mix-blend-mode:normal"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 836 B |
BIN
images/nav/save-59.png
Normal file
After Width: | Height: | Size: 928 B |
6
images/nav/save.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="4.7625mm" height="4.7625mm" version="1.1" viewBox="0 0 4.7625 4.7625" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-123.47 -217.85)">
|
||||
<path d="m126.38 220.44c-0.1323-0.12965-0.3228-0.21167-0.52917-0.21167-0.43921 0-0.79375 0.35454-0.79375 0.79375 0 0.3466 0.22225 0.63765 0.52917 0.74612 0.0185-0.56885 0.33602-1.0636 0.79375-1.3282m-0.76994 1.6404h-1.6113v-3.7042h2.9554l0.74877 0.74877v1.1959c0.19844 0.0688 0.37571 0.17198 0.52917 0.31486v-1.7304l-1.0583-1.0583h-3.175c-0.29369 0-0.52917 0.23812-0.52917 0.52917v3.7042c0 0.29104 0.23548 0.52917 0.52917 0.52917h1.8018c-0.0926-0.1614-0.15875-0.33867-0.1905-0.52917m-1.3467-2.3812h2.3812v-1.0583h-2.3812v1.0583m2.5797 2.9104-0.72761-0.79375 0.30692-0.30692 0.42069 0.42069 0.94985-0.94985 0.30692 0.37306-1.2568 1.2568" fill="#f9f9f9" stroke-width=".26458"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 888 B |
BIN
images/nre/nre-powered.xcf
Normal file
BIN
images/nre/nre-powered_200w.jxl
Normal file
BIN
images/nre/nre-powered_200w.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
images/nre/nre-powered_200w.webp
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
images/nre/nre-powered_400w.jxl
Normal file
BIN
images/nre/nre-powered_400w.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
images/nre/nre-powered_400w.webp
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
images/nre/nre-powered_800w.jxl
Normal file
BIN
images/nre/nre-powered_800w.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
images/nre/nre-powered_800w.webp
Normal file
After Width: | Height: | Size: 19 KiB |
70
index.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<script src="./js/lib.main.js" defer></script>
|
||||
<script src="./js/index.js" defer></script>
|
||||
<title>OwlBoard</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Loading Box -->
|
||||
<div id="loading">
|
||||
<div class="spinner">
|
||||
</div>
|
||||
<p id="loading_desc">Loading</p>
|
||||
</div>
|
||||
|
||||
<!-- Popup Menu -->
|
||||
<div id="top_button" class="hide_micro">
|
||||
<picture aria-label="Menu" class="sidebar_control" id="sidebar_open_short" onclick="sidebarOpen()">
|
||||
<source srcset="/images/nav/hamburger.svg" type="image/svg+xml">
|
||||
<img src="hamburger_40.png" alt="Open menu">
|
||||
</picture>
|
||||
<picture aria-label="Close Menu" class="sidebar_control" id="sidebar_close_short" onclick="sidebarClose()">
|
||||
<source srcset="/images/nav/close.svg" type="image/svg+xml">
|
||||
<img src="close-40.png" alt="Close menu">
|
||||
</picture>
|
||||
</div>
|
||||
<div id="sidebar">
|
||||
<a href="/">Home</a>
|
||||
<a href="/find-code.html">Code Search</a>
|
||||
<a href="/settings.html">Settings</a>
|
||||
<a href="/help.html">Help</a>
|
||||
<a href="/issue.html">Report Issue</a>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Begins -->
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<br>
|
||||
<form action="board.html">
|
||||
<input class="lookup-box" type="text" id="crs-lookup" name="stn" placeholder="Enter CRS/TIPLOC" autocomplete="off"/>
|
||||
<br>
|
||||
<input type="submit" value="Lookup Board" class="lookup-button" onclick="vibe('ok')">
|
||||
</form>
|
||||
|
||||
<h2>Quick Links</h2>
|
||||
<div id="quick_links">
|
||||
</div>
|
||||
<div class="text-description">
|
||||
<p>Customise your quick links on the <a href="/settings.html">Settings</a> page.</p>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<footer>
|
||||
<p>Created by <a href="https://fredboniface.co.uk" target="_blank" rel="noreferrer noopener">Fred Boniface</a> - 0.0.3</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
58
issue.html
Normal file
@ -0,0 +1,58 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./styles/issue.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<script src="./js/lib.main.js" defer></script>
|
||||
<script src="./js/issue.js" defer></script>
|
||||
<title>OwlBoard - Report</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Loading Box -->
|
||||
<div id="loading">
|
||||
<div class="spinner">
|
||||
</div>
|
||||
<p id="loading_desc">Loading</p>
|
||||
</div>
|
||||
<div id="top_button" class="hide_micro">
|
||||
<a href="/">
|
||||
<picture aria-label="Home" class="sidebar_control">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Home">
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Report an Issue</h2>
|
||||
<p>To help diagnosing an issue, data about your browser and device will be
|
||||
collected alongside the data that you enter below.</p>
|
||||
<p>The data will be available publically in the <a href="https://git.fjla.uk/fred.boniface/owlboard/issues">
|
||||
OwlBoard Issue Tracker</a>. A preview will be shown before the data is sent.</p>
|
||||
<label for="subject">Subject:</label><br>
|
||||
<input type="text" name="subject" id="subject" class="text-entry"/><br>
|
||||
<label for="content">Message:</label><br>
|
||||
<textarea name="message" id="message" class="text-entry-long"></textarea><br>
|
||||
<input type="submit" name="submit" id="submit" label="Preview" class="lookup-button" onclick="submit()">
|
||||
<div id="preflight">
|
||||
<h3>Check & Send</h3>
|
||||
<h3>---</h3>
|
||||
<h4 id="pre_subject"></h4>
|
||||
<p id="pre_message"></p>
|
||||
<button id="send" class="lookup-button" onclick="send()">Send</button>
|
||||
<button id="cancel" class="lookup-button" onclick="cancel()">Cancel</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
97
js/find-code.js
Normal file
@ -0,0 +1,97 @@
|
||||
hideLoading();
|
||||
|
||||
async function fetchEntry(){ // This can be condensed
|
||||
showLoading();
|
||||
var name = document.getElementById("name")
|
||||
var crs = document.getElementById("3alpha")
|
||||
var nlc = document.getElementById("nlc")
|
||||
var tiploc = document.getElementById("tiploc")
|
||||
var stanox = document.getElementById("stanox")
|
||||
|
||||
var values = {
|
||||
name: name.value,
|
||||
crs: crs.value,
|
||||
nlc: nlc.value,
|
||||
tiploc: tiploc.value,
|
||||
stanox: stanox.value
|
||||
}
|
||||
parseData(values)
|
||||
}
|
||||
|
||||
async function parseData(values){
|
||||
vibe()
|
||||
if (values.crs != ""){
|
||||
setLoadingDesc(`Searching\n${values.crs.toUpperCase()}`)
|
||||
var data = await getData("crs", values.crs)
|
||||
} else if (values.nlc != ""){
|
||||
setLoadingDesc(`Searching\n${values.nlc.toUpperCase()}`)
|
||||
var data = await getData("nlc", values.nlc)
|
||||
} else if (values.tiploc != ""){
|
||||
setLoadingDesc(`Searching\n${values.tiploc.toUpperCase()}`)
|
||||
var data = await getData("tiploc", values.tiploc)
|
||||
} else if (values.stanox != ""){
|
||||
setLoadingDesc(`Searching\n${values.stanox.toUpperCase()}`)
|
||||
var data = await getData("stanox", values.stanox)
|
||||
} else if (values.name != ""){
|
||||
setLoadingDesc(`Searching\n${values.name}`)
|
||||
var data = await getData("name", values.name)
|
||||
} else {
|
||||
log("find-code.parseData: No data entered", "WARN")
|
||||
await clearForm();
|
||||
document.getElementById("name").value = "No data entered"
|
||||
vibe("err");
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
displayData(data);
|
||||
}
|
||||
|
||||
async function getData(type, value){
|
||||
log(`find-code.getData: Looking for: ${type} '${value}'`, "INFO")
|
||||
try {
|
||||
var url = `${window.location.origin}/api/v1/find/${type}/${value}`;
|
||||
var resp = await fetch(url);
|
||||
return await resp.json()
|
||||
} catch (err) {
|
||||
log(`find-code.getData: Error getting data: ${err}`, "WARN")
|
||||
vibe("err")
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
async function displayData(data){
|
||||
hideLoading();
|
||||
if (data.status === "failed" || data == ""){
|
||||
log(`find-code.displayData: Unable to find data`, "WARN")
|
||||
clearForm();
|
||||
document.getElementById("name").value = "Not Found";
|
||||
} else {
|
||||
log(`find-code.displayData: Inserting data`, "INFO")
|
||||
vibe("ok")
|
||||
try {
|
||||
document.getElementById("name").value = data['0']['NLCDESC']
|
||||
} catch (err) {}
|
||||
try {
|
||||
document.getElementById("3alpha").value = data['0']['3ALPHA']
|
||||
} catch (err) {}
|
||||
try {
|
||||
document.getElementById("nlc").value = data['0']['NLC']
|
||||
} catch (err) {}
|
||||
try {
|
||||
document.getElementById("tiploc").value = data['0']['TIPLOC']
|
||||
} catch (err) {}
|
||||
try {
|
||||
document.getElementById("stanox").value = data['0']['STANOX']
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
|
||||
async function clearForm(){
|
||||
document.getElementById("name").value = ""
|
||||
document.getElementById("3alpha").value = ""
|
||||
document.getElementById("nlc").value = ""
|
||||
document.getElementById("tiploc").value = ""
|
||||
document.getElementById("stanox").value = ""
|
||||
vibe("ok");
|
||||
hideLoading();
|
||||
}
|
26
js/index.js
Normal file
@ -0,0 +1,26 @@
|
||||
// Init:
|
||||
pageInit();
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js");
|
||||
}
|
||||
|
||||
async function pageInit() {
|
||||
await loadQuickLinks();
|
||||
hideLoading(); // From lib.main
|
||||
}
|
||||
|
||||
async function gotoBoard(station){
|
||||
vibe("ok")
|
||||
window.location.assign(`${window.location.origin}/board.html?stn=${station}`);
|
||||
}
|
||||
|
||||
async function loadQuickLinks(){
|
||||
var data = await getQuickLinks(); // From lib.main
|
||||
var buttons = "";
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
buttons += `
|
||||
<button class="actionbutton" onclick="gotoBoard('${data[i]}')">${data[i].toUpperCase()}</button>`
|
||||
}
|
||||
document.getElementById("quick_links").insertAdjacentHTML("beforeend", buttons)
|
||||
}
|
88
js/issue.js
Normal file
@ -0,0 +1,88 @@
|
||||
init();
|
||||
|
||||
async function init() {
|
||||
hideLoading()
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
setLoadingDesc("Collecting\nData")
|
||||
showLoading()
|
||||
var browserData = await getBrowserData();
|
||||
setLoadingDesc("Reading\nForm")
|
||||
var formData = await getFormData();
|
||||
preflight({browserData: browserData, formData: formData})
|
||||
}
|
||||
|
||||
async function getFormData() {
|
||||
let data = {}
|
||||
data.subject = document.getElementById("subject").value
|
||||
data.message = document.getElementById("message").value
|
||||
return data
|
||||
}
|
||||
|
||||
async function getBrowserData() {
|
||||
let data = {}
|
||||
data.userAgent = navigator.userAgent
|
||||
data.userAgentData = JSON.stringify(navigator.userAgentData)
|
||||
data.localStorage = JSON.stringify(await storageAvailable('localStorage'))
|
||||
data.sessionStorage = JSON.stringify(await storageAvailable('sessionStorage'))
|
||||
data.viewport = `${window.innerWidth} x ${window.innerHeight}`
|
||||
return data
|
||||
}
|
||||
|
||||
async function preflight(data) {
|
||||
document.getElementById("pre_subject").textContent = data.formData.subject
|
||||
pre_msg = `UserAgent: ${data.browserData.userAgent}
|
||||
\nUserAgentData: ${data.browserData.userAgentData}
|
||||
\nlocalStorage Avail: ${data.browserData.localStorage}
|
||||
\nsessionStorage Avail: ${data.browserData.sessionStorage}
|
||||
\nViewport size: ${data.browserData.viewport}
|
||||
\nUser message:\n\n${data.formData.message}`
|
||||
document.getElementById("pre_message").innerText = pre_msg
|
||||
hideLoading()
|
||||
document.getElementById("preflight").style = "display: block"
|
||||
sessionStorage.setItem("preflight_subject", data.formData.subject)
|
||||
sessionStorage.setItem("preflight_msg", pre_msg)
|
||||
}
|
||||
|
||||
async function cancel() {
|
||||
document.getElementById("preflight").style = "display: none"
|
||||
}
|
||||
|
||||
async function send() {
|
||||
setLoadingDesc("Sending\nData")
|
||||
document.getElementById("preflight").style = "display: none"
|
||||
showLoading()
|
||||
var subject = sessionStorage.getItem("preflight_subject");
|
||||
var msg = sessionStorage.getItem("preflight_msg")
|
||||
if (typeof subject != "string") {
|
||||
subject = document.getElementById("preflight_subject").innerText
|
||||
}
|
||||
if (typeof msg != "string") {
|
||||
msg = document.getElementById("preflight_msg")
|
||||
}
|
||||
var payload = JSON.stringify({subject: subject, msg: msg})
|
||||
console.log(payload);
|
||||
let opt = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
redirect: 'follow',
|
||||
body: payload
|
||||
}
|
||||
var res = await fetch(`${window.location.origin}/api/v1/issue`, opt)
|
||||
if (res.status == 200) {
|
||||
setLoadingDesc("Success")
|
||||
vibe("ok")
|
||||
await delay(2500)
|
||||
window.location.replace("/")
|
||||
} else {
|
||||
setLoadingDesc("Error")
|
||||
vibe("err")
|
||||
await delay(2500)
|
||||
hideLoading()
|
||||
document.getElementById("preflight").style = "display: none;"
|
||||
}
|
||||
}
|
248
js/lib.board.js
Normal file
@ -0,0 +1,248 @@
|
||||
/* Fetch Functions */
|
||||
async function publicLdb(stn) {
|
||||
var url = `${window.location.origin}/api/v1/ldb/${stn}`;
|
||||
var resp = await fetch(url);
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
/* Set page heading */
|
||||
async function setHeaders(title,time) {
|
||||
var prefix = `OwlBoard - `
|
||||
document.title = `${prefix}${title}`
|
||||
document.getElementById("stn_name").textContent = title
|
||||
document.getElementById("fetch_time").textContent = time.toLocaleTimeString()
|
||||
sessionStorage.setItem("board_location", title);
|
||||
}
|
||||
|
||||
/* Display No Trains Message */
|
||||
async function displayNoTrains() {
|
||||
log("No Trains", "WARN")
|
||||
document.getElementById('no_services').style = "display: block;";
|
||||
hideLoading();
|
||||
}
|
||||
|
||||
/* Parse the value of `platform` to account for unknown platforms */
|
||||
async function parsePlatform(svc){
|
||||
if (svc.platform != undefined) {
|
||||
var platform = svc.platform;
|
||||
} else {
|
||||
var platform = "-";
|
||||
}
|
||||
if (svc.platformChanged) { // Not present in public API, ready for staff version.
|
||||
var changed = "changed";
|
||||
} else {
|
||||
var changed = "";
|
||||
}
|
||||
return {num: platform, change: changed}
|
||||
}
|
||||
|
||||
|
||||
/* Change value of time strings to fit well on small screens */
|
||||
async function parseTime(string){
|
||||
switch (string) {
|
||||
case "Delayed":
|
||||
var output = "LATE";
|
||||
var change = "changed";
|
||||
break;
|
||||
case "Cancelled":
|
||||
var output = "CANC";
|
||||
var change = "cancelled";
|
||||
break;
|
||||
case "On time":
|
||||
var output = "RT";
|
||||
var change = "";
|
||||
break;
|
||||
case "":
|
||||
var output = "-";
|
||||
var change = "";
|
||||
break;
|
||||
case undefined:
|
||||
var output = "-";
|
||||
var change = "";
|
||||
break;
|
||||
case "No report":
|
||||
var output = "-";
|
||||
var change = "";
|
||||
break;
|
||||
case "undefined":
|
||||
var output = false;
|
||||
var change = "";
|
||||
break;
|
||||
default:
|
||||
var output = string;
|
||||
var change = "changed";
|
||||
}
|
||||
return {data: output, changed: change};
|
||||
}
|
||||
|
||||
/* Convert multiple Origin/Destinations to single string */
|
||||
async function parseName(location) {
|
||||
if (Array.isArray(location)) {
|
||||
var name = `${location[0]['locationName']} & ${location[1]['locationName']}`
|
||||
return name;
|
||||
}
|
||||
else {
|
||||
return location.locationName;
|
||||
}
|
||||
}
|
||||
|
||||
// Display Alert Messages
|
||||
async function displayAlerts(array) {
|
||||
var counter = 0
|
||||
var messages = ""
|
||||
for(var i = 0; i < array.length; i++) {
|
||||
// Increment counter
|
||||
counter += 1;
|
||||
// Reset Vars
|
||||
messages += `<p>${array[i]}</p>`;
|
||||
}
|
||||
if (counter > 0) {
|
||||
document.getElementById("alerts_msg").insertAdjacentHTML("beforeend", messages)
|
||||
document.getElementById("alerts").style = "display:block"
|
||||
document.getElementById("alerts_bar").style = "display:block"
|
||||
if (counter == 1) {
|
||||
document.getElementById("alert_bar_note").textContent = `There is ${counter} active alert`
|
||||
} else if (counter > 1) {
|
||||
document.getElementById("alert_bar_note").textContent = `There are ${counter} active alerts`
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Show/Hide alerts box */
|
||||
async function inflateAlerts() {
|
||||
document.getElementById("alerts_msg").style = "display:block;";
|
||||
document.getElementById("alert_expand_arrow").style = "transform: rotate(180deg);";
|
||||
document.getElementById("alerts_bar").setAttribute("onclick", "deflateAlerts()")
|
||||
}
|
||||
|
||||
async function deflateAlerts() {
|
||||
document.getElementById("alerts_msg").style = "display.none;";
|
||||
document.getElementById("alert_expand_arrow").style = "transform: rotate(0deg);";
|
||||
document.getElementById("alerts_bar").setAttribute("onclick", "inflateAlerts()")
|
||||
}
|
||||
|
||||
/*//// SERVICE DETAIL LISTS ////*/
|
||||
// Build calling list: -- This outputs calling point data to sessionStorage in the format: key{pre: [{PREVIOUS_Stops}], post: [{POST_STOPS}]}
|
||||
async function buildCallLists(svc) {
|
||||
var sSvcId = svc.serviceID;
|
||||
var oSvcData = {
|
||||
plat: svc.platform,
|
||||
sta: svc.sta,
|
||||
eta: svc.eta,
|
||||
std: svc.std,
|
||||
etd: svc.etd
|
||||
};
|
||||
try {
|
||||
if (typeof svc.previousCallingPoints.callingPointList.callingPoint != 'undefined') {
|
||||
let array = await makeArray(svc.previousCallingPoints.callingPointList.callingPoint);
|
||||
oSvcData.pre = array;
|
||||
}
|
||||
} catch (err) { /* Do nothing if ERR */ }
|
||||
try {
|
||||
if (typeof svc.subsequentCallingPoints.callingPointList.callingPoint != 'undefined') {
|
||||
let array = await makeArray(svc.subsequentCallingPoints.callingPointList.callingPoint);
|
||||
oSvcData.post = array;
|
||||
}
|
||||
} catch (err) { /* Do nothing if ERR */ }
|
||||
sessionStorage.setItem(sSvcId, JSON.stringify(oSvcData))
|
||||
}
|
||||
|
||||
/* Display calling list: - Read data from sessionStorage and write to DOM. */
|
||||
async function showCalls(id) {
|
||||
log(`Showing details for service ${id}`, "INFO")
|
||||
var svcDetail = await JSON.parse(sessionStorage.getItem(id));
|
||||
var pre = "";
|
||||
var post = "";
|
||||
if (typeof svcDetail.pre != 'undefined') {
|
||||
for(var preCall = 0; preCall < svcDetail.pre.length; preCall++) {
|
||||
pre += await singleCall(svcDetail.pre[preCall]);
|
||||
}
|
||||
}
|
||||
if (typeof svcDetail.post != 'undefined') {
|
||||
for(var postCall = 0; postCall < svcDetail.post.length; postCall++) {
|
||||
post += await singleCall(svcDetail.post[postCall]);
|
||||
}
|
||||
}
|
||||
/* Run retreived data through parsers */
|
||||
var thisStd = await parseTime(svcDetail.std);
|
||||
var thisEtd = await parseTime(svcDetail.etd);
|
||||
var thisSta = await parseTime(svcDetail.sta);
|
||||
var thisEta = await parseTime(svcDetail.eta);
|
||||
/* Prepare data for this station */
|
||||
if (thisStd.data != "-") {
|
||||
var sTime = `${thisStd.data}`
|
||||
var eTime = `${thisEtd.data}`
|
||||
var change = thisEtd.changed
|
||||
} else {
|
||||
var sTime = `${thisSta.data}`
|
||||
var eTime = `${thisEta.data}`
|
||||
var change = thisEta.changed
|
||||
};
|
||||
|
||||
let here = `<tr>
|
||||
<td class="detail-name detail-name-here detail-table-content">${sessionStorage.getItem("board_location")}</td>
|
||||
<td class="detail-table-content">${sTime}</td>
|
||||
<td class="detail-table-content ${change}">${eTime}</td>
|
||||
</tr> `
|
||||
/* Prepare then insert DOM Data */
|
||||
let dom = ` <div id="${id}" class="call-data">
|
||||
<p class="close-data" onclick="hideCalls('${id}')">X</p>
|
||||
<table class="call-table">
|
||||
<tr>
|
||||
<th class="detail-name-head">Location</th>
|
||||
<th class="time">Schedule</th>
|
||||
<th class="time">Act/Est</th>
|
||||
</tr>
|
||||
${pre}
|
||||
${here}
|
||||
${post}
|
||||
</table>
|
||||
</div>`
|
||||
|
||||
document.body.insertAdjacentHTML("beforeend", dom);
|
||||
document.getElementById(id).style = "display: block;";
|
||||
return;
|
||||
}
|
||||
|
||||
async function hideCalls(id) {
|
||||
let element = document.getElementById(id)
|
||||
element.style = "display: none;";
|
||||
element.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Builds the train data information in to a table row */
|
||||
async function singleCall(data) {
|
||||
if (typeof data.et != "undefined") {
|
||||
var time = await parseTime(data.et)
|
||||
} else if (typeof data.at != "undefined") {
|
||||
var time = await parseTime(data.at)
|
||||
}
|
||||
return `<tr>
|
||||
<td class="detail-name detail-table-content">${data.locationName}</td>
|
||||
<td class="detail-table-content">${data.st}</td>
|
||||
<td class="detail-table-content ${time.changed}">${time.data}</td>
|
||||
</tr>`
|
||||
}
|
||||
|
||||
/* Error Handler */
|
||||
async function errorHandler() {
|
||||
if (sessionStorage.getItem("failcount")) {
|
||||
var errCount = parseInt(sessionStorage.getItem("failcount"))
|
||||
} else {
|
||||
var errCount = 0;
|
||||
}
|
||||
errCount += 1;
|
||||
sessionStorage.setItem("failcount", errCount.toString())
|
||||
if (errCount < 10){
|
||||
await delay(3000);
|
||||
vibe("err")
|
||||
location.reload()
|
||||
} else {
|
||||
sessionStorage.removeItem("failcount");
|
||||
window.location.assign("conn-err.html")
|
||||
}
|
||||
}
|
132
js/lib.main.js
Normal file
@ -0,0 +1,132 @@
|
||||
/* Feature Detectors */
|
||||
|
||||
/* Valid values for ${type}: localstorage, sessionstorage */
|
||||
async function storageAvailable(type) { // Currently not used
|
||||
try {
|
||||
let storage = window[type];
|
||||
let x = '__storage_test__';
|
||||
storage.setItem(x, "test");
|
||||
storage.getItem(x);
|
||||
storage.removeItem(x);
|
||||
log(`lib.main.storageAvailable: ${type} is available`, "INFO")
|
||||
return true;
|
||||
} catch (err) {
|
||||
log(`lib.main.storageAvailable: ${type} is not available`, "ERR")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Array Converter
|
||||
Converts a string to a single item array */
|
||||
async function makeArray(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
var array = [];
|
||||
array.push(data);
|
||||
return array;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Timeouts */
|
||||
/* Usage: '' */
|
||||
const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
|
||||
|
||||
/* Log Helper */
|
||||
/* Values for level: 1, 2, 3 */
|
||||
/* Maintains backwards compatibility for previous
|
||||
implementation of log helper */
|
||||
async function log(msg, type) {
|
||||
var time = new Date().toISOString();
|
||||
switch (type) {
|
||||
case "ERR":
|
||||
console.error(`${time} - ${msg}`);
|
||||
break;
|
||||
case "WARN":
|
||||
console.warn(`${time} - ${msg}`);
|
||||
break;
|
||||
case "INFO":
|
||||
console.info(`${time} - ${msg}`);
|
||||
break;
|
||||
default:
|
||||
console.log(`${time} - ${msg}`);
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
/* Show/Hide - Menu Control */
|
||||
async function sidebarOpen() {
|
||||
document.getElementById("sidebar").style.width = "50%";
|
||||
document.getElementById("sidebar_open_short").style.display = "none";
|
||||
document.getElementById("sidebar_close_short").style.display = "block";
|
||||
}
|
||||
|
||||
async function sidebarClose() {
|
||||
document.getElementById("sidebar").style.width = "0%"
|
||||
document.getElementById("sidebar_open_short").style.display = "block";
|
||||
document.getElementById("sidebar_close_short").style.display = "none";
|
||||
}
|
||||
|
||||
/* Loading Box Control */
|
||||
async function hideLoading() {
|
||||
document.getElementById("loading").style = "display: none;";
|
||||
}
|
||||
|
||||
/* DEPRECIATED: Alias for hideLoading() - Marked for removal*/
|
||||
async function clearLoading() {
|
||||
log("Depreciated function called - clearLoading() - Alias to hideLoading()", "WARN")
|
||||
await hideLoading();
|
||||
}
|
||||
|
||||
async function showLoading() {
|
||||
document.getElementById("loading").style = "display: block;";
|
||||
}
|
||||
|
||||
async function setLoadingDesc(desc) {
|
||||
document.getElementById("loading_desc").textContent = `${desc}`;
|
||||
}
|
||||
|
||||
/* Fetch User Settings */
|
||||
async function getQuickLinks() {
|
||||
var defaults =
|
||||
["bri","lwh","srd","mtp","rda","cfn",
|
||||
"sml","shh","pri","avn","sar","svb"];
|
||||
try {
|
||||
if (localStorage.getItem("qlOpt")) {
|
||||
var data = JSON.parse(localStorage.getItem("qlOpt"));
|
||||
} else {
|
||||
data = defaults;
|
||||
}
|
||||
} catch (err) {
|
||||
data = defaults;
|
||||
}
|
||||
return data.sort();
|
||||
}
|
||||
|
||||
/* Fetch a known query parameter from the pages URL */
|
||||
async function getQuery(param) {
|
||||
var params = new URLSearchParams(window.location.search)
|
||||
var query = params.get(param)
|
||||
if (query) {
|
||||
return query
|
||||
} else {
|
||||
return 'false'
|
||||
}
|
||||
}
|
||||
|
||||
async function vibe(type) {
|
||||
let canVibrate = "vibrate" in navigator || "mozVibrate" in navigator
|
||||
if (canVibrate && !("vibrate" in navigator)){
|
||||
navigator.vibrate = navigator.mozVibrate
|
||||
}
|
||||
switch (type) {
|
||||
case "err":
|
||||
navigator.vibrate([300])
|
||||
break;
|
||||
case "ok":
|
||||
navigator.vibrate([50,50,50])
|
||||
break;
|
||||
default:
|
||||
navigator.vibrate(30)
|
||||
}
|
||||
}
|
57
js/settings.js
Normal file
@ -0,0 +1,57 @@
|
||||
// Init:
|
||||
const ql = ["ql0","ql1","ql2","ql3","ql4","ql5","ql6","ql7","ql8","ql9","ql10","ql11"]
|
||||
storageAvailable("localStorage");
|
||||
getQl();
|
||||
hideLoading();
|
||||
|
||||
async function getQl(){
|
||||
var qlOpt = await getQuickLinks()
|
||||
if (qlOpt){
|
||||
var i = 0
|
||||
while (i < 12) {
|
||||
if (qlOpt[i] != 'undefined') {
|
||||
document.getElementById(`ql${i}`).value = qlOpt[i]
|
||||
i +=1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function setQl(){
|
||||
await showLoading();
|
||||
var qlSet = []
|
||||
for (i in ql) {
|
||||
var opt = document.getElementById(`ql${i}`).value
|
||||
if (opt != ""){
|
||||
qlSet.push(opt)
|
||||
}
|
||||
qlSet.sort()
|
||||
}
|
||||
localStorage.setItem("qlOpt", JSON.stringify(qlSet))
|
||||
log(`settings.setQl: User settings saved`, "INFO")
|
||||
await hideLoading();
|
||||
await showDone();
|
||||
vibe("ok")
|
||||
await delay(800);
|
||||
hideDone();
|
||||
}
|
||||
|
||||
async function clearQl(){
|
||||
showLoading();
|
||||
localStorage.removeItem("qlOpt")
|
||||
log(`settings.setQl: User settings reset to default`, "INFO")
|
||||
getQl()
|
||||
await hideLoading();
|
||||
await showDone();
|
||||
vibe("ok");
|
||||
await delay(800);
|
||||
hideDone();
|
||||
}
|
||||
|
||||
async function showDone() {
|
||||
document.getElementById("done").style = "opacity: 1";
|
||||
}
|
||||
|
||||
async function hideDone() {
|
||||
document.getElementById("done").style = "opacity: 0";
|
||||
}
|
235
js/simple-board.js
Normal file
@ -0,0 +1,235 @@
|
||||
/* Page Init: */
|
||||
init()
|
||||
|
||||
/* Init function */
|
||||
async function init() {
|
||||
console.time("Loading Time")
|
||||
setLoadingDesc(`Loading\nservices`)
|
||||
var stn = await getQuery("stn");
|
||||
setLoadingDesc(`Loading\n${stn.toUpperCase()}`)
|
||||
log(`init: Looking up: ${stn}`);
|
||||
var sv = await getQuery("sv");
|
||||
log(`init: Staff Version: ${sv}`);
|
||||
if (sv === 'true') {
|
||||
log("init: Staff Version not supported yet.")
|
||||
log("init: Unable to proceed.")
|
||||
} else {
|
||||
try {
|
||||
var data = await publicLdb(stn)
|
||||
setLoadingDesc(`${stn.toUpperCase()}\nParsing Data`)
|
||||
log("simple-board.init: Fetched LDB Data", "INFO")
|
||||
} catch (err) {
|
||||
var data = "err"
|
||||
setLoadingDesc(`Waiting\nConnection`)
|
||||
log(`simple-board.init: Error fetching data: ${err}`, "ERR")
|
||||
}
|
||||
parseLdb(data)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for any errors in data returned from the Fetch call
|
||||
If no errors, if there are none, call buildPage(). */
|
||||
async function parseLdb(data) {
|
||||
if (data.ERROR == "NOT_FOUND") { // Station not found
|
||||
hideLoading();
|
||||
document.getElementById("error_notice").style = "display: block;";
|
||||
document.getElementById("err_not_found").style = "display: block;";
|
||||
setHeaders("Not Found",new Date())
|
||||
} else if (data == false) { // No data for station
|
||||
hideLoading();
|
||||
document.getElementById("error_notice").style = "display: block;";
|
||||
document.getElementById("err_no_data").style = "display:block;";
|
||||
setHeaders("No Data",new Date())
|
||||
} else if (data == "err") { // Connection Error
|
||||
await delay(2000);
|
||||
hideLoading();
|
||||
document.getElementById("error_notice").style = "display: block;";
|
||||
document.getElementById("err_conn").style = "display: block;";
|
||||
setHeaders("Connection Error",new Date())
|
||||
showLoading();
|
||||
await delay(5000);
|
||||
log(`parseLdb: Passing to error handler`, "ERR")
|
||||
errorHandler();
|
||||
} else {
|
||||
buildPage(data);
|
||||
}
|
||||
}
|
||||
|
||||
// Build and Display Functions
|
||||
async function buildPage(data) {
|
||||
setLoadingDesc('Loading\nData')
|
||||
var stationName = data.GetStationBoardResult.locationName;
|
||||
log(`buildPage: Data ready for ${stationName}`);
|
||||
var generateTime = new Date(await data.GetStationBoardResult.generatedAt);
|
||||
log(`buildPage: Data prepared at ${generateTime.toLocaleString()}`)
|
||||
setHeaders(stationName, generateTime);
|
||||
// Check for notices and if true pass to function
|
||||
if (data.GetStationBoardResult.nrccMessages) {
|
||||
setLoadingDesc('Loading\nAlerts')
|
||||
await displayAlerts(await makeArray(data.GetStationBoardResult.nrccMessages.message));
|
||||
}
|
||||
if (data.GetStationBoardResult.trainServices) {
|
||||
setLoadingDesc('Loading\nTrains')
|
||||
displayTrains(await makeArray(data.GetStationBoardResult.trainServices.service))
|
||||
} else {
|
||||
displayNoTrains()
|
||||
}
|
||||
if (data.GetStationBoardResult.ferryServices) {
|
||||
setLoadingDesc('Loading\nFerries')
|
||||
displayFerry(await makeArray(data.GetStationBoardResult.ferryServices.service))
|
||||
}
|
||||
if (data.GetStationBoardResult.busServices) {
|
||||
setLoadingDesc('Loading\nBusses')
|
||||
displayBus(await makeArray(data.GetStationBoardResult.busServices.service))
|
||||
}
|
||||
console.timeEnd("Loading Time")
|
||||
}
|
||||
|
||||
|
||||
async function displayTrains(data) {
|
||||
log(`simple-board.displayTrains: Inserting data in DOM`)
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
// Reset Vars
|
||||
var svc = data[i];
|
||||
displayService(svc);
|
||||
buildCallLists(svc);
|
||||
}
|
||||
|
||||
hideLoading();
|
||||
document.getElementById("output").style = "display:block;";
|
||||
log(`simple-board.displayTrains: Insertion complete`)
|
||||
}
|
||||
|
||||
async function displayFerry(ferrySvc) {
|
||||
for(var i = 0; i < ferrySvc.length; i++) {
|
||||
displayFerryService(ferrySvc[i])
|
||||
}
|
||||
}
|
||||
|
||||
async function displayBus(busSvc) {
|
||||
for(var i = 0; i < busSvc.length; i++) {
|
||||
displayBusService(busSvc[i])
|
||||
buildCallLists(busSvc[i])
|
||||
}
|
||||
}
|
||||
|
||||
async function displayService(svc) {
|
||||
var table = document.getElementById("output");
|
||||
|
||||
// Determine Time Message
|
||||
var sta = await parseTime(svc.sta);
|
||||
var eta = await parseTime(svc.eta);
|
||||
var std = await parseTime(svc.std);
|
||||
var etd = await parseTime(svc.etd);
|
||||
// Determine Platform Message
|
||||
//if (svc.platform != undefined){var plt = svc.platform} else {var plt = "-"};
|
||||
var plt = await parsePlatform(svc);
|
||||
// Define Table Row
|
||||
var row = `
|
||||
<table>
|
||||
<tr>
|
||||
<td class="name name-item" onclick="showCalls('${svc.serviceID}')">${await parseName(svc.origin.location)}</td>
|
||||
<td class="name name-item" onclick="showCalls('${svc.serviceID}')">${await parseName(svc.destination.location)}</td>
|
||||
<td class="plat ${plt.changed}">${plt.num}</td>
|
||||
<td class="time">${sta.data}</td>
|
||||
<td class="time ${eta.changed}">${eta.data}</td>
|
||||
<td class="time">${std.data}</td>
|
||||
<td class="time ${etd.changed}">${etd.data}</td>
|
||||
</tr>
|
||||
</table>`
|
||||
// Put Table Row
|
||||
table.insertAdjacentHTML("beforeend", row)
|
||||
// Display Operator
|
||||
if (svc.operator) {
|
||||
var opRow = `<p class="msg op">A ${svc.operator} service</p>`
|
||||
table.insertAdjacentHTML("beforeend", opRow);
|
||||
}
|
||||
// Parse cancelReason & delayReason
|
||||
if (svc.cancelReason) {
|
||||
var cancelRow = `<p class="msg">${svc.cancelReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", cancelRow);
|
||||
}
|
||||
if (svc.delayReason) {
|
||||
var delayRow = `<p class="msg">${svc.delayReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", delayRow);
|
||||
}
|
||||
}
|
||||
|
||||
async function displayFerryService(svc) {
|
||||
var table = document.getElementById("ferry");
|
||||
log(JSON.stringify(svc))
|
||||
// Determine Time Message
|
||||
var sta = await parseTime(svc.sta);
|
||||
var eta = await parseTime(svc.eta);
|
||||
var std = await parseTime(svc.std);
|
||||
var etd = await parseTime(svc.etd);
|
||||
// Determine Platform Message
|
||||
var plt = "";
|
||||
// Define Table Row
|
||||
var row = `
|
||||
<table>
|
||||
<tr>
|
||||
<td class="name name-item">${await parseName(svc.origin.location)}</td>
|
||||
<td class="name name-item">${await parseName(svc.destination.location)}</td>
|
||||
<td class="plat}">${plt}</td>
|
||||
<td class="time">${sta.data}</td>
|
||||
<td class="time ${eta.changed}">${eta.data}</td>
|
||||
<td class="time">${std.data}</td>
|
||||
<td class="time ${etd.changed}">${etd.data}</td>
|
||||
</tr>
|
||||
</table>`
|
||||
// Put Table Row
|
||||
table.insertAdjacentHTML("beforeend", row)
|
||||
// Parse cancelReason & delayReason
|
||||
if (svc.cancelReason) {
|
||||
var cancelRow = `<p class="msg">${svc.cancelReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", cancelRow);
|
||||
}
|
||||
if (svc.delayReason) {
|
||||
var delayRow = `<p class="msg">${svc.delayReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", delayRow);
|
||||
}
|
||||
document.getElementById("ferry").style = "display:block"
|
||||
}
|
||||
|
||||
async function displayBusService(svc) {
|
||||
var table = document.getElementById("bus");
|
||||
log(JSON.stringify(svc))
|
||||
// Determine Time Message
|
||||
var sta = await parseTime(svc.sta);
|
||||
var eta = await parseTime(svc.eta);
|
||||
var std = await parseTime(svc.std);
|
||||
var etd = await parseTime(svc.etd);
|
||||
// Determine Platform Message
|
||||
var plt = "";
|
||||
// Define Table Row
|
||||
var row = `
|
||||
<table>
|
||||
<tr>
|
||||
<td class="name name-item" onclick="showCalls('${svc.serviceID}')">${svc.origin.location.locationName}</td>
|
||||
<td class="name name-item" onclick="showCalls('${svc.serviceID}')">${svc.destination.location.locationName}</td>
|
||||
<td class="plat}">${plt}</td>
|
||||
<td class="time">${sta.data}</td>
|
||||
<td class="time ${eta.changed}">${eta.data}</td>
|
||||
<td class="time">${std.data}</td>
|
||||
<td class="time ${etd.changed}">${etd.data}</td>
|
||||
</tr>
|
||||
</table>`
|
||||
// Put Table Row
|
||||
table.insertAdjacentHTML("beforeend", row)
|
||||
// Display operator
|
||||
if (svc.operator) {
|
||||
var opRow = `<p class="msg op">A ${svc.operator} service</p>`
|
||||
table.insertAdjacentHTML("beforeend", opRow);
|
||||
}
|
||||
// Parse cancelReason & delayReason
|
||||
if (svc.cancelReason) {
|
||||
var cancelRow = `<p class="msg">${svc.cancelReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", cancelRow);
|
||||
}
|
||||
if (svc.delayReason) {
|
||||
var delayRow = `<p class="msg">${svc.delayReason}</p>`
|
||||
table.insertAdjacentHTML("beforeend", delayRow);
|
||||
}
|
||||
document.getElementById("bus").style = "display:block"
|
||||
}
|
24
js/stat.js
Normal file
@ -0,0 +1,24 @@
|
||||
init();
|
||||
|
||||
async function init() {
|
||||
display(await get())
|
||||
}
|
||||
|
||||
async function get() {
|
||||
var url = `${window.location.origin}/api/v1/stats`;
|
||||
var resp = await fetch(url);
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
async function display(data) {
|
||||
document.getElementById('server_host').textContent = `HOST: ${data.host}`;
|
||||
let dat = data.dat[0]
|
||||
console.log(JSON.stringify(dat))
|
||||
document.getElementById('time').textContent = dat.since;
|
||||
document.getElementById('ldbws').textContent = dat.ldbws || "0";
|
||||
document.getElementById('ldbsvws').textContent = dat.ldbsvws || "0";
|
||||
document.getElementById('corpus').textContent = dat.corpus || "0";
|
||||
document.getElementById('stations').textContent = dat.stations || "0";
|
||||
document.getElementById('users').textContent = dat.user || "0";
|
||||
document.getElementById('meta').textContent = dat.meta || "0";
|
||||
}
|
33
manifest.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "OwlBoard",
|
||||
"short_name": "OwlBoard",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#404c55",
|
||||
"description": "Live station departures - aimed at train-crew.",
|
||||
"categories": "travel,utilities",
|
||||
"lang": "en",
|
||||
"orientation": "portrait",
|
||||
"theme_color": "#00b7b7",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/app-icons/maskable/mask-icon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/any/plain-logo.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/images/app-icons/any/plain-logo-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
}
|
||||
]
|
||||
}
|
72
settings.html
Normal file
@ -0,0 +1,72 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="description" content="OwlBoard - Live train departures for traincrew."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="application-name" content="OwlBoard">
|
||||
<meta name="author" content="Frederick Boniface">
|
||||
<meta name="theme-color" content="#00b7b7">
|
||||
<link rel="apple-touch-icon" href="/images/app-icons/any/apple-192.png">
|
||||
<link rel="stylesheet" type="text/css" href="./styles/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="./styles/settings.css"/>
|
||||
<link rel="icon" type="image/svg+xml" href="./images/icon.svg"/>
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<title>OwlBoard - Settings</title>
|
||||
<script src="./js/lib.main.js" defer></script>
|
||||
<script src="./js/settings.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loading">
|
||||
<div class="spinner">
|
||||
</div>
|
||||
<p>Loading</p>
|
||||
</div>
|
||||
|
||||
<div id="done">
|
||||
<!-- Insert white tick SVG Here -->
|
||||
<picture id="save-icon">
|
||||
<source srcset="./images/nav/save.svg" type="image/svg+xml">
|
||||
<img src="./images/nav/save-59.png" alt="">
|
||||
</picture>
|
||||
<p>Saved</p>
|
||||
</div>
|
||||
|
||||
<div id="top_button" class="hide_micro">
|
||||
<a href="/">
|
||||
<picture aria-label="Home" class="sidebar_control">
|
||||
<source srcset="/images/nav/back.svg" type="image/svg+xml">
|
||||
<img src="back-40.png" alt="Home">
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<picture>
|
||||
<source srcset="/images/logo/wide_logo.svg" type="image/svg+xml">
|
||||
<source media="(max-height: 739px)" srcset="/images/logo/logo-full-200.png" type="image/png">
|
||||
<source srcset="/images/logo/logo-full-250.png" type="image/png">
|
||||
<img class="titleimg" src="/images/logo/logo-full-250.png" alt="OwlBoard Logo">
|
||||
</picture>
|
||||
<h2>Settings</h2>
|
||||
<p>Any settings you apply will only apply to the device you are using now.</p>
|
||||
|
||||
<label>Personal Quick Links:</label><br>
|
||||
<p>Enter one CRS/3ALPHA code per box</p>
|
||||
<input type="text" maxlength="3" id="ql0" name="ql0" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql1" name="ql1" autocomplete="off" class="small-lookup-box"><br>
|
||||
<input type="text" maxlength="3" id="ql2" name="ql2" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql3" name="ql3" autocomplete="off" class="small-lookup-box"><br>
|
||||
<input type="text" maxlength="3" id="ql4" name="ql4" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql5" name="ql5" autocomplete="off" class="small-lookup-box"><br>
|
||||
<input type="text" maxlength="3" id="ql6" name="ql6" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql7" name="ql7" autocomplete="off" class="small-lookup-box"><br>
|
||||
<input type="text" maxlength="3" id="ql8" name="ql8" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql9" name="ql9" autocomplete="off" class="small-lookup-box"><br>
|
||||
<input type="text" maxlength="3" id="ql10" name="ql10" autocomplete="off" class="small-lookup-box">
|
||||
<input type="text" maxlength="3" id="ql11" name="ql11" autocomplete="off" class="small-lookup-box"><br>
|
||||
<button onclick="setQl()" class="lookup-button">Apply</button>
|
||||
<button onclick="clearQl()" class="lookup-button">Defaults</button>
|
||||
|
||||
</body>
|
||||
</html>
|
45
stat.html
Normal file
@ -0,0 +1,45 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OwlBoard - STATS</title>
|
||||
<script src="./js/stat.js"></script>
|
||||
</head>
|
||||
<body style="text-align:center">
|
||||
<h1>OwlBoard Server Stats</h1>
|
||||
<h2 id="server_host"></h2>
|
||||
<p>Counters Reset - <span id="time"></span></p>
|
||||
<table style="margin:auto;text-align:center;">
|
||||
<tr>
|
||||
<th>Resource</th>
|
||||
<th>Hit Count</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LDBWS</td>
|
||||
<td id="ldbws"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LDBSVWS</td>
|
||||
<td id="ldbsvws"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB-CORPUS</td>
|
||||
<td id="corpus"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB-Stations</td>
|
||||
<td id="stations"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB-Users</td>
|
||||
<td id="users"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB-Meta</td>
|
||||
<td id="meta"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br><br>
|
||||
<p>The statistics represent hits & queries on all servers attached to the database.
|
||||
Multiple servers are served by each database server.</p>
|
||||
</body>
|
||||
</html>
|
351
styles/boards.css
Normal file
@ -0,0 +1,351 @@
|
||||
/* Hide when loading */
|
||||
.hide-when-loading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Main Notices: */
|
||||
.main-notice {
|
||||
display: none;
|
||||
margin-top: 150px;
|
||||
}
|
||||
|
||||
.notices-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#no_services {
|
||||
width: 75%;
|
||||
margin: auto;
|
||||
margin-top: 110px;
|
||||
margin-bottom: 30px;
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* Fixed Content: */
|
||||
#header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: var(--overlay-color);
|
||||
color: var(--second-text-color);
|
||||
}
|
||||
|
||||
#station_name {
|
||||
position: absolute;
|
||||
max-width: 50%;
|
||||
left: 7px;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.header-large{
|
||||
left: 0;
|
||||
text-align: left;
|
||||
font-size: 13pt;
|
||||
margin-top: -2px;
|
||||
overflow-wrap: anywhere;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
@media (min-width: 380px){
|
||||
.header-large{
|
||||
font-size: 13pt;
|
||||
margin-top: 9px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@media (min-width: 580px){
|
||||
.header-large{
|
||||
font-size: 19pt;
|
||||
margin-top: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.header-small {
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
/* NRCC Notices */
|
||||
#alerts{
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#alerts_bar{
|
||||
display: none;
|
||||
position: absolute;
|
||||
margin-top:50px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: var(--main-alert-color);
|
||||
color: var(--second-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#alert_icon{
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
margin-top: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
#alert_bar_note {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
margin-top: 8px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
#alert_expand_arrow {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-weight: 900;
|
||||
color: var(--second-text-color);
|
||||
transition: transform 0.25s linear;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#alerts_msg{
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
width: 100%;
|
||||
background-color: var(--main-alert-color);
|
||||
background-image: radial-gradient(var(--second-alert-color) 10%,var(--main-alert-color) 70%); /* Undecided whether this actually looks better than plain orange? */
|
||||
}
|
||||
|
||||
#alerts_msg p {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
#output {
|
||||
display: none;
|
||||
width: 100%;
|
||||
margin-top: 65px;
|
||||
}
|
||||
|
||||
table {
|
||||
color: white;
|
||||
width: 100%;
|
||||
margin-top: 3px;
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
caption{
|
||||
padding-top: 5px;
|
||||
padding-bottom: 10px;
|
||||
font-size: larger;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.secondary-table{
|
||||
margin-top: 25px;
|
||||
}
|
||||
.name{
|
||||
width: 25%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-name-head {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-name{
|
||||
text-align: left;
|
||||
}
|
||||
.name-item, .name, .plat, .time {
|
||||
font-size: 12px;
|
||||
}
|
||||
.name-item {
|
||||
color: var(--board-name-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.plat{
|
||||
width: 4%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.time{
|
||||
width: 11.5%;
|
||||
text-align: center;
|
||||
}
|
||||
.msg{
|
||||
width: 95%;
|
||||
font-size: 10px;
|
||||
margin: 0;
|
||||
margin-left: 3px;
|
||||
text-align: left;
|
||||
color: var(--note-text-color);
|
||||
}
|
||||
|
||||
.close-data {
|
||||
position: absolute;
|
||||
right: 19px;
|
||||
top: -8px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.detail-name-head, .name-item, .name, .plat, .time, .close-data {
|
||||
font-size: 16px;
|
||||
}
|
||||
.msg {
|
||||
font-size: 13px
|
||||
}
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.detail-name-head, .name-item, .name, .plat, .time, .close-data {
|
||||
font-size: 18px;
|
||||
}
|
||||
.msg {
|
||||
font-size: 14px
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.detail-name-head, .name-item, .name, .plat, .time, .close-data {
|
||||
font-size: 20px;
|
||||
}
|
||||
.msg {
|
||||
font-size: 15px
|
||||
}
|
||||
}
|
||||
|
||||
.call-data {
|
||||
display: none;
|
||||
border-radius: 20px;
|
||||
width: 93%;
|
||||
max-height: 75%;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
margin: 2%;
|
||||
padding-top: 30px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 25px;
|
||||
background-color: var(--overlay-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.detail-name {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.detail-name:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 0.5em;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
margin-right: -100%;
|
||||
margin-left: 30px;
|
||||
border-top: 1px solid;
|
||||
}
|
||||
|
||||
.call-table {
|
||||
margin: auto;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.detail-name-here {
|
||||
color: var(--board-name-color);
|
||||
}
|
||||
|
||||
.detail-table-content {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
.detail-table-content {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.detail-table-content {
|
||||
font-size: 21px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.detail-table-content {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.changed{
|
||||
animation: pulse-change 1.5s linear infinite;
|
||||
}
|
||||
.cancelled {
|
||||
animation: pulse-cancel 1.5s linear infinite;
|
||||
}
|
||||
|
||||
/* Footer: */
|
||||
#footer {
|
||||
position: fixed;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-image: linear-gradient(to left, var(--accent-color), azure 190px);
|
||||
}
|
||||
|
||||
#footer img {
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
#nre_logo {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
#owlboard_logo {
|
||||
position: absolute;
|
||||
right: 60px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
#home_icon {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
right: 40px;
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes pulse-change {
|
||||
50% {
|
||||
color: var(--main-warning-color);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-cancel {
|
||||
50% {
|
||||
color: var(--main-alert-color);
|
||||
}
|
||||
}
|
13
styles/find-code.css
Normal file
@ -0,0 +1,13 @@
|
||||
/*Overrides*/
|
||||
.titleimg{
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
.small-lookup-box{
|
||||
width: 25%;
|
||||
min-width: 75px;
|
||||
max-width: 125px;
|
||||
}
|
||||
#name{
|
||||
width: 75%;
|
||||
max-width: 275px;
|
||||
}
|
95
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
styles/fonts/firamono/firamono-500.ttf
Normal file
BIN
styles/fonts/firamono/firamono-500.woff
Normal file
BIN
styles/fonts/firamono/firamono-500.woff2
Normal file
BIN
styles/fonts/firamono/firamono-regular.ttf
Normal file
BIN
styles/fonts/firamono/firamono-regular.woff
Normal file
BIN
styles/fonts/firamono/firamono-regular.woff2
Normal file
55
styles/fonts/urwgothic/LICENSING_DETAIL
Normal file
@ -0,0 +1,55 @@
|
||||
https://www.tug.org/fonts/lppl-urw.txt
|
||||
|
||||
https://lists.dante.de/pipermail/ctan-ann/2009-June/003741.html
|
||||
|
||||
From: Jerzy B. Ludwichowski
|
||||
Subject: URW++ making original 35 fonts available under LPPL
|
||||
|
||||
I am forwarding the message below on behalf of Peter Rosenfeld, Managing
|
||||
Director of URW++, who has kindly agreed to make the basic 35 PostScript
|
||||
fonts also available under the LPPL. At his request, I'll be
|
||||
disseminating the information throughout the TeX community.
|
||||
|
||||
Many thanks to Dr. Rosenfeld!
|
||||
|
||||
Many thanks are also due to Karl Berry, TUG President, for his unswerving
|
||||
support and advice and Bogus\{}aw Jackowski, lead TeX Gyre developer,
|
||||
for pushing the issue.
|
||||
|
||||
Best,
|
||||
Jerzy
|
||||
|
||||
...............................................................
|
||||
|
||||
From: Peter Rosenfeld
|
||||
Date: Mon, 22 Jun 2009 11:33:29 +0200
|
||||
Subject: URW++ original 35 fonts available under LPPL
|
||||
|
||||
To whom it may concern,
|
||||
|
||||
Many years ago, URW++ Design and Development Inc. released their
|
||||
Type 1 implementations of the basic 35 PostScript fonts under the
|
||||
GNU General Public License and the Aladdin Ghostscript Free Public
|
||||
License.
|
||||
|
||||
We now additionally release them under the LaTeX Project Public License
|
||||
(http://www.latex-project.org/lppl), either version 1 or (at your
|
||||
option) any later version.
|
||||
|
||||
Of course, this additional licensing applies to the original URW++
|
||||
material, not any subsequent changes and additions made by other
|
||||
parties.
|
||||
|
||||
The original font files are widely available, for instance as part of
|
||||
the Ghostscript 4.00 release, and therefore we are not releasing any new
|
||||
font files. Those interested can replace the license terms in those
|
||||
original files accordingly. Responsibility for ensuring that no
|
||||
material is incorrectly licensed remains with the distributor, as
|
||||
always.
|
||||
|
||||
We hope this additional licensing will make our fonts even more widely
|
||||
available and usable in the free software community, such as the TeX
|
||||
Gyre Project.
|
||||
|
||||
Sincerely,
|
||||
Peter Rosenfeld (Managing Director, URW++)
|
BIN
styles/fonts/urwgothic/urwgothic.ttf
Normal file
BIN
styles/fonts/urwgothic/urwgothic.woff
Normal file
BIN
styles/fonts/urwgothic/urwgothic.woff2
Normal file
BIN
styles/fonts/urwgothic/urwgothicDemi.ttf
Normal file
BIN
styles/fonts/urwgothic/urwgothicDemi.woff
Normal file
BIN
styles/fonts/urwgothic/urwgothicDemi.woff2
Normal file
13
styles/help.css
Normal file
@ -0,0 +1,13 @@
|
||||
/* Glossary */
|
||||
table, th, td {
|
||||
border: 1px solid;
|
||||
border-color: lightgrey;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#table {
|
||||
color: lightgrey;
|
||||
width: 80%;
|
||||
max-width: 700px;
|
||||
margin: auto;
|
||||
}
|
20
styles/issue.css
Normal file
@ -0,0 +1,20 @@
|
||||
#preflight {
|
||||
display: none;
|
||||
border-radius: 20px;
|
||||
width: 93%;
|
||||
max-height: 80%;
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
margin: 2%;
|
||||
padding-top: 30px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 25px;
|
||||
background-color: var(--overlay-color);
|
||||
color: var(--second-text-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
318
styles/main.css
Normal file
@ -0,0 +1,318 @@
|
||||
/* 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;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'urwgothic';
|
||||
src: url('/styles/fonts/urwgothic/urwgothic.woff2') format('woff2'),
|
||||
url('/styles/fonts/urwgothic/urwgothic.woff') format('woff'),
|
||||
url('/styles/fonts/urwgothic/urwgothic.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'urwgothic';
|
||||
src: url('/styles/fonts/urwgothic/urwgothicDemi.woff2') format('woff2'),
|
||||
url('/styles/fonts/urwgothic/urwgothicDemi.woff') format('woff'),
|
||||
url('/styles/fonts/urwgothic/urwgothicDemi.ttf') format('truetype');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
/* COLOR VARS */
|
||||
:root {
|
||||
--main-bg-color: #404c55;
|
||||
--second-bg-color: #2b343c; /* Use as first arg in radial gradient */
|
||||
--accent-color: #007979;
|
||||
--overlay-color: #3c6f79de;
|
||||
--main-text-color: #00b7b7;
|
||||
--second-text-color: azure;
|
||||
--note-text-color: #9de7ff;
|
||||
--link-color: azure;
|
||||
--box-border-color: ;
|
||||
--link-visited-color: azure;
|
||||
--main-alert-color: #ed6d00;
|
||||
--second-alert-color: #e77f00; /* Use as second arg in radial gradient */
|
||||
--main-warning-color: orange;
|
||||
--board-name-color: #fcfc09;
|
||||
}
|
||||
/* Loading Box: */
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||
}
|
||||
}
|
||||
.spinner::before {
|
||||
animation: 1.5s linear infinite spinner;
|
||||
animation-play-state: inherit;
|
||||
border: solid 5px var(--overlay-color);
|
||||
border-bottom-color: var(--second-text-color);
|
||||
border-radius: 50%;
|
||||
content: "";
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
margin: auto;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
will-change: transform;
|
||||
}
|
||||
#loading {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin: auto;
|
||||
background-color: var(--overlay-color);
|
||||
border-radius: 45px;
|
||||
padding: 20px;
|
||||
padding-bottom: 1px;
|
||||
min-width: 90px;
|
||||
max-width: 90px;
|
||||
}
|
||||
#loading p {
|
||||
padding-top: 50px;
|
||||
font-weight: bolder;
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
|
||||
/* MAIN */
|
||||
html{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: var(--main-bg-color);
|
||||
background-image: radial-gradient(var(--second-bg-color), var(--main-bg-color));
|
||||
color: var(--main-text-color);
|
||||
font-family: urwgothic, sans-serif;
|
||||
text-align: center;
|
||||
padding-bottom: 60px; /*Footer height*/
|
||||
}
|
||||
body a {color:var(--link-color)}
|
||||
body a:visited {color:var(--link-visited-color)}
|
||||
.titleimg {
|
||||
width: 45%;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
width: 200px;
|
||||
height: 131px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
@media only screen and (min-height: 740px) {.titleimg{width: 250px;height: 164px;}}
|
||||
|
||||
.lookup-box {
|
||||
text-align: center;
|
||||
border: black;
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 18px;
|
||||
text-transform: uppercase;
|
||||
font-family: urwgothic, sans-serif;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.text-entry {
|
||||
text-align: center;
|
||||
border: black;
|
||||
width: 75%;
|
||||
max-width: 250px;
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 12px;
|
||||
font-family: urwgothic, sans-serif;
|
||||
transition: 0.2s;
|
||||
}
|
||||
.text-entry-long{
|
||||
text-align: left;
|
||||
border: black;
|
||||
width: 75%;
|
||||
max-width: 250px;
|
||||
height: 30%;
|
||||
max-height: 350px;
|
||||
border-radius: 20px;
|
||||
padding: 10px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 12px;
|
||||
font-family: urwgothic, sans-serif;
|
||||
transition: 0.2s;
|
||||
}
|
||||
label {
|
||||
font-weight: 900;
|
||||
}
|
||||
.small-lookup-box {
|
||||
text-align: center;
|
||||
border: black;
|
||||
border-radius: 40px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: uppercase;
|
||||
font-family: urwgothic, sans-serif;
|
||||
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: normal;
|
||||
font-family: urwgothic, sans-serif;
|
||||
padding: 5px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#quick_links{
|
||||
width: 75%;
|
||||
max-width: 300px;
|
||||
margin: auto;
|
||||
}
|
||||
.actionbutton {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
font-family: firamono, monospace;
|
||||
font-weight: 400;
|
||||
cursor: pointer;
|
||||
background-color: var(--accent-color);
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
color: var(--link-color);
|
||||
padding: 3px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.inlinelink {
|
||||
text-decoration: underline;
|
||||
color: var(--link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
/* START MENU STYLE */
|
||||
#top_button {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
.sidebar_control {
|
||||
background-color: transparent;
|
||||
color: var(--link-color);
|
||||
border: none;
|
||||
font-family: sans-serif;
|
||||
font-size: larger;
|
||||
cursor: pointer;
|
||||
}
|
||||
#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: urwgothic, sans-serif;
|
||||
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;
|
||||
font-size: smaller;
|
||||
color: var(--second-text-color);
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
}
|
||||
footer a {
|
||||
text-decoration: underline;
|
||||
color: var(--link-color);
|
||||
}
|
||||
footer a:visited {
|
||||
color: var(--link-visited-color);
|
||||
}
|
||||
footer a:hover {
|
||||
color: beige;
|
||||
}
|
31
styles/settings.css
Normal file
@ -0,0 +1,31 @@
|
||||
.small-lookup-box{
|
||||
max-width: 100px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#done {
|
||||
opacity: 0;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin: auto;
|
||||
background-color: var(--overlay-color);
|
||||
border-radius: 45px;
|
||||
padding: 20px;
|
||||
padding-bottom: 1px;
|
||||
min-width: 90px;
|
||||
max-width: 90px;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
#done img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
#done p {
|
||||
padding-top: 0px;
|
||||
font-weight: bolder;
|
||||
overflow-wrap: normal;
|
||||
}
|
82
sw.js
Normal file
@ -0,0 +1,82 @@
|
||||
/* Service Worker */
|
||||
|
||||
const appVersion = "0.0.3"
|
||||
const cacheName = `owlboard-${appVersion}`
|
||||
const cacheIDs = [cacheName]
|
||||
const cacheFiles = [
|
||||
"/404.html",
|
||||
"/conn-err.html",
|
||||
"/help.html",
|
||||
"/",
|
||||
"/issue.html",
|
||||
"/find-code.html",
|
||||
"/settings.html",
|
||||
"/manifest.json",
|
||||
"/styles/fonts/firamono/firamono-500.woff2",
|
||||
"/styles/fonts/firamono/firamono-regular.woff2",
|
||||
"/styles/fonts/urwgothic/urwgothic.woff2",
|
||||
"/styles/fonts/urwgothic/urwgothicDemi.woff2",
|
||||
"/styles/boards.css",
|
||||
"/styles/find-code.css",
|
||||
"/styles/help.css",
|
||||
"/styles/issue.css",
|
||||
"/styles/main.css",
|
||||
"/styles/settings.css",
|
||||
"/js/find-code.js",
|
||||
"/js/index.js",
|
||||
"/js/issue.js",
|
||||
"/js/lib.board.js",
|
||||
"/js/lib.main.js",
|
||||
"/js/settings.js",
|
||||
"/js/simple-board.js",
|
||||
"/images/icon.svg",
|
||||
"/images/logo/wide_logo.svg",
|
||||
"/images/logo/mono-logo.svg",
|
||||
"images/app-icons/any/plain-logo.svg",
|
||||
"images/app-icons/any/plain-logo-512.png",
|
||||
"/images/nav/alert_icon.svg",
|
||||
"/images/nav/save.svg",
|
||||
"/images/nav/home_icon.svg",
|
||||
"/images/nav/back.svg",
|
||||
"/images/nav/hamburger.svg",
|
||||
"/images/nav/close.svg",
|
||||
"/images/nre/nre-powered_400w.webp",
|
||||
"/images/nre/nre-powered_400w.jxl"
|
||||
]
|
||||
|
||||
self.addEventListener("install", (e) => {
|
||||
console.log("[Service Worker] Install");
|
||||
e.waitUntil(
|
||||
(async () => {
|
||||
const cache = await caches.open(cacheName);
|
||||
console.log("[Service Worker] Caching app data");
|
||||
await cache.addAll(cacheFiles);
|
||||
})()
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (e) => {
|
||||
e.respondWith(
|
||||
(async () => {
|
||||
const r = await caches.match(e.request);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
const response = await fetch(e.request);
|
||||
console.log(`[Service Worker] Not cached - fetching from server: ${e.request.url}`);
|
||||
return response;
|
||||
})()
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function (event) {
|
||||
event.waitUntil(caches.keys().then(function (keys) {
|
||||
return Promise.all(keys.filter(function (key) {
|
||||
return !cacheIDs.includes(key);
|
||||
}).map(function (key) {
|
||||
return caches.delete(key);
|
||||
}));
|
||||
}).then(function () {
|
||||
return self.clients.claim();
|
||||
}));
|
||||
});
|