commiting while gfx ar enot working right
4
copy.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# rm -rf /home/martin/dev/menuserver/dist/*
|
||||
cp -r /home/martin/dev/svelte-traintimes/public/* /home/martin/dev/traintimesPWA/live
|
26
package-lock.json
generated
@ -1640,6 +1640,11 @@
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"dev": true
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
|
||||
@ -2221,6 +2226,14 @@
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"lie": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
||||
"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
|
||||
"requires": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"livereload": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.1.tgz",
|
||||
@ -2257,6 +2270,14 @@
|
||||
"resolved": "https://registry.npmjs.org/local-access/-/local-access-1.0.1.tgz",
|
||||
"integrity": "sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA=="
|
||||
},
|
||||
"localforage": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz",
|
||||
"integrity": "sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==",
|
||||
"requires": {
|
||||
"lie": "3.1.1"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
||||
@ -3119,6 +3140,11 @@
|
||||
"picomatch": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"redaxios": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/redaxios/-/redaxios-0.2.0.tgz",
|
||||
"integrity": "sha512-lrDld2bVWIBrW+S1HPMyP8OvEtpHPIfmXyW7T7xTox1SM4/M3aC5X55xa2vRR3LZHwCvpMQAgCye8IyICzkKpA=="
|
||||
},
|
||||
"redent": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
|
||||
|
@ -24,7 +24,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.2",
|
||||
"localforage": "^1.7.3",
|
||||
"muicss": "^0.10.1",
|
||||
"redaxios": "^0.2.0",
|
||||
"rollup-plugin-replace": "^2.2.0",
|
||||
"sirv-cli": "^0.4.4",
|
||||
"spectre.css": "^0.5.8",
|
||||
|
9
public/browserconfig.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/img/mstile-150x150.png"/>
|
||||
<TileColor>#2b5797</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 49 KiB |
BIN
public/img/Icon-144.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
public/img/Icon-192.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
public/img/Icon-36.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/img/Icon-48.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
public/img/Icon-512.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
public/img/Icon-72.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
public/img/Icon-96.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
public/img/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
public/img/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
public/img/favicon-16x16.png
Normal file
After Width: | Height: | Size: 984 B |
BIN
public/img/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/img/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/img/mstile-150x150.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
public/img/photothumb.db
Normal file
33
public/img/safari-pinned-tab.svg
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="192.000000pt" height="192.000000pt" viewBox="0 0 192.000000 192.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,192.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M440 1789 c-80 -4 -104 -10 -149 -35 -63 -34 -117 -94 -145 -162 -19
|
||||
-45 -20 -74 -20 -637 l0 -590 25 -56 c32 -67 91 -128 156 -160 l48 -23 605 -1
|
||||
605 0 53 28 c69 35 118 86 151 156 l26 56 0 585 c-1 534 -2 590 -18 637 -33
|
||||
94 -133 180 -231 199 -47 8 -969 11 -1106 3z m389 -79 c21 0 51 -44 51 -74 l0
|
||||
-34 80 -1 c79 -1 80 -1 80 23 0 40 21 74 51 85 57 20 112 -21 112 -83 0 -17 5
|
||||
-26 16 -26 68 0 143 -50 172 -115 17 -37 19 -74 19 -455 0 -265 -4 -429 -11
|
||||
-454 -6 -23 -28 -55 -55 -81 l-44 -43 85 -89 c91 -94 101 -118 63 -153 -41
|
||||
-38 -61 -28 -194 105 l-125 125 -168 0 -167 0 -128 -125 c-136 -134 -157 -145
|
||||
-196 -103 -35 38 -26 60 65 155 l85 88 -35 30 c-19 16 -44 48 -55 70 -18 38
|
||||
-19 65 -19 468 -1 404 1 431 19 467 32 63 105 110 171 110 11 0 16 8 14 23 -3
|
||||
48 53 104 93 91 8 -2 17 -4 21 -4z"/>
|
||||
<path d="M819 1532 c-48 -15 -65 -75 -31 -106 16 -14 43 -16 172 -17 169 0
|
||||
190 7 190 62 0 25 -21 57 -38 60 -22 4 -282 4 -293 1z"/>
|
||||
<path d="M735 1342 c-93 -5 -94 -6 -94 -192 0 -143 2 -160 19 -175 18 -16 48
|
||||
-18 301 -18 l282 -1 18 23 c17 20 19 42 19 176 0 133 -2 154 -18 168 -15 14
|
||||
-52 17 -242 19 -124 2 -252 2 -285 0z"/>
|
||||
<path d="M685 741 c-35 -22 -50 -67 -35 -107 12 -32 55 -57 93 -56 44 1 88 50
|
||||
81 89 -9 52 -15 63 -43 78 -34 17 -63 16 -96 -4z"/>
|
||||
<path d="M1138 745 c-49 -27 -58 -97 -18 -137 55 -54 139 -31 154 43 7 38 -9
|
||||
71 -44 92 -34 21 -56 21 -92 2z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -4,10 +4,22 @@
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||
|
||||
<title>Svelte app</title>
|
||||
<title>Traintimes</title>
|
||||
|
||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||
<!--<link rel='stylesheet' href='/global.css'>-->
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="mask-icon" href="/img/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="apple-mobile-web-app-title" content="Train Times">
|
||||
<meta name="application-name" content="Train Times">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
|
||||
<!--<link rel='stylesheet' href='/global.c
|
||||
ss'>-->
|
||||
<link rel='stylesheet' href='/build/bundle.css'>
|
||||
|
||||
<script defer src='/build/bundle.js'></script>
|
||||
|
46
public/manifest.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "Train Times",
|
||||
"short_name": "Train Times",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/img/Icon-36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/img/Icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"start_url": ".",
|
||||
"imgdisplay": "standalone",
|
||||
"display": "standalone"
|
||||
}
|
110
public/service-worker.js
Normal file
@ -0,0 +1,110 @@
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
const CACHE_VERSION = 8;
|
||||
const dataCacheName = `traintimesData-v${CACHE_VERSION}`;
|
||||
const cacheName = `traintimePWA-final-${CACHE_VERSION}`;
|
||||
const filesToCache = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/service-worker.js',
|
||||
'/manifest.json',
|
||||
'/favicon.png',
|
||||
'/browserconfig.xml',
|
||||
'/build/bundle.css',
|
||||
'/build/bundle.js',
|
||||
'/build/fonts/fujicons.css',
|
||||
'/build/fonts/fujicons.ttf',
|
||||
'/img/Icon-36.png',
|
||||
'/img/Icon-48.png',
|
||||
'/img/Icon-72.png',
|
||||
'/img/Icon-96.png',
|
||||
'/img/Icon-144.png',
|
||||
'/img/Icon-192.png',
|
||||
'/img/Icon-512.png'
|
||||
];
|
||||
|
||||
self.addEventListener('install', function(e) {
|
||||
console.log('[ServiceWorker] Install');
|
||||
e.waitUntil(
|
||||
caches.open(cacheName).then(function(cache) {
|
||||
console.log('[ServiceWorker] Caching app shell');
|
||||
|
||||
return cache.addAll(filesToCache);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function(e) {
|
||||
console.log('[ServiceWorker] Activate');
|
||||
e.waitUntil(
|
||||
caches.keys().then(function(keyList) {
|
||||
return Promise.all(keyList.map(function(key) {
|
||||
if (key !== cacheName && key !== dataCacheName) {
|
||||
console.log('[ServiceWorker] Removing old cache', key);
|
||||
|
||||
return caches.delete(key);
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
/*
|
||||
* Fixes a corner case in which the app wasn't returning the latest data.
|
||||
* You can reproduce the corner case by commenting out the line below and
|
||||
* then doing the following steps: 1) load app for first time so that the
|
||||
* initial New York City data is shown 2) press the refresh button on the
|
||||
* app 3) go offline 4) reload the app. You expect to see the newer NYC
|
||||
* data, but you actually see the initial data. This happens because the
|
||||
* service worker is not yet activated. The code below essentially lets
|
||||
* you activate the service worker faster.
|
||||
*/
|
||||
return self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(e) {
|
||||
console.warn('[Service Worker] Fetch', e.request.url);
|
||||
const dataUrl = '/getnexttraintimes?';
|
||||
if (e.request.url.indexOf(dataUrl) > -1) {
|
||||
console.log('!');
|
||||
|
||||
/*
|
||||
* When the request URL contains dataUrl, the app is asking for fresh
|
||||
* weather data. In this case, the service worker always goes to the
|
||||
* network and then caches the response. This is called the "Cache then
|
||||
* network" strategy:
|
||||
* https://jakearchibald.com/2014/offline-cookbook/#cache-then-network
|
||||
*/
|
||||
e.respondWith(
|
||||
caches.open(dataCacheName).then(function(cache) {
|
||||
return fetch(e.request).then(function(response) {
|
||||
cache.put(e.request.url, response.clone());
|
||||
|
||||
return response;
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
else
|
||||
|
||||
/*
|
||||
* The app is asking for app shell files. In this scenario the app uses the
|
||||
* "Cache, falling back to the network" offline strategy:
|
||||
* https://jakearchibald.com/2014/offline-cookbook/#cache-falling-back-to-network
|
||||
*/
|
||||
e.respondWith(
|
||||
caches.match(e.request).then(function(response) {
|
||||
return response || fetch(e.request);
|
||||
})
|
||||
);
|
||||
});
|
@ -30,10 +30,7 @@
|
||||
|
||||
|
||||
<style lang="scss" global>
|
||||
@import "node_modules/spectre.css/src/spectre.scss";
|
||||
/* @import "./css/custom.scss";*/
|
||||
/*@import './fonts/fonts.css';
|
||||
@import './fonts/gotham.css';*/
|
||||
@import "./css/global.scss";
|
||||
@import './fonts/fujicons.css';
|
||||
|
||||
.up,
|
||||
|
@ -2,6 +2,8 @@
|
||||
import {pop} from 'svelte-spa-router';
|
||||
|
||||
export let page;
|
||||
let showFav = false;
|
||||
|
||||
let titleText = 'Traintimes';
|
||||
$: currentMode = (page === 'Home') ? 0 : 1;
|
||||
|
||||
@ -9,6 +11,10 @@
|
||||
pop();
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@ -33,18 +39,21 @@
|
||||
<section class="navbar-section">
|
||||
{#if currentMode === 1}
|
||||
<span on:click={goBack} class="">
|
||||
<i class="fa-2x fa fa-back" style="color:white;"></i>
|
||||
<i class="fa-2x fa fa-back-chevron" style="color:white;"></i>
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
|
||||
<span class="text-bold navbar-brand mx-2 text-uppercase">{titleText}</span>
|
||||
<span class="text-bold navbar-brand mx-1 text-uppercase">{titleText}</span>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="navbar-section">
|
||||
<a href="/#/settings" class="btn btn-link text-secondary">Settings</a>
|
||||
<a href="/#/favourites" class="btn btn-link text-secondary">Favourites</a>
|
||||
<section class="navbar-section text-right">
|
||||
<a href="/#/tweets" class="btn bg-primary ">Tweets</a>
|
||||
<a href="/#/settings" class="btn bg-primary ">Settings</a>
|
||||
{#if showFav}
|
||||
<a href="/#/favourites" class="btn bg-primary">Favourites</a>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
|
||||
|
@ -1,21 +1,40 @@
|
||||
<script>
|
||||
import SettingsInput from "./SettingsInput.svelte";
|
||||
import {state} from '../store/store';
|
||||
|
||||
let editorVisible = false;
|
||||
let itemId;
|
||||
let startStation;
|
||||
let destStation;
|
||||
let deleteEnabled = false;
|
||||
let deleteEnabled = !(typeof startStation === 'string');
|
||||
let canSave;
|
||||
|
||||
$: {
|
||||
console.log('typeof startStation', typeof startStation);
|
||||
canSave = (typeof startStation === 'object') && (typeof destStation === 'object');
|
||||
}
|
||||
|
||||
function deleteItem() {
|
||||
console.log('>> Delete item');
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
console.log('>> Close item');
|
||||
// console.log('>> Close item');
|
||||
|
||||
startStation = '';
|
||||
destStation = '';
|
||||
editorVisible = false;
|
||||
}
|
||||
|
||||
function saveEditor() {
|
||||
console.log('>> Save editor');
|
||||
async function saveEditor() {
|
||||
// console.log('>> Save editor');
|
||||
await state.saveRoute({startStation, destStation});
|
||||
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
function newEditor() {
|
||||
editorVisible = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -23,38 +42,42 @@
|
||||
|
||||
</style>
|
||||
|
||||
<span>SettingsEditor</span>
|
||||
<div class="mui-container ">
|
||||
{#if editorVisible}
|
||||
<div class="container ">
|
||||
<div class="mui-row card">
|
||||
<div class="mui--text-headline">New Route</div>
|
||||
<div class="mui--align-middle">
|
||||
<div class='mui-col-xs-12 mui-col-md-5'>
|
||||
<div class="text-subhead">New Route</div>
|
||||
<div class="grid-3">
|
||||
<div class=''>
|
||||
<SettingsInput bind:returnValue={startStation} label="Departure Station" name="startStation"/>
|
||||
</div>
|
||||
<div class='mui-col-xs-12 mui-col-md-2'>
|
||||
<i class="fa fa-thick-arrow fa-2x mui--align-middle">
|
||||
<div class='text-center'>
|
||||
<i class="fa fa-thick-arrow fa-2x mui--align-middle"></i>
|
||||
</div>
|
||||
<div class='mui-col-xs-12 mui-col-md-5'>
|
||||
<div class=''>
|
||||
<SettingsInput bind:returnValue={destStation} label="Destination Station" name="destStation"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="my text-right">
|
||||
<button class="btn btn-danger btn-sm" id="delete" type="button" disabled={deleteEnabled} on:click={deleteItem}>
|
||||
Delete
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm" type="button" on:click={closeEditor}>
|
||||
Close
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm" id="save" type="button" on:click={saveEditor}>
|
||||
<button class="btn btn-primary btn-sm" id="save" type="button" on:click={saveEditor} disabled={!canSave}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<button class="btn btn-primary" id="new" type="button" on:click={newEditor}>
|
||||
Add a new route
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
|
@ -3,8 +3,8 @@
|
||||
import {onMount} from 'svelte';
|
||||
import {searchStation} from '../libs/stations';
|
||||
|
||||
export let returnValue;
|
||||
export let value;
|
||||
export let returnValue = '';
|
||||
let value = '';
|
||||
|
||||
export let name;
|
||||
export let label;
|
||||
@ -12,22 +12,32 @@
|
||||
let debouncedDoSearch;
|
||||
let searchResults = [];
|
||||
|
||||
$: {
|
||||
if (returnValue === '') {
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
|
||||
// $: visible = (searchResults.length > 0) ?
|
||||
|
||||
onMount(async () => {
|
||||
debouncedDoSearch = debounce(doSearch, 500);
|
||||
debouncedDoSearch = debounce(doSearch, 750);
|
||||
});
|
||||
|
||||
function doSearch() {
|
||||
returnValue = '';
|
||||
// console.log(`doSearch ${name}`, value)
|
||||
if (value.length >= 2)
|
||||
searchResults = searchStation(value);
|
||||
else
|
||||
searchResults = [];
|
||||
}
|
||||
|
||||
function selectItem(e) {
|
||||
// console.log('>> selectItem', e);
|
||||
let [id, name] = e.target.dataset.content.split(',');
|
||||
|
||||
returnValue = id;
|
||||
returnValue = {id,name};
|
||||
value = name;
|
||||
|
||||
searchResults = [];
|
||||
@ -41,7 +51,7 @@
|
||||
|
||||
<span class="mui-dropdown--right">
|
||||
<label for={name}>{label}</label>
|
||||
<input {name} on:keyup={debouncedDoSearch} bind:value />
|
||||
<input autocomplete="off" {name} on:keyup={debouncedDoSearch} bind:value />
|
||||
{#if searchResults.length > 0}
|
||||
<ul class="mui-dropdown__menu mui--is-open">
|
||||
{#each searchResults as item, index}
|
||||
|
@ -1,12 +1,20 @@
|
||||
<script>
|
||||
import {state} from '../store/store';
|
||||
import SettingsListItem from "./SettingsListItem.svelte";
|
||||
|
||||
let _routes = [];
|
||||
|
||||
state.routes.subscribe(async (v) => {
|
||||
_routes = v;
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
background: #f55a4e;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<span>SettingsList</span>
|
||||
{#each _routes as item, i (item.id)}
|
||||
<SettingsListItem item={item} id={i}/>
|
||||
|
||||
{/each}
|
||||
|
60
src/components/SettingsListItem.svelte
Normal file
@ -0,0 +1,60 @@
|
||||
<script>
|
||||
import { longpress } from '../libs/longpress.js';
|
||||
import { slide } from 'svelte/transition';
|
||||
import {state} from '../store/store.js';
|
||||
|
||||
export let item;
|
||||
export let id;
|
||||
let buttonsVisible = false;
|
||||
let duration = 1000;
|
||||
|
||||
function deleteItem() {
|
||||
console.log(`delete: ${id}`);
|
||||
buttonsVisible = false;
|
||||
state.deleteRoute(id);
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
buttonsVisible = false
|
||||
}
|
||||
|
||||
function saveEditor() {
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div out:slide|local>
|
||||
<div class="grid card ">
|
||||
<div class="col-5">{item.startStation.name}</div>
|
||||
<div class="col-1"><i class="fa fa-thick-arrow fa-1x mui--align-middle"></i></div>
|
||||
<div class="col-5">{item.destStation.name}</div>
|
||||
<div class="col-1"><button class="btn btn-sm" on:click="{() => buttonsVisible = !buttonsVisible}"><i class="fa fa-menu"></i></button></div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{#if buttonsVisible}
|
||||
<div class="my grid-3" transition:slide>
|
||||
<button class="btn btn-danger btn-sm" id="delete" type="button" on:click={deleteItem}>
|
||||
Delete
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm" id="save" type="button" on:click={saveEditor}>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<button class="btn btn-sm" type="button" on:click={closeEditor}>
|
||||
Close
|
||||
</button>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
@ -1,8 +1,10 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
import axios from 'axios';
|
||||
import { fade } from 'svelte/transition';
|
||||
import axios from 'redaxios';
|
||||
import {push} from 'svelte-spa-router';
|
||||
|
||||
import {state} from '../store/store';
|
||||
import reducer from '../libs/reducer';
|
||||
|
||||
export let fromStation;
|
||||
@ -10,11 +12,23 @@
|
||||
|
||||
let list = []
|
||||
let otherDetails = {};
|
||||
let baseUrl = 'http://localhost:8100';
|
||||
let baseUrl = state.getBaseUrl();
|
||||
let doUpdate = true;
|
||||
|
||||
let fetchInterval;
|
||||
|
||||
onMount(async () => {
|
||||
|
||||
await fetchData();
|
||||
|
||||
fetchInterval = setInterval(async () => {
|
||||
console.log('Timetable update')
|
||||
await fetchData();
|
||||
}, 120000);
|
||||
});
|
||||
|
||||
onDestroy(async () => {
|
||||
clearInterval(fetchInterval);
|
||||
});
|
||||
|
||||
async function fetchData() {
|
||||
@ -23,8 +37,9 @@
|
||||
const url = baseUrl.concat(routeUrl)
|
||||
await axios.get(url)
|
||||
.then((d) => {
|
||||
list = reducer.reduceTrainTimetable(d.data)
|
||||
otherDetails = reducer.reduceOtherDetails(d.data)
|
||||
const data = JSON.parse(d.data);
|
||||
list = reducer.reduceTrainTimetable(data)
|
||||
otherDetails = reducer.reduceOtherDetails(data)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -42,10 +57,10 @@
|
||||
<div>
|
||||
<section>
|
||||
{#if otherDetails.nrMessagesExist === true}
|
||||
<div class="mui--bg-danger mui--text-white nrccAlert" style="padding:2px;">
|
||||
<div class="nrccAlert" style="padding:2px;">
|
||||
<ul>
|
||||
{#each otherDetails.nrMessages as item}
|
||||
<li><i class="fa fa-info mui--align-middle"></i> {item.msg}
|
||||
<li class="alert bg-danger"><i class="fa fa-info mui--align-middle"></i> {item.msg}
|
||||
{#if item.link}
|
||||
<a href={item.link}>{item.linkText}</a>
|
||||
{/if}
|
||||
@ -59,9 +74,9 @@
|
||||
|
||||
{#if list.length > 0}
|
||||
|
||||
{#each list as item}
|
||||
<div class="mui-row card mui--align-bottom">
|
||||
<div class="mui-col-xs-5 mui-col-md-4 mui--align-middle">
|
||||
{#each list as item, i (item.serviceIdUrlSafe)}
|
||||
<div class="grid card mui--align-bottom" transition:fade|local>
|
||||
<div class="col-5 mui--align-middle">
|
||||
<span on:click={viewService(item.serviceIdUrlSafe)}>{item.location}</span>
|
||||
<span class="mui--text-accent">{item.carriageCount}</span>
|
||||
<div>
|
||||
@ -70,13 +85,13 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mui-col-xs-2 mui-col-md-3 mui--text-center mui--align-middle time">{item.time}</div>
|
||||
<div class="col-2 text-center mui--align-middle time">{item.time}</div>
|
||||
|
||||
{#if item.isCancelled}
|
||||
<div class="mui-col-xs-5 mui-col-md-5 mui--text-center mui--align-middle delayed"><i class="fa fa-alert fa-1x mui--align-middle"></i>{item.cancel}</div>
|
||||
<div class="col-5 text-center mui--align-middle delayed"><i class="fa fa-alert fa-1x mui--align-middle"></i>{item.cancel}</div>
|
||||
{:else}
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--text-center mui--align-middle {item.statusMode}">{item.status}</div>
|
||||
<div class="mui-col-xs-2 mui-col-md-2 mui--text-center mui--align-middle">{item.platform}</div>
|
||||
<div class="col-3 text-center mui--align-middle {item.statusMode}">{item.status}</div>
|
||||
<div class="col-2 text-center mui--align-middle">{item.platform}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -1,8 +1,11 @@
|
||||
<script>
|
||||
import { fade } from 'svelte/transition';
|
||||
import {findStation} from '../libs/stations'
|
||||
import {minuteFloor, LocalStorage} from '../libs/utils'
|
||||
import {push} from 'svelte-spa-router';
|
||||
import axios from 'axios';
|
||||
import axios from 'redaxios';
|
||||
|
||||
import {state} from '../store/store';
|
||||
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
|
||||
@ -12,7 +15,7 @@
|
||||
let startStationName;
|
||||
let destStationName;
|
||||
let url;
|
||||
let baseUrl = 'http://localhost:8100';
|
||||
let baseUrl = state.getBaseUrl();
|
||||
let displayTime;
|
||||
let trainData = {eta: 'OFF', sta: 'OFF'};
|
||||
let status;
|
||||
@ -81,20 +84,51 @@
|
||||
const workingUrl = url.concat(`&mh=${minuteHash}`)
|
||||
axios.get(workingUrl)
|
||||
.then((d) => {
|
||||
trainData = {...d.data}
|
||||
trainData = {...JSON.parse(d.data)};
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.entry {
|
||||
.TRcard {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.7rem 0rem;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 0.4rem;
|
||||
border-bottom-color: #666666;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.TRcard .entry {
|
||||
align-items: left;
|
||||
display: flex;
|
||||
display: -ms-flexbox;
|
||||
/* -ms-flex: 1 0 0;
|
||||
flex: 1 0 0;*/
|
||||
-ms-flex-align: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.TRcard .entry:not(:first-child):last-child {
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
|
||||
align-items: right;
|
||||
}
|
||||
|
||||
.entryOld {
|
||||
height: 36px;
|
||||
margin: 6px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.TRcard {
|
||||
.TRcardOld {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
min-height: 48px;
|
||||
@ -111,11 +145,11 @@
|
||||
</style>
|
||||
|
||||
<div class="columns TRcard">
|
||||
<div class='column col-7 entry'>
|
||||
<div class='entry ml-1'>
|
||||
<div>{startStationName}</div>
|
||||
<div>{destStationName}</div>
|
||||
</div>
|
||||
<div class='column col-5 text-right entry'>
|
||||
<div class='entry text-right'>
|
||||
<span class="btn {status}" on:click={onClick}>{displayTime}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,22 +1,23 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
import {minuteFloor, LocalStorage} from '../libs/utils'
|
||||
import axios from 'axios';
|
||||
import axios from 'redaxios';
|
||||
|
||||
import {state} from '../store/store';
|
||||
import reducer from '../libs/reducer';
|
||||
|
||||
export let serviceId;
|
||||
|
||||
let list = [];
|
||||
let baseUrl = 'http://localhost:8100';
|
||||
let baseUrl = state.getBaseUrl();
|
||||
let doUpdate = true;
|
||||
let serviceInterval;
|
||||
|
||||
onMount(async () => {
|
||||
fetchServiceData();
|
||||
await fetchServiceData();
|
||||
|
||||
serviceInterval = setInterval(() => {
|
||||
console.log('Do service update')
|
||||
fetchServiceData()
|
||||
serviceInterval = setInterval(async () => {
|
||||
console.log('Service update')
|
||||
await fetchServiceData()
|
||||
}, 120000);
|
||||
});
|
||||
|
||||
@ -24,17 +25,14 @@
|
||||
clearInterval(serviceInterval);
|
||||
});
|
||||
|
||||
function fetchServiceData() {
|
||||
console.log('>> TrainService: fetchServiceData');
|
||||
// http://localhost:8100/getservice?serviceid=TDKWvQdeuviRyNYP7lk7gA
|
||||
async function fetchServiceData() {
|
||||
if (doUpdate === true) {
|
||||
const routeUrl = `/getservice?serviceid=${serviceId}`
|
||||
const url = baseUrl.concat(routeUrl)
|
||||
axios.get(url)
|
||||
await axios.get(url)
|
||||
.then((d) => {
|
||||
console.log(d);
|
||||
list = reducer.reduceTrainService(d.data);
|
||||
|
||||
const data = JSON.parse(d.data);
|
||||
list = reducer.reduceTrainService(data);
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -45,19 +43,19 @@
|
||||
</style>
|
||||
|
||||
<section>
|
||||
<div class="mui-row card mui--align-bottom">
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Station</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Due</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Estimated</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">Arrived</div>
|
||||
<div class="grid card text-subhead">
|
||||
<div class="col-3 text-center">Station</div>
|
||||
<div class="col-3 text-center">Due</div>
|
||||
<div class="col-3 text-center">Estimated</div>
|
||||
<div class="col-3 text-center">Arrived</div>
|
||||
</div>
|
||||
{#if list.length > 0}
|
||||
{#each list as item}
|
||||
<div class="mui-row card mui--align-bottom {item.classCancel}">
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">{item.locationName}</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle">{item.st}</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle {item.etMode}">{item.et}</div>
|
||||
<div class="mui-col-xs-3 mui-col-md-3 mui--align-middle {item.atMode}">{item.at}</div>
|
||||
<div class="grid card {item.classCancel}">
|
||||
<div class="col-3 text-center">{item.locationName}</div>
|
||||
<div class="col-3 text-center">{item.st}</div>
|
||||
<div class="col-3 text-center {item.etMode}">{item.et}</div>
|
||||
<div class="col-3 text-center {item.atMode}">{item.at}</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
64
src/components/Twitter.svelte
Normal file
@ -0,0 +1,64 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
import {state} from '../store/store';
|
||||
|
||||
export let id;
|
||||
|
||||
let tweetData;
|
||||
let tweet;
|
||||
let inReply = false;
|
||||
let tweetBody = ''
|
||||
|
||||
$: {
|
||||
if (tweet) {
|
||||
inReply = (tweet && tweet.in_reply_to_status_id !== null);
|
||||
tweetBody = (tweet && tweet.truncated) ? tweet.extended_tweet.full_text : tweet.text;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
tweetData = state.getTweetByID(id);
|
||||
tweet = JSON.parse(tweetData.tweet);
|
||||
});
|
||||
|
||||
function viaImgCache(url) {
|
||||
const cache = (true) ? 'https://image.silvrtree.co.uk/48,fit,q80/' : '';
|
||||
return `${cache}${url}`;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.avatar {
|
||||
max-width: 48px;
|
||||
max-height: 48px;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
{#if tweet}
|
||||
<div class="card">
|
||||
<blockquote>
|
||||
<div class="tweet-header">
|
||||
<div class="grid">
|
||||
<img class='avatar col-2' src={viaImgCache(tweet.user.profile_image_url_https)} alt="@{tweet.user.screen_name}"/>
|
||||
<div class="col-10 ml-2">
|
||||
<div class="text-subhead">{tweet.user.name}</div>
|
||||
<div>@{tweet.user.screen_name}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if inReply}
|
||||
<div>
|
||||
Replying to @{tweet.in_reply_to_screen_name}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="tweetBody">
|
||||
{tweetBody}
|
||||
</div>
|
||||
<div>
|
||||
<small class="text-highlight2">{tweet.created_at}</small>
|
||||
</div>
|
||||
</blockquote>
|
||||
</div>
|
||||
{/if}
|
199
src/components/TwitterSettings.svelte
Normal file
@ -0,0 +1,199 @@
|
||||
<script>
|
||||
import {state} from '../store/store';
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
|
||||
let _following;
|
||||
let mounted = false;
|
||||
|
||||
onMount(async () => {
|
||||
_following = state.getTwitterFollowing();
|
||||
mounted=(Object.keys(_following).length > 0);
|
||||
});
|
||||
|
||||
onDestroy(async () => {
|
||||
state.saveTwitterFollowing(_following);
|
||||
});
|
||||
|
||||
state.twitterFollowing.subscribe(async (v) => {
|
||||
_following = v;
|
||||
mounted=(Object.keys(_following).length > 0);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container ">
|
||||
<div class="text-dark text-subhead">Twitter</div>
|
||||
{#if mounted}
|
||||
<div class="grid-1">
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.nationalrailenq.follow}>
|
||||
@nationalrailenq
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.networkrail.follow}>
|
||||
@networkrail
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailSCOT.follow}>
|
||||
@NetworkRailSCOT
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.AvantiWestCoast.follow}>
|
||||
@AvantiWestCoast
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.CalSleeper.follow}>
|
||||
@CalSleeper
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.CrossCountryUK.follow}>
|
||||
@CrossCountryUK
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.Eurostar.follow}>
|
||||
@Eurostar
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.EurostarUK.follow}>
|
||||
@EurostarUK
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.GatwickExpress.follow}>
|
||||
@GatwickExpress
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.GlasgowSubway.follow}>
|
||||
@GlasgowSubway
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.GWRHelp.follow}>
|
||||
@GWRHelp
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.HeathrowExpress.follow}>
|
||||
@HeathrowExpress
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.LNER.follow}>
|
||||
@LNER
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.LNRailway.follow}>
|
||||
@LNRailway
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.northernassist.follow}>
|
||||
@northernassist
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.ScotRail.follow}>
|
||||
@ScotRail
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.Stansted_Exp.follow}>
|
||||
@Stansted_Exp
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.TfL.follow}>
|
||||
@TfL
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailBHM.follow}>
|
||||
@NetworkRailBHM
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailEDB.follow}>
|
||||
@NetworkRailEDB
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailEUS.follow}>
|
||||
@NetworkRailEUS
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailGLC.follow}>
|
||||
@NetworkRailGLC
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailKGX.follow}>
|
||||
@NetworkRailKGX
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailLST.follow}>
|
||||
@NetworkRailLST
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailMAN.follow}>
|
||||
@NetworkRailMAN
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.NetworkRailVIC.follow}>
|
||||
@NetworkRailVIC
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label-body">
|
||||
<input type="checkbox" bind:checked={_following.BTPScotland.follow}>
|
||||
@BTPScotland
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
277
src/css/entireframework.min.css
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
/* Copyright 2014 Owen Versteeg; MIT licensed */
|
||||
body, textarea, input, select {
|
||||
background: 0;
|
||||
border-radius: 0;
|
||||
font: 16px sans-serif;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.smooth {
|
||||
transition: all .2s
|
||||
}
|
||||
|
||||
.btn, .nav a {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0 20px;
|
||||
width: auto
|
||||
}
|
||||
|
||||
label > * {
|
||||
display: inline
|
||||
}
|
||||
|
||||
form > * {
|
||||
display: block;
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #999;
|
||||
border-radius: 6px;
|
||||
border: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 2px 0;
|
||||
padding: 12px 30px 14px
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #888
|
||||
}
|
||||
|
||||
.btn:active, .btn:focus {
|
||||
background: #777
|
||||
}
|
||||
|
||||
.btn-a {
|
||||
background: #0ae
|
||||
}
|
||||
|
||||
.btn-a:hover {
|
||||
background: #09d
|
||||
}
|
||||
|
||||
.btn-a:active, .btn-a:focus {
|
||||
background: #08b
|
||||
}
|
||||
|
||||
.btn-b {
|
||||
background: #3c5
|
||||
}
|
||||
|
||||
.btn-b:hover {
|
||||
background: #2b4
|
||||
}
|
||||
|
||||
.btn-b:active, .btn-b:focus {
|
||||
background: #2a4
|
||||
}
|
||||
|
||||
.btn-c {
|
||||
background: #d33
|
||||
}
|
||||
|
||||
.btn-c:hover {
|
||||
background: #c22
|
||||
}
|
||||
|
||||
.btn-c:active, .btn-c:focus {
|
||||
background: #b22
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
border-radius: 4px;
|
||||
padding: 10px 14px 11px
|
||||
}
|
||||
|
||||
.row {
|
||||
margin: 1% 0;
|
||||
overflow: auto
|
||||
}
|
||||
|
||||
.col {
|
||||
float: left
|
||||
}
|
||||
|
||||
.table, .c12 {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.c11 {
|
||||
width: 91.66%
|
||||
}
|
||||
|
||||
.c10 {
|
||||
width: 83.33%
|
||||
}
|
||||
|
||||
.c9 {
|
||||
width: 75%
|
||||
}
|
||||
|
||||
.c8 {
|
||||
width: 66.66%
|
||||
}
|
||||
|
||||
.c7 {
|
||||
width: 58.33%
|
||||
}
|
||||
|
||||
.c6 {
|
||||
width: 50%
|
||||
}
|
||||
|
||||
.c5 {
|
||||
width: 41.66%
|
||||
}
|
||||
|
||||
.c4 {
|
||||
width: 33.33%
|
||||
}
|
||||
|
||||
.c3 {
|
||||
width: 25%
|
||||
}
|
||||
|
||||
.c2 {
|
||||
width: 16.66%
|
||||
}
|
||||
|
||||
.c1 {
|
||||
width: 8.33%
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3em
|
||||
}
|
||||
|
||||
.btn, h2 {
|
||||
font-size: 2em
|
||||
}
|
||||
|
||||
.ico {
|
||||
font: 33px Arial Unicode MS, Lucida Sans Unicode
|
||||
}
|
||||
|
||||
.addon, .btn-sm, .nav, textarea, input, select {
|
||||
outline: 0;
|
||||
font-size: 14px
|
||||
}
|
||||
|
||||
textarea, input, select {
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc
|
||||
}
|
||||
|
||||
textarea:focus, input:focus, select:focus {
|
||||
border-color: #5ab
|
||||
}
|
||||
|
||||
textarea, input[type=text] {
|
||||
-webkit-appearance: none;
|
||||
width: 13em
|
||||
}
|
||||
|
||||
.addon {
|
||||
padding: 8px 12px;
|
||||
box-shadow: 0 0 0 1px #ccc
|
||||
}
|
||||
|
||||
.nav, .nav .current, .nav a:hover {
|
||||
background: #000;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.nav {
|
||||
height: 24px;
|
||||
padding: 11px 0 15px
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: #aaa;
|
||||
padding-right: 1em;
|
||||
position: relative;
|
||||
top: -1px
|
||||
}
|
||||
|
||||
.nav .pagename {
|
||||
font-size: 22px;
|
||||
top: 1px
|
||||
}
|
||||
|
||||
.btn.btn-close {
|
||||
background: #000;
|
||||
float: right;
|
||||
font-size: 25px;
|
||||
margin: -54px 7px;
|
||||
display: none
|
||||
}
|
||||
|
||||
@media (min-width: 1310px) {
|
||||
.container {
|
||||
margin: auto;
|
||||
width: 1270px
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 870px) {
|
||||
.row .col {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.btn.btn-close {
|
||||
display: block
|
||||
}
|
||||
|
||||
.nav {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
.pagename {
|
||||
margin-top: -11px
|
||||
}
|
||||
|
||||
.nav:active, .nav:focus {
|
||||
height: auto
|
||||
}
|
||||
|
||||
.nav div:before {
|
||||
background: #000;
|
||||
border-bottom: 10px double;
|
||||
border-top: 3px solid;
|
||||
content: '';
|
||||
float: right;
|
||||
height: 4px;
|
||||
position: relative;
|
||||
right: 3px;
|
||||
top: 14px;
|
||||
width: 20px
|
||||
}
|
||||
|
||||
.nav a {
|
||||
padding: .5em 0;
|
||||
display: block;
|
||||
width: 50%
|
||||
}
|
||||
}
|
||||
|
||||
.table th, .table td {
|
||||
padding: .5em;
|
||||
text-align: left
|
||||
}
|
||||
|
||||
.table tbody > :nth-child(2n-1) {
|
||||
background: #ddd
|
||||
}
|
||||
|
||||
.msg {
|
||||
padding: 1.5em;
|
||||
background: #def;
|
||||
border-left: 5px solid #59d
|
||||
}
|
896
src/css/global.scss
Normal file
@ -0,0 +1,896 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto+Condensed');
|
||||
|
||||
/* Global Styles */
|
||||
|
||||
|
||||
|
||||
:root {
|
||||
--primary-color: #607D8B;
|
||||
--dark-color: #294c5d;
|
||||
--light-color: #CFD8DC;
|
||||
--danger-color: #dc3545;
|
||||
--success-color: #28a745;
|
||||
--highlight-color: #dcc894;
|
||||
--highlight-color2: #dca394;
|
||||
|
||||
--navbar-height: 4rem;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
a.active{
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dataRow {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Text Styles*/
|
||||
.x-large {
|
||||
font-size: 4rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 3rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.text-dark {
|
||||
color: var(--dark-color);
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: var(--success-color);
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.text-highlight {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.text-highlight2 {
|
||||
color: var(--highlight-color2);
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.text-lowercase {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.text-uppercase {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.text-capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.text-title, h3 {
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.text-subhead, h4 {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.text-body2, h5 {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.text-body1 {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.text-caption {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
/* Center All */
|
||||
.all-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
padding: 1rem;
|
||||
border: #ccc 1px dotted;
|
||||
margin: 0.7rem 0;
|
||||
}
|
||||
|
||||
/* List */
|
||||
.list {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.list li {
|
||||
padding-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
/* Padding */
|
||||
.p {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.p-1 {
|
||||
padding: 1rem;
|
||||
}
|
||||
.p-2 {
|
||||
padding: 2rem;
|
||||
}
|
||||
.p-3 {
|
||||
padding: 3rem;
|
||||
}
|
||||
.py {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.py-1 {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.py-2 {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
.py-3 {
|
||||
padding: 3rem 0;
|
||||
}
|
||||
|
||||
/* Margin */
|
||||
.m {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
.m-1 {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: .2rem !important;
|
||||
}
|
||||
|
||||
.ml-1 {
|
||||
margin-left: .2rem !important;
|
||||
}
|
||||
|
||||
.mr-1 {
|
||||
margin-right: .2rem !important;
|
||||
}
|
||||
|
||||
.mt-1 {
|
||||
margin-top: .2rem !important;
|
||||
}
|
||||
|
||||
.mx-1 {
|
||||
margin-left: 1rem !important;
|
||||
margin-right: 1rem !important;
|
||||
}
|
||||
|
||||
.m-2 {
|
||||
margin: 2rem;
|
||||
}
|
||||
|
||||
.mb-2 {
|
||||
margin-bottom: .4rem !important;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: .4rem !important;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: .4rem !important;
|
||||
}
|
||||
|
||||
.mt-2 {
|
||||
margin-top: .4rem !important;
|
||||
}
|
||||
|
||||
.mx-2 {
|
||||
margin-left: 2rem !important;
|
||||
margin-right: 2rem !important;
|
||||
}
|
||||
|
||||
.m-3 {
|
||||
margin: 3rem;
|
||||
}
|
||||
.my {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.my-1 {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.my-2 {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.my-3 {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
display: -ms-flexbox;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin-left: -.4rem;
|
||||
margin-right: -.4rem;
|
||||
}
|
||||
|
||||
/* Grid */
|
||||
.grid-1 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
|
||||
.column,
|
||||
/*.columns {
|
||||
margin-left: 4%; }
|
||||
.column:first-child,
|
||||
.columns:first-child {
|
||||
margin-left: 0; }*/
|
||||
|
||||
.col-1 {
|
||||
width: 8.33333%;
|
||||
}
|
||||
|
||||
.col-2 {
|
||||
width: 16.66667%;
|
||||
}
|
||||
|
||||
.col-3 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.col-4 {
|
||||
width: 33.33333%;
|
||||
}
|
||||
|
||||
.col-5 {
|
||||
width: 41.66667%;
|
||||
}
|
||||
|
||||
.col-6 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.col-7 {
|
||||
width: 58.33333%;
|
||||
}
|
||||
|
||||
.col-8 {
|
||||
width: 66.66667%;
|
||||
}
|
||||
|
||||
.col-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.col-10 {
|
||||
width: 83.33333%;
|
||||
}
|
||||
|
||||
.col-11 {
|
||||
width: 91.66667%;
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.col-1-3rd {
|
||||
width: 30.6666666667%;
|
||||
}
|
||||
|
||||
.col-2-3rd {
|
||||
width: 65.3333333333%;
|
||||
}
|
||||
|
||||
.col-half {
|
||||
width: 48%;
|
||||
}
|
||||
|
||||
/* Offsets */
|
||||
.offset-1-col {
|
||||
margin-left: 8.66666666667%;
|
||||
}
|
||||
|
||||
.offset-2-col {
|
||||
margin-left: 17.3333333333%;
|
||||
}
|
||||
|
||||
.offset-3-col {
|
||||
margin-left: 26%;
|
||||
}
|
||||
|
||||
.offset-4-col {
|
||||
margin-left: 34.6666666667%;
|
||||
}
|
||||
|
||||
.offset-5-col {
|
||||
margin-left: 43.3333333333%;
|
||||
}
|
||||
|
||||
.offset-6-col {
|
||||
margin-left: 52%;
|
||||
}
|
||||
|
||||
.offset-7-col {
|
||||
margin-left: 60.6666666667%;
|
||||
}
|
||||
|
||||
.offset-8-col {
|
||||
margin-left: 69.3333333333%;
|
||||
}
|
||||
|
||||
.offset-9-col {
|
||||
margin-left: 78.0%;
|
||||
}
|
||||
|
||||
.offset-10-col {
|
||||
margin-left: 86.6666666667%;
|
||||
}
|
||||
|
||||
.offset-11-col {
|
||||
margin-left: 95.3333333333%;
|
||||
}
|
||||
|
||||
.offset-1-3rd-col {
|
||||
margin-left: 34.6666666667%;
|
||||
}
|
||||
|
||||
.offset-2-3rd-col {
|
||||
margin-left: 69.3333333333%;
|
||||
}
|
||||
|
||||
.offset-half-col {
|
||||
margin-left: 52%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
padding: 0.4rem 1.3rem;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
transition: opacity 0.2s ease-in;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 1rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
font-size: 0.6rem;
|
||||
padding: 0.1rem 0.4rem;
|
||||
text-align: center;
|
||||
margin: 0.3rem;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 0.7rem;
|
||||
margin: 1rem 0;
|
||||
opacity: 0.9;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.bg-primary,
|
||||
.badge-primary,
|
||||
.alert-primary {
|
||||
background: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.btn-light,
|
||||
.bg-light,
|
||||
.badge-light,
|
||||
.alert-light {
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-dark,
|
||||
.bg-dark,
|
||||
.badge-dark,
|
||||
.alert-dark {
|
||||
background: var(--dark-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-danger,
|
||||
.bg-danger,
|
||||
.badge-danger,
|
||||
.alert-danger {
|
||||
background: var(--danger-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-success,
|
||||
.bg-success,
|
||||
.badge-success,
|
||||
.alert-success {
|
||||
background: var(--success-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-white,
|
||||
.bg-white,
|
||||
.badge-white,
|
||||
.alert-white {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
opacity: 0.60;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
.btn:enabled:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bg-light,
|
||||
.badge-light {
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.round-img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
input {
|
||||
margin: .2rem 0;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
display: block;
|
||||
margin-top: 0.3rem;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
input[type='email'],
|
||||
input[type='password'],
|
||||
input[type='date'],
|
||||
select,
|
||||
textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.1rem;
|
||||
/*font-size: 1.2rem;*/
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
input[type='submit'],
|
||||
button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
label,
|
||||
legend {
|
||||
display: block;
|
||||
margin-bottom: .1rem;
|
||||
font-weight: 600; }
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
display: inline; }
|
||||
label > .label-body {
|
||||
display: inline-block;
|
||||
margin-left: .5rem;
|
||||
font-weight: normal;
|
||||
background-color: #dcc894;
|
||||
}
|
||||
|
||||
|
||||
table th,
|
||||
table td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table th {
|
||||
background: var(--light-color);
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
position:fixed;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.7rem 0rem;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 1rem;
|
||||
min-height: var(--navbar-height);
|
||||
}
|
||||
|
||||
|
||||
.navbar ul {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: #fff;
|
||||
padding: 0.45rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.navbar a:hover {
|
||||
color: var(--light-color);
|
||||
}
|
||||
|
||||
.navbar .welcome span {
|
||||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
.navbar .navbar-section {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
display: -ms-flexbox;
|
||||
-ms-flex: 1 0 0;
|
||||
flex: 1 0 0;
|
||||
-ms-flex-align: center;
|
||||
}
|
||||
|
||||
.navbar .navbar-section:not(:first-child):last-child {
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.navbar .navbar-brand {
|
||||
font-size: 125%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* Mobile Styles */
|
||||
@media (max-width: 700px) {
|
||||
.hide-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.grid-2,
|
||||
.grid-3,
|
||||
.grid-4 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Text Styles */
|
||||
.x-large {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*:root {
|
||||
--primary-color: #64B5F6;
|
||||
--dark-color: #333333;
|
||||
--light-color: #f4f4f4;
|
||||
--danger-color: #dc3545;
|
||||
--success-color: #28a745;
|
||||
--medium-color: #999999;
|
||||
}*/
|
||||
|
||||
.table-responsive {
|
||||
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cardV2 {
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 4px 0 rgba(0,0,0,.14), 0 3px 4px 0 rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
|
||||
/*display: flex;
|
||||
flex-direction: column;*/
|
||||
min-width: 0;
|
||||
/*position: relative;
|
||||
word-wrap: break-word;*/
|
||||
}
|
||||
|
||||
table {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
margin-bottom: 1rem;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
tbody tr:nth-of-type(odd){
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
tbody td {
|
||||
border-top: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 2.2rem;
|
||||
margin-bottom: 2rem;
|
||||
border-width: 0;
|
||||
border-top: 1px solid var(--dark-color); }
|
||||
|
||||
|
||||
|
||||
.modalWindow {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.2);
|
||||
z-index: 99999;
|
||||
opacity:0;
|
||||
pointer-events: none;
|
||||
text-align:center;
|
||||
}
|
||||
.modalWindow:target {
|
||||
opacity:1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.modalWindow > div {
|
||||
width: 500px;
|
||||
position: relative;
|
||||
margin: 10% auto;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
header + div.container {
|
||||
position: relative;
|
||||
top:var(--navbar-height);
|
||||
min-height: calc(100vh - var(--navbar-height));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MUI Dropdown module
|
||||
*/
|
||||
.mui-dropdown {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-mui-toggle="dropdown"] {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.mui-dropdown__menu {
|
||||
position: absolute;
|
||||
display: none;
|
||||
min-width: 160px;
|
||||
padding: 5px 3px;
|
||||
margin: 2px 0 0;
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
background-color: #FFF;
|
||||
border-radius: 2px;
|
||||
z-index: 1;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid var(--light-color);
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
.mui-dropdown__menu {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
@supports (-ms-ime-align: auto) {
|
||||
.mui-dropdown__menu {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.12);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
.mui-dropdown__menu.mui--is-open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mui-dropdown__menu > li > a {
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
clear: both;
|
||||
font-weight: normal;
|
||||
line-height: 1.429;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
.mui-dropdown__menu > li > a:hover, .mui-dropdown__menu > li > a:focus {
|
||||
text-decoration: none;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
|
||||
.mui-dropdown__menu > .mui--is-disabled > a, .mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus {
|
||||
color: #EEEEEE;
|
||||
}
|
||||
|
||||
.mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus {
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.mui-dropdown__menu--right {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.mui-dropdown--up > .mui-dropdown__menu {
|
||||
margin: 0 0 2px;
|
||||
}
|
||||
|
||||
.mui-dropdown--right > .mui-dropdown__menu {
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
.mui-dropdown--left > .mui-dropdown__menu {
|
||||
margin: 0 2px 0 0;
|
||||
}
|
29
src/libs/longpress.js
Normal file
@ -0,0 +1,29 @@
|
||||
export function longpress(node, duration) {
|
||||
let timer;
|
||||
|
||||
const handleMousedown = () => {
|
||||
console.log('>> handleMousedown');
|
||||
timer = setTimeout(() => {
|
||||
node.dispatchEvent(
|
||||
new CustomEvent('longpress')
|
||||
);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
const handleMouseup = () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
|
||||
node.addEventListener('mousedown', handleMousedown);
|
||||
node.addEventListener('mouseup', handleMouseup);
|
||||
|
||||
return {
|
||||
update(newDuration) {
|
||||
duration = newDuration;
|
||||
},
|
||||
destroy() {
|
||||
node.removeEventListener('mousedown', handleMousedown);
|
||||
node.removeEventListener('mouseup', handleMouseup);
|
||||
}
|
||||
};
|
||||
}
|
@ -41,7 +41,7 @@ const reducer = {
|
||||
const symbol = ['💠', '🚉'];
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
console.log('>> reduceTrainService');
|
||||
console.log(data);
|
||||
// console.log(data);
|
||||
if (typeof data.trainServices === 'object' && data.trainServices !== null)
|
||||
for (const item of data.trainServices) {
|
||||
// console.log(item)
|
||||
|
24
src/main.js
@ -1,5 +1,7 @@
|
||||
import App from './App.svelte';
|
||||
|
||||
import { state } from './store/store';
|
||||
|
||||
const app = new App({
|
||||
'target': document.body,
|
||||
'props': {
|
||||
@ -7,4 +9,26 @@ const app = new App({
|
||||
}
|
||||
});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
//
|
||||
navigator.serviceWorker.ready.then(function(reg) {
|
||||
console.warn('Ready??', reg);
|
||||
// main();
|
||||
});
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
navigator.serviceWorker
|
||||
.register('./service-worker.js')
|
||||
.then((r) => {
|
||||
console.warn('Service Worker Registered', r.scope);
|
||||
})
|
||||
.catch((error) => {
|
||||
// registration failed
|
||||
console.error(`Registration failed with ${ error}`);
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
export default app;
|
||||
|
25
src/pages/Favourites.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
background: #f55a4e;
|
||||
padding: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<h1>Favourites</h1>
|
||||
|
||||
<div class="grid-2">
|
||||
<div>a</div>
|
||||
<div>b</div>
|
||||
<div>c</div>
|
||||
<div>d</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -1,10 +1,24 @@
|
||||
<script>
|
||||
import TrainRoute from "../components/TrainRoute.svelte";
|
||||
import {state} from '../store/store';
|
||||
|
||||
let _routes = [];
|
||||
|
||||
state.routes.subscribe(async (v) => {
|
||||
_routes = v;
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<TrainRoute destStation="glq" startStation="dbe"/>
|
||||
{#each _routes as item}
|
||||
<TrainRoute destStation={item.destStation.id} startStation={item.startStation.id}/>
|
||||
|
||||
{/each}
|
||||
|
||||
|
||||
<!-- <TrainRoute destStation="glq" startStation="dbe"/>
|
||||
<TrainRoute destStation="dbe" startStation="glq"/>
|
||||
<TrainRoute destStation="glc" startStation="ptk"/>
|
||||
<TrainRoute destStation="ptk" startStation="dbe"/>
|
||||
@ -14,7 +28,7 @@
|
||||
<TrainRoute destStation="glc" startStation="bhi"/>
|
||||
<TrainRoute destStation="bhi" startStation="glc"/>
|
||||
<TrainRoute destStation="dbe" startStation="dmr"/>
|
||||
<TrainRoute destStation="dmr" startStation="glc"/>
|
||||
<TrainRoute destStation="dmr" startStation="glc"/>-->
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -10,8 +10,7 @@
|
||||
|
||||
</style>
|
||||
|
||||
<div class="mui--appbar-height"></div>
|
||||
<div class="mui-container">
|
||||
<div class="container">
|
||||
<TrainService {serviceId}/>
|
||||
</div>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import SettingsEditor from "../components/SettingsEditor.svelte";
|
||||
import SettingsList from "../components/SettingsList.svelte";
|
||||
import TwitterSettings from "../components/TwitterSettings.svelte";
|
||||
|
||||
</script>
|
||||
|
||||
@ -9,8 +10,10 @@
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<span>Settings</span>
|
||||
<div class="text-dark text-subhead">Settings</div>
|
||||
|
||||
<SettingsEditor/>
|
||||
<SettingsList/>
|
||||
<hr/>
|
||||
<TwitterSettings/>
|
||||
</div>
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<div class="container">
|
||||
<div>
|
||||
<div class="mui--text-center mui--text-accent">{fromStationName} TO {destStationName}</div>
|
||||
<div class="text-center text-dark text-subhead">{fromStationName} TO {destStationName}</div>
|
||||
<TimetableList {fromStation} {destStation}/>
|
||||
|
||||
<!--<timetable-list :fromStation="$route.params.fromStation" :destStation="$route.params.destStation"/>-->
|
||||
|
39
src/pages/Twitter.svelte
Normal file
@ -0,0 +1,39 @@
|
||||
<script>
|
||||
import {onMount, onDestroy} from 'svelte';
|
||||
import {state} from '../store/store';
|
||||
import Twitter from "../components/Twitter.svelte";
|
||||
|
||||
let _tweets = [];
|
||||
|
||||
let serviceInterval;
|
||||
|
||||
onMount(async () => {
|
||||
await state.getTweets();
|
||||
|
||||
serviceInterval = setInterval(async () => {
|
||||
console.log('Twitter update')
|
||||
await state.getTweets();
|
||||
}, 300000);
|
||||
});
|
||||
|
||||
onDestroy(async () => {
|
||||
clearInterval(serviceInterval);
|
||||
});
|
||||
|
||||
state.tweetList.subscribe(async (v) => {
|
||||
_tweets = v;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="text-subhead">Twitter</div>
|
||||
{#each _tweets as item, i (item)}
|
||||
<Twitter id={item}/>
|
||||
{/each}
|
||||
|
||||
</div>
|
@ -11,6 +11,8 @@ import Home from './pages/Home.svelte';
|
||||
import Service from './pages/Service.svelte';
|
||||
import Timetable from './pages/Timetable.svelte';
|
||||
import Settings from './pages/Settings.svelte';
|
||||
import Favourites from './pages/Favourites.svelte';
|
||||
import Twitter from './pages/Twitter.svelte';
|
||||
import NotFound from './pages/NotFound.svelte';
|
||||
|
||||
const routes = new Map();
|
||||
@ -18,6 +20,8 @@ routes.set('/', Home);
|
||||
routes.set('/timetable/:fromStation/:destStation', Timetable);
|
||||
routes.set('/service/:serviceId', Service);
|
||||
routes.set('/settings', Settings);
|
||||
routes.set('/favourites', Favourites);
|
||||
routes.set('/tweets', Twitter);
|
||||
routes.set('*', NotFound);
|
||||
|
||||
export default routes;
|
||||
|
281
src/store/store.js
Normal file
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Created by WebStorm.
|
||||
* User: martin
|
||||
* Date: 28/04/2020
|
||||
* Time: 11:28
|
||||
|
||||
*/
|
||||
import axios from 'redaxios';
|
||||
|
||||
import { writable, get } from 'svelte/store';
|
||||
import localforage from 'localforage';
|
||||
const baseUrl = (ENV === 'production') ? (`${location.protocol }//${ location.hostname}`) : 'http://localhost:8100';
|
||||
|
||||
let started = false;
|
||||
const twitterAccounts = {
|
||||
'nationalrailenq': {
|
||||
'id': 33546465,
|
||||
'follow': false
|
||||
},
|
||||
'networkrail': {
|
||||
'id': 365344176,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailSCOT': {
|
||||
'id': 402687948,
|
||||
'follow': false
|
||||
},
|
||||
'AvantiWestCoast': {
|
||||
'id': 1143560758476906497,
|
||||
'follow': false
|
||||
},
|
||||
'CalSleeper': {
|
||||
'id': 2870293725,
|
||||
'follow': false
|
||||
},
|
||||
'CrossCountryUK': {
|
||||
'id': 153368708,
|
||||
'follow': false
|
||||
},
|
||||
'Eurostar': {
|
||||
'id': 98412169,
|
||||
'follow': false
|
||||
},
|
||||
'EurostarUK': {
|
||||
'id': 59742254,
|
||||
'follow': false
|
||||
},
|
||||
'GatwickExpress': {
|
||||
'id': 163816182,
|
||||
'follow': false
|
||||
},
|
||||
'GlasgowSubway': {
|
||||
'id': 224607925,
|
||||
'follow': false
|
||||
},
|
||||
'GWRHelp': {
|
||||
'id': 15589815,
|
||||
'follow': false
|
||||
},
|
||||
'HeathrowExpress': {
|
||||
'id': 20240678,
|
||||
'follow': false
|
||||
},
|
||||
'LNER': {
|
||||
'id': 313306238,
|
||||
'follow': false
|
||||
},
|
||||
'LNRailway': {
|
||||
'id': 910487328627535872,
|
||||
'follow': false
|
||||
},
|
||||
'northernassist': {
|
||||
'id': 194512268,
|
||||
'follow': false
|
||||
},
|
||||
'ScotRail': {
|
||||
'id': 61569136,
|
||||
'follow': false
|
||||
},
|
||||
'Stansted_Exp': {
|
||||
'id': 257511611,
|
||||
'follow': false
|
||||
},
|
||||
'TfL': {
|
||||
'id': 47319664,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailBHM': {
|
||||
'id': 583910976,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailEDB': {
|
||||
'id': 586614081,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailEUS': {
|
||||
'id': 581807264,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailGLC': {
|
||||
'id': 421061171,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailKGX': {
|
||||
'id': 459192871,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailLST': {
|
||||
'id': 581826097,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailMAN': {
|
||||
'id': 583895871,
|
||||
'follow': false
|
||||
},
|
||||
'NetworkRailVIC': {
|
||||
'id': 587354752,
|
||||
'follow': false
|
||||
},
|
||||
'BTPScotland': {
|
||||
'id': 957256160,
|
||||
'follow': false
|
||||
}
|
||||
};
|
||||
|
||||
const state = {
|
||||
'twitterFollowing': writable({}),
|
||||
'twitterFollowingList' : writable([]),
|
||||
'tweetList' : writable([]),
|
||||
'tweets' : writable([]),
|
||||
'favourites' : writable([]),
|
||||
'routes' : writable([]),
|
||||
'routeIndex' : writable(0),
|
||||
incrementRouteIndex() {
|
||||
this.routeIndex.update(v => v + 1);
|
||||
},
|
||||
async saveRoute(newRoute) {
|
||||
// console.log('Newroute', newRoute);
|
||||
const _newRoute = { ...newRoute };
|
||||
_newRoute.id = get(this.routeIndex);
|
||||
|
||||
this.routes.update((v) => {
|
||||
// console.log('update', [...v, _newRoute]);
|
||||
|
||||
return [...v, _newRoute];
|
||||
});
|
||||
this.incrementRouteIndex();
|
||||
},
|
||||
deleteRoute(id) {
|
||||
const pre = get(this.routes).slice(0, id);
|
||||
|
||||
const post = get(this.routes).slice(id + 1);
|
||||
|
||||
this.routes.set([...pre, ...post]);
|
||||
},
|
||||
async getTweets() {
|
||||
// console.log('>> getTweets');
|
||||
// console.log('>> state.twitterFollowingList', get(state.twitterFollowingList));
|
||||
const list = get(state.twitterFollowingList).map((item) => {
|
||||
return item[1].id;
|
||||
})/* .join(',')*/;
|
||||
// console.log('>> actual ids', list);
|
||||
// const routeUrl = `/twitter?t=${list}`;
|
||||
const routeUrl = '/twitter';
|
||||
const twitterUrl = baseUrl.concat(routeUrl);
|
||||
const postReq = {
|
||||
'method':'post',
|
||||
'url': twitterUrl,
|
||||
'data' : {
|
||||
list
|
||||
}
|
||||
};
|
||||
// console.log(postReq);
|
||||
await axios(postReq)
|
||||
.then((d) => {
|
||||
// console.log('>> retrieved', d);
|
||||
const data = JSON.parse(d.data);
|
||||
const list = data.map((item) => {
|
||||
return item.id;
|
||||
});
|
||||
|
||||
const tMap = data.map((item) => {
|
||||
return [item.id, item];
|
||||
});
|
||||
|
||||
this.tweetList.set(list);
|
||||
this.tweets.set(new Map(tMap));
|
||||
});
|
||||
},
|
||||
getTweetByID(id) {
|
||||
return get(this.tweets).get(id);
|
||||
},
|
||||
getTwitterFollowing() {
|
||||
return get(this.twitterFollowing);
|
||||
},
|
||||
saveTwitterFollowing(newVals) {
|
||||
this.twitterFollowing.set(newVals);
|
||||
},
|
||||
|
||||
getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
localforage.getItem('twitterFollowing').then((value) => {
|
||||
if (value !== null) state.twitterFollowing.set(value);
|
||||
else {
|
||||
state.twitterFollowing.set(twitterAccounts);
|
||||
localforage.setItem('twitterFollowing', twitterAccounts).catch((err) => {
|
||||
// This code runs if there were any errors
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
// console.log('twitterFollowing', get(state.twitterFollowing));
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
localforage.getItem('favourites').then((value) => {
|
||||
if (value !== null) state.favourites.set(value);
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
localforage.getItem('routes').then((value) => {
|
||||
if (value !== null) state.routes.set(value);
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
localforage.getItem('routeIndex').then((value) => {
|
||||
if (value !== null) state.routeIndex.set(value);
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
state.favourites.subscribe((v) => {
|
||||
console.log('>> Store.state.favourites', v);
|
||||
});
|
||||
|
||||
state.routes.subscribe((v) => {
|
||||
if (started)
|
||||
// console.log('>> Store.state.routes', v);
|
||||
localforage.setItem('routes', v).catch((err) => {
|
||||
// This code runs if there were any errors
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
state.routeIndex.subscribe((v) => {
|
||||
if (started)
|
||||
// console.log('>> Store.state.routeIndex', v);
|
||||
localforage.setItem('routeIndex', v).catch((err) => {
|
||||
// This code runs if there were any errors
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
state.twitterFollowing.subscribe((v) => {
|
||||
if (started)
|
||||
// console.log('>> Store.state.twitterFollowing', v);
|
||||
localforage.setItem('twitterFollowing', v).catch((err) => {
|
||||
// This code runs if there were any errors
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
const list = Object.entries(get(state.twitterFollowing)).filter((item) => {
|
||||
if (item[1].follow) return item;
|
||||
});
|
||||
|
||||
state.twitterFollowingList.set(list);
|
||||
});
|
||||
|
||||
// started = true;
|
||||
setTimeout(() => {
|
||||
started = true;
|
||||
}, 250);
|
||||
|
||||
export { state };
|
21
test.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<html ⚡>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>amp-twitter - Example 1</title>
|
||||
<script async src="https://cdn.ampproject.org/v0.js"></script>
|
||||
<script custom-element="amp-twitter" src="https://cdn.ampproject.org/v0/amp-twitter-0.1.js" async></script>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
|
||||
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<amp-twitter
|
||||
width="375"
|
||||
height="472"
|
||||
layout="responsive"
|
||||
data-tweetid="1255922296860090400"
|
||||
>
|
||||
</amp-twitter>
|
||||
</body>
|
||||
</html>
|