feat: Replace number inputs with new v-number-input compontent (#6767)

This commit is contained in:
Michael Genson
2025-12-22 18:45:52 -06:00
committed by GitHub
parent c64c2d25e7
commit 193b823688
12 changed files with 80 additions and 134 deletions

View File

@@ -144,11 +144,13 @@
variant="underlined"
@update:model-value="setFieldValue(field, index, $event)"
/>
<v-text-field
<v-number-input
v-else-if="field.type === 'number'"
:model-value="field.value"
type="number"
variant="underlined"
control-variant="stacked"
inset
:precision="null"
@update:model-value="setFieldValue(field, index, $event)"
/>
<v-checkbox

View File

@@ -22,12 +22,15 @@
cols="12"
class="flex-grow-0 flex-shrink-0"
>
<v-text-field
<v-number-input
v-model="model.quantity"
variant="solo"
:precision="null"
:min="0"
hide-details
control-variant="stacked"
inset
density="compact"
type="number"
:placeholder="$t('recipe.quantity')"
@keypress="quantityFilter"
>
@@ -38,7 +41,7 @@
{{ $globals.icons.arrowUpDown }}
</v-icon>
</template>
</v-text-field>
</v-number-input>
</v-col>
<v-col
v-if="!state.isRecipe"

View File

@@ -10,14 +10,17 @@
v-for="(item, key, index) in modelValue"
:key="index"
>
<v-text-field
density="compact"
<v-number-input
:model-value="modelValue[key]"
:label="labels[key].label"
:suffix="labels[key].suffix"
type="number"
density="compact"
autocomplete="off"
variant="underlined"
control-variant="stacked"
inset
:precision="null"
:min="0"
@update:model-value="updateValue(key, $event)"
/>
</div>

View File

@@ -11,27 +11,27 @@
<v-container class="ma-0 pa-0">
<v-row>
<v-col cols="3">
<v-text-field
:model-value="recipeServings"
type="number"
<v-number-input
:model-value="recipe.recipeServings"
:min="0"
hide-spin-buttons
:precision="null"
density="compact"
:label="$t('recipe.servings')"
variant="underlined"
@update:model-value="validateInput($event, 'recipeServings')"
control-variant="hidden"
@update:model-value="recipe.recipeServings = $event"
/>
</v-col>
<v-col cols="3">
<v-text-field
:model-value="recipeYieldQuantity"
type="number"
<v-number-input
:model-value="recipe.recipeYieldQuantity"
:min="0"
hide-spin-buttons
:precision="null"
density="compact"
:label="$t('recipe.yield')"
variant="underlined"
@update:model-value="validateInput($event, 'recipeYieldQuantity')"
control-variant="hidden"
@update:model-value="recipe.recipeYieldQuantity = $event"
/>
</v-col>
<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";
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>

View File

@@ -65,13 +65,13 @@
</v-card-title>
<v-card-text class="mt-n5">
<div class="mt-4 d-flex align-center">
<v-text-field
<v-number-input
:model-value="yieldQuantity"
type="number"
:precision="null"
:min="0"
variant="underlined"
hide-spin-buttons
@update:model-value="recalculateScale(parseFloat($event) || 0)"
control-variant="hidden"
@update:model-value="recalculateScale($event || 0)"
/>
<v-tooltip
location="end"

View File

@@ -4,7 +4,19 @@
<v-card-text class="pb-3 pt-1">
<div class="d-md-flex align-center mb-2" style="gap: 20px">
<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>
<InputLabelType
v-model="listItem.unit"
@@ -158,6 +170,15 @@ export default defineNuxtComponent({
},
});
watch(
() => props.modelValue.quantity,
() => {
if (!props.modelValue.quantity) {
listItem.value.quantity = 0;
}
},
);
watch(
() => props.modelValue.food,
(newFood) => {
@@ -221,3 +242,10 @@ export default defineNuxtComponent({
},
});
</script>
<style scoped>
.centered-number-input :deep(.v-field) {
display: flex;
align-items: center;
}
</style>

View File

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

View File

@@ -34,7 +34,7 @@
"vue-advanced-cropper": "^2.8.9",
"vue-draggable-plus": "^0.6.0",
"vuetify": "^3.9.7",
"vuetify-nuxt-module": "^0.18.8"
"vuetify-nuxt-module": "^0.18.9"
},
"devDependencies": {
"@nuxt/eslint": "^1.2.0",

View File

@@ -134,18 +134,22 @@
<v-card>
<v-card-text>
<div>
<v-text-field
<v-number-input
v-model="settings.maxMissingFoods"
type="number"
:precision="null"
:min="0"
control-variant="stacked"
inset
hide-details
hide-spin-buttons
:label="$t('recipe-finder.max-missing-ingredients')"
/>
<v-text-field
<v-number-input
v-model="settings.maxMissingTools"
type="number"
:precision="null"
:min="0"
control-variant="stacked"
inset
hide-details
hide-spin-buttons
:label="$t('recipe-finder.max-missing-tools')"
class="mt-4"
/>

View File

@@ -30,9 +30,11 @@
/>
<v-card-text>
<v-text-field
<v-number-input
v-model="numberOfDays"
type="number"
:min="1"
control-variant="stacked"
inset
:label="$t('meal-plan.numberOfDays-label')"
:hint="$t('meal-plan.numberOfDays-hint')"
persistent-hint

View File

@@ -27,7 +27,6 @@ import type HelpIcon from "@/components/global/HelpIcon.vue";
import type ImageCropper from "@/components/global/ImageCropper.vue";
import type InputColor from "@/components/global/InputColor.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 MarkdownEditor from "@/components/global/MarkdownEditor.vue";
import type RecipeJsonEditor from "@/components/global/RecipeJsonEditor.vue";
@@ -69,7 +68,6 @@ declare module "vue" {
ImageCropper: typeof ImageCropper;
InputColor: typeof InputColor;
InputLabelType: typeof InputLabelType;
InputQuantity: typeof InputQuantity;
LanguageDialog: typeof LanguageDialog;
MarkdownEditor: typeof MarkdownEditor;
RecipeJsonEditor: typeof RecipeJsonEditor;

View File

@@ -11082,7 +11082,7 @@ vite-plugin-vue-tracer@^1.0.1:
pathe "^2.0.3"
source-map-js "^1.2.1"
vite-plugin-vuetify@^2.1.0:
vite-plugin-vuetify@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/vite-plugin-vuetify/-/vite-plugin-vuetify-2.1.2.tgz#8e28dcb5b20f4635d350010547654cf2b4dad373"
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/shared" "3.5.22"
vuetify-nuxt-module@^0.18.8:
version "0.18.8"
resolved "https://registry.yarnpkg.com/vuetify-nuxt-module/-/vuetify-nuxt-module-0.18.8.tgz#04b7b04606cbf22cb9b8317309db6166a8058654"
integrity sha512-57J0MgmRTyEX4ZIIXZUyY+UodDi+hoJ9/UnUZQoBbpTc/9WAZyRonaJedIcHLnTBKyIxxWdvtWHkJdosngX3NQ==
vuetify-nuxt-module@^0.18.9:
version "0.18.9"
resolved "https://registry.yarnpkg.com/vuetify-nuxt-module/-/vuetify-nuxt-module-0.18.9.tgz#154b8f8e689da4fac3bcb2372ef0e745b8e0b536"
integrity sha512-jr+Hujsw5U465LKJD1/SQgqJIXuJNbXM0HOp9vPmtPFPlGFwZ4kb1YfUPNmuCEDaSIY6rkb7+W+FEJvt9PQELQ==
dependencies:
"@nuxt/kit" "^3.12.4"
defu "^6.1.4"
@@ -11238,7 +11238,7 @@ vuetify-nuxt-module@^0.18.8:
ufo "^1.5.4"
unconfig "^0.5.5"
upath "^2.0.1"
vite-plugin-vuetify "^2.1.0"
vite-plugin-vuetify "^2.1.2"
vuetify "^3.7.0"
vuetify@^3.7.0: