some stuff, updated events added bin calendar

This commit is contained in:
Martin Donnelly 2021-05-16 21:25:18 +01:00
parent bc76161779
commit 37ac96a11c
41 changed files with 3955 additions and 9062 deletions

13
.eslintrc.json Normal file → Executable file
View File

@ -5,16 +5,21 @@
}, },
"env": { "env": {
"es6": true, "es6": true,
"browser": true "browser": true,
"node": true
}, },
"extends": [
"eslint:recommended"
],
"plugins": [ "plugins": [
"svelte3" "svelte3"
], ],
"ignorePatterns": [
"public/build/"
],
"overrides": [ "overrides": [
{ {
"files": [ "files": ["**/*.svelte"],
"**/*.svelte"
],
"processor": "svelte3/svelte3" "processor": "svelte3/svelte3"
} }
], ],

0
.gitignore vendored Normal file → Executable file
View File

0
.idea/.gitignore vendored Normal file → Executable file
View File

View File

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

0
.idea/jsLibraryMappings.xml Normal file → Executable file
View File

0
.idea/jsLinters/eslint.xml Normal file → Executable file
View File

0
.idea/misc.xml Normal file → Executable file
View File

0
.idea/modules.xml Normal file → Executable file
View File

0
.idea/svelte-silvrtree.iml Normal file → Executable file
View File

0
.idea/vcs.xml Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

4
copy.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
# rm -rf /home/martin/dev/silvrgit/dist/*
cp -r /home/martin/dev/Svelte/svelte-silvrtree/public/* /home/martin/dev/Server/silvrgit/dist

25
orig.eslintrc.json Executable file
View File

@ -0,0 +1,25 @@
module.exports = {
parserOptions: {
ecmaVersion: 2019,
sourceType: 'module'
},
env: {
es6: true,
browser: true
},
plugins: [
'svelte3'
],
overrides: [
{
files: [
'*.svelte'
],
processor: 'svelte3/svelte3'
}
],
rules: {
},
settings: {
}
};

5500
package-lock.json generated Normal file → Executable file

File diff suppressed because it is too large Load Diff

34
package.json Normal file → Executable file
View File

@ -4,22 +4,32 @@
"scripts": { "scripts": {
"build": "rollup -c", "build": "rollup -c",
"dev": "rollup -c -w", "dev": "rollup -c -w",
"start": "sirv public" "start": "sirv public",
"lint": "eslint . --ext .js,.svelte --fix"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "^11.0.0", "@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^7.0.0", "@rollup/plugin-node-resolve": "^11.1.0",
"eslint": "^6.8.0", "eslint": "^7.26.0",
"eslint-plugin-svelte3": "^2.7.3", "eslint-plugin-import": "^2.23.2",
"rollup": "^1.20.0", "eslint-plugin-node": "^11.1.0",
"rollup-plugin-livereload": "^1.0.0", "eslint-plugin-promise": "^5.1.0",
"rollup-plugin-svelte": "^5.0.3", "eslint-plugin-standard": "^5.0.0",
"rollup-plugin-terser": "^5.1.2", "eslint-plugin-svelte3": "^3.2.0",
"svelte": "^3.0.0" "prettier": "^2.3.0",
"prettier-plugin-svelte": "^2.3.0",
"rollup": "^2.38.0",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-terser": "^7.0.2",
"svelte": "^3.32.0"
}, },
"dependencies": { "dependencies": {
"@rakh/svelte-revealer": "file:../svelte-revealer",
"fecha": "^4.2.0", "fecha": "^4.2.0",
"moment": "^2.24.0", "moment": "^2.29.1",
"sirv-cli": "^0.4.4" "rollup-plugin-replace": "^2.2.0",
"sirv-cli": "^1.0.10"
} }
} }

24
public/build/bundle.css Normal file → Executable file
View File

@ -1,22 +1,2 @@
.svelte-oqm7j5{font-size:90%} .card.svelte-1qugser{position:relative;background-color:#fff;min-height:72px}.mui--text-display3.svelte-1qugser{font-family:"Roboto Slab", "Helvetica Neue", Helvetica, Arial}.temp0.svelte-1qugser,.temp1.svelte-1qugser,.temp2.svelte-1qugser,.temp3.svelte-1qugser,.temp4.svelte-1qugser,.temp5.svelte-1qugser{color:rgb(80, 181, 221)}.temp6.svelte-1qugser{color:rgb(78, 178, 206)}.temp7.svelte-1qugser{color:rgb(76, 176, 190)}.temp8.svelte-1qugser{color:rgb(73, 173, 175)}.temp9.svelte-1qugser{color:rgb(72, 171, 159)}.temp10.svelte-1qugser{color:rgb(70, 168, 142)}.temp11.svelte-1qugser{color:rgb(68, 166, 125)}.temp12.svelte-1qugser{color:rgb(66, 164, 108)}.temp13.svelte-1qugser{color:rgb(102, 173, 94)}.temp14.svelte-1qugser{color:rgb(135, 190, 64)}.temp15.svelte-1qugser{color:rgb(179, 204, 26)}.temp16.svelte-1qugser{color:rgb(214, 213, 28)}.temp17.svelte-1qugser{color:rgb(249, 202, 3)}.temp18.svelte-1qugser{color:rgb(246, 181, 3)}.temp19.svelte-1qugser{color:rgb(244, 150, 26)}.temp20.svelte-1qugser{color:rgb(236, 110, 5)}.day.svelte-1qugser{font-family:"Roboto Slab", "Helvetica Neue", Helvetica, Arial,
.routeBox.svelte-12mw410{border:1px dotted silver} SansSerif;text-transform:uppercase}.summary.svelte-1qugser::first-letter{text-transform:capitalize}.routeBox.svelte-12mw410{border:1px dotted silver}.svelte-1m5utr5{font-size:90%}.timerContainer.svelte-1woqwo5.svelte-1woqwo5{border:1px solid #BDBDBD;background-color:#EEEEEE}.inner.svelte-1woqwo5.svelte-1woqwo5{display:flex;color:#333;flex-direction:column;align-items:center;justify-content:center}.timer-value.svelte-1woqwo5.svelte-1woqwo5{display:flex;color:#333;flex-direction:row;align-items:center;justify-content:center;font-size:24px;height:100%;width:100%}.timer-value.svelte-1woqwo5 small.svelte-1woqwo5{font-size:18px;margin-left:4px}.svelte-1juin59{padding:3px}.pointer.svelte-1juin59{cursor:pointer}.up.svelte-1juin59,.down.svelte-1juin59{display:inline-block;background-size:contain;width:0.8em;height:0.8em}.up.svelte-1juin59,.down.svelte-1juin59{background-image:url("data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m0.82549 1.3138h5.6797l1.136 2e-7 -3.4078 5.8215z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A")}.up.svelte-1juin59{background-image:url("data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m1.3226 7.6324v-5.6797l2e-7 -1.136 5.8215 3.4078z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A")}
.card.svelte-1y1eghs{position:relative;background-color:#fff;min-height:72px}.mui--text-display3.svelte-1y1eghs{font-family:"Roboto Slab", "Helvetica Neue", Helvetica, Arial}.temp0.svelte-1y1eghs,.temp1.svelte-1y1eghs,.temp2.svelte-1y1eghs,.temp3.svelte-1y1eghs,.temp4.svelte-1y1eghs,.temp5.svelte-1y1eghs{color:rgb(80, 181, 221)
}.temp6.svelte-1y1eghs{color:rgb(78, 178, 206)
}.temp7.svelte-1y1eghs{color:rgb(76, 176, 190)
}.temp8.svelte-1y1eghs{color:rgb(73, 173, 175)
}.temp9.svelte-1y1eghs{color:rgb(72, 171, 159)
}.temp10.svelte-1y1eghs{color:rgb(70, 168, 142)
}.temp11.svelte-1y1eghs{color:rgb(68, 166, 125)
}.temp12.svelte-1y1eghs{color:rgb(66, 164, 108)
}.temp13.svelte-1y1eghs{color:rgb(102, 173, 94)
}.temp14.svelte-1y1eghs{color:rgb(135, 190, 64)
}.temp15.svelte-1y1eghs{color:rgb(179, 204, 26)
}.temp16.svelte-1y1eghs{color:rgb(214, 213, 28)
}.temp17.svelte-1y1eghs{color:rgb(249, 202, 3)
}.temp18.svelte-1y1eghs{color:rgb(246, 181, 3)
}.temp19.svelte-1y1eghs{color:rgb(244, 150, 26)
}.temp20.svelte-1y1eghs{color:rgb(236, 110, 5)
}.day.svelte-1y1eghs{font-family:"Roboto Slab", "Helvetica Neue", Helvetica, Arial, SansSerif;text-transform:uppercase}.summary.svelte-1y1eghs::first-letter{text-transform:capitalize
}
/*# sourceMappingURL=bundle.css.map */

12
public/build/bundle.css.map Normal file → Executable file
View File

@ -2,15 +2,19 @@
"version": 3, "version": 3,
"file": "bundle.css", "file": "bundle.css",
"sources": [ "sources": [
"../../Revealer.svelte",
"../../Fx.svelte", "../../Fx.svelte",
"../../Route.svelte", "../../Route.svelte",
"../../Timer.svelte",
"../../Weather.svelte" "../../Weather.svelte"
], ],
"sourcesContent": [ "sourcesContent": [
"<script>\n import {onMount} from 'svelte';\n\n let fxData={};\n\n onMount(async () => {\n await update();\n });\n\n async function update() {\n await getFX();\n\n const now = new Date();\n const mod = 1800000 - (now.getTime() % 1800000);\n\n const fxUpdateFn = function () {\n update();\n };\n\n setTimeout(fxUpdateFn.bind(this), mod + 10);\n }\n\n function reduceFX(data) {\n\n if (data.rates !== undefined) {\n const gpbex = (1 / data.rates.GBP);\n const sekex = (gpbex * data.rates.SEK);\n fxData = {\n 'usd': 1,\n 'gbp': data.rates.GBP,\n 'sek': data.rates.SEK,\n 'gpbe': gpbex,\n 'sekex': sekex\n };\n }\n\n }\n\n async function getFX() {\n\n const res = await fetch(\"http://localhost:9000/fx\");\n const json = await res.json();\n\n if (json) reduceFX(json);\n }\n</script>\n\n<style>\n * {\n font-size: 90%;\n }\n</style>\n\n{#if fxData.gpbe}\n<span>\n &pound;1 = &dollar;{parseFloat(fxData.gpbe.toFixed(2))} = { parseFloat(fxData.sekex.toFixed(2))} SEK\n</span>\n\n{/if}\n\n\n", "<script>\n import {slide} from 'svelte/transition';\n\n let viewMode = 0;\n let icon;\n\n $: icon = (viewMode === 0) ? 'up' : 'down';\n\n function changeViewMode() {\n viewMode = (viewMode === 0) ? 1 : 0;\n }\n</script>\n\n<style>\n * {\n padding: 3px;\n }\n .pointer {cursor: pointer;}\n .up, .down{\n display:inline-block;\n background-size: contain;\n width:0.8em;\n height:0.8em;\n }\n .up, .down{\n background-image: url(\"data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m0.82549 1.3138h5.6797l1.136 2e-7 -3.4078 5.8215z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A\");\n }\n .up{\n background-image: url(\"data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m1.3226 7.6324v-5.6797l2e-7 -1.136 5.8215 3.4078z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A\");\n }\n</style>\n\n\n<div><div on:click={changeViewMode} class=\"pointer {icon}\"></div>\n <span on:click={changeViewMode} class=\"pointer\"><slot name=\"header\">No header was provided</slot></span>\n</div>\n{#if viewMode === 1}\n <div transition:slide>\n <slot></slot>\n </div>\n{/if}\n",
"<script>\n import {route} from './store';\n\n let visible = false;\n let fromStation;\n let toStation;\n let url;\n let routeData = {};\n let services = [];\n\n route.subscribe(async (v) => {\n console.log('>> route', v);\n fromStation = v.fromStation;\n toStation = v.toStation;\n visible = (fromStation !== '') ? !visible : false;\n\n // url = `https://traintimes.silvrtree.co.uk/gettrains?from=${ fromStation }&to=${ toStation}`;\n\n url = `http://localhost:8100/gettrains?from=${fromStation}&to=${toStation}`;\n\n if (fromStation !== '' && visible) {\n await update();\n }\n });\n\n function reduceRoute(data) {\n const newData = {};\n\n newData.fromName = data.locationName;\n newData.toName = data.filterLocationName;\n newData.services = [];\n\n\n if (typeof data.trainServices === 'object' && data.trainServices !== null)\n for (const item of data.trainServices) {\n const dest = item.destination[0];\n const via = dest.via !== null ? `<em>${dest.via}</em>` : '';\n const platform = item.platform !== null ? item.platform : '💠';\n const time = item.sta !== null ? item.sta : `D ${item.std}`;\n const status = item.eta !== null ? item.eta : item.etd;\n const cls = (status.toLowerCase() === 'on time') ? 'ontime' : 'delayed';\n newData.services.push({\n 'location': dest.locationName,\n 'time': time,\n 'via': via,\n 'class': cls,\n 'status': status,\n 'platform': platform,\n 'cancelReason': item.cancelReason,\n 'type': 'train',\n 'isCancelled': item.isCancelled,\n icon: ''\n });\n }\n\n if (typeof data.busServices === 'object' && data.busServices !== null)\n for (const item of data.busServices) {\n const dest = item.destination[0];\n const via = dest.via !== null ? `<em>${dest.via}</em>` : '';\n const platform = item.platform !== null ? item.platform : '';\n const time = item.sta !== null ? item.sta : `D ${item.std}`;\n const status = item.eta !== null ? item.eta : item.etd;\n const cls = (status.toLowerCase() === 'on time') ? 'ontime' : 'delayed';\n newData.services.push({\n 'location': dest.locationName,\n 'time': time,\n 'via': via,\n 'class': cls,\n 'status': status,\n 'platform': platform,\n 'cancelReason': item.cancelReason,\n 'type': 'bus',\n 'isCancelled': item.isCancelled,\n icon: '🚌 '\n });\n }\n\n routeData = newData;\n services = newData.services;\n\n console.log(routeData);\n }\n\n async function update() {\n await getRoute();\n\n const now = new Date();\n const mod = 180000 - (now.getTime() % 180000);\n\n const routeUpdateFn = function () {\n update();\n };\n\n if(visible) setTimeout(routeUpdateFn.bind(this), mod + 10);\n\n }\n\n\n async function getRoute() {\n console.log('Get route', url);\n\n const res = await fetch(url);\n const json = await res.json();\n\n if (json) {\n console.log(json);\n // data = json;\n reduceRoute(json);\n }\n\n\n }\n\n</script>\n\n<style>\n .routeBox {\n border:1px dotted silver;\n }\n</style>\n\n{#if visible}\n<div class=\"routeBox\">\n <div>{routeData.fromName} TO {routeData.toName}</div>\n <table class=\"mui-table mui-table-bordered\">\n <thead>\n <tr>\n <th>Destination</th>\n <th>Time</th>\n <th>Status</th>\n <th>Platform</th>\n </tr>\n </thead>\n\n <tbody>\n {#each services as item}\n <tr>\n\n <td>{item.icon}{item.location} {@html item.via}</td>\n <td class={item.class}>{item.time}</td>\n {#if !item.isCancelled}\n <td class={item.class}>{item.status}</td>\n <td>{item.platform}</td>\n {:else}\n <td colspan=\"2\" class=\"delayed\">❌ {item.cancelReason}</td>\n {/if}\n </tr>\n {/each}\n </tbody>\n </table>\n\n</div>\n{/if}\n\n", "<script>\n import {onMount} from 'svelte';\n\n const __url = (__ENV__ === 'production') ? 'https://silvrtree.co.uk' : 'http://localhost:9000';\n\n\n let fxData={};\n\n onMount(async () => {\n await update();\n });\n\n async function update() {\n await getFX();\n\n const now = new Date();\n const mod = 1800000 - (now.getTime() % 1800000);\n\n const fxUpdateFn = function () {\n update();\n };\n\n setTimeout(fxUpdateFn.bind(this), mod + 10);\n }\n\n function reduceFX(data) {\n\n if (data.rates !== undefined) {\n const gpbex = (1 / data.rates.GBP);\n const sekex = (gpbex * data.rates.SEK);\n fxData = {\n 'usd': 1,\n 'gbp': data.rates.GBP,\n 'sek': data.rates.SEK,\n 'gpbe': gpbex,\n 'sekex': sekex\n };\n }\n\n }\n\n async function getFX() {\n\n const res = await fetch(`${__url}/fx`);\n const json = await res.json();\n\n if (json) reduceFX(json);\n }\n</script>\n\n<style>\n * {\n font-size: 90%;\n }\n</style>\n\n{#if fxData.gpbe}\n<span>\n &pound;1 = &dollar;{parseFloat(fxData.gpbe.toFixed(2))} = { parseFloat(fxData.sekex.toFixed(2))} SEK\n</span>\n\n{/if}\n\n\n",
"<script>\n import {onMount} from 'svelte';\n import {format} from 'fecha';\n\n let weatherData;\n\n onMount(async () => {\n await update();\n });\n\n async function update() {\n await getWeather();\n\n const now = new Date();\n const mod = 1800000 - (now.getTime() % 1800000);\n\n const weatherUpdateFn = function () {\n update();\n };\n\n setTimeout(weatherUpdateFn.bind(this), mod + 10);\n }\n\n function reduceOpenWeather(item) {\n // Openweather returns timestamps in seconds. Moment requires them in milliseconds.\n\n const ts = new Date(item.dt * 1000);\n\n const weatherBlock = item.weather[0];\n\n return {\n 'timestamp': item.dt,\n 'icon': `wi-owm-${weatherBlock.id}`,\n 'summary': weatherBlock.description,\n 'tempHigh': parseInt(item.temp.max, 10),\n 'tempLow': parseInt(item.temp.min, 10),\n 'tempMorn' : parseInt(item.temp.morn, 10),\n 'tempDay' : parseInt(item.temp.day, 10),\n 'tempEve' : parseInt(item.temp.eve, 10),\n 'tempNight' : parseInt(item.temp.night, 10),\n 'datelong': format(ts, 'isoDateTime'),\n 'time': item.dt,\n 'date': format(ts, 'D/M'),\n 'day': format(ts, 'ddd'),\n 'tempHighClass': `temp${parseInt(item.temp.max, 10)}`,\n 'tempLowClass': `temp${parseInt(item.temp.min, 10)}`\n\n };\n }\n\n async function getWeather() {\n\n const res = await fetch(\"http://localhost:9000/weather\");\n const json = await res.json();\n\n if (json) {\n weatherData = json.list.map((item) => {\n // Reduce the data\n return reduceOpenWeather(item);\n });\n }\n }\n\n</script>\n\n<style>\n .card {\n position: relative;\n background-color: #fff;\n min-height: 72px;\n }\n\n .mui--text-display3 {\n font-family: \"Roboto Slab\", \"Helvetica Neue\", Helvetica, Arial;\n }\n\n .temp0, .temp1, .temp2, .temp3, .temp4, .temp5 {\n color: rgb(80, 181, 221)\n }\n\n .temp6 {\n color: rgb(78, 178, 206)\n }\n\n .temp7 {\n color: rgb(76, 176, 190)\n }\n\n .temp8 {\n color: rgb(73, 173, 175)\n }\n\n .temp9 {\n color: rgb(72, 171, 159)\n }\n\n .temp10 {\n color: rgb(70, 168, 142)\n }\n\n .temp11 {\n color: rgb(68, 166, 125)\n }\n\n .temp12 {\n color: rgb(66, 164, 108)\n }\n\n .temp13 {\n color: rgb(102, 173, 94)\n }\n\n .temp14 {\n color: rgb(135, 190, 64)\n }\n\n .temp15 {\n color: rgb(179, 204, 26)\n }\n\n .temp16 {\n color: rgb(214, 213, 28)\n }\n\n .temp17 {\n color: rgb(249, 202, 3)\n }\n\n .temp18 {\n color: rgb(246, 181, 3)\n }\n\n .temp19 {\n color: rgb(244, 150, 26)\n }\n\n .temp20 {\n color: rgb(236, 110, 5)\n }\n\n .day {\n font-family: \"Roboto Slab\", \"Helvetica Neue\", Helvetica, Arial, SansSerif;\n text-transform: uppercase;\n }\n\n .summary::first-letter {\n text-transform: capitalize\n }\n</style>\n\n<div id='weather'>\n\n {#if weatherData}\n {#each weatherData as item}\n <div class=\"card mui--z1 mui-col-md-6 mui-col-lg-4\">\n <div class=\"mui-col-md-3\">\n <div class=\"mui--text-accent mui--text-title day mui--text-center\">{item.day}</div>\n <div class=\"mui--text-dark-secondary mui--text-subhead mui--text-center\">{item.date}</div>\n </div>\n <div class=\"mui-col-md-7\">\n <div>\n <i class=\"mui--text-headline wi {item.icon }\"></i>\n <span class=\"mui--text-display1 {item.tempHighClass}\">{item.tempHigh}°</span> /\n <span class=\"mui--text-headline {item.tempLowClass}\">{item.tempLow}°</span>\n </div>\n <div class=\"mui--text-caption summary\">{item.summary}</div>\n </div>\n <div class=\"mui-col-md-2\">\n <div class=\"mui--text-caption\">{item.tempMorn}°</div>\n <div class=\"mui--text-caption\">{item.tempDay}°</div>\n <div class=\"mui--text-caption\">{item.tempEve}°</div>\n <div class=\"mui--text-caption\">{item.tempNight}°</div>\n </div>\n </div>\n {/each}\n {/if}\n\n</div>\n" "<script>\n import {route} from './store';\n\n const __url = (__ENV__ === 'production') ? 'https://traintimes.silvrtree.co.uk' : 'http://localhost:8100';\n\n let visible = false;\n let fromStation;\n let toStation;\n let url;\n let routeData = {};\n let services = [];\n\n route.subscribe(async (v) => {\n console.log('>> route', v);\n fromStation = v.fromStation;\n toStation = v.toStation;\n visible = (fromStation !== '') ? !visible : false;\n\n // url = `https://traintimes.silvrtree.co.uk/gettrains?from=${ fromStation }&to=${ toStation}`;\n\n url = `${__url}/gettrains?from=${fromStation}&to=${toStation}`;\n\n if (fromStation !== '' && visible) {\n await update();\n }\n });\n\n function reduceRoute(data) {\n const newData = {};\n\n newData.fromName = data.locationName;\n newData.toName = data.filterLocationName;\n newData.services = [];\n\n\n if (typeof data.trainServices === 'object' && data.trainServices !== null)\n for (const item of data.trainServices) {\n const dest = item.destination[0];\n const via = dest.via !== null ? `<em>${dest.via}</em>` : '';\n const platform = item.platform !== null ? item.platform : '💠';\n const time = item.sta !== null ? item.sta : `D ${item.std}`;\n const status = item.eta !== null ? item.eta : item.etd;\n const cls = (status.toLowerCase() === 'on time') ? 'ontime' : 'delayed';\n newData.services.push({\n 'location': dest.locationName,\n 'time': time,\n 'via': via,\n 'class': cls,\n 'status': status,\n 'platform': platform,\n 'cancelReason': item.cancelReason,\n 'type': 'train',\n 'isCancelled': item.isCancelled,\n icon: ''\n });\n }\n\n if (typeof data.busServices === 'object' && data.busServices !== null)\n for (const item of data.busServices) {\n const dest = item.destination[0];\n const via = dest.via !== null ? `<em>${dest.via}</em>` : '';\n const platform = item.platform !== null ? item.platform : '';\n const time = item.sta !== null ? item.sta : `D ${item.std}`;\n const status = item.eta !== null ? item.eta : item.etd;\n const cls = (status.toLowerCase() === 'on time') ? 'ontime' : 'delayed';\n newData.services.push({\n 'location': dest.locationName,\n 'time': time,\n 'via': via,\n 'class': cls,\n 'status': status,\n 'platform': platform,\n 'cancelReason': item.cancelReason,\n 'type': 'bus',\n 'isCancelled': item.isCancelled,\n icon: '🚌 '\n });\n }\n\n routeData = newData;\n services = newData.services;\n\n console.log(routeData);\n }\n\n async function update() {\n await getRoute();\n\n const now = new Date();\n const mod = 180000 - (now.getTime() % 180000);\n\n const routeUpdateFn = function () {\n update();\n };\n\n if(visible) setTimeout(routeUpdateFn.bind(this), mod + 10);\n\n }\n\n\n async function getRoute() {\n console.log('Get route', url);\n\n const res = await fetch(url);\n const json = await res.json();\n\n if (json) {\n console.log(json);\n // data = json;\n reduceRoute(json);\n }\n\n\n }\n\n</script>\n\n<style>\n .routeBox {\n border:1px dotted silver;\n }\n</style>\n\n{#if visible}\n<div class=\"routeBox\">\n <div>{routeData.fromName} TO {routeData.toName}</div>\n <table class=\"mui-table mui-table-bordered\">\n <thead>\n <tr>\n <th>Destination</th>\n <th>Time</th>\n <th>Status</th>\n <th>Platform</th>\n </tr>\n </thead>\n\n <tbody>\n {#each services as item}\n <tr>\n\n <td>{item.icon}{item.location} {@html item.via}</td>\n <td class={item.class}>{item.time}</td>\n {#if !item.isCancelled}\n <td class={item.class}>{item.status}</td>\n <td>{item.platform}</td>\n {:else}\n <td colspan=\"2\" class=\"delayed\">❌ {item.cancelReason}</td>\n {/if}\n </tr>\n {/each}\n </tbody>\n </table>\n\n</div>\n{/if}\n\n",
"<script>\n import {tweened} from 'svelte/motion';\n import Revealer from '@rakh/svelte-revealer';\n\n let timerVisible = false;\n let range = 25;\n let start;\n let timerID = 0;\n let snd;\n // let timer = 0;\n\n $: startVal = range * 60;\n $: timer = tweened(startVal);\n\n $: minutes = Math.floor($timer / 60);\n $: minname = minutes > 1 ? \"mins\" : \"min\";\n $: seconds = Math.floor($timer - minutes * 60)\n\n const progress = tweened(0, {duration: 1000})\n $: {\n $progress = 1 - ($timer / startVal)\n }\n\n function complete() {\n snd = new Audio('stuff/bell.mp3');\n snd.play();\n\n }\n\n function stopTimer() {\n clearInterval(timerID);\n timerID = 0;\n }\n\n function showTimer() {\n timerVisible = !timerVisible;\n if (!timerVisible) {\n // clearTimer\n stopTimer();\n }\n }\n\n function startTimer() {\n\n if (timerID !== 0) {\n stopTimer();\n } else {\n timerID = setInterval(() => {\n if ($timer > 0) $timer--\n else {\n stopTimer();\n complete();\n }\n }, 1000);\n\n }\n\n }\n\n</script>\n\n<style>\n .timerContainer {\n border: 1px solid #BDBDBD;\n background-color: #EEEEEE;\n\n }\n\n .inner {\n display: flex;\n /*mix-blend-mode: difference;*/\n color: #333;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n }\n\n .timer-value {\n display: flex;\n /*mix-blend-mode: difference;*/\n color: #333;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n height: 100%;\n width: 100%;\n }\n\n .timer-value small {\n font-size: 18px;\n margin-left: 4px;\n }\n</style>\n<div id=\"timer\">\n <Revealer>\n <span slot=\"header\">Timer</span>\n <div class=\"timerContainer\">\n <div class=\"inner\">\n <label>\n <input type=\"range\" bind:value={range} min=1 max=60>\n <button on:click={startTimer} class=\"mui-btn mui-btn&#45;&#45;flat mui-btn&#45;&#45;dark\">\n {#if timerID === 0}\n Start\n {:else}\n Stop\n {/if}\n </button>\n </label>\n\n </div>\n <div class=\"timer-value\" style=\"color: hsl({120 * (1-$progress)}deg, 50%, 50%) !important\">\n <span>{minutes}mins</span>\n <small>{seconds}s</small>\n </div>\n\n </div>\n </Revealer>\n</div>\n\n",
"<script>\n import {onMount} from 'svelte';\n import {format} from 'fecha';\n\n const __url = (__ENV__ === 'production') ? 'https://silvrtree.co.uk/weather' : 'http://localhost:9000/weather';\n\n let weatherData;\n\n onMount(async () => {\n await update();\n });\n\n async function update() {\n await getWeather();\n\n const now = new Date();\n const mod = 1800000 - (now.getTime() % 1800000);\n\n const weatherUpdateFn = function () {\n update();\n };\n\n setTimeout(weatherUpdateFn.bind(this), mod + 10);\n }\n\n function reduceOpenWeather(item) {\n // Openweather returns timestamps in seconds. Moment requires them in milliseconds.\n\n const ts = new Date(item.dt * 1000);\n\n const weatherBlock = item.weather[0];\n\n return {\n 'timestamp': item.dt,\n 'icon': `wi-owm-${weatherBlock.id}`,\n 'summary': weatherBlock.description,\n 'tempHigh': parseInt(item.temp.max, 10),\n 'tempLow': parseInt(item.temp.min, 10),\n 'tempMorn' : parseInt(item.temp.morn, 10),\n 'tempDay' : parseInt(item.temp.day, 10),\n 'tempEve' : parseInt(item.temp.eve, 10),\n 'tempNight' : parseInt(item.temp.night, 10),\n 'datelong': format(ts, 'isoDateTime'),\n 'time': item.dt,\n 'date': format(ts, 'D/M'),\n 'day': format(ts, 'ddd'),\n 'tempHighClass': `temp${parseInt(item.temp.max, 10)}`,\n 'tempLowClass': `temp${parseInt(item.temp.min, 10)}`\n\n };\n }\n\n async function getWeather() {\n\n const res = await fetch(__url);\n const json = await res.json();\n\n if (json) {\n weatherData = json.list.map((item) => {\n // Reduce the data\n return reduceOpenWeather(item);\n });\n }\n }\n\n</script>\n\n<style>\n .card {\n position: relative;\n background-color: #fff;\n min-height: 72px;\n }\n\n .mui--text-display3 {\n font-family: \"Roboto Slab\", \"Helvetica Neue\", Helvetica, Arial;\n }\n\n .temp0, .temp1, .temp2, .temp3, .temp4, .temp5 {\n color: rgb(80, 181, 221)\n }\n\n .temp6 {\n color: rgb(78, 178, 206)\n }\n\n .temp7 {\n color: rgb(76, 176, 190)\n }\n\n .temp8 {\n color: rgb(73, 173, 175)\n }\n\n .temp9 {\n color: rgb(72, 171, 159)\n }\n\n .temp10 {\n color: rgb(70, 168, 142)\n }\n\n .temp11 {\n color: rgb(68, 166, 125)\n }\n\n .temp12 {\n color: rgb(66, 164, 108)\n }\n\n .temp13 {\n color: rgb(102, 173, 94)\n }\n\n .temp14 {\n color: rgb(135, 190, 64)\n }\n\n .temp15 {\n color: rgb(179, 204, 26)\n }\n\n .temp16 {\n color: rgb(214, 213, 28)\n }\n\n .temp17 {\n color: rgb(249, 202, 3)\n }\n\n .temp18 {\n color: rgb(246, 181, 3)\n }\n\n .temp19 {\n color: rgb(244, 150, 26)\n }\n\n .temp20 {\n color: rgb(236, 110, 5)\n }\n\n .day {\n font-family: \"Roboto Slab\", \"Helvetica Neue\", Helvetica, Arial, SansSerif;\n text-transform: uppercase;\n }\n\n .summary::first-letter {\n text-transform: capitalize\n }\n</style>\n\n<div id='weather'>\n\n {#if weatherData}\n {#each weatherData as item}\n <div class=\"card mui--z1 mui-col-md-6 mui-col-lg-4\">\n <div class=\"mui-col-md-3 mui-col-sm-6 mui-col-xs-6\">\n <div class=\"mui--text-accent mui--text-title day mui--text-center\">{item.day}</div>\n <div class=\"mui--text-dark-secondary mui--text-subhead mui--text-center\">{item.date}</div>\n </div>\n <div class=\"mui-col-md-7 mui-col-sm-6 mui-col-xs-6\">\n <div>\n <i class=\"mui--text-headline wi {item.icon }\"></i>\n <span class=\"mui--text-display1 {item.tempHighClass}\">{item.tempHigh}°</span> /\n <span class=\"mui--text-headline {item.tempLowClass}\">{item.tempLow}°</span>\n </div>\n <div class=\"mui--text-caption summary\">{item.summary}</div>\n </div>\n <div class=\"mui-col-md-2 mui--hidden-xs mui--hidden-sm\">\n <div class=\"mui--text-caption\">{item.tempMorn}°</div>\n <div class=\"mui--text-caption\">{item.tempDay}°</div>\n <div class=\"mui--text-caption\">{item.tempEve}°</div>\n <div class=\"mui--text-caption\">{item.tempNight}°</div>\n </div>\n </div>\n {/each}\n {/if}\n\n</div>\n"
], ],
"names": [], "names": [],
"mappings": "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" "mappings": "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"
} }

6347
public/build/bundle.js Normal file → Executable file

File diff suppressed because one or more lines are too long

2
public/build/bundle.js.map Normal file → Executable file

File diff suppressed because one or more lines are too long

0
public/favicon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

6
public/gfx/bin.svg Normal file
View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" version="1.1" viewBox="0 0 1000 1000" xml:space="preserve">
<path d="M322 11a59 59 0 0 0-46 46c-1 9-2 10-8 11-24 3-42 11-56 23-8 7-17 21-20 31l-1 4h496l5 5c8 8 5 20-6 24-3 1-90 2-265 2H162v46h33l1 8a238013 238013 0 0 1 78 777c2 2 279 3 279 1l-10-12c-10-12-21-32-26-49-3-15-3-43 0-58 8-31 33-64 60-77 23-13 31-15 60-15 19 0 25 0 25-2 0-10 50-498 51-499l58-46c42-33 58-47 61-53 6-11 8-26 3-39-2-9-6-13-31-38s-29-28-38-31c-10-3-28-3-161-3H455v-7c0-3-2-12-6-18-7-13-19-24-32-29-8-3-83-4-95-2zm84 39c7 3 11 8 11 14 0 2-6 3-52 3-48 0-52 0-52-4 1-4 6-11 12-13 8-3 73-3 81 0zm396 91c17 9 9 35-10 35-3 0-8-3-12-6-5-4-6-6-6-13s1-9 6-14c7-6 14-7 22-2zM483 251c6 5 6 13 1 19l-4 5h-56c-50 1-58 0-62-2-6-4-8-10-6-17 3-9 4-9 65-9 57 0 58 0 62 4z"/>
<path fill="#ff0000"
d="M615 811c-32 8-58 33-67 65a90 90 0 0 0 175 45c4-13 3-36-1-49a91 91 0 0 0-107-61zm34 61c11 6 17 14 17 27 0 30-38 41-56 16-10-13-4-35 12-43 10-6 16-6 27 0z"/>
</svg>

After

Width:  |  Height:  |  Size: 993 B

0
public/gfx/popout.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 111 B

After

Width:  |  Height:  |  Size: 111 B

6
public/global.css Normal file → Executable file
View File

@ -1959,3 +1959,9 @@ li {
} }
.trendDown:before{content:'▼'} .trendDown:before{content:'▼'}
.foodBin, .glassBin, .blueBin, .greenBin, .bothBin {
width:18px;
height:18px;
}

2
public/index.html Normal file → Executable file
View File

@ -4,7 +4,7 @@
<meta charset='utf-8'> <meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'> <meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title> <title>Slack</title>
<link rel='icon' type='image/png' href='/favicon.png'> <link rel='icon' type='image/png' href='/favicon.png'>
<link href="//fonts.googleapis.com/css2?family=Roboto+Slab&display=swap" rel="stylesheet"> <link href="//fonts.googleapis.com/css2?family=Roboto+Slab&display=swap" rel="stylesheet">

BIN
public/stuff/bell.mp3 Executable file

Binary file not shown.

60
rollup.config.js Normal file → Executable file
View File

@ -1,29 +1,52 @@
import svelte from 'rollup-plugin-svelte'; import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs'; import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload'; import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser'; import { terser } from 'rollup-plugin-terser';
import replace from 'rollup-plugin-replace';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH; const production = !process.env.ROLLUP_WATCH;
function serve() {
let server;
function toExit() {
if (server) server.kill(0);
}
return {
writeBundle() {
if (server) return;
server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
'stdio': ['ignore', 'inherit', 'inherit'],
'shell': true
});
process.on('SIGTERM', toExit);
process.on('exit', toExit);
}
};
}
export default { export default {
'input': 'src/main.js', 'input': 'src/main.js',
'output': { 'output': {
'sourcemap': false, 'sourcemap': true,
'format': 'iife', 'format': 'iife',
'name': 'app', 'name': 'app',
'file': 'public/build/bundle.js' 'file': 'public/build/bundle.js'
}, },
'plugins': [ 'plugins': [
svelte({ svelte({
// enable run-time checks when not in production 'compilerOptions': {
'dev': !production, // enable run-time checks when not in production
// we'll extract any component CSS out into 'dev': !production
// a separate file - better for performance
'css': css => {
css.write('public/build/bundle.css');
} }
}), }),
// we'll extract any component CSS out into
// a separate file - better for performance
css({ 'output': 'bundle.css' }),
// If you have external dependencies installed from // If you have external dependencies installed from
// npm, you'll most likely need these plugins. In // npm, you'll most likely need these plugins. In
@ -35,6 +58,10 @@ export default {
'dedupe': ['svelte'] 'dedupe': ['svelte']
}), }),
commonjs(), commonjs(),
replace({
'exclude': 'node_modules/**',
'__ENV__': JSON.stringify(production ? 'production' : 'development')
}),
// In dev mode, call `npm run start` once // In dev mode, call `npm run start` once
// the bundle has been generated // the bundle has been generated
@ -52,20 +79,3 @@ export default {
'clearScreen': false 'clearScreen': false
} }
}; };
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
'stdio': ['ignore', 'inherit', 'inherit'],
'shell': true
});
}
}
};
}

122
src/App.svelte Normal file → Executable file
View File

@ -1,39 +1,39 @@
<script> <script>
import Panel from './components/Panel.svelte'; import Panel from './components/Panel.svelte';
import Header from './components/Header.svelte'; import Header from './components/Header.svelte';
import Events from './components/Events.svelte'; import Events from './components/Events.svelte';
import Password from './components/Password.svelte'; import Password from './components/Password.svelte';
import Bitcoin from './components/Bitcoin.svelte'; import Bitcoin from './components/Bitcoin.svelte';
import Weather from './components/Weather.svelte'; import Weather from './components/Weather.svelte';
import Fx from './components/Fx.svelte'; import Fx from './components/Fx.svelte';
import Train from './components/Train.svelte'; import Train from './components/Train.svelte';
import Route from "./components/Route.svelte"; import Route from './components/Route.svelte';
import Timer from './components/Timer.svelte';
import Bins from './components/Bins.svelte';
export let events = []; export let events = [];
function popitoutSmall(e) { function popitoutSmall(e) {
if (e.target.dataset.url) { if (e.target.dataset.url) {
const newwindow = window.open(e.target.dataset.url, 'name', 'height=400,width=520');
if (window.focus) {
newwindow.focus();
}
let newwindow = window.open(e.target.dataset.url, 'name', 'height=400,width=520'); return false;
if (window.focus) {
newwindow.focus();
}
return false;
}
} }
}
function popitout(e) { function popitout(e) {
if (e.target.dataset.url) { if (e.target.dataset.url) {
const newwindow = window.open(e.target.dataset.url, 'name', 'height=600,width=570');
if (window.focus) {
newwindow.focus();
}
let newwindow = window.open(e.target.dataset.url, 'name', 'height=600,width=570'); return false;
if (window.focus) {
newwindow.focus();
}
return false;
}
} }
}
</script> </script>
<main> <main>
@ -96,32 +96,39 @@
<li><a href="http://jade-lang.com/demo/">Jade Tester</a></li> <li><a href="http://jade-lang.com/demo/">Jade Tester</a></li>
<li><a href="https://es6console.com/">ES6 Console</a></li> <li><a href="https://es6console.com/">ES6 Console</a></li>
<li><a href="https://crontab.guru/">Cron Guru</a></li> <li><a href="https://crontab.guru/">Cron Guru</a></li>
<li><a href="https://fontdrop.info/">FontDrop</a> </li> <li><a href="https://fontdrop.info/">FontDrop</a></li>
<li><a href="https://ondras.zarovi.cz/sql/demo/">SQLDesigner</a></li>
<li><a href="http://www.databaseanswers.org/data_models/index.htm">Database Models</a></li>
<li><a href="https://www.typescriptlang.org/play?#">Typescript Play</a></li>
</ul> </ul>
<Password/> <Password/>
<Timer/>
</Panel> </Panel>
<Panel> <Panel>
<div class="mui--text-title mui-text-black">Bitcoin <Bitcoin/></div> <div class="mui--text-title mui-text-black">Bitcoin
<ul> <Bitcoin/>
<li><a href="https://www.bitstamp.net">Bitstamp</a></li> </div>
<li><a href="https://www.kraken.net">Kraken</a></li> <ul>
<li><a href="https://cryptowat.ch/">Cryptowat.ch</a></li> <li><a href="https://www.bitstamp.net">Bitstamp</a></li>
<li><a href="http://www.coindesk.com/price/">BTC Chart</a></li> <li><a href="https://www.kraken.net">Kraken</a></li>
<li><a href="https://bitcoinwisdom.com/">BTC Chart 2</a></li> <li><a href="https://cryptowat.ch/">Cryptowat.ch</a></li>
<li><a href="http://bitcoinity.org/markets/bitstamp/USD">BitStamp Chart</a></li> <li><a href="http://www.coindesk.com/price/">BTC Chart</a></li>
<li><a href="http://btc-chart.com/market/bitstamp/86400">Bitstamp Chart 2</a></li> <li><a href="https://bitcoinwisdom.com/">BTC Chart 2</a></li>
<li><a href="https://bitbargain.co.uk">BitBargin UK</a></li> <li><a href="http://bitcoinity.org/markets/bitstamp/USD">BitStamp Chart</a></li>
<li><a href="https://yacuna.com/">Yacuna UK</a></li> <li><a href="http://btc-chart.com/market/bitstamp/86400">Bitstamp Chart 2</a></li>
<li><a href="http://blockchain.info/">Blockchain</a></li> <li><a href="https://bitbargain.co.uk">BitBargin UK</a></li>
<li><a href="http://bitminter.com/">Bitminter</a></li> <li><a href="https://yacuna.com/">Yacuna UK</a></li>
<li><a href="http://preev.com/">BTC Exchange Rate</a></li> <li><a href="http://blockchain.info/">Blockchain</a></li>
<li><a href="http://www.silvrtree.co.uk/watch.html">CFT Watcher</a> <li><a href="http://bitminter.com/">Bitminter</a></li>
<span style="cursor: pointer;" data-url="http://www.silvrtree.co.uk/watch.html"> <li><a href="http://preev.com/">BTC Exchange Rate</a></li>
<img on:click|stopPropagation={popitoutSmall} src="gfx/popout.png" alt="CFT Watcher" data-url="http://www.silvrtree.co.uk/watch.html"> <li><a href="http://www.silvrtree.co.uk/watch.html">CFT Watcher</a>
<span style="cursor: pointer;" data-url="http://www.silvrtree.co.uk/watch.html">
<img on:click|stopPropagation={popitoutSmall} src="gfx/popout.png" alt="CFT Watcher"
data-url="http://www.silvrtree.co.uk/watch.html">
</span> </span>
</li> </li>
</ul> </ul>
</Panel> </Panel>
</div> </div>
<div class="mui-row"> <div class="mui-row">
@ -174,7 +181,8 @@
<li> <li>
<a href="http://www.bordersweather.co.uk/wxlightning.php">Borders Lightning</a> <a href="http://www.bordersweather.co.uk/wxlightning.php">Borders Lightning</a>
</li> </li>
<li><a href='http://www.lightningmaps.org/blitzortung/europe/index.php?bo_page=map&lang=en'>Best Live Lightning</a></li> <li><a href='https://www.lightningmaps.org/#m=oss;t=3;s=0;o=0;b=;ts=0;y=56.6056;x=-4.1777;z=8;d=2;dl=2;dc=0;'>Best
Live Lightning</a></li>
<li><a href="http://www.madpaddler.net/wxais.php">Ships</a></li> <li><a href="http://www.madpaddler.net/wxais.php">Ships</a></li>
<li><a href='http://www.raintoday.co.uk/'>Rain Today</a></li> <li><a href='http://www.raintoday.co.uk/'>Rain Today</a></li>
</ul> </ul>
@ -251,7 +259,9 @@
</Panel> </Panel>
<Panel> <Panel>
<div class="mui--text-title mui-text-black">Travel <Fx/></div> <div class="mui--text-title mui-text-black">Travel
<Fx/>
</div>
<!-- Travel --> <!-- Travel -->
<div> <div>
@ -284,7 +294,8 @@
<li> <li>
<a href="http://ojp.nationalrail.co.uk/service/ldbboard/dep/WES/DBE/To?ar=true">WES->DBE</a> <a href="http://ojp.nationalrail.co.uk/service/ldbboard/dep/WES/DBE/To?ar=true">WES->DBE</a>
<span style="cursor: pointer;"><img <span style="cursor: pointer;"><img
on:click|stopPropagation={popitout} src="gfx/popout.png" data-url="http://ojp.nationalrail.co.uk/service/ldbboard/dep/WES/DBE/To?ar=true#skip-content-hold"></span> on:click|stopPropagation={popitout} src="gfx/popout.png"
data-url="http://ojp.nationalrail.co.uk/service/ldbboard/dep/WES/DBE/To?ar=true#skip-content-hold"></span>
/ /
<a href="http://www.traintime.uk/index.php?view=desktop&from=WES&to=DBE">Advanced</a> <a href="http://www.traintime.uk/index.php?view=desktop&from=WES&to=DBE">Advanced</a>
</li> </li>
@ -398,10 +409,11 @@
</div> </div>
<Weather/> <Weather/>
<Bins/>
</div> </div>
</main> </main>
<style > <style>
</style> </style>

View File

@ -0,0 +1,71 @@
<script>
let todayStr;
let tomorrowStr;
let outString;
let binIcon = function (iconColour) {
return `<svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="18" version="1.1" viewBox="0 0 1000 1000" xml:space="preserve">
<path fill="${iconColour}" d="M322 11a59 59 0 0 0-46 46c-1 9-2 10-8 11-24 3-42 11-56 23-8 7-17 21-20 31l-1 4h496l5 5c8 8 5 20-6 24-3 1-90 2-265 2H162v46h33l1 8a238013 238013 0 0 1 78 777c2 2 279 3 279 1l-10-12c-10-12-21-32-26-49-3-15-3-43 0-58 8-31 33-64 60-77 23-13 31-15 60-15 19 0 25 0 25-2 0-10 50-498 51-499l58-46c42-33 58-47 61-53 6-11 8-26 3-39-2-9-6-13-31-38s-29-28-38-31c-10-3-28-3-161-3H455v-7c0-3-2-12-6-18-7-13-19-24-32-29-8-3-83-4-95-2zm84 39c7 3 11 8 11 14 0 2-6 3-52 3-48 0-52 0-52-4 1-4 6-11 12-13 8-3 73-3 81 0zm396 91c17 9 9 35-10 35-3 0-8-3-12-6-5-4-6-6-6-13s1-9 6-14c7-6 14-7 22-2zM483 251c6 5 6 13 1 19l-4 5h-56c-50 1-58 0-62-2-6-4-8-10-6-17 3-9 4-9 65-9 57 0 58 0 62 4z"/>
<path fill="${iconColour}"
d="M615 811c-32 8-58 33-67 65a90 90 0 0 0 175 45c4-13 3-36-1-49a91 91 0 0 0-107-61zm34 61c11 6 17 14 17 27 0 30-38 41-56 16-10-13-4-35 12-43 10-6 16-6 27 0z"/>
</svg>
`;
};
$: {
const today = new Date();
todayStr = calcDay(today);
tomorrowStr = calcDay(today.setDate(today.getDate() + 1));
outString = todayStr.length > 0 ? `Today: ${todayStr}` : "";
if (tomorrowStr.length > 0) {
outString =
todayStr.length > 0 ? `${outString}, Tomorrow: ${tomorrowStr}` : `Tomorrow: ${tomorrowStr}`;
}
}
const glassArray = ["0-5", "1-2", "2-2", "2-30", "3-27", "4-25", "5-22", "6-20", "7-17", "8-14", "9-12", "10-9", "11-7",];
const blueArray = ["0-7", "0-21", "1-18", "2-4", "3-1", "3-15", "4-13", "4-27", "5-24", "6-8", "7-5", "7-19", "8-16", "8-19", "9-28", "10-11", "11-9", "11-23",];
const greenArray = ["0-14", "1-25", "3-8", "4-20", "6-1", "7-12", "8-23", "10-4", "11-16",];
const bothArray = ["1-4", "2-18", "3-29", "5-10", "6-22", "8-2", "9-14", "10-25",];
function calcDay(d) {
const n = new Date(d);
let output = "";
const day = n.getDay();
const partString = `${n.getMonth()}-${n.getDate()}`;
if (day === 3) output = binIcon("#db7e32");
if (day === 2 && glassArray.indexOf(partString) !== -1) {
output = binIcon("#212121");
}
if (day === 4) {
if (blueArray.indexOf(partString) !== -1) {
output = binIcon("#3535ff");
} else if (greenArray.indexOf(partString) !== -1) {
output = binIcon("#359235");
} else if (bothArray.indexOf(partString) !== -1) {
output = `${binIcon("#3535ff")}${binIcon("#359235")}`;
}
}
return output;
}
</script>
<div>
Bins: {@html outString}
</div>
<style>
</style>

175
src/components/Bitcoin.svelte Normal file → Executable file
View File

@ -1,125 +1,140 @@
<script> <script>
import {get, writable} from 'svelte/store'; import { get, writable } from 'svelte/store';
import {onMount} from 'svelte'; import { onMount } from 'svelte';
const __url = (__ENV__ === 'production') ? 'https://silvrtree.co.uk' : 'http://localhost:9000';
const data = { const data = {
'lastGBP': 0.0, 'lastGBP': 0.0,
'lastUSD': 0.0, 'lastUSD': 0.0,
'lows': {'gbp': 0, 'usd': 0}, 'lows': { 'gbp': 0, 'usd': 0 },
'highs': {'gbp': 0, 'usd': 0}, 'highs': { 'gbp': 0, 'usd': 0 },
'eclass': '', 'eclass': '',
'balance': 0.0, 'balance': 0.0,
'trend': 0 'trend': 0
}; };
let lastUSD = 0, lastGBP, owned, eclass="", trendClass=""; let lastUSD = 0, lastGBP, owned, eclass = '', trendClass = '';
let spread = { 'low':0, 'high':0 };
const myBTC = 0.02395617;
let myWallet = 0.00;
const btcData = writable(data); const btcData = writable(data);
const balance = writable(0); const balance = writable(0);
btcData.subscribe(btcObj => { btcData.subscribe(btcObj => {
lastUSD = btcObj.lastUSD; lastUSD = btcObj.lastUSD;
lastGBP = btcObj.lastGBP; lastGBP = btcObj.lastGBP;
eclass = btcObj.eclass; eclass = btcObj.eclass;
}); });
onMount(async () => { onMount(async () => {
await update(); await update();
}); });
function calcHighLow(history) {
const low = Math.min(...history);
const high = Math.max(...history);
return { low, high };
}
function recalc(freshBTC) { function recalc(freshBTC) {
let data = get(btcData); let data = get(btcData);
data.gbp = freshBTC.bpi.GBP.rate_float; data.gbp = freshBTC.bpi.GBP.rate_float;
data.usd = freshBTC.bpi.USD.rate_float; data.usd = freshBTC.bpi.USD.rate_float;
data.trend = freshBTC.trend; data.trend = freshBTC.trend;
let lastGBP = data.lastGBP; let lastGBP = data.lastGBP;
let lastUSD; let lastUSD;
const g = data.gbp; const g = data.gbp;
const u = data.usd; const u = data.usd;
const lows = data.lows; const lows = data.lows;
const highs = data.highs; const highs = data.highs;
let eclass = data.eclass;
const balance = data.balance;
let trend = data.trend;
if ((trend === undefined) || (trend === null)) trend = 1; spread = calcHighLow(freshBTC.history);
if (g !== undefined) { let eclass = data.eclass;
if (data.lastGBP !== 0) const balance = data.balance;
eclass = g > lastGBP ? 'up' : 'down'; let trend = data.trend;
else {
lows.gbp = g;
lows.usd = u;
highs.gbp = g; if ((trend === undefined) || (trend === null)) trend = 1;
highs.usd = u;
eclass = '';
}
lastGBP = g;
lastUSD = u;
if (g < lows.gbp) lows.gbp = g; if (g !== undefined) {
if (u < lows.usd) lows.usd = u; if (data.lastGBP !== 0)
eclass = g > lastGBP ? 'up' : 'down';
else {
lows.gbp = g;
lows.usd = u;
if (highs.gbp < g) highs.gbp = g; highs.gbp = g;
if (highs.usd < u) highs.usd = u; highs.usd = u;
eclass = '';
if (trend > 1.00)
trendClass = 'trendUp';
else if (trend < 1.00)
trendClass = 'trendDown';
else
trendClass = '';
data = {
lastGBP,
lastUSD,
lows,
highs,
eclass,
balance,
trend
};
} }
data.stub = Math.random(Number.MAX_SAFE_INTEGER).toString(32); lastGBP = g;
lastUSD = u;
btcData.set(data); if (g < lows.gbp) lows.gbp = g;
if (u < lows.usd) lows.usd = u;
if (highs.gbp < g) highs.gbp = g;
if (highs.usd < u) highs.usd = u;
if (trend > 1.00)
trendClass = 'trendUp';
else if (trend < 1.00)
trendClass = 'trendDown';
else
trendClass = '';
myWallet = myBTC * lastGBP;
data = {
lastGBP,
lastUSD,
lows,
highs,
eclass,
balance,
trend
};
}
data.stub = Math.random(Number.MAX_SAFE_INTEGER).toString(32);
btcData.set(data);
} }
async function update() { async function update() {
await getBtc(); await getBtc();
const now = new Date(); const now = new Date();
const mod = 300000 - (now.getTime() % 300000); const mod = 300000 - (now.getTime() % 300000);
const btcupdateFn = function () { const btcupdateFn = () => {
update(); update();
}; };
setTimeout(btcupdateFn.bind(this), mod + 10); setTimeout(btcupdateFn.bind(this), mod + 10);
} }
async function getBtc() { async function getBtc() {
const res = await fetch(`${__url}/btc`);
const json = await res.json();
const res = await fetch("http://localhost:9000/btc"); if (json)
const json = await res.json(); recalc(json);
if (json) {
recalc(json);
}
} }
// &#36;${parseFloat(btcdata.lastUSD.toFixed(2)) } / &pound;${parseFloat(btcdata.lastGBP.toFixed(2))} <div>&#8383;${balance} &pound;${parseFloat(owned.toFixed(2))}</div> // &#36;${parseFloat(btcdata.lastUSD.toFixed(2)) } / &pound;${parseFloat(btcdata.lastGBP.toFixed(2))} <div>&#8383;${balance} &pound;${parseFloat(owned.toFixed(2))}</div>
</script> </script>
{#if lastUSD!==0} {#if lastUSD !== 0}
<span id="trend" class="{trendClass}"> </span> <span id="trend" class="{trendClass}" > </span>
<span id="btc" class="{eclass}">&#36;{lastUSD.toFixed(2)} / &pound;{lastGBP.toFixed(2)} <span id="btc" class="{eclass}" title="24 Hours: Low: {spread.low.toFixed(2)} / High: {spread.high.toFixed(2)}">&#36;{lastUSD.toFixed(2)} / &pound;{lastGBP.toFixed(2)} </span>
</span> <span></span>
<div class="{eclass}" style="font-size: 85%;">&pound;{myWallet.toFixed(2)}</div>
{/if} {/if}

61
src/components/Events.svelte Normal file → Executable file
View File

@ -1,38 +1,39 @@
<script> <script>
import { onMount} from 'svelte'; import { onMount } from 'svelte';
export let events; import Bins from './Bins.svelte';
onMount(async () => { export let events;
// calculate the dates
update(); onMount(async () => {
// calculate the dates
update();
});
const update = () => {
const now = new Date;
const mod = 3600000 - (now.getTime() % 3600000);
events = events.map((item) => {
item.days = Math.ceil(getDays(now, item.event));
item.weeks = Math.ceil(getDays(now, item.event) / 7);
return item;
}); });
const update = () => { const clockFn = function () {
const now = new Date; update();
const mod = 3600000 - (now.getTime() % 3600000);
events = events.map((item) => {
item.days = Math.ceil(getDays(now, item.event));
item.weeks = Math.ceil(getDays(now, item.event) / 7);
return item;
});
const clockFn = function () {
update();
};
setTimeout(clockFn.bind(this), mod + 10);
}; };
const getDays = (startdate, enddate) => { setTimeout(clockFn.bind(this), mod + 10);
let r, s, e; };
s = startdate.getTime();
e = enddate.getTime();
r = (e - s) / (24 * 60 * 60 * 1000);
return r; const getDays = (startdate, enddate) => {
} let r, s, e;
s = startdate.getTime();
e = enddate.getTime();
r = (e - s) / (24 * 60 * 60 * 1000);
return r;
};
</script> </script>
<div id="container" class="mui-panel"> <div id="container" class="mui-panel">
@ -43,7 +44,11 @@
</div> </div>
{/each} {/each}
<div class='mui-col-xs-12 mui-col-md-3'>
<Bins />
</div>
</div> </div>
</div> </div>

90
src/components/Fx.svelte Normal file → Executable file
View File

@ -1,61 +1,59 @@
<script> <script>
import {onMount} from 'svelte'; import { onMount } from 'svelte';
let fxData={}; const __url = __ENV__ === 'production' ? 'https://silvrtree.co.uk' : 'http://localhost:9000';
onMount(async () => { let fxData = {};
await update();
});
async function update() { onMount(async () => {
await getFX(); await update();
});
const now = new Date(); async function update() {
const mod = 1800000 - (now.getTime() % 1800000); await getFX();
const fxUpdateFn = function () { const now = new Date();
update(); const mod = 1800000 - (now.getTime() % 1800000);
};
setTimeout(fxUpdateFn.bind(this), mod + 10); const fxUpdateFn = () => {
update();
};
setTimeout(fxUpdateFn.bind(this), mod + 10);
}
function reduceFX(data) {
if (data.rates !== undefined) {
const gpbex = 1 / data.rates.GBP;
const sekex = gpbex * data.rates.SEK;
fxData = {
'usd': 1,
'gbp': data.rates.GBP,
'sek': data.rates.SEK,
'gpbe': gpbex,
'sekex': sekex
};
} }
}
function reduceFX(data) { async function getFX() {
const res = await fetch(`${__url}/fx`);
const json = await res.json();
if (data.rates !== undefined) { if (json) reduceFX(json);
const gpbex = (1 / data.rates.GBP); }
const sekex = (gpbex * data.rates.SEK);
fxData = {
'usd': 1,
'gbp': data.rates.GBP,
'sek': data.rates.SEK,
'gpbe': gpbex,
'sekex': sekex
};
}
}
async function getFX() {
const res = await fetch("http://localhost:9000/fx");
const json = await res.json();
if (json) reduceFX(json);
}
</script> </script>
<style>
* {
font-size: 90%;
}
</style>
{#if fxData.gpbe} {#if fxData.gpbe}
<span> <span>
&pound;1 = &dollar;{parseFloat(fxData.gpbe.toFixed(2))} = { parseFloat(fxData.sekex.toFixed(2))} SEK &pound;1 = &dollar;{parseFloat(fxData.gpbe.toFixed(2))} = {parseFloat(
</span> fxData.sekex.toFixed(2)
)} SEK
</span>
{/if} {/if}
<style>
* {
font-size: 90%;
}
</style>

0
src/components/Header.svelte Normal file → Executable file
View File

0
src/components/Panel.svelte Normal file → Executable file
View File

83
src/components/Password.svelte Normal file → Executable file
View File

@ -1,73 +1,78 @@
<script> <script>
import Revealer from '@rakh/svelte-revealer';
Array.prototype.random = function () { Array.prototype.random = function () {
return this[Math.floor((Math.random() * this.length))]; return this[Math.floor((Math.random() * this.length))];
}; };
let longPassword; let longPassword;
let shortPassword; let shortPassword;
const alpha = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', const alpha = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const whitespace = ['.', '~', '#', '!', '$', '+', '-', '+']; const whitespace = ['.', '~', '#', '!', '$', '+', '-', '+'];
const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; const numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const left = ['Alabama', 'Alaska', 'Arizona', 'Maryland', 'Nevada', 'Mexico', 'Texas', 'Utah', 'Glasgow', 'Inverness', 'Edinburgh', 'Dumbarton', const left = ['Alabama', 'Alaska', 'Arizona', 'Maryland', 'Nevada', 'Mexico', 'Texas', 'Utah', 'Glasgow', 'Inverness', 'Edinburgh', 'Dumbarton',
'Balloch', 'Renton', 'Cardross', 'Dundee', 'Paisley', 'Balloch', 'Renton', 'Cardross', 'Dundee', 'Paisley',
'Hamilton', 'Greenock', 'Falkirk', 'Hamilton', 'Greenock', 'Falkirk',
'Irvine', 'Irvine',
'Renfrew', 'Renfrew',
'Erskine', 'Erskine',
'London', 'London',
'Hammersmith', 'Hammersmith',
'Islington', 'Islington',
'Silver', 'Black', 'Yellow', 'Purple', 'White', 'Pink', 'Red', 'Orange', 'Brown', 'Green', 'Blue', 'Amber', 'Aqua', 'Silver', 'Black', 'Yellow', 'Purple', 'White', 'Pink', 'Red', 'Orange', 'Brown', 'Green', 'Blue', 'Amber', 'Aqua',
'Azure', 'Bronze', 'Coral', 'Copper', 'Crimson', 'Cyan', 'Ginger', 'Gold', 'Indigo', 'Jade', 'Ruby', 'Cedar', 'Cream', 'Peach', 'Sepcia', 'Azure', 'Bronze', 'Coral', 'Copper', 'Crimson', 'Cyan', 'Ginger', 'Gold', 'Indigo', 'Jade', 'Ruby', 'Cedar', 'Cream', 'Peach', 'Sepcia',
'Mercyful', 'Cyber', 'Ultra', 'Hunter', 'Electric', 'Steel', 'Fire', 'Smoke', 'Thunder', 'Pewter', 'Stone', 'Iron', 'Shadow', 'Grey', 'Mocha', 'Mercyful', 'Cyber', 'Ultra', 'Hunter', 'Electric', 'Steel', 'Fire', 'Smoke', 'Thunder', 'Pewter', 'Stone', 'Iron', 'Shadow', 'Grey', 'Mocha',
'Wood', 'Space', 'Manic', 'Grunt', 'X-Ray', 'Sabbra','Atomic' 'Wood', 'Space', 'Manic', 'Grunt', 'X-Ray', 'Sabbra', 'Atomic'
]; ];
const right = ['Aganju', 'Cygni', 'Akeron', 'Antares', 'Aragoth', 'Ardus', 'Carpenter', 'Cooper', 'Dahin', 'Capella', 'Endriago', 'Gallina', const right = ['Aganju', 'Cygni', 'Akeron', 'Antares', 'Aragoth', 'Ardus', 'Carpenter', 'Cooper', 'Dahin', 'Capella', 'Endriago', 'Gallina',
'Fenris', 'Freya', 'Glenn', 'Grissom', 'Jotunheim', 'Kailaasa', 'Lagarto', 'Muspelheim', 'Nifleheim', 'Primus', 'Vega', 'Ragnarok', 'Shepard', 'Fenris', 'Freya', 'Glenn', 'Grissom', 'Jotunheim', 'Kailaasa', 'Lagarto', 'Muspelheim', 'Nifleheim', 'Primus', 'Vega', 'Ragnarok', 'Shepard',
'Slayton', 'Tarsis', 'Mercury', 'Venus', 'Mars', 'Earth', 'Terra', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Europa', 'Ganymede', 'Slayton', 'Tarsis', 'Mercury', 'Venus', 'Mars', 'Earth', 'Terra', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Europa', 'Ganymede',
'Callisto', 'Titan', 'Juno', 'Eridanus', 'Scorpius', 'Crux', 'Cancer', 'Taurus', 'Lyra', 'Andromeda', 'Virgo', 'Aquarius', 'Cygnus', 'Corvus', 'Callisto', 'Titan', 'Juno', 'Eridanus', 'Scorpius', 'Crux', 'Cancer', 'Taurus', 'Lyra', 'Andromeda', 'Virgo', 'Aquarius', 'Cygnus', 'Corvus',
'Taurus', 'Draco', 'Perseus', 'Pegasus', 'Gemini', 'Columbia', 'Bootes', 'Orion', 'Deneb', 'Merope', 'Agate', 'Amber', 'Beryl', 'Calcite', 'Taurus', 'Draco', 'Perseus', 'Pegasus', 'Gemini', 'Columbia', 'Bootes', 'Orion', 'Deneb', 'Merope', 'Agate', 'Amber', 'Beryl', 'Calcite',
'Citrine', 'Coral', 'Diamond', 'Emerald', 'Garnet', 'Jade', 'Lapis', 'Moonstone', 'Obsidian', 'Onyx', 'Opal', 'Pearl', 'Quartz', 'Ruby', 'Citrine', 'Coral', 'Diamond', 'Emerald', 'Garnet', 'Jade', 'Lapis', 'Moonstone', 'Obsidian', 'Onyx', 'Opal', 'Pearl', 'Quartz', 'Ruby',
'Sapphire', 'Topaz', 'Iron', 'Lead', 'Nickel', 'Copper', 'Zinc', 'Tin', 'Manes', 'Argon', 'Neon', 'Alpha', 'Bravo', 'Charlie', 'Delta', 'Sapphire', 'Topaz', 'Iron', 'Lead', 'Nickel', 'Copper', 'Zinc', 'Tin', 'Manes', 'Argon', 'Neon', 'Alpha', 'Bravo', 'Charlie', 'Delta',
'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliett', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra', 'Echo', 'Foxtrot', 'Golf', 'Hotel', 'India', 'Juliett', 'Kilo', 'Lima', 'Mike', 'November', 'Oscar', 'Papa', 'Quebec', 'Romeo', 'Sierra',
'Tango', 'Uniform', 'Victor', 'Whisky', 'Xray', 'Yankee', 'Zulu', 'Fate', 'Miner', 'Blaster', 'Click', 'Noise', 'Cadabra', 'Shotgun']; 'Tango', 'Uniform', 'Victor', 'Whisky', 'Xray', 'Yankee', 'Zulu', 'Fate', 'Miner', 'Blaster', 'Click', 'Noise', 'Cadabra', 'Shotgun'];
function randomAmount(i) { function randomAmount(i) {
let str = ''; let str = '';
for (let t = 0; t < i; t++) for (let t = 0; t < i; t++)
str = str + alpha.random(); str = str + alpha.random();
return str; return str;
} }
function generatePassword(e) { function generatePassword(e) {
// const ws = whitespace.random(); // const ws = whitespace.random();
const ws = '.'; const ws = '.';
longPassword = (`${left.random() } ${ right.random() } ${ numberCluster()}`).split(' ').join(ws); longPassword = (`${left.random() } ${ right.random() } ${ numberCluster()}`).split(' ').join(ws);
shortPassword = (`${randomAmount(5) } ${ randomAmount(5)}`).split(' ').join(ws); shortPassword = (`${randomAmount(5) } ${ randomAmount(5)}`).split(' ').join(ws);
} }
function numberCluster() { function numberCluster() {
return numbers.random() + numbers.random() + numbers.random(); return numbers.random() + numbers.random() + numbers.random();
} }
</script> </script>
<div id="passwords"> <div id="passwords">
<button on:click={generatePassword} class="mui-btn mui-btn--flat" id='newPassword'>Generate Password</button> <Revealer>
{#if longPassword} <span slot="header">Generate Password</span>
<div id='passwordOut' class='password'> <button on:click={generatePassword} class="mui-btn mui-btn&#45;&#45;flat" id='newPassword'>New Password</button>
<div>Long: {longPassword}</div><div>Short: {shortPassword}</div> {#if longPassword}
</div> <div id='passwordOut' class='password'>
{/if} <div>Long: {longPassword}</div><div>Short: {shortPassword}</div>
</div>
{/if}
</Revealer>
</div> </div>

40
src/components/Revealer.svelte Executable file
View File

@ -0,0 +1,40 @@
<script>
import { slide } from 'svelte/transition';
let viewMode = 0;
let icon;
$: icon = (viewMode === 0) ? 'up' : 'down';
function changeViewMode() {
viewMode = (viewMode === 0) ? 1 : 0;
}
</script>
<style>
* {
padding: 3px;
}
.up, .down{
display:inline-block;
background-size: contain;
width:0.8em;
height:0.8em;
}
.up, .down{
background-image: url("data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m0.82549 1.3138h5.6797l1.136 2e-7 -3.4078 5.8215z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A");
}
.up{
background-image: url("data:image/svg+xml,%3Csvg width='32' height='32' version='1.1' viewBox='0 0 8.4667 8.4667' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m1.3226 7.6324v-5.6797l2e-7 -1.136 5.8215 3.4078z' style='stroke-width:.035938;stroke:%23000'/%3E%3C/svg%3E%0A");
}
</style>
<div><div on:click={changeViewMode} class="{icon}"></div>
<span on:click={changeViewMode}><slot name="header">No header was provided</slot></span>
</div>
{#if viewMode === 1}
<div transition:slide>
<slot></slot>
</div>
{/if}

4
src/components/Route.svelte Normal file → Executable file
View File

@ -1,6 +1,8 @@
<script> <script>
import {route} from './store'; import {route} from './store';
const __url = (__ENV__ === 'production') ? 'https://traintimes.silvrtree.co.uk' : 'http://localhost:8100';
let visible = false; let visible = false;
let fromStation; let fromStation;
let toStation; let toStation;
@ -16,7 +18,7 @@
// url = `https://traintimes.silvrtree.co.uk/gettrains?from=${ fromStation }&to=${ toStation}`; // url = `https://traintimes.silvrtree.co.uk/gettrains?from=${ fromStation }&to=${ toStation}`;
url = `http://localhost:8100/gettrains?from=${fromStation}&to=${toStation}`; url = `${__url}/gettrains?from=${fromStation}&to=${toStation}`;
if (fromStation !== '' && visible) { if (fromStation !== '' && visible) {
await update(); await update();

120
src/components/Timer.svelte Executable file
View File

@ -0,0 +1,120 @@
<script>
import {tweened} from 'svelte/motion';
import Revealer from '@rakh/svelte-revealer';
let timerVisible = false;
let range = 25;
let start;
let timerID = 0;
let snd;
// let timer = 0;
$: startVal = range * 60;
$: timer = tweened(startVal);
$: minutes = Math.floor($timer / 60);
$: minname = minutes > 1 ? "mins" : "min";
$: seconds = Math.floor($timer - minutes * 60)
const progress = tweened(0, {duration: 1000})
$: {
$progress = 1 - ($timer / startVal)
}
function complete() {
snd = new Audio('stuff/bell.mp3');
snd.play();
}
function stopTimer() {
clearInterval(timerID);
timerID = 0;
}
function showTimer() {
timerVisible = !timerVisible;
if (!timerVisible) {
// clearTimer
stopTimer();
}
}
function startTimer() {
if (timerID !== 0) {
stopTimer();
} else {
timerID = setInterval(() => {
if ($timer > 0) $timer--
else {
stopTimer();
complete();
}
}, 1000);
}
}
</script>
<style>
.timerContainer {
border: 1px solid #BDBDBD;
background-color: #EEEEEE;
}
.inner {
display: flex;
/*mix-blend-mode: difference;*/
color: #333;
flex-direction: column;
align-items: center;
justify-content: center;
}
.timer-value {
display: flex;
/*mix-blend-mode: difference;*/
color: #333;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 24px;
height: 100%;
width: 100%;
}
.timer-value small {
font-size: 18px;
margin-left: 4px;
}
</style>
<div id="timer">
<Revealer>
<span slot="header">Timer</span>
<div class="timerContainer">
<div class="inner">
<label>
<input type="range" bind:value={range} min=1 max=60>
<button on:click={startTimer} class="mui-btn mui-btn&#45;&#45;flat mui-btn&#45;&#45;dark">
{#if timerID === 0}
Start
{:else}
Stop
{/if}
</button>
</label>
</div>
<div class="timer-value" style="color: hsl({120 * (1-$progress)}deg, 50%, 50%) !important">
<span>{minutes}mins</span>
<small>{seconds}s</small>
</div>
</div>
</Revealer>
</div>

50
src/components/Train.svelte Normal file → Executable file
View File

@ -1,60 +1,60 @@
<script> <script>
import {onMount} from 'svelte'; import { onMount } from 'svelte';
import { route } from './store'; import { route } from './store';
const __url = (__ENV__ === 'production') ? 'https://traintimes.silvrtree.co.uk' : 'http://localhost:8100';
export let fromStation; export let fromStation;
export let toStation; export let toStation;
let url; let url;
let data = { 'eta':'OFF', 'sta': 'OFF' }; let data = { 'eta':'OFF', 'sta': 'OFF' };
let display = { title:'TRAIN', status:'delayed', output:'OFF'}; const display = { 'title':'TRAIN', 'status':'delayed', 'output':'OFF' };
// $: url = `https://traintimes.silvrtree.co.uk/getnexttraintimes?from=${ fromStation }&to=${ toStation}`; // $: url = `https://traintimes.silvrtree.co.uk/getnexttraintimes?from=${ fromStation }&to=${ toStation}`;
$: { $: {
url = `http://localhost:8100/getnexttraintimes?from=${ fromStation }&to=${ toStation}`; url = `${__url}/getnexttraintimes?from=${ fromStation }&to=${ toStation}`;
display.title = `${ fromStation.toUpperCase() }${ toStation.toUpperCase()}`; display.title = `${ fromStation.toUpperCase() }${ toStation.toUpperCase()}`;
} }
// recalc stuff // recalc stuff
$: { $: {
display.output = (data.eta.toLowerCase() === 'on time') ? data.sta : data.eta; display.output = (data.eta.toLowerCase() === 'on time') ? data.sta : data.eta;
display.status = (data.eta.toLowerCase() === 'on time') ? 'ontime' : 'delayed'; display.status = (data.eta.toLowerCase() === 'on time') ? 'ontime' : 'delayed';
} }
onMount(async () => { onMount(async () => {
await update(); await update();
}); });
async function update() { async function update() {
await getTrain(); await getTrain();
const now = new Date(); const now = new Date();
const mod = 120000 - (now.getTime() % 120000); const mod = 120000 - (now.getTime() % 120000);
const trainUpdateFn = function () { const trainUpdateFn = function () {
update(); update();
}; };
setTimeout(trainUpdateFn.bind(this), mod + 10); setTimeout(trainUpdateFn.bind(this), mod + 10);
} }
async function getTrain() { async function getTrain() {
const res = await fetch(url); const res = await fetch(url);
const json = await res.json(); const json = await res.json();
if (json) { if (json) {
console.log(json); console.log(json);
data = json; data = json;
} }
} }
function clickHandler(){ function clickHandler() {
console.log('click', data); console.log('click', data);
route.set({fromStation, toStation}); route.set({ fromStation, toStation });
} }
</script> </script>
<style> <style>

155
src/components/Weather.svelte Normal file → Executable file
View File

@ -1,6 +1,11 @@
<script> <script>
import {onMount} from 'svelte'; import { onMount } from "svelte";
import {format} from 'fecha'; import { format } from "fecha";
const __url =
__ENV__ === "production"
? "https://silvrtree.co.uk/weather"
: "http://localhost:9000/weather";
let weatherData; let weatherData;
@ -29,40 +34,73 @@
const weatherBlock = item.weather[0]; const weatherBlock = item.weather[0];
return { return {
'timestamp': item.dt, timestamp: item.dt,
'icon': `wi-owm-${weatherBlock.id}`, icon: `wi-owm-${weatherBlock.id}`,
'summary': weatherBlock.description, summary: weatherBlock.description,
'tempHigh': parseInt(item.temp.max, 10), tempHigh: parseInt(item.temp.max, 10),
'tempLow': parseInt(item.temp.min, 10), tempLow: parseInt(item.temp.min, 10),
'tempMorn' : parseInt(item.temp.morn, 10), tempMorn: parseInt(item.temp.morn, 10),
'tempDay' : parseInt(item.temp.day, 10), tempDay: parseInt(item.temp.day, 10),
'tempEve' : parseInt(item.temp.eve, 10), tempEve: parseInt(item.temp.eve, 10),
'tempNight' : parseInt(item.temp.night, 10), tempNight: parseInt(item.temp.night, 10),
'datelong': format(ts, 'isoDateTime'), datelong: format(ts, "isoDateTime"),
'time': item.dt, time: item.dt,
'date': format(ts, 'D/M'), date: format(ts, "D/M"),
'day': format(ts, 'ddd'), day: format(ts, "ddd"),
'tempHighClass': `temp${parseInt(item.temp.max, 10)}`, tempHighClass: `temp${parseInt(item.temp.max, 10)}`,
'tempLowClass': `temp${parseInt(item.temp.min, 10)}` tempLowClass: `temp${parseInt(item.temp.min, 10)}`,
}; };
} }
async function getWeather() { async function getWeather() {
const res = await fetch(__url);
const res = await fetch("http://localhost:9000/weather");
const json = await res.json(); const json = await res.json();
if (json) { if (json) {
weatherData = json.list.map((item) => { weatherData = json.list.map((item) => {
// Reduce the data // Reduce the data
return reduceOpenWeather(item); return reduceOpenWeather(item);
}); });
} }
} }
</script> </script>
<div id="weather">
{#if weatherData}
{#each weatherData as item}
<div class="card mui--z1 mui-col-md-6 mui-col-lg-4">
<div class="mui-col-md-3 mui-col-sm-6 mui-col-xs-6">
<div
class="mui--text-accent mui--text-title day mui--text-center"
>{item.day}</div>
<div
class="mui--text-dark-secondary mui--text-subhead mui--text-center"
>{item.date}</div>
</div>
<div class="mui-col-md-7 mui-col-sm-6 mui-col-xs-6">
<div>
<i class="mui--text-headline wi {item.icon}" />
<span class="mui--text-display1 {item.tempHighClass}"
>{item.tempHigh}°</span
>
/
<span class="mui--text-headline {item.tempLowClass}"
>{item.tempLow}°</span
>
</div>
<div class="mui--text-caption summary">{item.summary}</div>
</div>
<div class="mui-col-md-2 mui--hidden-xs mui--hidden-sm">
<div class="mui--text-caption">{item.tempMorn}°</div>
<div class="mui--text-caption">{item.tempDay}°</div>
<div class="mui--text-caption">{item.tempEve}°</div>
<div class="mui--text-caption">{item.tempNight}°</div>
</div>
</div>
{/each}
{/if}
</div>
<style> <style>
.card { .card {
position: relative; position: relative;
@ -74,105 +112,82 @@
font-family: "Roboto Slab", "Helvetica Neue", Helvetica, Arial; font-family: "Roboto Slab", "Helvetica Neue", Helvetica, Arial;
} }
.temp0, .temp1, .temp2, .temp3, .temp4, .temp5 { .temp0,
color: rgb(80, 181, 221) .temp1,
.temp2,
.temp3,
.temp4,
.temp5 {
color: rgb(80, 181, 221);
} }
.temp6 { .temp6 {
color: rgb(78, 178, 206) color: rgb(78, 178, 206);
} }
.temp7 { .temp7 {
color: rgb(76, 176, 190) color: rgb(76, 176, 190);
} }
.temp8 { .temp8 {
color: rgb(73, 173, 175) color: rgb(73, 173, 175);
} }
.temp9 { .temp9 {
color: rgb(72, 171, 159) color: rgb(72, 171, 159);
} }
.temp10 { .temp10 {
color: rgb(70, 168, 142) color: rgb(70, 168, 142);
} }
.temp11 { .temp11 {
color: rgb(68, 166, 125) color: rgb(68, 166, 125);
} }
.temp12 { .temp12 {
color: rgb(66, 164, 108) color: rgb(66, 164, 108);
} }
.temp13 { .temp13 {
color: rgb(102, 173, 94) color: rgb(102, 173, 94);
} }
.temp14 { .temp14 {
color: rgb(135, 190, 64) color: rgb(135, 190, 64);
} }
.temp15 { .temp15 {
color: rgb(179, 204, 26) color: rgb(179, 204, 26);
} }
.temp16 { .temp16 {
color: rgb(214, 213, 28) color: rgb(214, 213, 28);
} }
.temp17 { .temp17 {
color: rgb(249, 202, 3) color: rgb(249, 202, 3);
} }
.temp18 { .temp18 {
color: rgb(246, 181, 3) color: rgb(246, 181, 3);
} }
.temp19 { .temp19 {
color: rgb(244, 150, 26) color: rgb(244, 150, 26);
} }
.temp20 { .temp20 {
color: rgb(236, 110, 5) color: rgb(236, 110, 5);
} }
.day { .day {
font-family: "Roboto Slab", "Helvetica Neue", Helvetica, Arial, SansSerif; font-family: "Roboto Slab", "Helvetica Neue", Helvetica, Arial,
SansSerif;
text-transform: uppercase; text-transform: uppercase;
} }
.summary::first-letter { .summary::first-letter {
text-transform: capitalize text-transform: capitalize;
} }
</style> </style>
<div id='weather'>
{#if weatherData}
{#each weatherData as item}
<div class="card mui--z1 mui-col-md-6 mui-col-lg-4">
<div class="mui-col-md-3">
<div class="mui--text-accent mui--text-title day mui--text-center">{item.day}</div>
<div class="mui--text-dark-secondary mui--text-subhead mui--text-center">{item.date}</div>
</div>
<div class="mui-col-md-7">
<div>
<i class="mui--text-headline wi {item.icon }"></i>
<span class="mui--text-display1 {item.tempHighClass}">{item.tempHigh}°</span> /
<span class="mui--text-headline {item.tempLowClass}">{item.tempLow}°</span>
</div>
<div class="mui--text-caption summary">{item.summary}</div>
</div>
<div class="mui-col-md-2">
<div class="mui--text-caption">{item.tempMorn}°</div>
<div class="mui--text-caption">{item.tempDay}°</div>
<div class="mui--text-caption">{item.tempEve}°</div>
<div class="mui--text-caption">{item.tempNight}°</div>
</div>
</div>
{/each}
{/if}
</div>

0
src/components/store.js Normal file → Executable file
View File

5
src/main.js Normal file → Executable file
View File

@ -4,7 +4,10 @@ const app = new App({
'target': document.body, 'target': document.body,
'props': { 'props': {
'events' : [ 'events' : [
{ 'event': new Date(2020, 0, 1), 'label': 'Contract Ends:' }
{ 'event': new Date(2022, 6, 22), 'label': 'Flat sold by:' },
{ 'event': new Date(2021, 4, 22), 'label': 'Vac 1 End' },
{ 'event': new Date(2021, 6, 31), 'label': '12 Wk End' }
] ]
} }