Beginning of a Material UI

This commit is contained in:
Lucas Verney 2017-09-20 04:11:40 +02:00
parent 762d2866b8
commit 1cf5ca992a
18 changed files with 260 additions and 70 deletions

View File

@ -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>

View File

@ -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": {

View File

@ -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>

View File

@ -1,12 +0,0 @@
<template>
<nav>
<ul>
<router-link to="scan">Scan something!</router-link>
</ul>
</nav>
</template>
<script>
export default {
};
</script>

View 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>

View File

@ -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>

View File

@ -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',

View File

@ -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,
},
], ],
}); });

View File

@ -11,4 +11,7 @@ export default {
}, },
); );
}, },
setTitle({ commit }, { title }) {
commit(types.SET_TITLE, { title });
},
}; };

View File

@ -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,
}; };

View File

@ -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';

View File

@ -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
View 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>

View 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
View 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
View 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>