Beginning of a Material UI
This commit is contained in:
parent
762d2866b8
commit
1cf5ca992a
@ -3,7 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Food</title>
|
<title>Food</title>
|
||||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"vue": "^2.4.2",
|
"vue": "^2.4.2",
|
||||||
"vue-router": "^2.7.0",
|
"vue-router": "^2.7.0",
|
||||||
|
"vuetify": "^0.15.7",
|
||||||
"vuex": "^2.4.0"
|
"vuex": "^2.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
43
src/App.vue
43
src/App.vue
@ -1,23 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<v-app toolbar>
|
||||||
<h1>Food scanning</h1>
|
<NavigationDrawer :isDrawerVisible="isDrawerVisible"/>
|
||||||
|
<v-toolbar class="indigo" dark>
|
||||||
|
<v-toolbar-side-icon @click.stop="showHideDrawer"></v-toolbar-side-icon>
|
||||||
|
<v-toolbar-title>{{ title }}</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
<main>
|
||||||
|
<v-container fluid>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</v-container>
|
||||||
|
</main>
|
||||||
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import NavigationDrawer from '@/components/NavigationDrawer';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
components: {
|
||||||
|
NavigationDrawer,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
title() {
|
||||||
|
return this.$store.getters.title;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isDrawerVisible: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showHideDrawer() {
|
||||||
|
this.isDrawerVisible = !this.isDrawerVisible;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#app {
|
|
||||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
text-align: center;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin-top: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<template>
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<router-link to="scan">Scan something!</router-link>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
};
|
|
||||||
</script>
|
|
51
src/components/NavigationDrawer.vue
Normal file
51
src/components/NavigationDrawer.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<v-navigation-drawer
|
||||||
|
persistent
|
||||||
|
clipped
|
||||||
|
enable-resize-watcher
|
||||||
|
v-model="isDrawerVisible"
|
||||||
|
>
|
||||||
|
<v-list>
|
||||||
|
<v-list-tile :to="{ name: 'Home' }" exact>
|
||||||
|
<v-list-tile-action>
|
||||||
|
<v-icon>home</v-icon>
|
||||||
|
</v-list-tile-action>
|
||||||
|
<v-list-tile-content>
|
||||||
|
<v-list-tile-title>Home</v-list-tile-title>
|
||||||
|
</v-list-tile-content>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile :to="{ name: 'Scan' }">
|
||||||
|
<v-list-tile-action>
|
||||||
|
<v-icon>search</v-icon>
|
||||||
|
</v-list-tile-action>
|
||||||
|
<v-list-tile-content>
|
||||||
|
<v-list-tile-title>Scan</v-list-tile-title>
|
||||||
|
</v-list-tile-content>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile :to="{ name: 'ManualBarcode' }">
|
||||||
|
<v-list-tile-action>
|
||||||
|
<v-icon>search</v-icon>
|
||||||
|
</v-list-tile-action>
|
||||||
|
<v-list-tile-content>
|
||||||
|
<v-list-tile-title>Find by barcode</v-list-tile-title>
|
||||||
|
</v-list-tile-content>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile :to="{ name: 'Preferences' }">
|
||||||
|
<v-list-tile-action>
|
||||||
|
<v-icon>settings</v-icon>
|
||||||
|
</v-list-tile-action>
|
||||||
|
<v-list-tile-content>
|
||||||
|
<v-list-tile-title>Preferences</v-list-tile-title>
|
||||||
|
</v-list-tile-content>
|
||||||
|
</v-list-tile>
|
||||||
|
</v-list>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
isDrawerVisible: Boolean,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -1,41 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<template v-if="isLoading">
|
|
||||||
<p>Loading…</p>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<h2>{{ this.product.product_name }}</h2>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Barcode</th>
|
|
||||||
<td>{{ $route.params.barcode }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
created() {
|
|
||||||
this.fetchData();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
// Fetch again when the component is updated
|
|
||||||
$route: 'fetchData',
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
product() {
|
|
||||||
return this.$store.getters.product;
|
|
||||||
},
|
|
||||||
isLoading() {
|
|
||||||
return this.$store.getters.isLoading;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
fetchData() {
|
|
||||||
this.$store.dispatch('getProduct', { EAN: this.$route.params.barcode });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,12 +1,16 @@
|
|||||||
// The Vue build version to load with the `import` command
|
// The Vue build version to load with the `import` command
|
||||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import Vuetify from 'vuetify';
|
||||||
|
import '../node_modules/vuetify/dist/vuetify.min.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
Vue.use(Vuetify);
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
/* eslint-disable no-new */
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Router from 'vue-router';
|
import Router from 'vue-router';
|
||||||
|
|
||||||
import Home from '@/components/Home';
|
import Home from '@/views/Home';
|
||||||
import Scan from '@/components/Scan';
|
import ManualBarcode from '@/views/ManualBarcode';
|
||||||
import Product from '@/components/Product';
|
import Scan from '@/views/Scan';
|
||||||
|
import Product from '@/views/Product';
|
||||||
|
import Preferences from '@/views/Preferences';
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
@ -19,10 +21,20 @@ export default new Router({
|
|||||||
name: 'Scan',
|
name: 'Scan',
|
||||||
component: Scan,
|
component: Scan,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/barcode',
|
||||||
|
name: 'ManualBarcode',
|
||||||
|
component: ManualBarcode,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/barcode/:barcode',
|
path: '/barcode/:barcode',
|
||||||
name: 'Product',
|
name: 'Product',
|
||||||
component: Product,
|
component: Product,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/preferences',
|
||||||
|
name: 'Preferences',
|
||||||
|
component: Preferences,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -11,4 +11,7 @@ export default {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
setTitle({ commit }, { title }) {
|
||||||
|
commit(types.SET_TITLE, { title });
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
product: state => state.product,
|
product: state => state.product,
|
||||||
isLoading: state => state.isLoading,
|
isLoading: state => state.isLoading,
|
||||||
|
title: state => state.title,
|
||||||
};
|
};
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export const IS_LOADING = 'IS_LOADING';
|
export const IS_LOADING = 'IS_LOADING';
|
||||||
export const STORE_PRODUCT = 'STORE_PRODUCT';
|
export const STORE_PRODUCT = 'STORE_PRODUCT';
|
||||||
|
export const SET_TITLE = 'SET_TITLE';
|
||||||
|
@ -3,6 +3,7 @@ import * as types from './mutations-types';
|
|||||||
export const initialState = {
|
export const initialState = {
|
||||||
product: null,
|
product: null,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
title: 'Food scanning',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
@ -13,4 +14,7 @@ export const mutations = {
|
|||||||
[types.IS_LOADING](state) {
|
[types.IS_LOADING](state) {
|
||||||
state.isLoading = true;
|
state.isLoading = true;
|
||||||
},
|
},
|
||||||
|
[types.SET_TITLE](state, { title }) {
|
||||||
|
state.title = title;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
23
src/views/Home.vue
Normal file
23
src/views/Home.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>Let's start scanning!</h2>
|
||||||
|
<v-btn
|
||||||
|
dark
|
||||||
|
fab
|
||||||
|
fixed
|
||||||
|
bottom
|
||||||
|
right
|
||||||
|
class="pink"
|
||||||
|
>
|
||||||
|
<v-icon>search</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('setTitle', { title: 'Food scanning' });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
40
src/views/ManualBarcode.vue
Normal file
40
src/views/ManualBarcode.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<v-form v-model="valid" ref="form">
|
||||||
|
<v-text-field
|
||||||
|
label="EAN13 barcode"
|
||||||
|
v-model="ean13"
|
||||||
|
:rules="ean13Rules"
|
||||||
|
:counter="13"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
></v-text-field>
|
||||||
|
<p class="text-xs-right">
|
||||||
|
<v-btn @click="submit" :disabled="!valid" :class="{ green: valid }">Find</v-btn>
|
||||||
|
</p>
|
||||||
|
</v-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('setTitle', { title: 'Manual barcode' });
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
ean13: '',
|
||||||
|
ean13Rules: [
|
||||||
|
v => !!v || 'EAN13 barcode is required.',
|
||||||
|
v => /^\d{13}$/.test(v) || 'EAN13 barcode is invalid.',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit() {
|
||||||
|
if (this.$refs.form.validate()) {
|
||||||
|
this.$router.push({ name: 'Product', params: { barcode: this.ean13 } });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
11
src/views/Preferences.vue
Normal file
11
src/views/Preferences.vue
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<p>TODO</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('setTitle', { title: 'Preferences' });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
72
src/views/Product.vue
Normal file
72
src/views/Product.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<v-flex class="text-xs-center">
|
||||||
|
<template v-if="isLoading">
|
||||||
|
<p>Loading…</p>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p><img :src="this.product.image_front_small_url"></p>
|
||||||
|
<v-tabs centered>
|
||||||
|
<v-tabs-items>
|
||||||
|
<v-tabs-content id="tab-overview">
|
||||||
|
<v-card flat>
|
||||||
|
<v-card-text>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-tabs-content>
|
||||||
|
<v-tabs-content id="tab-nutrition">
|
||||||
|
<v-card flat>
|
||||||
|
<v-card-text>
|
||||||
|
<v-data-table
|
||||||
|
hide-actions
|
||||||
|
>
|
||||||
|
<template slot="items" scope="props">
|
||||||
|
<td>{{ props.item.name }}</td>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-tabs-content>
|
||||||
|
<v-tabs-content id="tab-labels">
|
||||||
|
<v-card flat>
|
||||||
|
<v-card-text>Bidule</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-tabs-content>
|
||||||
|
</v-tabs-items>
|
||||||
|
<v-tabs-bar class="cyan">
|
||||||
|
<v-tabs-slider class="yellow"></v-tabs-slider>
|
||||||
|
<v-tabs-item href="#tab-overview">Overview</v-tabs-item>
|
||||||
|
<v-tabs-item href="#tab-nutrition">Nutrition</v-tabs-item>
|
||||||
|
<v-tabs-item href="#tab-labels">Labels</v-tabs-item>
|
||||||
|
</v-tabs-bar>
|
||||||
|
</v-tabs>
|
||||||
|
</template>
|
||||||
|
</v-flex>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
this.$store.dispatch('setTitle', { title: 'Loading' });
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// Fetch again when the component is updated
|
||||||
|
$route: 'fetchData',
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
product() {
|
||||||
|
const product = this.$store.getters.product;
|
||||||
|
this.$store.dispatch('setTitle', { title: product.product_name });
|
||||||
|
return product;
|
||||||
|
},
|
||||||
|
isLoading() {
|
||||||
|
return this.$store.getters.isLoading;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData() {
|
||||||
|
this.$store.dispatch('getProduct', { EAN: this.$route.params.barcode });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user