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:
@@ -7,6 +7,74 @@ export type TranslationMetadata = {
|
||||
fieldsModifiedSinceTranslation?: string[];
|
||||
};
|
||||
|
||||
// Ingredient discriminated union types
|
||||
export type IngredientSection = {
|
||||
name?: string;
|
||||
type: 'section';
|
||||
list: [{
|
||||
name: string;
|
||||
unit: string;
|
||||
amount: string;
|
||||
}];
|
||||
};
|
||||
|
||||
export type IngredientReference = {
|
||||
name?: string;
|
||||
type: 'reference';
|
||||
baseRecipeRef: string; // ObjectId as string
|
||||
includeIngredients: boolean;
|
||||
showLabel: boolean;
|
||||
labelOverride?: string;
|
||||
itemsBefore?: [{
|
||||
name: string;
|
||||
unit: string;
|
||||
amount: string;
|
||||
}];
|
||||
itemsAfter?: [{
|
||||
name: string;
|
||||
unit: string;
|
||||
amount: string;
|
||||
}];
|
||||
// Populated after server-side resolution
|
||||
resolvedRecipe?: {
|
||||
_id: string;
|
||||
name: string;
|
||||
short_name: string;
|
||||
ingredients?: IngredientSection[];
|
||||
translations?: any;
|
||||
};
|
||||
};
|
||||
|
||||
export type IngredientItem = IngredientSection | IngredientReference;
|
||||
|
||||
// Instruction discriminated union types
|
||||
export type InstructionSection = {
|
||||
name?: string;
|
||||
type: 'section';
|
||||
steps: [string];
|
||||
};
|
||||
|
||||
export type InstructionReference = {
|
||||
name?: string;
|
||||
type: 'reference';
|
||||
baseRecipeRef: string; // ObjectId as string
|
||||
includeInstructions: boolean;
|
||||
showLabel: boolean;
|
||||
labelOverride?: string;
|
||||
stepsBefore?: [string];
|
||||
stepsAfter?: [string];
|
||||
// Populated after server-side resolution
|
||||
resolvedRecipe?: {
|
||||
_id: string;
|
||||
name: string;
|
||||
short_name: string;
|
||||
instructions?: InstructionSection[];
|
||||
translations?: any;
|
||||
};
|
||||
};
|
||||
|
||||
export type InstructionItem = InstructionSection | InstructionReference;
|
||||
|
||||
// Translated recipe type (English version)
|
||||
export type TranslatedRecipeType = {
|
||||
short_name: string;
|
||||
@@ -17,18 +85,8 @@ export type TranslatedRecipeType = {
|
||||
note?: string;
|
||||
category: string;
|
||||
tags?: string[];
|
||||
ingredients?: [{
|
||||
name?: string;
|
||||
list: [{
|
||||
name: string;
|
||||
unit: string;
|
||||
amount: string;
|
||||
}]
|
||||
}];
|
||||
instructions?: [{
|
||||
name?: string;
|
||||
steps: string[];
|
||||
}];
|
||||
ingredients?: IngredientItem[];
|
||||
instructions?: InstructionItem[];
|
||||
images?: [{
|
||||
alt: string;
|
||||
caption?: string;
|
||||
@@ -68,20 +126,11 @@ export type RecipeModelType = {
|
||||
portions?: string;
|
||||
cooking?: string;
|
||||
total_time?: string;
|
||||
ingredients?: [{
|
||||
name?: string;
|
||||
list: [{
|
||||
name: string;
|
||||
unit: string;
|
||||
amount: string;
|
||||
}]
|
||||
}]
|
||||
instructions?: [{
|
||||
name?: string;
|
||||
steps: [string]
|
||||
}]
|
||||
ingredients?: IngredientItem[];
|
||||
instructions?: InstructionItem[];
|
||||
preamble?: String
|
||||
addendum?: string
|
||||
isBaseRecipe?: boolean;
|
||||
translations?: {
|
||||
en?: TranslatedRecipeType;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user