diff --git a/dev/ingredientScaler/index.js b/dev/ingredientScaler/index.js new file mode 100644 index 000000000000..f7ba9fd9cd6f --- /dev/null +++ b/dev/ingredientScaler/index.js @@ -0,0 +1,42 @@ +import { recipeIngredient } from "./recipeIngredient"; +import { recipeNumber } from "./recipeNumber"; + +export const ingredientScaler = { + process(ingredientArray, scale) { + console.log(scale); + let workingArray = ingredientArray.map(x => + ingredientScaler.markIngredient(x) + ); + return workingArray.map(x => ingredientScaler.adjustIngredients(x, scale)); + }, + + adjustIngredients(ingredient, scale) { + var scaledQuantity = new recipeNumber(ingredient.quantity).multiply(scale); + const newText = ingredient.text.replace( + ingredient.quantity, + scaledQuantity + ); + return { ...ingredient, quantity: scaledQuantity, text: newText }; + }, + + markIngredient(ingredient) { + console.log(ingredient); + const returnVar = ingredient.replace( + /^([\d/?[^\s&]*)(?: |\s)(\w*)/g, + (match, quantity, unit) => { + return `${unit}${quantity},${match}`; + } + ); + const split = returnVar.split(","); + const [unit, quantity, match] = split; + console.log("Split", unit, quantity, match); + const n = new recipeNumber(quantity); + const i = new recipeIngredient(n, unit); + const serializedQuantity = n.isFraction() ? n.toImproperFraction() : n; + return { + unit: i, + quantity: serializedQuantity.toString(), + text: match, + }; + }, +}; diff --git a/dev/ingredientScaler/recipeIngredient.js b/dev/ingredientScaler/recipeIngredient.js new file mode 100644 index 000000000000..8bc3e2f1dcf7 --- /dev/null +++ b/dev/ingredientScaler/recipeIngredient.js @@ -0,0 +1,75 @@ +export const recipeIngredient = function(quantity, unit) { + this.quantity = quantity; + this.unit = unit; +}; + +recipeIngredient.prototype.isSingular = function() { + return this.quantity > 0 && this.quantity <= 1; +}; + +recipeIngredient.prototype.pluralize = function() { + if (this.isSingular()) { + return this.unit; + } else { + return `${this.unit}s`; + } +}; + +recipeIngredient.prototype.getSingularUnit = function() { + if (this.isSingular()) { + return this.unit; + } else { + return this.unit.replace(/s$/, ""); + } +}; + +recipeIngredient.prototype.toString = function() { + return `${this.quantity.toString()} ${this.pluralize()}`; +}; + +recipeIngredient.prototype.convertUnits = function() { + const conversion = recipeIngredient.CONVERSIONS[this.unit] || {}; + if (conversion.min && this.quantity < conversion.min.value) { + this.unit = conversion.min.next; + this.quantity.multiply(conversion.to[this.unit]); + } else if (conversion.max && this.quantity >= conversion.max.value) { + this.unit = conversion.max.next; + this.quantity.multiply(conversion.to[this.unit]); + } + return this; +}; + +recipeIngredient.CONVERSIONS = { + cup: { + to: { + tablespoon: 16, + }, + min: { + value: 1 / 4, + next: "tablespoon", + }, + }, + tablespoon: { + to: { + teaspoon: 3, + cup: 1 / 16, + }, + min: { + value: 1, + next: "teaspoon", + }, + max: { + value: 4, + next: "cup", + }, + }, + teaspoon: { + to: { + tablespoon: 1 / 3, + }, + max: { + value: 3, + next: "tablespoon", + }, + }, +}; diff --git a/dev/ingredientScaler/recipeNumber.js b/dev/ingredientScaler/recipeNumber.js new file mode 100644 index 000000000000..74579aeb6378 --- /dev/null +++ b/dev/ingredientScaler/recipeNumber.js @@ -0,0 +1,166 @@ +export const recipeNumber = function(number) { + const match = number.match( + /^(?:(\d+)|(?:(\d+)(?: | ))?(?:(\d+)\/(\d+))?)$/ + ); + if (!match || !match[0] || match[4] == "0") { + throw `Invalid number: "${number}".`; + } + this.wholeNumber = +(match[1] || match[2]); + this.numerator = +match[3]; + this.denominator = +match[4]; +}; + +/** + * Determines if the number is a fraction. + * @this {recipeNumber} + * @return {boolean} If the number is a fraction. + */ +recipeNumber.prototype.isFraction = function() { + return !!(this.numerator && this.denominator); +}; + +/** + * Determines if the fraction is proper, which is defined as + * the numerator being strictly less than the denominator. + * @this {recipeNumber} + * @return {boolean} If the fraction is proper. + */ +recipeNumber.prototype.isProperFraction = function() { + return this.numerator < this.denominator; +}; + +/** + * Determines if the fraction is improper, which is defined as + * the numerator being greater than or equal to the denominator. + * @this {recipeNumber} + * @return {boolean} If the fraction is improper. + */ +recipeNumber.prototype.isImproperFraction = function() { + return this.numerator >= this.denominator; +}; + +/** + * Determines if the fraction is mixed, which is defined as + * a whole number with a proper fraction. + * @this {recipeNumber} + * @return {boolean} If the fraction is mixed. + */ +recipeNumber.prototype.isMixedFraction = function() { + return this.isProperFraction() && !isNaN(this.wholeNumber); +}; + +/** + * Simplifies fractions. Examples: + * 3/2 = 1 1/2 + * 4/2 = 2 + * 1 3/2 = 2 1/2 + * 0/1 = 0 + * 1 0/1 = 1 + * @this {recipeNumber} + * @return {recipeNumber} The instance. + */ +recipeNumber.prototype.simplifyFraction = function() { + if (this.isImproperFraction()) { + this.wholeNumber |= 0; + this.wholeNumber += Math.floor(this.numerator / this.denominator); + const modulus = this.numerator % this.denominator; + if (modulus) { + this.numerator = modulus; + } else { + this.numerator = this.denominator = NaN; + } + } else if (this.numerator == 0) { + this.wholeNumber |= 0; + this.numerator = this.denominator = NaN; + } + return this; +}; + +/** + * Reduces a fraction. Examples: + * 2/6 = 1/3 + * 6/2 = 3/1 + * @this {recipeNumber} + * @return {recipeNumber} The instance. + */ +recipeNumber.prototype.reduceFraction = function() { + if (this.isFraction()) { + const gcd = recipeNumber.gcd(this.numerator, this.denominator); + this.numerator /= gcd; + this.denominator /= gcd; + } + return this; +}; + +/** + * Converts proper fractions to improper fractions. Examples: + * 1 1/2 = 3/2 + * 3/2 = 3/2 + * 1/2 = 1/2 + * 2 = 2 + * + * @this {recipeNumber} + * @return {recipeNumber} The instance. + */ +recipeNumber.prototype.toImproperFraction = function() { + if (!isNaN(this.wholeNumber)) { + this.numerator |= 0; + this.denominator = this.denominator || 1; + this.numerator += this.wholeNumber * this.denominator; + this.wholeNumber = NaN; + } + return this; +}; + +/** + * Multiplies the number by some decimal value. + * @param {number} multiplier The multiplier. + * @this {recipeNumber} + * @return {recipeNumber} The instance. + */ +recipeNumber.prototype.multiply = function(multiplier) { + this.toImproperFraction(); + this.numerator *= multiplier; + return this.reduceFraction().simplifyFraction(); +}; + +/** + * Gets a string representation of the number. + * @this {recipeNumber} + * @return {string} The string representation of the number. + */ +recipeNumber.prototype.toString = function() { + let number = ""; + let fraction = ""; + if (!isNaN(this.wholeNumber)) { + number += this.wholeNumber; + } + if (this.isFraction()) { + fraction = `${this.numerator}/${this.denominator}`; + } + if (number && fraction) { + number += ` ${fraction}`; + } + return number || fraction; +}; + +/** + * Gets a numeric representation of the number. + * @this {recipeNumber} + * @return {number} The numeric representation of the number. + */ +recipeNumber.prototype.valueOf = function() { + let value = this.wholeNumber || 0; + value += this.numerator / this.denominator || 0; + return value; +}; + +/** + * Euclid's algorithm to find the greatest common divisor of two numbers. + * @param {number} a One number. + * @param {number} b Another number. + * @return {number} The GCD of the numbers. + */ +recipeNumber.gcd = function gcd(a, b) { + return b ? recipeNumber.gcd(b, a % b) : a; +}; diff --git a/dev/scripts/publish-release-branch.sh b/dev/scripts/publish-release-branch.sh new file mode 100644 index 000000000000..22bd2aa8eb3d --- /dev/null +++ b/dev/scripts/publish-release-branch.sh @@ -0,0 +1,11 @@ +git checkout dev +git merge --strategy=ours master # keep the content of this branch, but record a merge +git checkout master +git merge dev # fast-forward master up to the merge + + +## TODOs + +# Create New Branch v0.x.x +# Push Branch Version to Github +# Create Pull Request \ No newline at end of file diff --git a/frontend/src/App.vue b/frontend/src/App.vue index bb545577b9a9..d9df8bf27cc5 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -9,7 +9,7 @@ > - + @@ -19,7 +19,7 @@ - - \ No newline at end of file diff --git a/frontend/src/components/Debug/LogFile.vue b/frontend/src/components/Debug/LogFile.vue deleted file mode 100644 index 47f309496af9..000000000000 --- a/frontend/src/components/Debug/LogFile.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/Admin/Theme/ColorPickerDialog.vue b/frontend/src/components/FormHelpers/ColorPickerDialog.vue similarity index 100% rename from frontend/src/components/Admin/Theme/ColorPickerDialog.vue rename to frontend/src/components/FormHelpers/ColorPickerDialog.vue diff --git a/frontend/src/components/UI/DatePicker.vue b/frontend/src/components/FormHelpers/DatePicker.vue similarity index 100% rename from frontend/src/components/UI/DatePicker.vue rename to frontend/src/components/FormHelpers/DatePicker.vue diff --git a/frontend/src/components/FormHelpers/LanguageSelector.vue b/frontend/src/components/FormHelpers/LanguageSelector.vue new file mode 100644 index 000000000000..797157173dec --- /dev/null +++ b/frontend/src/components/FormHelpers/LanguageSelector.vue @@ -0,0 +1,48 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/Admin/MealPlanner/TimePickerDialog.vue b/frontend/src/components/FormHelpers/TimePickerDialog.vue similarity index 100% rename from frontend/src/components/Admin/MealPlanner/TimePickerDialog.vue rename to frontend/src/components/FormHelpers/TimePickerDialog.vue diff --git a/frontend/src/components/Admin/Backup/ImportSummaryDialog/DataTable.vue b/frontend/src/components/ImportSummaryDialog/DataTable.vue similarity index 100% rename from frontend/src/components/Admin/Backup/ImportSummaryDialog/DataTable.vue rename to frontend/src/components/ImportSummaryDialog/DataTable.vue diff --git a/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue b/frontend/src/components/ImportSummaryDialog/index.vue similarity index 97% rename from frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue rename to frontend/src/components/ImportSummaryDialog/index.vue index 4c2f8597d49d..c41aa912e4d9 100644 --- a/frontend/src/components/Admin/Backup/ImportSummaryDialog/index.vue +++ b/frontend/src/components/ImportSummaryDialog/index.vue @@ -45,7 +45,7 @@ \ No newline at end of file diff --git a/frontend/src/components/UI/SuccessFailureAlert.vue b/frontend/src/components/UI/SuccessFailureAlert.vue deleted file mode 100644 index f9ea6836028b..000000000000 --- a/frontend/src/components/UI/SuccessFailureAlert.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/components/UI/TheAppBar.vue b/frontend/src/components/UI/TheAppBar.vue index 1c556feb6a00..72947116ae93 100644 --- a/frontend/src/components/UI/TheAppBar.vue +++ b/frontend/src/components/UI/TheAppBar.vue @@ -35,7 +35,7 @@ mdi-magnify - + mdi-magnify - +