feat: implement base recipe references with customizable ingredients and instructions
Add comprehensive base recipe system allowing recipes to reference other recipes dynamically. References can include custom items before/after the base recipe content and render as unified lists. Features: - Mark recipes as base recipes with isBaseRecipe flag - Insert base recipe references at any position in ingredients/instructions - Add custom items before/after referenced content (itemsBefore/itemsAfter, stepsBefore/stepsAfter) - Combined rendering displays all items in single unified lists - Full edit/remove functionality for additional items with modal reuse - Empty item validation prevents accidental blank entries - HTML rendering in section titles for proper <wbr> and ­ support - Reference links in section headings with multiplier preservation - Subtle hover effects (2% scale) on add buttons - Translation support for all reference fields - Deletion handling expands references before removing base recipes
This commit is contained in:
@@ -29,17 +29,56 @@ const RecipeSchema = new mongoose.Schema(
|
||||
portions :{type:String, default: ""},
|
||||
cooking: {type:String, default: ""},
|
||||
total_time : {type:String, default: ""},
|
||||
ingredients : [ { name: {type: String, default: ""},
|
||||
list: [{name: {type: String, default: ""},
|
||||
unit: String,
|
||||
amount: String,
|
||||
}]
|
||||
ingredients: [{
|
||||
// Common fields
|
||||
name: { type: String, default: "" },
|
||||
type: { type: String, enum: ['section', 'reference'], default: 'section' },
|
||||
|
||||
// For type='section' (existing structure)
|
||||
list: [{
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}],
|
||||
|
||||
// For type='reference' (new base recipe references)
|
||||
baseRecipeRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
|
||||
includeIngredients: { type: Boolean, default: true },
|
||||
showLabel: { type: Boolean, default: true },
|
||||
labelOverride: { type: String, default: "" },
|
||||
itemsBefore: [{
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}],
|
||||
itemsAfter: [{
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}],
|
||||
}],
|
||||
instructions : [{name: {type: String, default: ""},
|
||||
steps: [String]}],
|
||||
instructions: [{
|
||||
// Common fields
|
||||
name: { type: String, default: "" },
|
||||
type: { type: String, enum: ['section', 'reference'], default: 'section' },
|
||||
|
||||
// For type='section' (existing structure)
|
||||
steps: [String],
|
||||
|
||||
// For type='reference' (new base recipe references)
|
||||
baseRecipeRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
|
||||
includeInstructions: { type: Boolean, default: true },
|
||||
showLabel: { type: Boolean, default: true },
|
||||
labelOverride: { type: String, default: "" },
|
||||
stepsBefore: [String],
|
||||
stepsAfter: [String],
|
||||
}],
|
||||
preamble : String,
|
||||
addendum : String,
|
||||
|
||||
// Base recipe flag
|
||||
isBaseRecipe: {type: Boolean, default: false},
|
||||
|
||||
// English translations
|
||||
translations: {
|
||||
en: {
|
||||
@@ -65,16 +104,38 @@ const RecipeSchema = new mongoose.Schema(
|
||||
final: {type: String},
|
||||
},
|
||||
ingredients: [{
|
||||
name: {type: String, default: ""},
|
||||
name: { type: String, default: "" },
|
||||
type: { type: String, enum: ['section', 'reference'], default: 'section' },
|
||||
list: [{
|
||||
name: {type: String, default: ""},
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}]
|
||||
}],
|
||||
baseRecipeRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
|
||||
includeIngredients: { type: Boolean, default: true },
|
||||
showLabel: { type: Boolean, default: true },
|
||||
labelOverride: { type: String, default: "" },
|
||||
itemsBefore: [{
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}],
|
||||
itemsAfter: [{
|
||||
name: { type: String, default: "" },
|
||||
unit: String,
|
||||
amount: String,
|
||||
}],
|
||||
}],
|
||||
instructions: [{
|
||||
name: {type: String, default: ""},
|
||||
steps: [String]
|
||||
name: { type: String, default: "" },
|
||||
type: { type: String, enum: ['section', 'reference'], default: 'section' },
|
||||
steps: [String],
|
||||
baseRecipeRef: { type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' },
|
||||
includeInstructions: { type: Boolean, default: true },
|
||||
showLabel: { type: Boolean, default: true },
|
||||
labelOverride: { type: String, default: "" },
|
||||
stepsBefore: [String],
|
||||
stepsAfter: [String],
|
||||
}],
|
||||
images: [{
|
||||
alt: String,
|
||||
|
||||
Reference in New Issue
Block a user