feat(panel): editor keeps the values when the sim changes; one-tap RESET back to the look

This commit is contained in:
2026-09-10 22:06:36 +07:00
parent 868ebfe6e2
commit 02bc3aa4da
3 changed files with 61 additions and 17 deletions
+54 -16
View File
@@ -36,6 +36,9 @@ interface AdjustmentPanelProps {
recipes: Recipe[];
currentRecipeId: string;
adjustments: ColorAdjustments;
// The values the active look ships with — a saved recipe's own set, a film
// sim's canonical set, or the neutral defaults. RESET puts them back.
lookDefaults: ColorAdjustments;
selectedFrame: FrameId;
// FRAME tab CROP. Only meaningful on the library's plain frames (the camera
// composes through its ratio band, polaroid/wall through their own window),
@@ -163,6 +166,7 @@ export default function AdjustmentPanel({
recipes,
currentRecipeId,
adjustments,
lookDefaults,
selectedFrame,
cropRatio,
onUpdateCropRatio,
@@ -246,6 +250,17 @@ export default function AdjustmentPanel({
const a = adjustments;
// RESET (parameter tabs): every number of the active look back on the value
// it ships with. Only the parameters count as "changed" — the groups below
// are part of the same look, so they light it too.
const lookDirty =
[...PARAM_DEFS.iq, ...PARAM_DEFS.wb, ...PARAM_DEFS.filters].some(
(d) => d.get(a) !== d.get(lookDefaults)
) ||
(a.colorChrome || 'none') !== (lookDefaults.colorChrome || 'none') ||
(a.colorChromeBlue || 'none') !== (lookDefaults.colorChromeBlue || 'none') ||
String(a.dynamicRange ?? 'auto') !== String(lookDefaults.dynamicRange ?? 'auto');
const renderChip = (c: ChipDef) => {
const tone = c.active
? 'border-amber-500/70 bg-amber-500/15'
@@ -302,6 +317,19 @@ export default function AdjustmentPanel({
})
);
const resetChip = (): ChipDef => ({
key: 'reset-params',
label: 'RESET',
active: false,
onPress: () => onUpdateAdjustments({ ...lookDefaults }),
});
// Pinned OUTSIDE the scroll row: the rows keep their scroll offset across
// tabs, so a RESET sitting inside one can be scrolled off just when it is
// wanted — after a tweak halfway along the strip.
const resetChipFixed = () =>
lookDirty ? <View className="pl-2">{renderChip(resetChip())}</View> : null;
const choiceChips = (
keyPrefix: string,
options: { v: string; d: string }[],
@@ -521,22 +549,28 @@ export default function AdjustmentPanel({
// opens its AUTO/DR100/DR200/DR400 strip above (same as the chrome
// groups on WB).
return (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
>
{paramChips(paramDefs.iq)}
{renderChip(groupChip('dr'))}
</ScrollView>
<View className="flex-row items-center">
{resetChipFixed()}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
>
{paramChips(paramDefs.iq)}
{renderChip(groupChip('dr'))}
</ScrollView>
</View>
);
case 'wb':
return (
<View>
<View className="flex-row items-center">
{resetChipFixed()}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 6 }}
>
{choiceChips(
@@ -561,13 +595,17 @@ export default function AdjustmentPanel({
case 'filters':
return (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 }}
>
{paramChips(paramDefs.filters)}
</ScrollView>
<View className="flex-row items-center">
{resetChipFixed()}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 }}
>
{paramChips(paramDefs.filters)}
</ScrollView>
</View>
);
case 'frame':
+4 -1
View File
@@ -228,9 +228,12 @@ export default function RecipeCreateModal({
setIso(null);
}, [visible, currentBase, initial]);
// Switching the simulation reloads its standard values into the form.
// Switching the simulation reloads its standard values into the form — not
// in the editor though: there the numbers on screen are the user's own, and
// swapping the base look under them must not throw them away.
const selectSim = (b: BaseFilter) => {
setSim(b);
if (initial) return;
const v = valuesOf(b);
setDr(v.dr);
setGrain(v.grain);