add basic functionality
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
ff2dea6a76
commit
d5b29bdc91
@ -0,0 +1,49 @@
|
||||
<script setup lang="ts">
|
||||
import { useShoppingListStore } from '../store/shoppingList';
|
||||
import { ref, reactive } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const store = useShoppingListStore();
|
||||
const router = useRouter();
|
||||
|
||||
const isValid = ref(false);
|
||||
const item = reactive({
|
||||
name: '',
|
||||
price: 0.99,
|
||||
user: '',
|
||||
});
|
||||
|
||||
const form = ref(null);
|
||||
|
||||
const submit = () => {
|
||||
store.items.push({
|
||||
name: item.name,
|
||||
price: item.price * 100,
|
||||
user: store.users.find(user => user.name === item.user),
|
||||
});
|
||||
router.push('/shopping-list');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-form ref="form" v-model="isValid" lazy-validation>
|
||||
<v-text-field
|
||||
label="Item Name"
|
||||
required
|
||||
v-model="item.name"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Price"
|
||||
suffix="€"
|
||||
required
|
||||
v-model="item.price"
|
||||
/>
|
||||
<v-select
|
||||
label="User"
|
||||
:items="store.users.map(user => user.name)"
|
||||
required
|
||||
v-model="item.user"
|
||||
/>
|
||||
<v-btn color="primary" @click="submit()">add item</v-btn>
|
||||
</v-form>
|
||||
</template>
|
@ -0,0 +1,39 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps } from 'vue';
|
||||
|
||||
defineProps({
|
||||
tabs: Array,
|
||||
title: String,
|
||||
});
|
||||
const tab = ref(null);
|
||||
|
||||
const back = () => {
|
||||
window.history.back();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-app-bar
|
||||
:collapse="false"
|
||||
:collapse-on-scroll="true"
|
||||
absolute
|
||||
color="blue accent-4"
|
||||
dark
|
||||
scroll-target="#scrolling-techniques-6"
|
||||
>
|
||||
<v-btn icon @click="back()">
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>{{ title }}</v-toolbar-title>
|
||||
<template v-if="tabs?.length" v-slot:extension>
|
||||
<v-tabs align-with-title v-model="tab">
|
||||
<slot name="tabs">
|
||||
<v-tab v-for="tab of tabs" :value="tab.name.toLowerCase().replaceAll(' ', '-')">{{ tab.name }}</v-tab>
|
||||
</slot>
|
||||
</v-tabs>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<v-main>
|
||||
<slot :tab="tab"/>
|
||||
</v-main>
|
||||
</template>
|
@ -1,152 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row class="text-center">
|
||||
<v-col cols="12">
|
||||
<v-img
|
||||
:src="logo"
|
||||
class="my-3"
|
||||
contain
|
||||
height="200"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col class="mb-4">
|
||||
<h1 class="display-2 font-weight-bold mb-3">
|
||||
Welcome to the Vuetify 3 Beta
|
||||
</h1>
|
||||
|
||||
<h4>Vite Preview</h4>
|
||||
|
||||
<p class="subheading font-weight-regular">
|
||||
For help and collaboration with other Vuetify developers,
|
||||
<br>please join our online
|
||||
<a
|
||||
href="https://community.vuetifyjs.com"
|
||||
target="_blank"
|
||||
>Discord Community</a>
|
||||
</p>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-5">
|
||||
What's next?
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(next, i) in whatsNext"
|
||||
:key="i"
|
||||
:href="next.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ next.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-5">
|
||||
Important Links
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(link, i) in importantLinks"
|
||||
:key="i"
|
||||
:href="link.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ link.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-5">
|
||||
Ecosystem
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(eco, i) in ecosystem"
|
||||
:key="i"
|
||||
:href="eco.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ eco.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import logo from '../assets/logo.svg'
|
||||
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
|
||||
data: () => ({
|
||||
ecosystem: [
|
||||
{
|
||||
text: 'vuetify-loader',
|
||||
href: 'https://github.com/vuetifyjs/vuetify-loader/tree/next',
|
||||
},
|
||||
{
|
||||
text: 'github',
|
||||
href: 'https://github.com/vuetifyjs/vuetify/tree/next',
|
||||
},
|
||||
{
|
||||
text: 'awesome-vuetify',
|
||||
href: 'https://github.com/vuetifyjs/awesome-vuetify',
|
||||
},
|
||||
],
|
||||
importantLinks: [
|
||||
{
|
||||
text: 'Chat',
|
||||
href: 'https://community.vuetifyjs.com',
|
||||
},
|
||||
{
|
||||
text: 'Made with Vuetify',
|
||||
href: 'https://madewithvuejs.com/vuetify',
|
||||
},
|
||||
{
|
||||
text: 'Twitter',
|
||||
href: 'https://twitter.com/vuetifyjs',
|
||||
},
|
||||
{
|
||||
text: 'Articles',
|
||||
href: 'https://medium.com/vuetify',
|
||||
},
|
||||
],
|
||||
logo,
|
||||
whatsNext: [
|
||||
{
|
||||
text: 'Explore components',
|
||||
href: 'https://vuetifyjs.com',
|
||||
},
|
||||
{
|
||||
text: 'Roadmap',
|
||||
href: 'https://vuetifyjs.com/introduction/roadmap/',
|
||||
},
|
||||
{
|
||||
text: 'Frequently Asked Questions',
|
||||
href: 'https://vuetifyjs.com/getting-started/frequently-asked-questions',
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
</script>
|
@ -0,0 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps } from 'vue';
|
||||
import { groupItemsByUser } from '../store/shoppingList';
|
||||
|
||||
defineProps({
|
||||
items: Array,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-list v-if="items.length" lines="theee" select-strategy="multiple">
|
||||
<div v-for="(items, user) of groupItemsByUser(items)">
|
||||
<v-list-subheader>{{ user }}</v-list-subheader>
|
||||
<div v-for="item in items">
|
||||
<v-list-item @click="item.isBought = !item.isBought">
|
||||
<v-list-item-title>{{ item.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ item.price / 100 }} €</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</v-list>
|
||||
<p v-else>There are no items in this list.</p>
|
||||
</template>
|
@ -0,0 +1,30 @@
|
||||
const lukas = {
|
||||
name: 'lukas',
|
||||
};
|
||||
|
||||
const laura = {
|
||||
name: 'laura'
|
||||
};
|
||||
|
||||
export const users = [ lukas, laura ];
|
||||
|
||||
export const dummyList = [
|
||||
{
|
||||
name: 'Banana',
|
||||
price: 200,
|
||||
user: lukas,
|
||||
isBought: false,
|
||||
},
|
||||
{
|
||||
name: 'Apple',
|
||||
price: 150,
|
||||
user: lukas,
|
||||
isBought: false,
|
||||
},
|
||||
{
|
||||
name: 'Butter',
|
||||
price: 149,
|
||||
user: laura,
|
||||
isBought: false,
|
||||
},
|
||||
];
|
@ -0,0 +1,36 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { dummyList, users } from './dummyData';
|
||||
|
||||
type User = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
type ShoppingItem = {
|
||||
name: string;
|
||||
price: number;
|
||||
isBought: boolean;
|
||||
user: User;
|
||||
};
|
||||
|
||||
export const useShoppingListStore = defineStore('shoppingList', {
|
||||
state() {
|
||||
return {
|
||||
items: dummyList as Array<ShoppingItem>,
|
||||
users: users as Array<User>,
|
||||
};
|
||||
},
|
||||
actions: {},
|
||||
getters: {
|
||||
openItems: state => state.items.filter(item => !item.isBought),
|
||||
boughtItems: state => state.items.filter(item => !!item.isBought),
|
||||
itemsByUser: state => groupItemsByUser(state.items),
|
||||
openItemsByUser: state => groupItemsByUser(state.items.filter(item => !item.isBought)),
|
||||
boughtItemsByUser: state => groupItemsByUser(state.items.filter(item => !!item.isBought)),
|
||||
},
|
||||
});
|
||||
|
||||
export const groupItemsByUser = items => items.reduce((groups, item) => {
|
||||
if (!groups[item.user.name]) groups[item.user.name] = [];
|
||||
groups[item.user.name].push(item);
|
||||
return groups;
|
||||
}, {});
|
@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultPage from '../components/DefaultPage.vue';
|
||||
import AddItemForm from '../components/AddItemForm.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultPage title="Add Item">
|
||||
<v-container>
|
||||
<AddItemForm/>
|
||||
</v-container>
|
||||
</DefaultPage>
|
||||
</template>
|
@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import DefaultPage from '../components/DefaultPage.vue';
|
||||
import ItemList from '../components/ItemList.vue';
|
||||
import { useShoppingListStore } from '../store/shoppingList';
|
||||
|
||||
const store = useShoppingListStore();
|
||||
|
||||
const tabs = [
|
||||
{ name: 'open items' },
|
||||
{ name: 'bought items' },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefaultPage :tabs="tabs" v-slot="slot" title="Shopping List">
|
||||
<v-container>
|
||||
<v-window v-model="slot.tab">
|
||||
<v-window-item value="open-items">
|
||||
<ItemList :items="store.openItems"></ItemList>
|
||||
</v-window-item>
|
||||
<v-window-item value="bought-items">
|
||||
<ItemList :items="store.boughtItems"></ItemList>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</v-container>
|
||||
<v-card-text style="display: flex; justify-content: end">
|
||||
<v-btn
|
||||
icon="mdi-plus"
|
||||
color="red"
|
||||
to="/add-item"
|
||||
elevation="8"
|
||||
size="large"
|
||||
/>
|
||||
</v-card-text>
|
||||
</DefaultPage>
|
||||
</template>
|
Loading…
Reference in New Issue