Update recipe card design, add temp debug path
This commit is contained in:
parent
66ccc5cf03
commit
486c6dc1ae
@ -5,18 +5,20 @@ import clsx from 'clsx/lite';
|
|||||||
|
|
||||||
export default async function AdminRecipePage() {
|
export default async function AdminRecipePage() {
|
||||||
const photos = await getPhotos({ hidden: 'only' });
|
const photos = await getPhotos({ hidden: 'only' });
|
||||||
const { fujifilmRecipe } = photos[0];
|
const { fujifilmRecipe, filmSimulation } = photos[0];
|
||||||
return (
|
return (
|
||||||
<SiteGrid
|
<SiteGrid
|
||||||
contentMain={<div className={clsx(
|
contentMain={<div className={clsx(
|
||||||
'w-full min-h-[600px]',
|
'w-full min-h-[min(500px,70vh)]',
|
||||||
'flex items-center justify-center',
|
'flex items-center justify-center',
|
||||||
)}>
|
)}>
|
||||||
{fujifilmRecipe &&
|
{(fujifilmRecipe && filmSimulation) &&
|
||||||
<PhotoRecipe recipe={fujifilmRecipe} />
|
<PhotoRecipe
|
||||||
|
recipe={fujifilmRecipe}
|
||||||
|
simulation={filmSimulation}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
</div>}
|
</div>}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,128 @@
|
|||||||
import { FujifilmRecipe } from '@/platforms/fujifilm/recipe';
|
import { FujifilmRecipe } from '@/platforms/fujifilm/recipe';
|
||||||
|
import { FilmSimulation } from '@/simulation';
|
||||||
|
import PhotoFilmSimulation from '@/simulation/PhotoFilmSimulation';
|
||||||
import clsx from 'clsx/lite';
|
import clsx from 'clsx/lite';
|
||||||
|
|
||||||
const addSign = (value: number) => value < 0 ? value : `+${value}`;
|
const addSign = (value = 0) => value < 0 ? value : `+${value}`;
|
||||||
|
|
||||||
export default function PhotoRecipe({ recipe: {
|
export default function PhotoRecipe({
|
||||||
|
recipe: {
|
||||||
dynamicRange,
|
dynamicRange,
|
||||||
|
whiteBalance,
|
||||||
|
highISONoiseReduction,
|
||||||
|
noiseReductionBasic,
|
||||||
highlight,
|
highlight,
|
||||||
shadow,
|
shadow,
|
||||||
color,
|
color,
|
||||||
highISONoiseReduction,
|
|
||||||
noiseReductionLegacy,
|
|
||||||
sharpness,
|
sharpness,
|
||||||
clarity,
|
clarity,
|
||||||
grainEffect,
|
|
||||||
colorChromeEffect,
|
colorChromeEffect,
|
||||||
colorChromeFXBlue,
|
colorChromeFXBlue,
|
||||||
whiteBalance,
|
grainEffect,
|
||||||
bwAdjustment,
|
bwAdjustment,
|
||||||
bwMagentaGreen,
|
bwMagentaGreen,
|
||||||
} }: { recipe: FujifilmRecipe }) {
|
},
|
||||||
return <div className="">
|
simulation,
|
||||||
|
}: {
|
||||||
|
recipe: FujifilmRecipe
|
||||||
|
simulation: FilmSimulation
|
||||||
|
}) {
|
||||||
|
const whiteBalanceFormatted = (whiteBalance?.type ?? 'auto')
|
||||||
|
.replaceAll('auto', ' ')
|
||||||
|
.replaceAll('-', ' ');
|
||||||
|
|
||||||
|
const hasCustomizedWhiteBalance =
|
||||||
|
Boolean(whiteBalance?.red) ||
|
||||||
|
Boolean(whiteBalance?.blue);
|
||||||
|
|
||||||
|
const hasBWAdjustments =
|
||||||
|
Boolean(bwAdjustment) ||
|
||||||
|
Boolean(bwMagentaGreen);
|
||||||
|
|
||||||
|
const renderDataSquare = (label: string, value: string | number = '0') => (
|
||||||
|
<div className={clsx(
|
||||||
|
'flex flex-col items-center justify-center',
|
||||||
|
'bg-dim rounded-md p-0.5',
|
||||||
|
)}>
|
||||||
|
<div>{typeof value === 'number' ? addSign(value) : value}</div>
|
||||||
|
<div>{label}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return <div className="flex gap-8">
|
||||||
|
<div className={clsx(
|
||||||
|
'w-[18rem] self-start',
|
||||||
|
'p-3',
|
||||||
|
'component-surface shadow-xs',
|
||||||
|
'space-y-3',
|
||||||
|
)}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<PhotoFilmSimulation {...{ simulation, className: 'grow' }} />
|
||||||
|
<div className="bg-dim rounded-md p-0.5">
|
||||||
|
<span>DR</span>
|
||||||
|
<span>{dynamicRange ?? 100}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="text-sm uppercase space-y-3"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{whiteBalanceFormatted.length <= 8 && 'AWB: '}
|
||||||
|
{whiteBalanceFormatted}
|
||||||
|
{hasCustomizedWhiteBalance && <>
|
||||||
|
{' '}
|
||||||
|
<span className="text-extra-dim">{'('}</span>
|
||||||
|
R{addSign(whiteBalance?.red ?? 0)}
|
||||||
|
<span className="text-extra-extra-dim"> / </span>
|
||||||
|
B{addSign(whiteBalance?.blue ?? 0)}
|
||||||
|
<span className="text-extra-dim">{')'}</span>
|
||||||
|
</>}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 *:w-full">
|
||||||
|
{renderDataSquare('Highlight', highlight)}
|
||||||
|
{renderDataSquare('Shadow', shadow)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 *:w-full">
|
||||||
|
{/* TODO: Confirm color vs saturation label */}
|
||||||
|
{renderDataSquare('Color', color)}
|
||||||
|
{renderDataSquare('Sharp', sharpness)}
|
||||||
|
{renderDataSquare('Clarity', clarity)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3 *:w-full">
|
||||||
|
{renderDataSquare('Chrome', colorChromeEffect)}
|
||||||
|
{renderDataSquare('FX Blue', colorChromeFXBlue)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{highISONoiseReduction !== undefined
|
||||||
|
? <>
|
||||||
|
<span>High ISO NR: </span>
|
||||||
|
<span>{addSign(highISONoiseReduction)}</span>
|
||||||
|
</>
|
||||||
|
: <>
|
||||||
|
<span>Noise Reduction: </span>
|
||||||
|
<span>{noiseReductionBasic}</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{grainEffect &&
|
||||||
|
<div>
|
||||||
|
Grain:
|
||||||
|
{' '}
|
||||||
|
{grainEffect.roughness}
|
||||||
|
<span className="text-extra-dim">{' / '}</span>
|
||||||
|
{grainEffect.size}
|
||||||
|
</div>}
|
||||||
|
{hasBWAdjustments &&
|
||||||
|
<div>
|
||||||
|
BW Adjustment:
|
||||||
|
{' '}
|
||||||
|
{addSign(bwAdjustment)}
|
||||||
|
{' '}
|
||||||
|
MG:
|
||||||
|
{addSign(bwMagentaGreen)}
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'px-3 py-2 max-w-[16rem]',
|
'px-3 py-2 max-w-[16rem]',
|
||||||
'text-left text-xs',
|
'text-left text-xs',
|
||||||
@ -47,9 +150,9 @@ export default function PhotoRecipe({ recipe: {
|
|||||||
<div>High ISO NR</div>
|
<div>High ISO NR</div>
|
||||||
<div>{addSign(highISONoiseReduction)}</div>
|
<div>{addSign(highISONoiseReduction)}</div>
|
||||||
</>}
|
</>}
|
||||||
{noiseReductionLegacy !== undefined && <>
|
{noiseReductionBasic !== undefined && <>
|
||||||
<div>NR</div>
|
<div>NR</div>
|
||||||
<div>{noiseReductionLegacy}</div>
|
<div>{noiseReductionBasic}</div>
|
||||||
</>}
|
</>}
|
||||||
{sharpness !== undefined && <>
|
{sharpness !== undefined && <>
|
||||||
<div>Sharpness</div>
|
<div>Sharpness</div>
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import { parseFujifilmMakerNote } from '.';
|
import { parseFujifilmMakerNote } from '.';
|
||||||
|
|
||||||
const TAG_ID_DEVELOPMENT_DYNAMIC_RANGE = 0x1403;
|
const TAG_ID_DEVELOPMENT_DYNAMIC_RANGE = 0x1403;
|
||||||
|
const TAG_ID_WHITE_BALANCE = 0x1002;
|
||||||
|
const TAG_ID_WHITE_BALANCE_FINE_TUNE = 0x100a;
|
||||||
|
const TAG_ID_NOISE_REDUCTION = 0x100e;
|
||||||
|
const TAG_ID_NOISE_REDUCTION_BASIC = 0x100b;
|
||||||
const TAG_ID_HIGHLIGHT = 0x1041;
|
const TAG_ID_HIGHLIGHT = 0x1041;
|
||||||
const TAG_ID_SHADOW = 0x1040;
|
const TAG_ID_SHADOW = 0x1040;
|
||||||
const TAG_ID_SATURATION = 0x1003;
|
const TAG_ID_SATURATION = 0x1003;
|
||||||
const TAG_ID_NOISE_REDUCTION = 0x100e;
|
|
||||||
const TAG_ID_NOISE_REDUCTION_BASIC = 0x100b;
|
|
||||||
const TAG_ID_SHARPNESS = 0x1001;
|
const TAG_ID_SHARPNESS = 0x1001;
|
||||||
const TAG_ID_CLARITY = 0x100f;
|
const TAG_ID_CLARITY = 0x100f;
|
||||||
const TAG_ID_GRAIN_EFFECT_ROUGHNESS = 0x1047;
|
|
||||||
const TAG_ID_GRAIN_EFFECT_SIZE = 0x104c;
|
|
||||||
const TAG_ID_COLOR_CHROME_EFFECT = 0x1048;
|
const TAG_ID_COLOR_CHROME_EFFECT = 0x1048;
|
||||||
const TAG_ID_COLOR_CHROME_FX_BLUE = 0x104e;
|
const TAG_ID_COLOR_CHROME_FX_BLUE = 0x104e;
|
||||||
const TAG_ID_WHITE_BALANCE = 0x1002;
|
const TAG_ID_GRAIN_EFFECT_ROUGHNESS = 0x1047;
|
||||||
const TAG_ID_WHITE_BALANCE_FINE_TUNE = 0x100a;
|
const TAG_ID_GRAIN_EFFECT_SIZE = 0x104c;
|
||||||
const TAG_ID_BW_ADJUSTMENT = 0x1049;
|
const TAG_ID_BW_ADJUSTMENT = 0x1049;
|
||||||
const TAG_ID_BW_MAGENTA_GREEN = 0x104b;
|
const TAG_ID_BW_MAGENTA_GREEN = 0x104b;
|
||||||
|
|
||||||
@ -21,39 +21,39 @@ type WeakStrong = 'off' | 'weak' | 'strong';
|
|||||||
|
|
||||||
export type FujifilmRecipe = Partial<{
|
export type FujifilmRecipe = Partial<{
|
||||||
dynamicRange: number
|
dynamicRange: number
|
||||||
highlight: number
|
|
||||||
shadow: number
|
|
||||||
color: number
|
|
||||||
highISONoiseReduction: number
|
|
||||||
noiseReductionLegacy: string
|
|
||||||
sharpness: number
|
|
||||||
clarity: number
|
|
||||||
grainEffect: {
|
|
||||||
roughness: WeakStrong
|
|
||||||
size: 'off' | 'small' | 'large'
|
|
||||||
}
|
|
||||||
colorChromeEffect: WeakStrong
|
|
||||||
colorChromeFXBlue: WeakStrong
|
|
||||||
whiteBalance: {
|
whiteBalance: {
|
||||||
type: string
|
type: string
|
||||||
red: number
|
red: number
|
||||||
blue: number
|
blue: number
|
||||||
}
|
}
|
||||||
|
highISONoiseReduction: number
|
||||||
|
noiseReductionBasic: string
|
||||||
|
highlight: number
|
||||||
|
shadow: number
|
||||||
|
color: number
|
||||||
|
sharpness: number
|
||||||
|
clarity: number
|
||||||
|
colorChromeEffect: WeakStrong
|
||||||
|
colorChromeFXBlue: WeakStrong
|
||||||
|
grainEffect: {
|
||||||
|
roughness: WeakStrong
|
||||||
|
size: 'off' | 'small' | 'large'
|
||||||
|
}
|
||||||
bwAdjustment: number
|
bwAdjustment: number
|
||||||
bwMagentaGreen: number
|
bwMagentaGreen: number
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const DEFAULT_GRAIN_EFFECT = {
|
|
||||||
roughness: 'off',
|
|
||||||
size: 'off',
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const DEFAULT_WHITE_BALANCE = {
|
const DEFAULT_WHITE_BALANCE = {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
red: 0,
|
red: 0,
|
||||||
blue: 0,
|
blue: 0,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const DEFAULT_GRAIN_EFFECT = {
|
||||||
|
roughness: 'off',
|
||||||
|
size: 'off',
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const processTone = (value: number) =>
|
export const processTone = (value: number) =>
|
||||||
value === 0 ? 0 : -(value / 16);
|
value === 0 ? 0 : -(value / 16);
|
||||||
|
|
||||||
@ -165,42 +165,6 @@ export const getFujifilmRecipeFromMakerNote = (
|
|||||||
case TAG_ID_DEVELOPMENT_DYNAMIC_RANGE:
|
case TAG_ID_DEVELOPMENT_DYNAMIC_RANGE:
|
||||||
recipe.dynamicRange = numbers[0];
|
recipe.dynamicRange = numbers[0];
|
||||||
break;
|
break;
|
||||||
case TAG_ID_HIGHLIGHT:
|
|
||||||
recipe.highlight = processTone(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_SHADOW:
|
|
||||||
recipe.shadow = processTone(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_SATURATION:
|
|
||||||
recipe.color = processSaturation(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_NOISE_REDUCTION:
|
|
||||||
recipe.highISONoiseReduction = processNoiseReduction(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_NOISE_REDUCTION_BASIC:
|
|
||||||
recipe.noiseReductionLegacy =
|
|
||||||
processNoiseReductionLegacy(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_SHARPNESS:
|
|
||||||
recipe.sharpness = processSharpness(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_CLARITY:
|
|
||||||
recipe.clarity = processClarity(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_GRAIN_EFFECT_ROUGHNESS:
|
|
||||||
if (!recipe.grainEffect) { recipe.grainEffect = DEFAULT_GRAIN_EFFECT; }
|
|
||||||
recipe.grainEffect.roughness = processWeakStrong(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_GRAIN_EFFECT_SIZE:
|
|
||||||
if (!recipe.grainEffect) { recipe.grainEffect = DEFAULT_GRAIN_EFFECT; }
|
|
||||||
recipe.grainEffect.size = processGrainEffectSize(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_COLOR_CHROME_EFFECT:
|
|
||||||
recipe.colorChromeEffect = processWeakStrong(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_COLOR_CHROME_FX_BLUE:
|
|
||||||
recipe.colorChromeFXBlue = processWeakStrong(numbers[0]);
|
|
||||||
break;
|
|
||||||
case TAG_ID_WHITE_BALANCE:
|
case TAG_ID_WHITE_BALANCE:
|
||||||
if (!recipe.whiteBalance) {
|
if (!recipe.whiteBalance) {
|
||||||
recipe.whiteBalance = DEFAULT_WHITE_BALANCE;
|
recipe.whiteBalance = DEFAULT_WHITE_BALANCE;
|
||||||
@ -214,6 +178,42 @@ export const getFujifilmRecipeFromMakerNote = (
|
|||||||
recipe.whiteBalance.red = processWhiteBalanceComponent(numbers[0]);
|
recipe.whiteBalance.red = processWhiteBalanceComponent(numbers[0]);
|
||||||
recipe.whiteBalance.blue = processWhiteBalanceComponent(numbers[1]);
|
recipe.whiteBalance.blue = processWhiteBalanceComponent(numbers[1]);
|
||||||
break;
|
break;
|
||||||
|
case TAG_ID_NOISE_REDUCTION:
|
||||||
|
recipe.highISONoiseReduction = processNoiseReduction(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_NOISE_REDUCTION_BASIC:
|
||||||
|
recipe.noiseReductionBasic =
|
||||||
|
processNoiseReductionLegacy(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_HIGHLIGHT:
|
||||||
|
recipe.highlight = processTone(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_SHADOW:
|
||||||
|
recipe.shadow = processTone(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_SATURATION:
|
||||||
|
recipe.color = processSaturation(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_SHARPNESS:
|
||||||
|
recipe.sharpness = processSharpness(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_CLARITY:
|
||||||
|
recipe.clarity = processClarity(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_COLOR_CHROME_EFFECT:
|
||||||
|
recipe.colorChromeEffect = processWeakStrong(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_COLOR_CHROME_FX_BLUE:
|
||||||
|
recipe.colorChromeFXBlue = processWeakStrong(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_GRAIN_EFFECT_ROUGHNESS:
|
||||||
|
if (!recipe.grainEffect) { recipe.grainEffect = DEFAULT_GRAIN_EFFECT; }
|
||||||
|
recipe.grainEffect.roughness = processWeakStrong(numbers[0]);
|
||||||
|
break;
|
||||||
|
case TAG_ID_GRAIN_EFFECT_SIZE:
|
||||||
|
if (!recipe.grainEffect) { recipe.grainEffect = DEFAULT_GRAIN_EFFECT; }
|
||||||
|
recipe.grainEffect.size = processGrainEffectSize(numbers[0]);
|
||||||
|
break;
|
||||||
case TAG_ID_BW_ADJUSTMENT:
|
case TAG_ID_BW_ADJUSTMENT:
|
||||||
recipe.bwAdjustment = numbers[0];
|
recipe.bwAdjustment = numbers[0];
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -9,10 +9,11 @@ import EntityLink, {
|
|||||||
EntityLinkExternalProps,
|
EntityLinkExternalProps,
|
||||||
} from '@/components/primitives/EntityLink';
|
} from '@/components/primitives/EntityLink';
|
||||||
import { LuChevronsUpDown } from 'react-icons/lu';
|
import { LuChevronsUpDown } from 'react-icons/lu';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx/lite';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import PhotoRecipe from '@/photo/PhotoRecipe';
|
import PhotoRecipe from '@/photo/PhotoRecipe';
|
||||||
import Tooltip from '@/components/Tooltip';
|
import Tooltip from '@/components/Tooltip';
|
||||||
|
|
||||||
export default function PhotoFilmSimulation({
|
export default function PhotoFilmSimulation({
|
||||||
simulation,
|
simulation,
|
||||||
type = 'icon-last',
|
type = 'icon-last',
|
||||||
@ -21,17 +22,19 @@ export default function PhotoFilmSimulation({
|
|||||||
prefetch,
|
prefetch,
|
||||||
countOnHover,
|
countOnHover,
|
||||||
recipe,
|
recipe,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
simulation: FilmSimulation
|
simulation: FilmSimulation
|
||||||
countOnHover?: number
|
countOnHover?: number
|
||||||
recipe?: FujifilmRecipe
|
recipe?: FujifilmRecipe
|
||||||
|
className?: string
|
||||||
} & EntityLinkExternalProps) {
|
} & EntityLinkExternalProps) {
|
||||||
const { small, medium, large } = labelForFilmSimulation(simulation);
|
const { small, medium, large } = labelForFilmSimulation(simulation);
|
||||||
|
|
||||||
const [shouldShowRecipe, setShouldShowRecipe] = useState(false);
|
const [shouldShowRecipe, setShouldShowRecipe] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-baseline">
|
<div className={clsx('space-y-baseline', className)}>
|
||||||
<div className="flex items-center gap-2 *:w-auto">
|
<div className="flex items-center gap-2 *:w-auto">
|
||||||
<EntityLink
|
<EntityLink
|
||||||
label={medium}
|
label={medium}
|
||||||
@ -61,7 +64,7 @@ export default function PhotoFilmSimulation({
|
|||||||
</Tooltip>}
|
</Tooltip>}
|
||||||
</div>
|
</div>
|
||||||
{recipe && shouldShowRecipe &&
|
{recipe && shouldShowRecipe &&
|
||||||
<PhotoRecipe recipe={recipe} />}
|
<PhotoRecipe {...{ recipe, simulation }} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user