
23 changed files with 8650 additions and 11725 deletions
File diff suppressed because it is too large
@ -1,31 +1,120 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<div id="nav"> |
|||
<router-link to="/">Home</router-link> | |
|||
<router-link to="/about">About</router-link> |
|||
</div> |
|||
<router-view /> |
|||
</div> |
|||
</template> |
|||
|
|||
<style> |
|||
#app { |
|||
font-family: "Avenir", Helvetica, Arial, sans-serif; |
|||
@font-face { |
|||
font-family: "syne"; |
|||
src: url("./assets/fonts/syne-bold-webfont.woff2") format("woff2"), |
|||
url("./assets/fonts/syne-bold-webfont.woff") format("woff"); |
|||
font-weight: 500; |
|||
font-style: normal; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: "syne"; |
|||
src: url("./assets/fonts/syne-extra-webfont.woff2") format("woff2"), |
|||
url("./assets/fonts/syne-extra-webfont.woff") format("woff"); |
|||
font-weight: 700; |
|||
font-style: normal; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: "syne"; |
|||
src: url("./assets/fonts/syne-italic-webfont.woff2") format("woff2"), |
|||
url("./assets/fonts/syne-italic-webfont.woff") format("woff"); |
|||
font-weight: normal; |
|||
font-style: italic; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: "synemono"; |
|||
src: url("./assets/fonts/syne-mono-webfont.woff2") format("woff2"), |
|||
url("./assets/fonts/syne-mono-webfont.woff") format("woff"); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: "syne"; |
|||
src: url("./assets/fonts/syne-regular-webfont.woff2") format("woff2"), |
|||
url("./assets/fonts/syne-regular-webfont.woff") format("woff"); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: "Material Icons"; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
src: local("Material Icons"), local("MaterialIcons-Regular"), |
|||
url("./assets/fonts/MaterialIcons-Regular.woff2") format("woff2"), |
|||
url("./assets/fonts/MaterialIcons-Regular.woff") format("woff"), |
|||
url("./assets/fonts/MaterialIcons-Regular.ttf") format("truetype"); |
|||
} |
|||
|
|||
.material-icons { |
|||
font-family: "Material Icons"; |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
font-size: 24px; /* Preferred icon size */ |
|||
display: inline-block; |
|||
line-height: 1; |
|||
text-transform: none; |
|||
letter-spacing: normal; |
|||
word-wrap: normal; |
|||
white-space: nowrap; |
|||
direction: ltr; |
|||
|
|||
/* Support for all WebKit browsers. */ |
|||
-webkit-font-smoothing: antialiased; |
|||
/* Support for Safari and Chrome. */ |
|||
text-rendering: optimizeLegibility; |
|||
|
|||
/* Support for Firefox. */ |
|||
-moz-osx-font-smoothing: grayscale; |
|||
text-align: center; |
|||
color: #2c3e50; |
|||
|
|||
/* Support for IE. */ |
|||
font-feature-settings: "liga"; |
|||
} |
|||
#nav { |
|||
padding: 30px; |
|||
|
|||
:root { |
|||
--yellow-ofo: #ffe706; |
|||
--yellow-ofo-rgb: 253, 230, 0; |
|||
} |
|||
|
|||
body { |
|||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, |
|||
Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, |
|||
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; |
|||
font-size: 1rem; |
|||
font-weight: 400; |
|||
line-height: 1.5; |
|||
color: #212529; |
|||
text-align: left; |
|||
background-color: var(--yellow-ofo); |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
} |
|||
|
|||
body, |
|||
html { |
|||
margin: 0; |
|||
padding: 0; |
|||
height: 100%; |
|||
} |
|||
|
|||
#app { |
|||
height: 100%; |
|||
} |
|||
|
|||
#nav a { |
|||
font-weight: bold; |
|||
color: #2c3e50; |
|||
* { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
#nav a.router-link-exact-active { |
|||
color: #42b983; |
|||
.camera .wrapper .inside { |
|||
z-index: 1; |
|||
} |
|||
</style> |
|||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 34 KiB |
@ -1,114 +0,0 @@ |
|||
<template> |
|||
<div class="hello"> |
|||
<h1>{{ msg }}</h1> |
|||
<p> |
|||
For a guide and recipes on how to configure / customize this project,<br /> |
|||
check out the |
|||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener" |
|||
>vue-cli documentation</a |
|||
>. |
|||
</p> |
|||
<h3>Installed CLI Plugins</h3> |
|||
<ul> |
|||
<li> |
|||
<a |
|||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" |
|||
target="_blank" |
|||
rel="noopener" |
|||
>babel</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" |
|||
target="_blank" |
|||
rel="noopener" |
|||
>eslint</a |
|||
> |
|||
</li> |
|||
</ul> |
|||
<h3>Essential Links</h3> |
|||
<ul> |
|||
<li> |
|||
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a> |
|||
</li> |
|||
<li> |
|||
<a href="https://forum.vuejs.org" target="_blank" rel="noopener" |
|||
>Forum</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a href="https://chat.vuejs.org" target="_blank" rel="noopener" |
|||
>Community Chat</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener" |
|||
>Twitter</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a> |
|||
</li> |
|||
</ul> |
|||
<h3>Ecosystem</h3> |
|||
<ul> |
|||
<li> |
|||
<a href="https://router.vuejs.org" target="_blank" rel="noopener" |
|||
>vue-router</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://github.com/vuejs/vue-devtools#vue-devtools" |
|||
target="_blank" |
|||
rel="noopener" |
|||
>vue-devtools</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener" |
|||
>vue-loader</a |
|||
> |
|||
</li> |
|||
<li> |
|||
<a |
|||
href="https://github.com/vuejs/awesome-vue" |
|||
target="_blank" |
|||
rel="noopener" |
|||
>awesome-vue</a |
|||
> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: "HelloWorld", |
|||
props: { |
|||
msg: String |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<!-- Add "scoped" attribute to limit CSS to this component only --> |
|||
<style scoped> |
|||
h3 { |
|||
margin: 40px 0 0; |
|||
} |
|||
ul { |
|||
list-style-type: none; |
|||
padding: 0; |
|||
} |
|||
li { |
|||
display: inline-block; |
|||
margin: 0 10px; |
|||
} |
|||
a { |
|||
color: #42b983; |
|||
} |
|||
</style> |
@ -1,5 +0,0 @@ |
|||
<template> |
|||
<div class="about"> |
|||
<h1>This is an about page</h1> |
|||
</div> |
|||
</template> |
@ -1,18 +1,68 @@ |
|||
<template> |
|||
<div class="home"> |
|||
<img alt="Vue logo" src="../assets/logo.png" /> |
|||
<HelloWorld msg="Welcome to Your Vue.js App" /> |
|||
<img class="logo" alt="logo" src="../assets/logo.png" /> |
|||
<h1><router-link to="/unlock">sblocca</router-link></h1> |
|||
<p> |
|||
verifica che la bici sia ancora carica 🔋. Se, usando i pulsanti viene |
|||
emesso un <em>bip</em> 🔊, procedi con lo sblocco 🔓. Altrimenti utilizza |
|||
il |
|||
<a |
|||
href="https://upload.disroot.org/r/uWcukzZ5#s/84kbXpkxXpX3kR2x1KwyVNX2Us93Zy1tSNC3oZ864=" |
|||
>metodo manuale</a |
|||
> |
|||
🛠️. |
|||
</p> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
// @ is an alias to /src |
|||
import HelloWorld from "@/components/HelloWorld.vue"; |
|||
|
|||
export default { |
|||
name: "home", |
|||
components: { |
|||
HelloWorld |
|||
} |
|||
name: "home" |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.home { |
|||
/* display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; */ |
|||
max-width: 500px; |
|||
height: 100%; |
|||
padding: 15px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.logo { |
|||
max-width: 100%; |
|||
width: 100%; |
|||
height: auto; |
|||
} |
|||
|
|||
/* img { |
|||
max-width: 100%; |
|||
} */ |
|||
|
|||
h1 { |
|||
font-family: "syne", serif; |
|||
font-weight: 700; |
|||
text-transform: uppercase; |
|||
padding: 15px; |
|||
border: 3px solid black; |
|||
cursor: pointer; |
|||
text-align: center; |
|||
} |
|||
|
|||
h1 a { |
|||
color: black; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
p a { |
|||
color: black; |
|||
} |
|||
|
|||
p a:hover { |
|||
color: black; |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,196 @@ |
|||
<template> |
|||
<div class="container"> |
|||
<h2 class="inquadra"> |
|||
Inquadra il qrcode |
|||
</h2> |
|||
<div class="camera"> |
|||
<qrcode-drop-zone @decode="onDecode" @init="logErrors"> |
|||
<qrcode-stream :camera="camera" @decode="onDecode" @init="onInit" /> |
|||
</qrcode-drop-zone> |
|||
|
|||
<qrcode-capture v-if="noStreamApiSupport" @decode="onDecode" /> |
|||
</div> |
|||
<p v-if="isInvalid">non è un qrcode di ofo 😟</p> |
|||
<p v-if="errored">si è verificato un errore, riprova!</p> |
|||
<div v-if="loading" class="loading">⏳⏳⏳</div> |
|||
<div class="decode-result"> |
|||
<div |
|||
class="decode-number" |
|||
v-for="letter in split(bikePin)" |
|||
v-bind:key="letter" |
|||
> |
|||
{{ letter }} |
|||
</div> |
|||
</div> |
|||
<p v-if="bikePin"> |
|||
🔓inserisci il codice! ricordati che il codice è unico per ogni |
|||
bicicletta, riusalo 🤯 |
|||
</p> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { QrcodeStream, QrcodeDropZone, QrcodeCapture } from "vue-qrcode-reader"; |
|||
import axios from "axios"; |
|||
|
|||
export default { |
|||
name: "Unlock", |
|||
components: { QrcodeStream, QrcodeDropZone, QrcodeCapture }, |
|||
data() { |
|||
return { |
|||
result: "", |
|||
error: "", |
|||
loading: false, |
|||
bikePin: "", |
|||
errored: false, |
|||
noStreamApiSupport: false, |
|||
camera: "auto", |
|||
isInvalid: undefined |
|||
}; |
|||
}, |
|||
methods: { |
|||
async onDecode(result) { |
|||
this.bikePin = ""; |
|||
this.errored = false; |
|||
this.turnCameraOff(); |
|||
if (result.startsWith("http://ofo.com/oneplate/")) { |
|||
const code = +result.split("/").slice(-1); |
|||
this.result = code; |
|||
this.getCode(code); |
|||
} else { |
|||
this.isInvalid = true; |
|||
} |
|||
|
|||
await this.timeout(3000); |
|||
this.turnCameraOn(); |
|||
this.isInvalid = undefined; |
|||
}, |
|||
logErrors(promise) { |
|||
promise.catch(console.error); |
|||
}, |
|||
async onInit(promise) { |
|||
try { |
|||
await promise; |
|||
} catch (error) { |
|||
if (error.name === "StreamApiNotSupportedError") { |
|||
this.noStreamApiSupport = true; |
|||
} |
|||
} |
|||
}, |
|||
resetValidationState() { |
|||
this.isInvalid = undefined; |
|||
}, |
|||
getCode(bikeId) { |
|||
this.loading = true; |
|||
axios |
|||
.get("https://api.coindesk.com/v1/bpi/currentprice.json") //add here the api enpoint w/ bikeId param |
|||
.then(response => { |
|||
//const pin = response.data //get pin from api response |
|||
const pin = "1234"; |
|||
this.bikePin = pin; |
|||
}) |
|||
.catch(error => { |
|||
this.errored = true; |
|||
this.result = ""; |
|||
}) |
|||
.finally(() => { |
|||
this.result = ""; |
|||
this.loading = false; |
|||
}); |
|||
}, |
|||
turnCameraOn() { |
|||
this.camera = "auto"; |
|||
}, |
|||
|
|||
turnCameraOff() { |
|||
this.camera = "off"; |
|||
}, |
|||
timeout(ms) { |
|||
return new Promise(resolve => { |
|||
window.setTimeout(resolve, ms); |
|||
}); |
|||
}, |
|||
split(text) { |
|||
return text.split(""); |
|||
} |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.container { |
|||
max-width: 500px; |
|||
height: 100%; |
|||
padding: 15px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.camera { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.camera .wrapper::before { |
|||
top: -6px; |
|||
bottom: -6px; |
|||
left: 45px; |
|||
right: 45px; |
|||
content: ""; |
|||
display: block; |
|||
position: absolute; |
|||
background: var(--yellow-ofo); |
|||
z-index: 0; |
|||
} |
|||
|
|||
.camera .wrapper::after { |
|||
left: -6px; |
|||
right: -6px; |
|||
top: 45px; |
|||
bottom: 45px; |
|||
content: ""; |
|||
display: block; |
|||
position: absolute; |
|||
background: var(--yellow-ofo); |
|||
z-index: 0; |
|||
} |
|||
|
|||
.camera .wrapper { |
|||
padding: 10px; |
|||
border: 5px solid black; |
|||
margin: 0 auto; |
|||
border-radius: 5px; |
|||
position: relative; |
|||
} |
|||
|
|||
.error { |
|||
font-weight: bold; |
|||
color: red; |
|||
} |
|||
|
|||
.inquadra, |
|||
.loading { |
|||
text-align: center; |
|||
} |
|||
|
|||
.inquadra { |
|||
font-family: "syne", serif; |
|||
font-weight: 700; |
|||
text-transform: uppercase; |
|||
} |
|||
|
|||
.decode-result { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-top: 25px; |
|||
} |
|||
|
|||
.decode-number { |
|||
padding: 15px; |
|||
border: 2px solid black; |
|||
margin: 5px; |
|||
font-weight: bold; |
|||
font-size: 1.5rem; |
|||
} |
|||
</style> |
File diff suppressed because it is too large
Loading…
Reference in new issue