Apply the CREATE form's knobs to the photo in realtime
Every row now feeds the open render as it is typed, so a recipe's effect is visible before it is saved. The draft is not an undo step: SAVE/EXPORT stays the only thing that commits it, and merely opening the tab changes nothing.
This commit is contained in:
@@ -324,6 +324,13 @@ export function Workspace() {
|
||||
[user, applyRecipe, t]
|
||||
);
|
||||
|
||||
// CREATE edits the photo live: each knob lands on the render as it is typed so
|
||||
// the recipe can be judged before saving. No undo entry — this is a draft, and
|
||||
// SAVE/EXPORT is what commits it.
|
||||
const previewCreatedRecipe = useCallback((draft: Pick<Recipe, 'baseFilter' | 'adjustments'>) => {
|
||||
setRecipe((prev) => ({ ...prev, ...draft, isCustom: true }));
|
||||
}, []);
|
||||
|
||||
// The phone's encrypted .recipe envelope (`shared/utils/recipeShare` is the
|
||||
// app's own file, byte-identical). Signed in only — a guest's recipe is never
|
||||
// written to disk.
|
||||
@@ -781,6 +788,7 @@ export function Workspace() {
|
||||
currentBase={recipe.baseFilter}
|
||||
current={recipe.adjustments}
|
||||
signedIn={!!user}
|
||||
onPreview={previewCreatedRecipe}
|
||||
onSave={(draft) => void addCreatedRecipe(draft)}
|
||||
onExport={exportRecipeFile}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { ChipRow, type ChipDef } from './ChipColumn';
|
||||
import { useI18n } from '../i18n/I18nProvider';
|
||||
import { DEFAULT_ADJUSTMENTS, FILM_SIMS } from '../../shared/utils/defaultRecipes';
|
||||
@@ -55,12 +55,14 @@ export function RecipeCreatePanel({
|
||||
currentBase,
|
||||
current,
|
||||
signedIn,
|
||||
onPreview,
|
||||
onSave,
|
||||
onExport,
|
||||
}: {
|
||||
currentBase?: BaseFilter;
|
||||
current?: ColorAdjustments | null;
|
||||
signedIn: boolean;
|
||||
onPreview: (draft: Pick<Recipe, 'baseFilter' | 'adjustments'>) => void;
|
||||
onSave: (draft: RecipeDraft) => void;
|
||||
onExport: (draft: RecipeDraft) => void;
|
||||
}) {
|
||||
@@ -153,6 +155,20 @@ export function RecipeCreatePanel({
|
||||
return { name: name.trim() || 'NEW RECIPE', baseFilter: sim, adjustments, frameId: 'none', useGeotag: true };
|
||||
};
|
||||
|
||||
// Realtime: every knob applies to the photo on screen as it is typed, so the
|
||||
// effect of the recipe is visible before saving it. Opening the tab is not an
|
||||
// edit — the first run (the seeded values) is skipped.
|
||||
const first = useRef(true);
|
||||
useEffect(() => {
|
||||
if (first.current) {
|
||||
first.current = false;
|
||||
return;
|
||||
}
|
||||
const { baseFilter, adjustments } = build();
|
||||
onPreview({ baseFilter, adjustments });
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [sim, dr, grain, cc, ccb, wbKey, wbRed, wbBlue, fHigh, fShadow, fColor, fNr, fSharp, fClarity, fEv]);
|
||||
|
||||
const opts = (
|
||||
prefix: string,
|
||||
options: { v: string; d: string }[],
|
||||
|
||||
Reference in New Issue
Block a user