|
|
@@ -0,0 +1,202 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <title>BiCiMon</title>
|
|
|
+ <link rel="shortcut icon" type="image/png" href="images/logo.png">
|
|
|
+ <script src="https://unpkg.com/alpinejs@3.9.5/dist/cdn.min.js" defer
|
|
|
+ integrity="sha384-uvrjP84ugVTfHtrnvF3/rM9lWkcO9x7yPo/Pnr9JjHbWjj6dbv5aL1Wmsu6HadlI"
|
|
|
+ crossorigin="anonymous"></script>
|
|
|
+ <script src="https://unpkg.com/nosleep.js@0.12.0/dist/NoSleep.min.js" defer
|
|
|
+ integrity="sha384-lp0XiAMtqqqjyVLBYjAcDQzxc2XyGj3sGESoiWbccHdpXjNUPUjWrq5GMqaGHGp9"
|
|
|
+ crossorigin="anonymous"></script>
|
|
|
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"
|
|
|
+ integrity="sha384-IJLmUY0f1ePPX6uSCJ9Bxik64/meJmjSYD7dHaJqTXXEBE4y+Oe9P2KBZa/z7p0Q" crossorigin="anonymous">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
+ <link rel="manifest" href="./manifest.json">
|
|
|
+ <meta name="mobile-web-app-capable" content="yes"/>
|
|
|
+ <meta name="mobile-web-app-status-bar-style" content="black"/>
|
|
|
+ <meta name="mobile-web-app-title" content="BiCiMon">
|
|
|
+ <meta name="theme-color" content="#2A3443"/>
|
|
|
+ <meta name="description" content="Bike Speedometer">
|
|
|
+ <link rel="stylesheet" href="./index.css">
|
|
|
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+<div class="container" x-data="main">
|
|
|
+ <div class="notification is-danger m-1" x-show="error" x-transition>
|
|
|
+ <span x-text="error"></span>
|
|
|
+ <button class="delete" @click="error = ''"></button>
|
|
|
+ </div>
|
|
|
+ <nav class="tabs is-boxed pb-3 mb-0" style="top: 0; padding-top: 3px; position: sticky; background: white">
|
|
|
+ <ul>
|
|
|
+ <li x-bind:class="page === 'dashboard' ? 'is-active' : ''" style="margin-left: 1rem"
|
|
|
+ @click="page = 'dashboard'">
|
|
|
+ <a>Dashboard</a>
|
|
|
+ </li>
|
|
|
+ <li x-bind:class="page === 'course' ? 'is-active' : ''" @click="page = 'course'">
|
|
|
+ <a>Course</a>
|
|
|
+ </li>
|
|
|
+ <li x-bind:class="page === 'settings' ? 'is-active' : ''" @click="page = 'settings'">
|
|
|
+ <a>🔧</a>
|
|
|
+ </li>
|
|
|
+ <li style="margin-left: auto; margin-right: 1rem" x-show="heading">
|
|
|
+ <span>🧭</span> <span x-text="fmtHeading()"></span>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </nav>
|
|
|
+
|
|
|
+ <div x-show="page === 'dashboard'" x-transition>
|
|
|
+ <template x-if="!time.update">
|
|
|
+ <div>
|
|
|
+ <div class="has-text-centered">Awaiting geolocation ...</div>
|
|
|
+ <progress class="progress is-small is-dark" max="100"></progress>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div class="has-text-centered">
|
|
|
+ <div>
|
|
|
+ <div class="title" style="font-size: 15rem; color: black; margin-bottom: 0; line-height: .8"
|
|
|
+ x-text="fmtCurrentSpeed()"></div>
|
|
|
+ <div class="heading" style="font-weight: bold">
|
|
|
+ km/h <span style="font-weight: normal; text-transform: initial"
|
|
|
+ x-show="time.updateDelay !== null">—
|
|
|
+ <span x-text="fmtUpdateDelay()"></span></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="level is-mobile dark-bg">
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">🏔 Altitude</p>
|
|
|
+ <p class="title">
|
|
|
+ <span x-text="round(altitude.current)"></span><small>±<span
|
|
|
+ x-text="round(altitude.accuracy)"></span>m</small>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">📍 Accuracy</p>
|
|
|
+ <p class="title">
|
|
|
+ <small>±</small><span x-text="round(positionAccuracy)"></span><small>m</small>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="level is-mobile">
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">🚴 Max</p>
|
|
|
+ <p class="title" x-text="fmtMaxSpeed()"></p>
|
|
|
+ <p class="heading">km/h</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">Ø Avg</p>
|
|
|
+ <p class="title" x-text="fmtAvgSpeed()"></p>
|
|
|
+ <p class="heading">km/h</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">⌛ Avg-Wait</p>
|
|
|
+ <p class="title" x-text="fmtAvgNoWaitSpeed()"></p>
|
|
|
+ <p class="heading">km/h</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="level is-mobile dark-bg">
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">⌚ Start</p>
|
|
|
+ <p class="title" x-text="fmtStartTime()"></p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">⏱ Trip</p>
|
|
|
+ <p class="title" x-text="fmtTripTime()"></p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level-item has-text-centered">
|
|
|
+ <div>
|
|
|
+ <p class="heading">⌛ Wait</p>
|
|
|
+ <p class="title" x-text="fmtWaitTime()"></p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template x-if="page === 'course'">
|
|
|
+ <div class="mx-1 mb-5">
|
|
|
+ <div class="is-flex is-justify-content-space-between px-2 scale">
|
|
|
+ <span>0
|
|
|
+ <math class="formula">
|
|
|
+ <mfrac>
|
|
|
+ <mn>km</mn>
|
|
|
+ <mn>h</mn>
|
|
|
+ </mfrac>
|
|
|
+ </math>
|
|
|
+ </span>
|
|
|
+ <span>
|
|
|
+ <span x-text="fmtMaxSpeed()"></span>
|
|
|
+ <math class="formula">
|
|
|
+ <mfrac>
|
|
|
+ <mn>km</mn>
|
|
|
+ <mn>h</mn>
|
|
|
+ </mfrac>
|
|
|
+ </math>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <template x-for="(sp, idx) in speed.timeseries.values">
|
|
|
+ <div>
|
|
|
+ <div
|
|
|
+ :class="{'has-background-danger': sp < speed.minRide, 'has-background-dark': sp >= speed.minRide}"
|
|
|
+ :style="{width: (sp * 100 / speed.max) + '%', height: clamp(1000 / speed.timeseries.values.length, 1, 10) + 'px'}">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div x-show="page === 'settings'" x-transition>
|
|
|
+ <section class="hero is-link" style="position: relative">
|
|
|
+ <div class="hero-body">
|
|
|
+ <p class="title">
|
|
|
+ BiCiMon
|
|
|
+ </p>
|
|
|
+ <p class="subtitle">
|
|
|
+ Bike Speedometer
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <a href="https://github.com/knrdl/bicimon#readme" target="_blank" rel="noopener noreferrer"
|
|
|
+ aria-label="View source on GitHub" style="position: absolute; right:0; top: 0">
|
|
|
+ <svg width="80" height="80" viewBox="0 0 250 250"
|
|
|
+ style="fill:#151513; color:#fff;"
|
|
|
+ aria-hidden="true">
|
|
|
+ <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
|
|
+ <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
|
|
+ fill="currentColor" style="transform-origin: 130px 106px;"></path>
|
|
|
+ <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
|
|
+ fill="currentColor"></path>
|
|
|
+ </svg>
|
|
|
+ </a>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <div class="is-flex is-justify-content-center mt-5">
|
|
|
+ <button @click="toggleNoSleep" class="is-rounded button"
|
|
|
+ :class="{'is-outlined': !noSleep, 'is-success': noSleep, 'is-info': !noSleep}">
|
|
|
+ <span x-show="noSleep" class="is-size-3">✓</span>
|
|
|
+ Try to keep screen on
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<script src="./index.js"></script>
|
|
|
+</body>
|
|
|
+</html>
|