1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-05 05:25:26 +02:00

Feature/shopping lists second try (#927)

* generate types

* use generated types

* ui updates

* init button link for common styles

* add links

* setup label views

* add delete confirmation

* reset when not saved

* link label to foods and auto set when adding to shopping list

* generate types

* use inheritence to manage exception handling

* fix schema generation and add test for open_api generation

* add header to api docs

* move list consilidation to service

* split list and list items controller

* shopping list/list item tests - PARTIAL

* enable recipe add/remove in shopping lists

* generate types

* linting

* init global utility components

* update types and add list item api

* fix import cycle and database error

* add container and border classes

* new recipe list component

* fix tests

* breakout item editor

* refactor item editor

* update bulk actions

* update input / color contrast

* type generation

* refactor controller dependencies

* include food/unit editor

* remove console.logs

* fix and update type generation

* fix incorrect type for column

* fix postgres error

* fix delete by variable

* auto remove refs

* fix typo
This commit is contained in:
Hayden 2022-01-16 15:24:24 -09:00 committed by GitHub
parent f794208862
commit 92cf97e401
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 2556 additions and 685 deletions

View file

@ -0,0 +1,31 @@
<template>
<div>
<v-btn outlined class="rounded-xl my-1 mx-1" :to="to">
<v-icon v-if="icon != ''" left>
{{ icon }}
</v-icon>
{{ text }}
</v-btn>
</div>
</template>
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
export default defineComponent({
props: {
to: {
type: String,
required: true,
},
text: {
type: String,
default: "Link",
},
icon: {
type: String,
default: "",
},
},
});
</script>

View file

@ -0,0 +1,25 @@
<template>
<pre>
{{ prettyJson }}
</pre>
</template>
<script lang="ts">
import { defineComponent } from "@nuxtjs/composition-api";
export default defineComponent({
props: {
data: {
type: Object,
required: true,
},
},
setup(props) {
const prettyJson = JSON.stringify(props.data, null, 2);
return {
prettyJson,
};
},
});
</script>

View file

@ -0,0 +1,66 @@
<template>
<v-text-field v-model="inputVal" label="Color">
<template #prepend>
<v-btn class="elevation-0" small height="30px" width="30px" :color="inputVal || 'grey'" @click="setRandomHex">
<v-icon color="white">
{{ $globals.icons.refreshCircle }}
</v-icon>
</v-btn>
</template>
<template #append>
<v-menu v-model="menu" left nudge-left="30" nudge-top="20" :close-on-content-click="false">
<template #activator="{ on }">
<v-icon v-on="on">
{{ $globals.icons.formatColorFill }}
</v-icon>
</template>
<v-card>
<v-card-text class="pa-0">
<v-color-picker v-model="inputVal" flat hide-inputs show-swatches swatches-max-height="200" />
</v-card-text>
</v-card>
</v-menu>
</template>
</v-text-field>
</template>
<script lang="ts">
import { defineComponent, computed, ref } from "@nuxtjs/composition-api";
export default defineComponent({
props: {
value: {
type: String,
required: true,
},
},
setup(props, context) {
const menu = ref(false);
const inputVal = computed({
get: () => {
return props.value;
},
set: (val) => {
context.emit("input", val);
},
});
function getRandomHex() {
return "#000000".replace(/0/g, function () {
return (~~(Math.random() * 16)).toString(16);
});
}
function setRandomHex() {
inputVal.value = getRandomHex();
}
return {
menu,
setRandomHex,
inputVal,
};
},
});
</script>

View file

@ -0,0 +1,87 @@
<template>
<v-autocomplete
v-model="itemVal"
v-bind="$attrs"
item-text="name"
return-object
:items="items"
:prepend-icon="icon || $globals.icons.tags"
clearable
hide-details
/>
</template>
<script lang="ts">
/**
* The InputLabelType component is a wrapper for v-autocomplete. It is used to abstract the selection functionality
* of some common types within Mealie. This can mostly be used with any type of object provided it has a name and id
* property. The name property is used to display the name of the object in the autocomplete dropdown. The id property
* is used to store the id of the object in the itemId property.
*
* Supported Types
* - MultiPurposeLabel
* - RecipeIngredientFood
* - RecipeIngredientUnit
*
* TODO: Add RecipeTag / Category to this selector
* Future Supported Types
* - RecipeTags
* - RecipeCategories
*
* Both the ID and Item can be synced. The item can be synced using the v-model syntax and the itemId can be synced
* using the .sync syntax `item-id.sync="item.labelId"`
*/
import { defineComponent, computed } from "@nuxtjs/composition-api";
import { MultiPurposeLabelSummary } from "~/types/api-types/labels";
import { IngredientFood, IngredientUnit } from "~/types/api-types/recipe";
export default defineComponent({
props: {
value: {
type: Object as () => MultiPurposeLabelSummary | IngredientFood | IngredientUnit,
required: false,
default: () => {
return {};
},
},
items: {
type: Array as () => Array<MultiPurposeLabelSummary | IngredientFood | IngredientUnit>,
required: true,
},
itemId: {
type: [String, Number],
default: undefined,
},
icon: {
type: String,
required: false,
default: undefined,
},
},
setup(props, context) {
const itemIdVal = computed({
get: () => {
return props.itemId || undefined;
},
set: (val) => {
context.emit("update:item-id", val);
},
});
const itemVal = computed({
get: () => {
return props.value;
},
set: (val) => {
itemIdVal.value = val?.id || undefined;
context.emit("input", val);
},
});
return {
itemVal,
itemIdVal,
};
},
});
</script>

View file

@ -0,0 +1,64 @@
<template>
<div class="d-flex align-center" style="max-width: 60px">
<v-text-field
v-model.number="quantity"
hide-details
label="Qty"
:min="min"
:max="max"
type="number"
class="rounded-xl"
small
text
>
</v-text-field>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from "@nuxtjs/composition-api";
export default defineComponent({
name: "VInputNumber",
props: {
label: {
type: String,
default: "Qty",
},
min: {
type: Number,
default: 0,
},
max: {
type: Number,
default: 9999,
},
rules: {
type: Array,
default: () => [],
},
step: {
type: Number,
default: 1,
},
value: {
type: Number,
default: 0,
},
},
setup(props, context) {
const quantity = computed({
get: () => {
return Number(props.value);
},
set: (val) => {
context.emit("input", val);
},
});
return {
quantity,
};
},
});
</script>