| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- <!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>
|