From db6411741ef1218ef53ddb4214fe917fc6d72bff Mon Sep 17 00:00:00 2001 From: Matt Cavanagh <1776058+Maelstromeous@users.noreply.github.com> Date: Fri, 16 Oct 2026 03:31:02 +0100 Subject: [PATCH 1/3] feat(web): show each recipe's ingredients in the recipe picker Rows are taller, with ingredient pictures under the Alt and tier badges. Hovering one gives the item and its per-minute rate for one building at 100%. Co-Authored-By: Claude Opus 5.5 (1M context) --- CHANGELOG.md | 1 + .../planner/products/RecipePicker.spec.ts | 11 +++ .../planner/products/RecipePicker.vue | 77 +++++++++++++++---- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da1d5100..daac944c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project are documented in this file. It mirrors the ## Unreleased +- **The Recipe picker shows each recipe's ingredients.** Rows in the picker are taller, with a picture of every ingredient under the Alt and tier badges. Hovering one names it and says how many a minute one building uses at 100%. - **Check your plan against your game save.** A new **Game options** button beside **Options** opens a dialog where you load a Satisfactory save. The planner reads it in your browser and keeps what it has unlocked: every recipe, every building, and the tiers reached. That list stays with the plan and syncs with it, and **Forget save** clears it. A file it cannot read is refused as not compatible, with the reason. The **Import world [WIP]** button is gone. - **Locked recipes get a padlock.** Once a save is loaded, the Recipe picker shows a padlock on each recipe and greys out the ones the save has not unlocked, standard recipes included. Clicking a padlock marks the recipe unlocked or locked by hand, and the mark survives loading a newer save. The tick beside the selected recipe is gone. - **Every alternate in one list.** Game options lists every alternate recipe with its rating, searchable and filterable by unlocked or locked. Clicking one marks it by hand. diff --git a/web/src/components/planner/products/RecipePicker.spec.ts b/web/src/components/planner/products/RecipePicker.spec.ts index dfc4e05a..763e573e 100644 --- a/web/src/components/planner/products/RecipePicker.spec.ts +++ b/web/src/components/planner/products/RecipePicker.spec.ts @@ -135,4 +135,15 @@ describe('Component: RecipePicker', () => { expect(subject.find('[data-testid="recipe-selection-locked"]').exists()).toBe(true) }) }) + + it('lists each recipe\'s ingredients with their per-minute rate for one building', () => { + const items = mountPicker('Wire', 'Wire').findComponent(VAutocomplete).props('items') as any[] + + expect(items.find(item => item.value === 'Wire')?.ingredients).toEqual([ + { part: 'CopperIngot', label: 'Copper Ingot: 15/min' }, + ]) + expect(items.find(item => item.value === 'Alternate_FusedWire')?.ingredients.map((i: any) => i.part)) + .toEqual(['CopperIngot', 'GoldIngot']) + }) }) + diff --git a/web/src/components/planner/products/RecipePicker.vue b/web/src/components/planner/products/RecipePicker.vue index e139d915..6b0f46eb 100644 --- a/web/src/components/planner/products/RecipePicker.vue +++ b/web/src/components/planner/products/RecipePicker.vue @@ -7,6 +7,7 @@ hide-details :items="items" label="Recipe" + :menu-props="{ maxHeight: 440 }" :model-value="modelValue" variant="outlined" @update:focused="focused = $event" @@ -27,22 +28,37 @@ {{ item.name }} - - - - - + + + + + + + + + + + + @@ -66,6 +82,8 @@ import { getRecipeRating, matchesRecipeQuery, RECIPE_RATINGS_SOURCE, RecipeTier, TIER_ORDER } from '@/utils/recipe-ratings' import { useRecipeUnlocks } from '@/composables/useRecipeUnlocks' import { isLockableRecipe } from '@/utils/recipe-unlocks' + import { getPartDisplayName } from '@/utils/helpers' + import { formatNumber } from '@/utils/numberFormatter' import type { FilterFunction } from 'vuetify' defineOptions({ inheritAttrs: false }) @@ -92,6 +110,11 @@ lockable: isLockableRecipe(recipe.id), locked: !isUnlocked(recipe.id), overridden: isOverridden(recipe.id), + // Per minute for one building at 100%, as the game's own recipe screen counts it. + ingredients: recipe.ingredients.map(ingredient => ({ + part: ingredient.part, + label: `${getPartDisplayName(ingredient.part)}: ${formatNumber(ingredient.perMin)}/min`, + })), })) .sort((a, b) => rank(a) - rank(b) || a.name.localeCompare(b.name))) @@ -128,6 +151,28 @@ width: 100%; } +.recipe-picker-meta { + display: flex; + flex-direction: column; + align-items: flex-end; + flex-shrink: 0; + gap: 4px; + padding: 4px 0; +} + +// Held open on a standard recipe, so its ingredients sit on the same line as every other row's. +.recipe-picker-tags-line { + display: flex; + align-items: center; + gap: 6px; + min-height: 20px; +} + +.recipe-picker-ingredients { + display: flex; + gap: 4px; +} + .recipe-picker :deep(.v-field__input) { flex-wrap: nowrap; } From 43591c41c8703e6241e8db8f374f73877c9ad17c Mon Sep 17 00:00:00 2001 From: Matt Cavanagh <1776058+Maelstromeous@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:17:36 +0100 Subject: [PATCH 2/3] fix(web): drop the trailing blank line lint rejects Co-Authored-By: Claude Opus 5.5 (1M context) --- web/src/components/planner/products/RecipePicker.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/components/planner/products/RecipePicker.spec.ts b/web/src/components/planner/products/RecipePicker.spec.ts index 763e573e..37885cb4 100644 --- a/web/src/components/planner/products/RecipePicker.spec.ts +++ b/web/src/components/planner/products/RecipePicker.spec.ts @@ -146,4 +146,3 @@ describe('Component: RecipePicker', () => { .toEqual(['CopperIngot', 'GoldIngot']) }) }) - From ab52fc8ab29d7a014db4d0ee6f0d6fd266a33710 Mon Sep 17 00:00:00 2001 From: Matt Cavanagh <1776058+Maelstromeous@users.noreply.github.com> Date: Sat, 17 Oct 2026 04:04:40 +0100 Subject: [PATCH 3/3] fix(web): rule off recipe picker rows and centre ingredients on untagged ones Co-Authored-By: Claude Opus 5.5 (1M context) --- .../components/planner/products/RecipePicker.vue | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/web/src/components/planner/products/RecipePicker.vue b/web/src/components/planner/products/RecipePicker.vue index 6b0f46eb..e0495f0b 100644 --- a/web/src/components/planner/products/RecipePicker.vue +++ b/web/src/components/planner/products/RecipePicker.vue @@ -25,11 +25,11 @@