Beginning of a Material UI
This commit is contained in:
parent
762d2866b8
commit
1cf5ca992a
@ -3,7 +3,8 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<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>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -18,6 +18,7 @@
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"vue": "^2.4.2",
|
||||
"vue-router": "^2.7.0",
|
||||
"vuetify": "^0.15.7",
|
||||
"vuex": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
43
src/App.vue
43
src/App.vue
@ -1,23 +1,42 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<h1>Food scanning</h1>
|
||||
<v-app toolbar>
|
||||
<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>
|
||||
</div>
|
||||
</v-container>
|
||||
</main>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NavigationDrawer from '@/components/NavigationDrawer';
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
NavigationDrawer,
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.$store.getters.title;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isDrawerVisible: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showHideDrawer() {
|
||||
this.isDrawerVisible = !this.isDrawerVisible;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
@ -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
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify';
|
||||
import '../node_modules/vuetify/dist/vuetify.min.css';
|
||||
import App from './App';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: '#app',
|
||||
|
@ -1,9 +1,11 @@
|
||||
import Vue from 'vue';
|
||||
import Router from 'vue-router';
|
||||
|
||||
import Home from '@/components/Home';
|
||||
import Scan from '@/components/Scan';
|
||||
import Product from '@/components/Product';
|
||||
import Home from '@/views/Home';
|
||||
import ManualBarcode from '@/views/ManualBarcode';
|
||||
import Scan from '@/views/Scan';
|
||||
import Product from '@/views/Product';
|
||||
import Preferences from '@/views/Preferences';
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
@ -19,10 +21,20 @@ export default new Router({
|
||||
name: 'Scan',
|
||||
component: Scan,
|
||||
},
|
||||
{
|
||||
path: '/barcode',
|
||||
name: 'ManualBarcode',
|
||||
component: ManualBarcode,
|
||||
},
|
||||
{
|
||||
path: '/barcode/:barcode',
|
||||
name: '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 {
|
||||
product: state => state.product,
|
||||
isLoading: state => state.isLoading,
|
||||
title: state => state.title,
|
||||
};
|
||||
|
@ -1,2 +1,3 @@
|
||||
export const IS_LOADING = 'IS_LOADING';
|
||||
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 = {
|
||||
product: null,
|
||||
isLoading: false,
|
||||
title: 'Food scanning',
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
@ -13,4 +14,7 @@ export const mutations = {
|
||||
[types.IS_LOADING](state) {
|
||||
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