Frontend/Deployment work.
Deployment now serves minified GZipped files. Frontend now has a responsive station title size. Need to: Change to an nginx container version that supports Brotli - I am after all the speed! Signed-off-by: Fred Boniface <fred@fjla.uk>
This commit is contained in:
parent
efb202577e
commit
302b749834
33
.test-tools/ferry-vc.json
Normal file
33
.test-tools/ferry-vc.json
Normal file
@ -0,0 +1,33 @@
|
||||
{"service":
|
||||
[
|
||||
{"sta":"16:07",
|
||||
"eta":"On time",
|
||||
"operator":"South Western Railway",
|
||||
"operatorCode":"SW",
|
||||
"serviceType":"ferry",
|
||||
"serviceID":"37782PHBR____",
|
||||
"origin":
|
||||
{"location":
|
||||
{"locationName":
|
||||
"Ryde Pier Head","crs":"RYP"
|
||||
}
|
||||
},
|
||||
"destination":
|
||||
{"location":
|
||||
{"locationName":"Portsmouth Harbour",
|
||||
"crs":"PMH"
|
||||
}
|
||||
},
|
||||
"previousCallingPoints":
|
||||
{"callingPointList":
|
||||
{"callingPoint":
|
||||
{"locationName":"Ryde Pier Head",
|
||||
"crs":"RYP",
|
||||
"st":"15:45",
|
||||
"et":"On time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{"std":"16:15","etd":"On time","operator":"South Western Railway","operatorCode":"SW","serviceType":"ferry","serviceID":"37746PHBR____","origin":{"location":{"locationName":"Portsmouth Harbour","crs":"PMH"}},"destination":{"location":{"locationName":"Ryde Pier Head","crs":"RYP"}},"subsequentCallingPoints":{"callingPointList":{"callingPoint":
|
||||
{"locationName":"Ryde Pier Head","crs":"RYP","st":"16:37","et":"On time"}}}}]}
|
@ -1,2 +1,3 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
*.xcf
|
@ -1,14 +1,10 @@
|
||||
FROM fedora:latest as compressor
|
||||
RUN dnf install brotli nodejs npm -y && npm i uglify-js -g
|
||||
COPY . /data/
|
||||
RUN rm -r /data/nginx
|
||||
RUN uglifyjs /data/js/*.js --compress --mangle
|
||||
RUN gzip -k -9 /data/*.json
|
||||
RUN gzip -k -9 /data/styles/*.css
|
||||
RUN gzip -k -9 /data/js/*.js
|
||||
RUN gzip -k -9 /data/*.html
|
||||
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 nginx:mainline-alpine-slim
|
||||
RUN rm /etc/nginx/nginx.conf
|
||||
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=compressor /data/ /site-static/
|
||||
COPY ./conf/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=compressor /data/out/ /site-static/
|
@ -14,6 +14,7 @@
|
||||
<link rel="manifest" type="application/json" href="./manifest.json"/>
|
||||
<script src="./js/main.js" defer></script>
|
||||
<script src="./js/boards.js" defer></script>
|
||||
<script src="./js/public-board.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading">
|
||||
@ -24,12 +25,16 @@
|
||||
|
||||
<div id="content">
|
||||
<div id="header">
|
||||
<h1 id="station_name"></h1>
|
||||
<p class="header-right">Data from:</p>
|
||||
<p id="fetch_time" class="header-right">Loading...</p>
|
||||
<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="nrcc_notices" class="hidden-while-loading">
|
||||
<div id="nrcc_notices">
|
||||
<p>
|
||||
Example NRCC Message Here... ... ...
|
||||
NRCC Messages can sometimes be long, and sometimes
|
||||
@ -51,7 +56,11 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="error_notice" class="main-notice hidden-while-loading">
|
||||
<div id="ferry" class="hide-when-loading">
|
||||
<p>Ferry Services</p>
|
||||
</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>
|
||||
|
37
static/conf/deploy.sh
Normal file
37
static/conf/deploy.sh
Normal file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Running UglifyJS"
|
||||
JSIN="/data/in/js/"
|
||||
JSOUT="/data/out/js"
|
||||
uglifyjs-folder "$JSIN" -x ".js" -eo "$JSOUT"
|
||||
|
||||
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"
|
||||
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
|
@ -1,29 +1,4 @@
|
||||
// Enable delays
|
||||
const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
|
||||
init()
|
||||
|
||||
/* Supporting Functions */
|
||||
async function init() {
|
||||
var stn = await getQuery("stn");
|
||||
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)
|
||||
log("init: Fetched LDB Data")
|
||||
parseLdb(data)
|
||||
} catch (err) {
|
||||
var data = null
|
||||
log("init: Unable to fetch LDB data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
@ -34,124 +9,15 @@ async function getQuery(param) {
|
||||
}
|
||||
}
|
||||
|
||||
async function publicLdb(stn) {
|
||||
var url = `${window.location.origin}/api/v1/ldb/${stn}`;
|
||||
var resp = await fetch(url);
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
// Set page headers
|
||||
async function setHeaders(title,time) {
|
||||
var prefix = `OwlBoard - `
|
||||
document.title = `${prefix}${title}`
|
||||
document.getElementById("station_name").innerHTML = title
|
||||
document.getElementById("stn_name").innerHTML = title
|
||||
document.getElementById("fetch_time").innerHTML = time.toLocaleTimeString()
|
||||
}
|
||||
|
||||
async function parseLdb(data) {
|
||||
if (data.ERROR == "NOT_FOUND") { // Station not found
|
||||
clearLoading();
|
||||
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
|
||||
clearLoading();
|
||||
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
|
||||
clearLoading();
|
||||
document.getElementById("error_notice").style = "display: block;";
|
||||
document.getElementById("err_conn").style = "display: block;";
|
||||
setHeaders("Connection Error",new Date())
|
||||
await delay(5000);
|
||||
log(`parseLdb: Waited five seconds, reloading`)
|
||||
location.reload()
|
||||
} else {
|
||||
buildPage(data);
|
||||
}
|
||||
}
|
||||
|
||||
// Build and Display Functions
|
||||
async function buildPage(data) {
|
||||
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) {
|
||||
displayNotices(data.GetStationBoardResult.nrccMessages.message)
|
||||
}
|
||||
if (typeof data.GetStationBoardResult.trainServices == 'undefined') {
|
||||
displayNoTrains()
|
||||
} else {
|
||||
displayTrains(data)
|
||||
}
|
||||
}
|
||||
|
||||
async function displayNotices(notices) {
|
||||
// Input: data.GetStationBoardResult.nrccMessages.messages
|
||||
// Processing: For each message, create a <p> inside #notices.
|
||||
// If there is more than one notice, scroll between them.
|
||||
// Output: Only to DOM.
|
||||
//document.getElementById("notices").innerHTML = notices;
|
||||
}
|
||||
|
||||
async function displayNoTrains() {
|
||||
document.getElementById('no_services').style = "display: block;";
|
||||
clearLoading();
|
||||
}
|
||||
|
||||
async function displayTrains(data) {
|
||||
log(`Inserting data in DOM`)
|
||||
for(var i = 0; i < data.GetStationBoardResult.trainServices.service.length; i++) {
|
||||
// Reset Vars
|
||||
var svc = data.GetStationBoardResult.trainServices.service[i];
|
||||
displayService(svc);
|
||||
}
|
||||
|
||||
clearLoading();
|
||||
log(`Insertion complete`)
|
||||
}
|
||||
|
||||
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">${svc.origin.location.locationName}</td>
|
||||
<td class="name">${svc.destination.location.locationName}</td>
|
||||
<td class="plat ${plat.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)
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Determine what should display in 'platform' column
|
||||
async function parsePlatform(svc){
|
||||
if (svc.platform != undefined) {
|
||||
var platform = svc.platform;
|
||||
@ -166,6 +32,7 @@ async function parsePlatform(svc){
|
||||
return {num: platform, change: changed}
|
||||
}
|
||||
|
||||
// Use different time strings to default to make better on small screens
|
||||
async function parseTime(string){
|
||||
switch (string) {
|
||||
case "Delayed":
|
||||
@ -185,7 +52,7 @@ async function parseTime(string){
|
||||
var change = "";
|
||||
break;
|
||||
case undefined:
|
||||
var output = "";
|
||||
var output = "-";
|
||||
var change = "";
|
||||
break;
|
||||
default:
|
||||
@ -195,11 +62,7 @@ async function parseTime(string){
|
||||
return {data: output, changed: change};
|
||||
}
|
||||
|
||||
// Sometimes the origin or destination names are undefined, need to catch that
|
||||
async function parseName(){
|
||||
}
|
||||
|
||||
// Log Helper
|
||||
function log(msg) {
|
||||
var time = new Date().toISOString();
|
||||
console.log(`${time} - ${msg}`)
|
||||
return;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// Toggle Loading Box
|
||||
async function clearLoading() {
|
||||
document.getElementById("loading").style = "display: none;";
|
||||
}
|
||||
@ -5,3 +6,12 @@ async function clearLoading() {
|
||||
async function showLoading() {
|
||||
document.getElementById("loading").style = "display: block;";
|
||||
}
|
||||
|
||||
// Enable delays
|
||||
const delay = ms => new Promise(res => setTimeout(res, ms));
|
||||
|
||||
// Log Helper
|
||||
function log(msg) {
|
||||
var time = new Date().toISOString();
|
||||
console.log(`${time} - ${msg}`)
|
||||
}
|
180
static/js/public-board.js
Normal file
180
static/js/public-board.js
Normal file
@ -0,0 +1,180 @@
|
||||
/* Page Init: */
|
||||
init()
|
||||
|
||||
/* Supporting Functions */
|
||||
async function init() {
|
||||
var stn = await getQuery("stn");
|
||||
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)
|
||||
log("init: Fetched LDB Data")
|
||||
parseLdb(data)
|
||||
} catch (err) {
|
||||
var data = null
|
||||
log("init: Unable to fetch LDB data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function publicLdb(stn) {
|
||||
var url = `${window.location.origin}/api/v1/ldb/${stn}`;
|
||||
var resp = await fetch(url);
|
||||
return await resp.json();}
|
||||
|
||||
|
||||
async function parseLdb(data) {
|
||||
if (data.ERROR == "NOT_FOUND") { // Station not found
|
||||
clearLoading();
|
||||
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
|
||||
clearLoading();
|
||||
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
|
||||
clearLoading();
|
||||
document.getElementById("error_notice").style = "display: block;";
|
||||
document.getElementById("err_conn").style = "display: block;";
|
||||
setHeaders("Connection Error",new Date())
|
||||
await delay(5000);
|
||||
log(`parseLdb: Waited five seconds, reloading`)
|
||||
location.reload()
|
||||
} else {
|
||||
buildPage(data);
|
||||
}
|
||||
}
|
||||
|
||||
// Build and Display Functions
|
||||
async function buildPage(data) {
|
||||
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) {
|
||||
displayNotices(data.GetStationBoardResult.nrccMessages.message)
|
||||
}
|
||||
if (typeof data.GetStationBoardResult.trainServices == 'undefined') {
|
||||
displayNoTrains()
|
||||
} else {
|
||||
displayTrains(data)
|
||||
}
|
||||
if (data.GetStationBoardResult.ferryServices) {
|
||||
displayFerry(data.GetStationBoardResult.ferryServices)
|
||||
}
|
||||
}
|
||||
|
||||
async function displayNotices(notices) {
|
||||
// Input: data.GetStationBoardResult.nrccMessages.messages
|
||||
// Processing: For each message, create a <p> inside #notices.
|
||||
// If there is more than one notice, scroll between them.
|
||||
// Output: Only to DOM.
|
||||
//document.getElementById("notices").innerHTML = notices;
|
||||
}
|
||||
|
||||
async function displayNoTrains() {
|
||||
document.getElementById('no_services').style = "display: block;";
|
||||
clearLoading();
|
||||
}
|
||||
|
||||
async function displayTrains(data) {
|
||||
log(`Inserting data in DOM`)
|
||||
for(var i = 0; i < data.GetStationBoardResult.trainServices.service.length; i++) {
|
||||
// Reset Vars
|
||||
var svc = data.GetStationBoardResult.trainServices.service[i];
|
||||
await displayService(svc);
|
||||
}
|
||||
|
||||
clearLoading();
|
||||
log(`Insertion complete`)
|
||||
}
|
||||
|
||||
async function displayFerry(ferrySvc) {
|
||||
log(JSON.stringify(ferrySvc))
|
||||
for(var i = 0; i < ferrySvc.service.length; i++) {
|
||||
displayFerryService(ferrySvc.service[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">${svc.origin.location.locationName}</td>
|
||||
<td class="name name-item">${svc.destination.location.locationName}</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)
|
||||
// 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">${svc.origin.location.locationName}</td>
|
||||
<td class="name name-item">${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)
|
||||
// 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"
|
||||
}
|
@ -29,13 +29,36 @@
|
||||
|
||||
#station_name {
|
||||
position: absolute;
|
||||
margin-top: 10px;
|
||||
font-size: 15pt;
|
||||
left: 10px;
|
||||
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;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
@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;
|
||||
@ -74,19 +97,28 @@
|
||||
}
|
||||
|
||||
table {
|
||||
color: white;
|
||||
width: 100%;
|
||||
margin-top: 3px;
|
||||
font-size: 10.5px;
|
||||
}
|
||||
|
||||
#ferry{
|
||||
margin-top: 45px;
|
||||
}
|
||||
.name{
|
||||
width: 25%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.name-item {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.plat{
|
||||
width: 4%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.time{
|
||||
width: 11.5%;
|
||||
text-align: center;
|
||||
@ -98,7 +130,7 @@ table {
|
||||
margin: 0;
|
||||
margin-left: 3px;
|
||||
text-align: left;
|
||||
color: white;
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.changed{
|
||||
@ -108,6 +140,6 @@ table {
|
||||
/* Animations */
|
||||
@keyframes pulse {
|
||||
50% {
|
||||
opacity: 0;
|
||||
color: orange;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user