mirror of
https://github.com/runyanjake/cooking.git
synced 2026-03-26 01:43:17 -07:00
Import recipes from original repo.
This commit is contained in:
parent
4bbb8e4cfe
commit
e182dd0244
@ -11,7 +11,9 @@
|
||||
"Bash(dir:*)",
|
||||
"Bash(findstr:*)",
|
||||
"Bash(timeout 10 npm run dev:*)",
|
||||
"Bash(grep:*)"
|
||||
"Bash(grep:*)",
|
||||
"Read(//c/Users/runya/Documents/repositories/recipes/recipes/docs/**)",
|
||||
"Bash(node scripts/import-recipes.js:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
77
app/page.tsx
77
app/page.tsx
@ -1,3 +1,4 @@
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
export default function Home() {
|
||||
@ -26,27 +27,65 @@ export default function Home() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="grid md:grid-cols-3 gap-8 pt-12">
|
||||
<div className="text-center space-y-3">
|
||||
<div className="text-4xl">🍳</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">Easy Recipes</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
Step-by-step instructions for home cooks of all skill levels
|
||||
</p>
|
||||
<section className="space-y-24 pt-16">
|
||||
<div className="flex flex-col md:flex-row items-center gap-12">
|
||||
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
|
||||
<Image
|
||||
src="/assets/want_to_cook.svg"
|
||||
alt="Person deciding what to cook"
|
||||
fill
|
||||
className="object-cover"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full md:w-2/5 space-y-4">
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Easy Recipes</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||
Step-by-step instructions for home cooks of all skill levels. Whether you're a beginner or an experienced cook, every recipe is written with clarity in mind.
|
||||
</p>
|
||||
<Link
|
||||
href="/recipes"
|
||||
className="inline-block px-5 py-2.5 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-700 dark:hover:bg-gray-200 transition-colors font-medium"
|
||||
>
|
||||
Browse Recipes
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center space-y-3">
|
||||
<div className="text-4xl">📸</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">Beautiful Photos</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
High-quality images to inspire your cooking journey
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col md:flex-row-reverse items-center gap-12">
|
||||
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
|
||||
<Image
|
||||
src="/assets/online_cookbook.svg"
|
||||
alt="Online cookbook illustration"
|
||||
fill
|
||||
className="object-cover"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full md:w-2/5 space-y-4">
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Beautiful Photos</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||
High-quality images accompany every recipe to inspire your cooking journey. See exactly what you're making before you start.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center space-y-3">
|
||||
<div className="text-4xl">🏷️</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 dark:text-white">Organized</h3>
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
Find recipes by tags, ingredients, and dietary preferences
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col md:flex-row items-center gap-12">
|
||||
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
|
||||
<Image
|
||||
src="/assets/recipe_sites_suck.svg"
|
||||
alt="Organized recipe collection"
|
||||
fill
|
||||
className="object-cover"
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full md:w-2/5 space-y-4">
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">No Nonsense</h2>
|
||||
<p className="text-lg text-gray-600 dark:text-gray-400">
|
||||
Just recipes. Find what you need quickly by browsing categories, filtering by tags, or searching by ingredient.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { Suspense } from 'react';
|
||||
import type { Metadata } from 'next';
|
||||
import { getAllRecipes, getAllCategories, getAllTags } from '@/lib/recipes';
|
||||
import RecipesClient from '@/components/RecipesClient';
|
||||
@ -23,7 +24,13 @@ export default function RecipesPage() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<RecipesClient recipes={recipes} categories={categories} tags={tags} />
|
||||
<Suspense fallback={
|
||||
<div className="text-center py-12 text-gray-500 dark:text-gray-400">
|
||||
Loading recipes...
|
||||
</div>
|
||||
}>
|
||||
<RecipesClient recipes={recipes} categories={categories} tags={tags} />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback, ReactNode } from 'react';
|
||||
import RecipesSidebar, { type FilterState } from './RecipesSidebar';
|
||||
import RecipesSidebar from './RecipesSidebar';
|
||||
import type { FilterState } from '@/lib/types';
|
||||
|
||||
interface RecipeLayoutProps {
|
||||
children: ReactNode;
|
||||
categories: string[];
|
||||
tags: string[];
|
||||
filters?: FilterState;
|
||||
onFilterChange?: (filters: FilterState) => void;
|
||||
showFilters?: boolean;
|
||||
}
|
||||
@ -15,14 +17,15 @@ export default function RecipeLayout({
|
||||
children,
|
||||
categories,
|
||||
tags,
|
||||
filters,
|
||||
onFilterChange,
|
||||
showFilters = true
|
||||
}: RecipeLayoutProps) {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
const handleFilterChange = useCallback((filters: FilterState) => {
|
||||
const handleFilterChange = useCallback((newFilters: FilterState) => {
|
||||
if (onFilterChange) {
|
||||
onFilterChange(filters);
|
||||
onFilterChange(newFilters);
|
||||
}
|
||||
}, [onFilterChange]);
|
||||
|
||||
@ -76,10 +79,11 @@ export default function RecipeLayout({
|
||||
</button>
|
||||
|
||||
{/* Sidebar content */}
|
||||
{showFilters && (
|
||||
{showFilters && filters && (
|
||||
<RecipesSidebar
|
||||
categories={categories}
|
||||
tags={tags}
|
||||
filters={filters}
|
||||
onFilterChange={handleFilterChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -28,7 +28,12 @@ export default function RecipePageClient({ recipe, sections }: RecipePageClientP
|
||||
|
||||
<header className="mb-8 space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
<span className="capitalize">{recipe.category}</span>
|
||||
<Link
|
||||
href={`/recipes?category=${encodeURIComponent(recipe.category)}`}
|
||||
className="capitalize hover:text-gray-900 dark:hover:text-white transition-colors"
|
||||
>
|
||||
{recipe.category}
|
||||
</Link>
|
||||
<span>•</span>
|
||||
<time dateTime={recipe.date}>
|
||||
Published {new Date(recipe.date).toLocaleDateString('en-US', {
|
||||
@ -84,13 +89,14 @@ export default function RecipePageClient({ recipe, sections }: RecipePageClientP
|
||||
|
||||
<div className="flex flex-wrap gap-2" role="list" aria-label="Recipe tags">
|
||||
{recipe.tags.map((tag) => (
|
||||
<span
|
||||
<Link
|
||||
key={tag}
|
||||
href={`/recipes?tags=${encodeURIComponent(tag)}`}
|
||||
role="listitem"
|
||||
className="px-3 py-1 text-sm bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-full"
|
||||
className="px-3 py-1 text-sm bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -127,7 +127,6 @@ export default function RecipeTabs({ sections, folderPath }: RecipeTabsProps) {
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
// Don't override <p> - let ReactMarkdown handle it to avoid hydration errors
|
||||
code: ({ inline, children, ...props }: any) => {
|
||||
if (inline) {
|
||||
return (
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useState, useMemo, useEffect, useCallback, useRef } from 'react';
|
||||
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
|
||||
import RecipeLayout from './RecipeLayout';
|
||||
import { FilterState } from './RecipesSidebar';
|
||||
import RecipeCard from './RecipeCard';
|
||||
import type { Recipe } from '@/lib/recipes';
|
||||
import type { FilterState } from '@/lib/types';
|
||||
|
||||
interface RecipesClientProps {
|
||||
recipes: Recipe[];
|
||||
@ -12,12 +13,52 @@ interface RecipesClientProps {
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
function parseFiltersFromParams(searchParams: URLSearchParams): FilterState {
|
||||
return {
|
||||
search: searchParams.get('search') || '',
|
||||
category: searchParams.get('category') || '',
|
||||
selectedTags: searchParams.get('tags')
|
||||
? [...new Set(searchParams.get('tags')!.split(',').filter(Boolean))]
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
function buildQueryString(filters: FilterState): string {
|
||||
const params = new URLSearchParams();
|
||||
if (filters.search) params.set('search', filters.search);
|
||||
if (filters.category) params.set('category', filters.category);
|
||||
if (filters.selectedTags.length > 0) params.set('tags', filters.selectedTags.join(','));
|
||||
const qs = params.toString();
|
||||
return qs ? `?${qs}` : '';
|
||||
}
|
||||
|
||||
export default function RecipesClient({ recipes, categories, tags }: RecipesClientProps) {
|
||||
const [filters, setFilters] = useState<FilterState>({
|
||||
search: '',
|
||||
category: '',
|
||||
selectedTags: [],
|
||||
});
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const [filters, setFilters] = useState<FilterState>(() =>
|
||||
parseFiltersFromParams(searchParams)
|
||||
);
|
||||
|
||||
// Track internal updates to avoid reacting to our own URL changes
|
||||
const isInternalUpdate = useRef(false);
|
||||
|
||||
// Sync URL → state on browser back/forward
|
||||
useEffect(() => {
|
||||
if (isInternalUpdate.current) {
|
||||
isInternalUpdate.current = false;
|
||||
return;
|
||||
}
|
||||
setFilters(parseFiltersFromParams(searchParams));
|
||||
}, [searchParams]);
|
||||
|
||||
// Update filters and sync to URL
|
||||
const updateFilters = useCallback((newFilters: FilterState) => {
|
||||
isInternalUpdate.current = true;
|
||||
setFilters(newFilters);
|
||||
router.replace(`${pathname}${buildQueryString(newFilters)}`, { scroll: false });
|
||||
}, [router, pathname]);
|
||||
|
||||
const filteredRecipes = useMemo(() => {
|
||||
return recipes.filter((recipe) => {
|
||||
@ -47,7 +88,8 @@ export default function RecipesClient({ recipes, categories, tags }: RecipesClie
|
||||
<RecipeLayout
|
||||
categories={categories}
|
||||
tags={tags}
|
||||
onFilterChange={setFilters}
|
||||
filters={filters}
|
||||
onFilterChange={updateFilters}
|
||||
showFilters={true}
|
||||
>
|
||||
<div className="mb-4 text-sm text-gray-600 dark:text-gray-400">
|
||||
|
||||
@ -3,49 +3,54 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import SelectedTags from './SelectedTags';
|
||||
import TagSelector from './TagSelector';
|
||||
import type { FilterState } from '@/lib/types';
|
||||
|
||||
interface RecipesSidebarProps {
|
||||
categories: string[];
|
||||
tags: string[];
|
||||
filters: FilterState;
|
||||
onFilterChange: (filters: FilterState) => void;
|
||||
}
|
||||
|
||||
export interface FilterState {
|
||||
search: string;
|
||||
category: string;
|
||||
selectedTags: string[];
|
||||
}
|
||||
|
||||
export default function RecipesSidebar({ categories, tags, onFilterChange }: RecipesSidebarProps) {
|
||||
const [search, setSearch] = useState('');
|
||||
const [category, setCategory] = useState('');
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||
export default function RecipesSidebar({ categories, tags, filters, onFilterChange }: RecipesSidebarProps) {
|
||||
const [searchInput, setSearchInput] = useState(filters.search);
|
||||
|
||||
// Sync external search changes (e.g. "Clear All" or URL-driven) to local input
|
||||
useEffect(() => {
|
||||
onFilterChange({ search, category, selectedTags });
|
||||
}, [search, category, selectedTags, onFilterChange]);
|
||||
setSearchInput(filters.search);
|
||||
}, [filters.search]);
|
||||
|
||||
// Debounce local search input → parent
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
if (searchInput !== filters.search) {
|
||||
onFilterChange({ ...filters, search: searchInput });
|
||||
}
|
||||
}, 300);
|
||||
return () => clearTimeout(timer);
|
||||
}, [searchInput, filters, onFilterChange]);
|
||||
|
||||
const handleTagToggle = (tag: string) => {
|
||||
setSelectedTags((prev) =>
|
||||
prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
|
||||
);
|
||||
const selectedTags = filters.selectedTags.includes(tag)
|
||||
? filters.selectedTags.filter((t) => t !== tag)
|
||||
: [...filters.selectedTags, tag];
|
||||
onFilterChange({ ...filters, selectedTags });
|
||||
};
|
||||
|
||||
const handleRemoveTag = (tag: string) => {
|
||||
setSelectedTags((prev) => prev.filter((t) => t !== tag));
|
||||
onFilterChange({ ...filters, selectedTags: filters.selectedTags.filter((t) => t !== tag) });
|
||||
};
|
||||
|
||||
const handleClearTags = () => {
|
||||
setSelectedTags([]);
|
||||
onFilterChange({ ...filters, selectedTags: [] });
|
||||
};
|
||||
|
||||
const handleClearFilters = () => {
|
||||
setSearch('');
|
||||
setCategory('');
|
||||
setSelectedTags([]);
|
||||
setSearchInput('');
|
||||
onFilterChange({ search: '', category: '', selectedTags: [] });
|
||||
};
|
||||
|
||||
const hasActiveFilters = search || category || selectedTags.length > 0;
|
||||
const hasActiveFilters = searchInput || filters.category || filters.selectedTags.length > 0;
|
||||
|
||||
return (
|
||||
<section aria-label="Recipe filters">
|
||||
@ -57,8 +62,8 @@ export default function RecipesSidebar({ categories, tags, onFilterChange }: Rec
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
value={searchInput}
|
||||
onChange={(e) => setSearchInput(e.target.value)}
|
||||
placeholder="Search recipes..."
|
||||
className="w-full px-2 py-1.5 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
@ -70,8 +75,8 @@ export default function RecipesSidebar({ categories, tags, onFilterChange }: Rec
|
||||
</label>
|
||||
<select
|
||||
id="category"
|
||||
value={category}
|
||||
onChange={(e) => setCategory(e.target.value)}
|
||||
value={filters.category}
|
||||
onChange={(e) => onFilterChange({ ...filters, category: e.target.value })}
|
||||
className="w-full px-2 py-1.5 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">All Categories</option>
|
||||
@ -89,14 +94,14 @@ export default function RecipesSidebar({ categories, tags, onFilterChange }: Rec
|
||||
</label>
|
||||
|
||||
<SelectedTags
|
||||
tags={selectedTags}
|
||||
tags={filters.selectedTags}
|
||||
onRemove={handleRemoveTag}
|
||||
onClear={handleClearTags}
|
||||
/>
|
||||
|
||||
<TagSelector
|
||||
availableTags={tags}
|
||||
selectedTags={selectedTags}
|
||||
selectedTags={filters.selectedTags}
|
||||
onToggleTag={handleTagToggle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -48,7 +48,7 @@ export default function TagSelector({ availableTags, selectedTags, onToggleTag }
|
||||
{isOpen && (
|
||||
<div
|
||||
id="tag-selector-dropdown"
|
||||
className="absolute top-full left-0 right-0 mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg z-50 max-h-80 flex flex-col"
|
||||
className="mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg max-h-48 flex flex-col"
|
||||
role="dialog"
|
||||
aria-label="Tag selection"
|
||||
>
|
||||
@ -62,7 +62,6 @@ export default function TagSelector({ availableTags, selectedTags, onToggleTag }
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder="Search tags..."
|
||||
className="w-full px-2 py-1.5 text-sm border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-900 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
autoFocus
|
||||
aria-describedby="tag-search-description"
|
||||
/>
|
||||
<span id="tag-search-description" className="sr-only">
|
||||
|
||||
@ -17,8 +17,8 @@ public/recipes/
|
||||
Each recipe follows this structure:
|
||||
```
|
||||
public/recipes/category/
|
||||
└── YYYY.MM.DD-recipe-slug/
|
||||
├── YYYY.MM.DD-recipe-slug.mdx
|
||||
└── recipe-slug/
|
||||
├── recipe-slug.mdx
|
||||
└── assets/
|
||||
├── hero.jpg
|
||||
├── step1.jpg
|
||||
@ -64,21 +64,21 @@ displayPhoto: "./assets/hero.jpg"
|
||||
- `slug` - URL-friendly identifier
|
||||
- `date` - Publication date (YYYY-MM-DD)
|
||||
- `lastUpdated` - Last modification date (YYYY-MM-DD)
|
||||
- `category` - Main category ID (references `../taxonomy.json`)
|
||||
- `tags` - Array of tag IDs (references `../taxonomy.json`)
|
||||
- `dietary` - Array of dietary tag IDs (references `../taxonomy.json`)
|
||||
- `category` - Main category (free-form string, e.g. "mains", "soups")
|
||||
- `tags` - Array of tags (free-form strings, e.g. ["italian", "chicken"])
|
||||
- `dietary` - Array of dietary tags (free-form strings, e.g. ["gluten-free"])
|
||||
- `cookTime` - Active cooking time in minutes
|
||||
- `prepTime` - Preparation time in minutes
|
||||
- `totalTime` - Total time in minutes
|
||||
- `difficulty` - Difficulty ID: easy, medium, or hard (references `../taxonomy.json`)
|
||||
- `difficulty` - Difficulty level: easy, medium, or hard
|
||||
- `servings` - Number of servings
|
||||
- `author` - Author ID (references `../authors.json`)
|
||||
- `author` - Author ID (references `public/authors.json`)
|
||||
- `description` - Brief description for SEO and cards
|
||||
- `featured` - Boolean for homepage featuring
|
||||
- `display` - Boolean to control visibility (set to false to hide recipe)
|
||||
- `displayPhoto` - Relative path to display photo (e.g., "./assets/hero.jpg")
|
||||
|
||||
**Note:** Use IDs from the reference files (`data/authors.json` and `data/taxonomy.json`) to ensure consistency and enable validation.
|
||||
**Note:** Author IDs must match entries in `public/authors.json`. Categories, tags, dietary, and difficulty are free-form strings — there is no taxonomy registry file.
|
||||
|
||||
#### Content Sections
|
||||
|
||||
@ -197,8 +197,8 @@ Choose from these categories:
|
||||
|
||||
## Adding New Recipes
|
||||
|
||||
1. Create recipe folder: `public/recipes/[category]/YYYY.MM.DD-recipe-name/`
|
||||
2. Create `YYYY.MM.DD-recipe-name.mdx` with frontmatter and content
|
||||
1. Create recipe folder: `public/recipes/[category]/recipe-name/`
|
||||
2. Create `recipe-name.mdx` with frontmatter and content
|
||||
3. Create `assets/` subfolder for images
|
||||
4. Add images to the `assets/` folder
|
||||
5. Reference images in MDX using relative paths: `./assets/image.jpg`
|
||||
@ -207,7 +207,6 @@ Choose from these categories:
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use consistent date formatting (YYYY.MM.DD)
|
||||
- Keep slugs URL-friendly (lowercase, hyphens)
|
||||
- Optimize images before adding (compress, resize)
|
||||
- Test recipes before publishing
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
---
|
||||
title: "Classic Chicken Parmesan"
|
||||
slug: "chicken-parmesan"
|
||||
date: "2026-02-05"
|
||||
lastUpdated: "2026-02-05"
|
||||
category: "mains"
|
||||
tags: ["italian", "chicken", "comfort-food", "family-friendly"]
|
||||
dietary: ["gluten-free-option"]
|
||||
cookTime: 45
|
||||
prepTime: 20
|
||||
totalTime: 65
|
||||
difficulty: "medium"
|
||||
servings: 4
|
||||
author: "pws"
|
||||
description: "A classic Italian-American dish featuring crispy breaded chicken topped with marinara sauce and melted cheese."
|
||||
featured: true
|
||||
display: true
|
||||
displayPhoto: "./assets/not-found.svg"
|
||||
---
|
||||
|
||||
# Classic Chicken Parmesan
|
||||
|
||||
A beloved Italian-American comfort food that combines crispy breaded chicken cutlets with rich marinara sauce and gooey melted cheese. Perfect for a family dinner or special occasion.
|
||||
|
||||
## Photos
|
||||
|
||||

|
||||
*Golden-brown chicken topped with bubbling cheese*
|
||||
|
||||

|
||||
*Perfectly crispy coating with melted mozzarella*
|
||||
|
||||

|
||||
*Served alongside spaghetti with fresh basil*
|
||||
|
||||
## Ingredients
|
||||
|
||||
### For the Chicken
|
||||
- 4 boneless, skinless chicken breasts (about 6-8 oz each)
|
||||
- 1 cup all-purpose flour
|
||||
- 2 large eggs, beaten
|
||||
- 2 cups Italian-style breadcrumbs
|
||||
- 1 cup grated Parmesan cheese (divided)
|
||||
- 1 teaspoon garlic powder
|
||||
- 1 teaspoon dried oregano
|
||||
- Salt and freshly ground black pepper to taste
|
||||
- 1/2 cup olive oil (for frying)
|
||||
|
||||
### For the Sauce & Topping
|
||||
- 2 cups marinara sauce (homemade or quality store-bought)
|
||||
- 1 1/2 cups shredded mozzarella cheese
|
||||
- 1/4 cup fresh basil leaves, torn
|
||||
- Extra Parmesan for serving
|
||||
|
||||
## Instructions
|
||||
|
||||
### Prep the Chicken
|
||||
1. Place **chicken breasts** between two sheets of **plastic wrap** and pound to an even 1/2-inch thickness using a meat mallet.
|
||||
2. Season both sides generously with **salt** and **pepper**.
|
||||
|
||||
### Set Up Breading Station
|
||||
3. Prepare three shallow dishes:
|
||||
- Dish 1: **All-purpose flour**
|
||||
- Dish 2: Beaten **eggs** with 1 tablespoon **water**
|
||||
- Dish 3: **Breadcrumbs** mixed with 1/2 cup **Parmesan**, **garlic powder**, and **oregano**
|
||||
|
||||
### Bread and Fry
|
||||
4. Dredge each breast in **flour** (shake off excess), dip in **egg** mixture, then press firmly into **breadcrumb** mixture, coating both sides thoroughly.
|
||||
5. In a large skillet, heat **olive oil** over medium-high heat until shimmering.
|
||||
6. Cook **chicken** for 4-5 minutes per side until golden brown and cooked through (internal temp 165°F). Work in batches if needed. Transfer to a paper towel-lined plate.
|
||||
|
||||
### Assemble and Bake
|
||||
7. Preheat oven to 400°F (200°C) or turn on broiler.
|
||||
8. Place fried **chicken** in a baking dish. Spoon **marinara sauce** over each piece, then top with **mozzarella** and remaining **Parmesan**.
|
||||
9. Bake for 10-12 minutes (or broil for 3-4 minutes) until cheese is melted and bubbly.
|
||||
10. Top with fresh torn **basil** and serve immediately with **pasta** or a side salad.
|
||||
|
||||
## Notes
|
||||
|
||||
### Tips for Success
|
||||
- **Even thickness**: Pounding the chicken ensures even cooking
|
||||
- **Don't overcrowd**: Fry in batches to maintain oil temperature
|
||||
- **Quality ingredients**: Use good marinara sauce for best flavor
|
||||
- **Make ahead**: Bread chicken up to 4 hours ahead and refrigerate
|
||||
- **Gluten-free option**: Substitute with gluten-free flour and breadcrumbs
|
||||
|
||||
### Storage
|
||||
- **Refrigerate**: Store leftovers in an airtight container for up to 3 days
|
||||
- **Reheat**: Warm in a 350°F oven for 15-20 minutes to maintain crispiness
|
||||
- **Freeze**: Freeze breaded (uncooked) chicken for up to 2 months
|
||||
|
||||
### Variations
|
||||
- **Baked version**: Skip frying and bake breaded chicken at 425°F for 20-25 minutes
|
||||
- **Spicy**: Add red pepper flakes to the breadcrumb mixture
|
||||
- **Extra crispy**: Use panko breadcrumbs instead of Italian breadcrumbs
|
||||
|
||||
## References
|
||||
|
||||
- Adapted from traditional Italian-American recipes
|
||||
- Inspired by *The Silver Spoon* Italian cookbook
|
||||
- Breading technique from classic French *cotoletta* method
|
||||
@ -1,148 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
id="svg2"
|
||||
sodipodi:docname="_svgclean2.svg"
|
||||
viewBox="0 0 260 310"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
bordercolor="#666666"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-y="19"
|
||||
fit-margin-left="0"
|
||||
pagecolor="#ffffff"
|
||||
fit-margin-top="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="768"
|
||||
showgrid="false"
|
||||
borderopacity="1.0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:cx="-57.248774"
|
||||
inkscape:cy="-575.52494"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:document-units="px"
|
||||
>
|
||||
<inkscape:grid
|
||||
id="grid3769"
|
||||
originy="-752.36218px"
|
||||
enabled="true"
|
||||
originx="-35.03125px"
|
||||
visible="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
type="xygrid"
|
||||
empspacing="4"
|
||||
/>
|
||||
</sodipodi:namedview
|
||||
>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(-242.06 -371.19)"
|
||||
>
|
||||
<path
|
||||
id="rect3757"
|
||||
style="stroke:#636363;stroke-width:6;fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m38 53v304h254v-226.22l-77.78-77.78h-176.22z"
|
||||
transform="translate(207.06 321.19)"
|
||||
/>
|
||||
<g
|
||||
id="g3915"
|
||||
transform="translate(0 17.678)"
|
||||
>
|
||||
<rect
|
||||
id="rect3759"
|
||||
style="stroke-linejoin:round;stroke:#a6a6a6;stroke-linecap:round;stroke-width:6;fill:#ffffff"
|
||||
height="150"
|
||||
width="130"
|
||||
y="451.19"
|
||||
x="307.06"
|
||||
/>
|
||||
<path
|
||||
id="path3761"
|
||||
d="m343.53 497.65 57.065 57.065"
|
||||
style="stroke-linejoin:round;stroke:#e00000;stroke-linecap:round;stroke-width:12;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
/>
|
||||
<path
|
||||
id="path3763"
|
||||
style="stroke-linejoin:round;stroke:#e00000;stroke-linecap:round;stroke-width:12;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m400.6 497.65-57.065 57.065"
|
||||
/>
|
||||
</g
|
||||
>
|
||||
<path
|
||||
id="rect3911"
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="stroke-linejoin:round;stroke:#636363;stroke-width:6;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m499.06 451.97h-77.782v-77.782"
|
||||
/>
|
||||
</g
|
||||
>
|
||||
<metadata
|
||||
id="metadata13"
|
||||
>
|
||||
<rdf:RDF
|
||||
>
|
||||
<cc:Work
|
||||
>
|
||||
<dc:format
|
||||
>image/svg+xml</dc:format
|
||||
>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
|
||||
/>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
|
||||
/>
|
||||
<dc:publisher
|
||||
>
|
||||
<cc:Agent
|
||||
rdf:about="http://openclipart.org/"
|
||||
>
|
||||
<dc:title
|
||||
>Openclipart</dc:title
|
||||
>
|
||||
</cc:Agent
|
||||
>
|
||||
</dc:publisher
|
||||
>
|
||||
</cc:Work
|
||||
>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/publicdomain/"
|
||||
>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction"
|
||||
/>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution"
|
||||
/>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
|
||||
/>
|
||||
</cc:License
|
||||
>
|
||||
</rdf:RDF
|
||||
>
|
||||
</metadata
|
||||
>
|
||||
</svg
|
||||
>
|
||||
|
Before Width: | Height: | Size: 3.9 KiB |
@ -1,116 +0,0 @@
|
||||
---
|
||||
title: "Perfect Chocolate Chip Cookies"
|
||||
slug: "chocolate-chip-cookies"
|
||||
date: "2026-02-08"
|
||||
lastUpdated: "2026-02-08"
|
||||
category: "desserts"
|
||||
tags: ["cookies", "chocolate", "baking", "dessert", "american"]
|
||||
dietary: ["vegetarian"]
|
||||
cookTime: 12
|
||||
prepTime: 15
|
||||
totalTime: 27
|
||||
difficulty: "easy"
|
||||
servings: 24
|
||||
author: "pws"
|
||||
description: "Classic chewy chocolate chip cookies with crispy edges and gooey centers, loaded with chocolate chips."
|
||||
featured: true
|
||||
display: true
|
||||
displayPhoto: "./assets/not-found.svg"
|
||||
---
|
||||
|
||||
# Perfect Chocolate Chip Cookies
|
||||
|
||||
The ultimate chocolate chip cookie recipe that delivers crispy edges, chewy centers, and loads of melty chocolate chips in every bite. This recipe has been tested and perfected to create bakery-style cookies at home.
|
||||
|
||||
## Photos
|
||||
|
||||

|
||||
*A stack of golden-brown cookies showing the perfect texture*
|
||||
|
||||

|
||||
*Gooey chocolate chips and perfect chewy texture*
|
||||
|
||||

|
||||
*Fresh from the oven with melted chocolate*
|
||||
|
||||

|
||||
*The perfect cookie and milk pairing*
|
||||
|
||||
## Ingredients
|
||||
|
||||
### Dry Ingredients
|
||||
- 2 1/4 cups (280g) all-purpose flour
|
||||
- 1 teaspoon baking soda
|
||||
- 1 teaspoon fine sea salt
|
||||
|
||||
### Wet Ingredients
|
||||
- 1 cup (2 sticks / 226g) unsalted butter, softened to room temperature
|
||||
- 3/4 cup (150g) granulated sugar
|
||||
- 3/4 cup (165g) packed light brown sugar
|
||||
- 2 large eggs, room temperature
|
||||
- 2 teaspoons pure vanilla extract
|
||||
|
||||
### Mix-ins
|
||||
- 2 cups (340g) semi-sweet chocolate chips
|
||||
- 1 cup (170g) milk chocolate chips (optional, for extra chocolate)
|
||||
- Flaky sea salt for topping (optional)
|
||||
|
||||
## Instructions
|
||||
|
||||
### Prepare
|
||||
1. Preheat oven to 375°F (190°C). Line two baking sheets with **parchment paper**.
|
||||
2. In a medium bowl, whisk together **flour**, **baking soda**, and **salt**. Set aside.
|
||||
|
||||
### Make the Dough
|
||||
3. In a large bowl or stand mixer, beat softened **butter** with both **sugars** on medium speed for 2-3 minutes until light and fluffy.
|
||||
4. Beat in **eggs** one at a time, then add **vanilla extract**. Mix until well combined, scraping down the sides of the bowl.
|
||||
5. With mixer on low speed, gradually add the **flour** mixture. Mix just until no flour streaks remain (don't overmix).
|
||||
6. Use a spatula or wooden spoon to fold in **chocolate chips** until evenly distributed.
|
||||
|
||||
### Chill (Important!)
|
||||
7. Cover bowl with **plastic wrap** and refrigerate for at least 30 minutes (or up to 72 hours for even better flavor). Cold dough = thicker cookies!
|
||||
|
||||
### Bake
|
||||
8. Use a cookie scoop or tablespoon to form balls (about 2 tablespoons each). Place 2 inches apart on prepared baking sheets.
|
||||
9. If using, sprinkle a tiny pinch of **flaky sea salt** on top of each dough ball.
|
||||
10. Bake for 10-12 minutes until edges are golden brown but centers still look slightly underdone.
|
||||
11. Let cookies cool on the baking sheet for 5 minutes (they'll continue to set), then transfer to a wire rack.
|
||||
|
||||
### Serve
|
||||
12. Serve warm or at room temperature. Best enjoyed with cold **milk**!
|
||||
|
||||
## Notes
|
||||
|
||||
### Tips for Success
|
||||
- **Room temperature ingredients**: Softened butter and eggs create the best texture
|
||||
- **Don't skip chilling**: Cold dough prevents spreading and creates thicker cookies
|
||||
- **Underbake slightly**: Cookies will look underdone but will set as they cool
|
||||
- **Use parchment paper**: Prevents sticking and promotes even browning
|
||||
- **Measure flour correctly**: Spoon and level flour, don't pack it
|
||||
|
||||
### Storage & Freezing
|
||||
- **Room temperature**: Store in an airtight container for up to 5 days
|
||||
- **Refresh**: Warm in a 300°F oven for 3-4 minutes to restore chewiness
|
||||
- **Freeze dough**: Scoop dough balls and freeze for up to 3 months. Bake from frozen, adding 1-2 minutes
|
||||
- **Freeze baked cookies**: Freeze baked cookies for up to 2 months
|
||||
|
||||
### Variations
|
||||
- **Brown butter cookies**: Brown the butter for a nutty, caramel flavor
|
||||
- **Thick and bakery-style**: Increase flour to 2 1/2 cups and chill overnight
|
||||
- **Double chocolate**: Add 1/4 cup cocoa powder to dry ingredients
|
||||
- **Mix-ins**: Try nuts, toffee bits, or different chocolate varieties
|
||||
- **Giant cookies**: Use 1/4 cup dough per cookie, bake 14-16 minutes
|
||||
|
||||
### Science Behind the Recipe
|
||||
- **Brown sugar**: Creates chewiness and moisture
|
||||
- **Granulated sugar**: Creates crispy edges
|
||||
- **Baking soda**: Promotes spreading and browning
|
||||
- **Chilling**: Allows flour to hydrate and flavors to develop
|
||||
- **Underbaking**: Keeps centers soft and gooey
|
||||
|
||||
## References
|
||||
|
||||
- Based on the classic Nestlé Toll House recipe
|
||||
- Chilling technique from *The Food Lab* by J. Kenji López-Alt
|
||||
- Brown butter variation inspired by *BraveTart* by Stella Parks
|
||||
- Tested with feedback from family and friends over multiple batches
|
||||
@ -1,148 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
id="svg2"
|
||||
sodipodi:docname="_svgclean2.svg"
|
||||
viewBox="0 0 260 310"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
bordercolor="#666666"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-y="19"
|
||||
fit-margin-left="0"
|
||||
pagecolor="#ffffff"
|
||||
fit-margin-top="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:zoom="1.4142136"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="768"
|
||||
showgrid="false"
|
||||
borderopacity="1.0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:cx="-57.248774"
|
||||
inkscape:cy="-575.52494"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:document-units="px"
|
||||
>
|
||||
<inkscape:grid
|
||||
id="grid3769"
|
||||
originy="-752.36218px"
|
||||
enabled="true"
|
||||
originx="-35.03125px"
|
||||
visible="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
type="xygrid"
|
||||
empspacing="4"
|
||||
/>
|
||||
</sodipodi:namedview
|
||||
>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(-242.06 -371.19)"
|
||||
>
|
||||
<path
|
||||
id="rect3757"
|
||||
style="stroke:#636363;stroke-width:6;fill:#ffffff"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m38 53v304h254v-226.22l-77.78-77.78h-176.22z"
|
||||
transform="translate(207.06 321.19)"
|
||||
/>
|
||||
<g
|
||||
id="g3915"
|
||||
transform="translate(0 17.678)"
|
||||
>
|
||||
<rect
|
||||
id="rect3759"
|
||||
style="stroke-linejoin:round;stroke:#a6a6a6;stroke-linecap:round;stroke-width:6;fill:#ffffff"
|
||||
height="150"
|
||||
width="130"
|
||||
y="451.19"
|
||||
x="307.06"
|
||||
/>
|
||||
<path
|
||||
id="path3761"
|
||||
d="m343.53 497.65 57.065 57.065"
|
||||
style="stroke-linejoin:round;stroke:#e00000;stroke-linecap:round;stroke-width:12;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
/>
|
||||
<path
|
||||
id="path3763"
|
||||
style="stroke-linejoin:round;stroke:#e00000;stroke-linecap:round;stroke-width:12;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m400.6 497.65-57.065 57.065"
|
||||
/>
|
||||
</g
|
||||
>
|
||||
<path
|
||||
id="rect3911"
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="stroke-linejoin:round;stroke:#636363;stroke-width:6;fill:none"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m499.06 451.97h-77.782v-77.782"
|
||||
/>
|
||||
</g
|
||||
>
|
||||
<metadata
|
||||
id="metadata13"
|
||||
>
|
||||
<rdf:RDF
|
||||
>
|
||||
<cc:Work
|
||||
>
|
||||
<dc:format
|
||||
>image/svg+xml</dc:format
|
||||
>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage"
|
||||
/>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/"
|
||||
/>
|
||||
<dc:publisher
|
||||
>
|
||||
<cc:Agent
|
||||
rdf:about="http://openclipart.org/"
|
||||
>
|
||||
<dc:title
|
||||
>Openclipart</dc:title
|
||||
>
|
||||
</cc:Agent
|
||||
>
|
||||
</dc:publisher
|
||||
>
|
||||
</cc:Work
|
||||
>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/publicdomain/"
|
||||
>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction"
|
||||
/>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution"
|
||||
/>
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks"
|
||||
/>
|
||||
</cc:License
|
||||
>
|
||||
</rdf:RDF
|
||||
>
|
||||
</metadata
|
||||
>
|
||||
</svg
|
||||
>
|
||||
|
Before Width: | Height: | Size: 3.9 KiB |
@ -1,73 +0,0 @@
|
||||
---
|
||||
title: "Instant Pot Chicken Noodle Soup"
|
||||
slug: "chicken-noodle-soup"
|
||||
date: "2026-02-08"
|
||||
lastUpdated: "2026-02-08"
|
||||
category: "soup"
|
||||
tags: ["soup", "chicken", "comfort-food", "instant-pot", "one-pot", "sick-day", "meal-prep"]
|
||||
dietary: []
|
||||
cookTime: 20
|
||||
prepTime: 10
|
||||
totalTime: 30
|
||||
difficulty: "easy"
|
||||
servings: 8
|
||||
author: "pws"
|
||||
description: "A comforting chicken noodle soup perfect for rainy or sick days. Made easy in the Instant Pot but can be adapted for stovetop cooking."
|
||||
featured: false
|
||||
display: true
|
||||
displayPhoto: "./assets/chicken-noodle-soup.png"
|
||||
---
|
||||
|
||||
# Instant Pot Chicken Noodle Soup
|
||||
|
||||
A great soup for rainy or sick days. This comforting classic is made simple with the Instant Pot, though it can easily be adapted for stovetop cooking. The recipe makes enough to fuel a whole sick week!
|
||||
|
||||
## Photos
|
||||
|
||||

|
||||
*Comforting homemade chicken noodle soup*
|
||||
|
||||
## Ingredients
|
||||
|
||||
### Main Ingredients
|
||||
- 2 tablespoons unsalted butter
|
||||
- 1 large onion, chopped
|
||||
- 2 medium carrots, chopped
|
||||
- 2 stalks celery, chopped
|
||||
- Kosher salt and fresh ground pepper to taste
|
||||
- 1 teaspoon thyme
|
||||
- 1 tablespoon parsley
|
||||
- 1 tablespoon oregano
|
||||
- 1 chicken bouillon cube or powder
|
||||
- 4 cups chicken broth
|
||||
- 2 pounds chicken (usually one Safeway or Costco chicken)
|
||||
- 4 cups water
|
||||
- 2 cups uncooked egg noodles
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Turn your Instant Pot to the saute setting.
|
||||
2. Add the **butter** and cook until melted. Add the **onion**, **carrots**, and **celery** and saute for 3 minutes until the **onion** softens and becomes translucent.
|
||||
3. Season with **salt** and **pepper**, then add the **thyme**, **parsley**, **oregano**, and **chicken bouillon**. Stir to combine.
|
||||
4. Pour in the **chicken broth**. Add the **chicken** pieces and another 4 cups of **water**.
|
||||
5. Close the lid. Set the Instant Pot to the Soup setting and set the timer to 7 minutes on high pressure.
|
||||
6. Once the Instant Pot cycle is complete, wait until the natural release cycle is complete before opening the instant pot.
|
||||
7. Remove the **chicken** pieces from the soup and shred with two forks.
|
||||
8. Add the **noodles** to the soup and set the Instant Pot to the saute setting again. Cook for another 6 minutes uncovered, or until the **noodles** are cooked.
|
||||
9. Turn off the Instant Pot. Add the shredded **chicken** back to the pot, taste for seasoning and adjust as necessary. Garnish with additional **parsley** if preferred.
|
||||
|
||||
## Notes
|
||||
|
||||
### Meal Prep Tips
|
||||
- **Make it last**: This recipe can make nearly a whole week of soup. Double it if you're feeling dangerous.
|
||||
- **Noodle absorption**: If doing meal prep with lots of noodles or macaroni, they tend to soak up the broth. Double the water and broth amounts if you want it to keep in the fridge and retain liquid, versus becoming more of a soup-casserole.
|
||||
|
||||
### Seasoning Tips
|
||||
- **Don't oversalt**: Watch the amount of salt in this recipe - it's pretty easy to over-salt if you're not careful, especially with the bouillon cube.
|
||||
|
||||
### Stovetop Adaptation
|
||||
This recipe can be made on the stovetop by simmering the ingredients in a large pot for about 30-40 minutes until the chicken is cooked through, then following the same steps for shredding and adding noodles.
|
||||
|
||||
## References
|
||||
|
||||
- [Jo Cooks - Instant Pot Chicken Noodle Soup](https://www.jocooks.com/recipes/instant-pot-chicken-noodle-soup/)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB |
Loading…
x
Reference in New Issue
Block a user