mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-25 11:45:21 -05:00
feat: Replace number inputs with new v-number-input compontent (#6767)
This commit is contained in:
@@ -144,11 +144,13 @@
|
|||||||
variant="underlined"
|
variant="underlined"
|
||||||
@update:model-value="setFieldValue(field, index, $event)"
|
@update:model-value="setFieldValue(field, index, $event)"
|
||||||
/>
|
/>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
v-else-if="field.type === 'number'"
|
v-else-if="field.type === 'number'"
|
||||||
:model-value="field.value"
|
:model-value="field.value"
|
||||||
type="number"
|
|
||||||
variant="underlined"
|
variant="underlined"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
|
:precision="null"
|
||||||
@update:model-value="setFieldValue(field, index, $event)"
|
@update:model-value="setFieldValue(field, index, $event)"
|
||||||
/>
|
/>
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
|
|||||||
@@ -22,12 +22,15 @@
|
|||||||
cols="12"
|
cols="12"
|
||||||
class="flex-grow-0 flex-shrink-0"
|
class="flex-grow-0 flex-shrink-0"
|
||||||
>
|
>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
v-model="model.quantity"
|
v-model="model.quantity"
|
||||||
variant="solo"
|
variant="solo"
|
||||||
|
:precision="null"
|
||||||
|
:min="0"
|
||||||
hide-details
|
hide-details
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
density="compact"
|
density="compact"
|
||||||
type="number"
|
|
||||||
:placeholder="$t('recipe.quantity')"
|
:placeholder="$t('recipe.quantity')"
|
||||||
@keypress="quantityFilter"
|
@keypress="quantityFilter"
|
||||||
>
|
>
|
||||||
@@ -38,7 +41,7 @@
|
|||||||
{{ $globals.icons.arrowUpDown }}
|
{{ $globals.icons.arrowUpDown }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-number-input>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
v-if="!state.isRecipe"
|
v-if="!state.isRecipe"
|
||||||
|
|||||||
@@ -10,14 +10,17 @@
|
|||||||
v-for="(item, key, index) in modelValue"
|
v-for="(item, key, index) in modelValue"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
density="compact"
|
|
||||||
:model-value="modelValue[key]"
|
:model-value="modelValue[key]"
|
||||||
:label="labels[key].label"
|
:label="labels[key].label"
|
||||||
:suffix="labels[key].suffix"
|
:suffix="labels[key].suffix"
|
||||||
type="number"
|
density="compact"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
variant="underlined"
|
variant="underlined"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
|
:precision="null"
|
||||||
|
:min="0"
|
||||||
@update:model-value="updateValue(key, $event)"
|
@update:model-value="updateValue(key, $event)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,27 +11,27 @@
|
|||||||
<v-container class="ma-0 pa-0">
|
<v-container class="ma-0 pa-0">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="3">
|
<v-col cols="3">
|
||||||
<v-text-field
|
<v-number-input
|
||||||
:model-value="recipeServings"
|
:model-value="recipe.recipeServings"
|
||||||
type="number"
|
|
||||||
:min="0"
|
:min="0"
|
||||||
hide-spin-buttons
|
:precision="null"
|
||||||
density="compact"
|
density="compact"
|
||||||
:label="$t('recipe.servings')"
|
:label="$t('recipe.servings')"
|
||||||
variant="underlined"
|
variant="underlined"
|
||||||
@update:model-value="validateInput($event, 'recipeServings')"
|
control-variant="hidden"
|
||||||
|
@update:model-value="recipe.recipeServings = $event"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="3">
|
<v-col cols="3">
|
||||||
<v-text-field
|
<v-number-input
|
||||||
:model-value="recipeYieldQuantity"
|
:model-value="recipe.recipeYieldQuantity"
|
||||||
type="number"
|
|
||||||
:min="0"
|
:min="0"
|
||||||
hide-spin-buttons
|
:precision="null"
|
||||||
density="compact"
|
density="compact"
|
||||||
:label="$t('recipe.yield')"
|
:label="$t('recipe.yield')"
|
||||||
variant="underlined"
|
variant="underlined"
|
||||||
@update:model-value="validateInput($event, 'recipeYieldQuantity')"
|
control-variant="hidden"
|
||||||
|
@update:model-value="recipe.recipeYieldQuantity = $event"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
@@ -85,37 +85,4 @@ import type { NoUndefinedField } from "~/lib/api/types/non-generated";
|
|||||||
import type { Recipe } from "~/lib/api/types/recipe";
|
import type { Recipe } from "~/lib/api/types/recipe";
|
||||||
|
|
||||||
const recipe = defineModel<NoUndefinedField<Recipe>>({ required: true });
|
const recipe = defineModel<NoUndefinedField<Recipe>>({ required: true });
|
||||||
|
|
||||||
const recipeServings = computed<number>({
|
|
||||||
get() {
|
|
||||||
return recipe.value.recipeServings;
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
validateInput(val.toString(), "recipeServings");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const recipeYieldQuantity = computed<number>({
|
|
||||||
get() {
|
|
||||||
return recipe.value.recipeYieldQuantity;
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
validateInput(val.toString(), "recipeYieldQuantity");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function validateInput(value: string | null, property: "recipeServings" | "recipeYieldQuantity") {
|
|
||||||
if (!value) {
|
|
||||||
recipe.value[property] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const number = parseFloat(value.replace(/[^0-9.]/g, ""));
|
|
||||||
if (isNaN(number) || number <= 0) {
|
|
||||||
recipe.value[property] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recipe.value[property] = number;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -65,13 +65,13 @@
|
|||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="mt-n5">
|
<v-card-text class="mt-n5">
|
||||||
<div class="mt-4 d-flex align-center">
|
<div class="mt-4 d-flex align-center">
|
||||||
<v-text-field
|
<v-number-input
|
||||||
:model-value="yieldQuantity"
|
:model-value="yieldQuantity"
|
||||||
type="number"
|
:precision="null"
|
||||||
:min="0"
|
:min="0"
|
||||||
variant="underlined"
|
variant="underlined"
|
||||||
hide-spin-buttons
|
control-variant="hidden"
|
||||||
@update:model-value="recalculateScale(parseFloat($event) || 0)"
|
@update:model-value="recalculateScale($event || 0)"
|
||||||
/>
|
/>
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
location="end"
|
location="end"
|
||||||
|
|||||||
@@ -4,7 +4,19 @@
|
|||||||
<v-card-text class="pb-3 pt-1">
|
<v-card-text class="pb-3 pt-1">
|
||||||
<div class="d-md-flex align-center mb-2" style="gap: 20px">
|
<div class="d-md-flex align-center mb-2" style="gap: 20px">
|
||||||
<div>
|
<div>
|
||||||
<InputQuantity v-model="listItem.quantity" />
|
<v-number-input
|
||||||
|
v-model="listItem.quantity"
|
||||||
|
hide-details
|
||||||
|
:label="$t('form.quantity-label-abbreviated')"
|
||||||
|
:min="0"
|
||||||
|
:precision="null"
|
||||||
|
variant="plain"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
|
density="compact"
|
||||||
|
class="centered-number-input"
|
||||||
|
style="width: 100px;"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<InputLabelType
|
<InputLabelType
|
||||||
v-model="listItem.unit"
|
v-model="listItem.unit"
|
||||||
@@ -158,6 +170,15 @@ export default defineNuxtComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue.quantity,
|
||||||
|
() => {
|
||||||
|
if (!props.modelValue.quantity) {
|
||||||
|
listItem.value.quantity = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue.food,
|
() => props.modelValue.food,
|
||||||
(newFood) => {
|
(newFood) => {
|
||||||
@@ -221,3 +242,10 @@ export default defineNuxtComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.centered-number-input :deep(.v-field) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="d-flex align-center"
|
|
||||||
style="max-width: 60px"
|
|
||||||
>
|
|
||||||
<v-text-field
|
|
||||||
v-model.number="quantity"
|
|
||||||
hide-details
|
|
||||||
:label="$t('form.quantity-label-abbreviated')"
|
|
||||||
:min="min"
|
|
||||||
:max="max"
|
|
||||||
type="number"
|
|
||||||
variant="plain"
|
|
||||||
density="compact"
|
|
||||||
style="width: 60px;"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default defineNuxtComponent({
|
|
||||||
name: "VInputNumber",
|
|
||||||
props: {
|
|
||||||
min: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
max: {
|
|
||||||
type: Number,
|
|
||||||
default: 9999,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
step: {
|
|
||||||
type: Number,
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ["update:modelValue"],
|
|
||||||
setup(props, context) {
|
|
||||||
const quantity = computed({
|
|
||||||
get: () => {
|
|
||||||
return Number(props.modelValue);
|
|
||||||
},
|
|
||||||
set: (val) => {
|
|
||||||
context.emit("update:modelValue", val);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
quantity,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
"vue-advanced-cropper": "^2.8.9",
|
"vue-advanced-cropper": "^2.8.9",
|
||||||
"vue-draggable-plus": "^0.6.0",
|
"vue-draggable-plus": "^0.6.0",
|
||||||
"vuetify": "^3.9.7",
|
"vuetify": "^3.9.7",
|
||||||
"vuetify-nuxt-module": "^0.18.8"
|
"vuetify-nuxt-module": "^0.18.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/eslint": "^1.2.0",
|
"@nuxt/eslint": "^1.2.0",
|
||||||
|
|||||||
@@ -134,18 +134,22 @@
|
|||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div>
|
<div>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
v-model="settings.maxMissingFoods"
|
v-model="settings.maxMissingFoods"
|
||||||
type="number"
|
:precision="null"
|
||||||
|
:min="0"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
hide-details
|
hide-details
|
||||||
hide-spin-buttons
|
|
||||||
:label="$t('recipe-finder.max-missing-ingredients')"
|
:label="$t('recipe-finder.max-missing-ingredients')"
|
||||||
/>
|
/>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
v-model="settings.maxMissingTools"
|
v-model="settings.maxMissingTools"
|
||||||
type="number"
|
:precision="null"
|
||||||
|
:min="0"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
hide-details
|
hide-details
|
||||||
hide-spin-buttons
|
|
||||||
:label="$t('recipe-finder.max-missing-tools')"
|
:label="$t('recipe-finder.max-missing-tools')"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -30,9 +30,11 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-number-input
|
||||||
v-model="numberOfDays"
|
v-model="numberOfDays"
|
||||||
type="number"
|
:min="1"
|
||||||
|
control-variant="stacked"
|
||||||
|
inset
|
||||||
:label="$t('meal-plan.numberOfDays-label')"
|
:label="$t('meal-plan.numberOfDays-label')"
|
||||||
:hint="$t('meal-plan.numberOfDays-hint')"
|
:hint="$t('meal-plan.numberOfDays-hint')"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
|
|||||||
2
frontend/types/components.d.ts
vendored
2
frontend/types/components.d.ts
vendored
@@ -27,7 +27,6 @@ import type HelpIcon from "@/components/global/HelpIcon.vue";
|
|||||||
import type ImageCropper from "@/components/global/ImageCropper.vue";
|
import type ImageCropper from "@/components/global/ImageCropper.vue";
|
||||||
import type InputColor from "@/components/global/InputColor.vue";
|
import type InputColor from "@/components/global/InputColor.vue";
|
||||||
import type InputLabelType from "@/components/global/InputLabelType.vue";
|
import type InputLabelType from "@/components/global/InputLabelType.vue";
|
||||||
import type InputQuantity from "@/components/global/InputQuantity.vue";
|
|
||||||
import type LanguageDialog from "@/components/global/LanguageDialog.vue";
|
import type LanguageDialog from "@/components/global/LanguageDialog.vue";
|
||||||
import type MarkdownEditor from "@/components/global/MarkdownEditor.vue";
|
import type MarkdownEditor from "@/components/global/MarkdownEditor.vue";
|
||||||
import type RecipeJsonEditor from "@/components/global/RecipeJsonEditor.vue";
|
import type RecipeJsonEditor from "@/components/global/RecipeJsonEditor.vue";
|
||||||
@@ -69,7 +68,6 @@ declare module "vue" {
|
|||||||
ImageCropper: typeof ImageCropper;
|
ImageCropper: typeof ImageCropper;
|
||||||
InputColor: typeof InputColor;
|
InputColor: typeof InputColor;
|
||||||
InputLabelType: typeof InputLabelType;
|
InputLabelType: typeof InputLabelType;
|
||||||
InputQuantity: typeof InputQuantity;
|
|
||||||
LanguageDialog: typeof LanguageDialog;
|
LanguageDialog: typeof LanguageDialog;
|
||||||
MarkdownEditor: typeof MarkdownEditor;
|
MarkdownEditor: typeof MarkdownEditor;
|
||||||
RecipeJsonEditor: typeof RecipeJsonEditor;
|
RecipeJsonEditor: typeof RecipeJsonEditor;
|
||||||
|
|||||||
@@ -11082,7 +11082,7 @@ vite-plugin-vue-tracer@^1.0.1:
|
|||||||
pathe "^2.0.3"
|
pathe "^2.0.3"
|
||||||
source-map-js "^1.2.1"
|
source-map-js "^1.2.1"
|
||||||
|
|
||||||
vite-plugin-vuetify@^2.1.0:
|
vite-plugin-vuetify@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.2.tgz#8e28dcb5b20f4635d350010547654cf2b4dad373"
|
resolved "https://registry.yarnpkg.com/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.2.tgz#8e28dcb5b20f4635d350010547654cf2b4dad373"
|
||||||
integrity sha512-I/wd6QS+DO6lHmuGoi1UTyvvBTQ2KDzQZ9oowJQEJ6OcjWfJnscYXx2ptm6S7fJSASuZT8jGRBL3LV4oS3LpaA==
|
integrity sha512-I/wd6QS+DO6lHmuGoi1UTyvvBTQ2KDzQZ9oowJQEJ6OcjWfJnscYXx2ptm6S7fJSASuZT8jGRBL3LV4oS3LpaA==
|
||||||
@@ -11224,10 +11224,10 @@ vue@^3.4, vue@^3.5.13, vue@^3.5.22:
|
|||||||
"@vue/server-renderer" "3.5.22"
|
"@vue/server-renderer" "3.5.22"
|
||||||
"@vue/shared" "3.5.22"
|
"@vue/shared" "3.5.22"
|
||||||
|
|
||||||
vuetify-nuxt-module@^0.18.8:
|
vuetify-nuxt-module@^0.18.9:
|
||||||
version "0.18.8"
|
version "0.18.9"
|
||||||
resolved "https://registry.yarnpkg.com/vuetify-nuxt-module/-/vuetify-nuxt-module-0.18.8.tgz#04b7b04606cbf22cb9b8317309db6166a8058654"
|
resolved "https://registry.yarnpkg.com/vuetify-nuxt-module/-/vuetify-nuxt-module-0.18.9.tgz#154b8f8e689da4fac3bcb2372ef0e745b8e0b536"
|
||||||
integrity sha512-57J0MgmRTyEX4ZIIXZUyY+UodDi+hoJ9/UnUZQoBbpTc/9WAZyRonaJedIcHLnTBKyIxxWdvtWHkJdosngX3NQ==
|
integrity sha512-jr+Hujsw5U465LKJD1/SQgqJIXuJNbXM0HOp9vPmtPFPlGFwZ4kb1YfUPNmuCEDaSIY6rkb7+W+FEJvt9PQELQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nuxt/kit" "^3.12.4"
|
"@nuxt/kit" "^3.12.4"
|
||||||
defu "^6.1.4"
|
defu "^6.1.4"
|
||||||
@@ -11238,7 +11238,7 @@ vuetify-nuxt-module@^0.18.8:
|
|||||||
ufo "^1.5.4"
|
ufo "^1.5.4"
|
||||||
unconfig "^0.5.5"
|
unconfig "^0.5.5"
|
||||||
upath "^2.0.1"
|
upath "^2.0.1"
|
||||||
vite-plugin-vuetify "^2.1.0"
|
vite-plugin-vuetify "^2.1.2"
|
||||||
vuetify "^3.7.0"
|
vuetify "^3.7.0"
|
||||||
|
|
||||||
vuetify@^3.7.0:
|
vuetify@^3.7.0:
|
||||||
|
|||||||
Reference in New Issue
Block a user