feat(scaling): implement Meez-styled batch size select dropdown with presets and custom multiplier option
This commit is contained in:
@@ -48,8 +48,18 @@ function convertItem(quantity: number, fromUnitId: string, toUnitId: string, ite
|
||||
throw new Error(`No reviewed equivalency from ${fromUnitId} to ${toUnitId}`);
|
||||
}
|
||||
|
||||
const SCALE_OPTIONS = [
|
||||
{ value: 0.5, label: "1/2x" },
|
||||
{ value: 1, label: "1x" },
|
||||
{ value: 2, label: "2x" },
|
||||
{ value: 3, label: "3x" },
|
||||
{ value: 4, label: "4x" },
|
||||
{ value: 5, label: "5x" },
|
||||
];
|
||||
|
||||
export default function RecipeCalculator({ components, units, basisUnitId, yieldQuantity, yieldUnitId, nutrition, cost, servings, showDerived = true, showPercentControls = true, yieldConversions = [], shelfLife }: Props) {
|
||||
const [factor, setFactor] = useState(1);
|
||||
const [isCustomScale, setIsCustomScale] = useState(false);
|
||||
const [calculatePercent,setCalculatePercent]=useState(showPercentControls);
|
||||
const [percentMode,setPercentMode]=useState<"standard"|"bakers">("standard");
|
||||
const [yieldDisplayUnitId, setYieldDisplayUnitId] = useState(yieldUnitId);
|
||||
@@ -59,6 +69,19 @@ export default function RecipeCalculator({ components, units, basisUnitId, yield
|
||||
const [activeAttentionId, setActiveAttentionId] = useState<string | null>(null);
|
||||
const validFactor = Number.isFinite(factor) && factor >= 0 ? factor : 0;
|
||||
|
||||
const matchedScaleOption = SCALE_OPTIONS.find((opt) => Math.abs(opt.value - factor) < 0.001);
|
||||
const showCustomInput = isCustomScale || !matchedScaleOption;
|
||||
|
||||
const handleScaleSelectChange = (e: Event) => {
|
||||
const val = (e.currentTarget as HTMLSelectElement).value;
|
||||
if (val === "custom") {
|
||||
setIsCustomScale(true);
|
||||
} else {
|
||||
setIsCustomScale(false);
|
||||
setFactor(Number(val));
|
||||
}
|
||||
};
|
||||
|
||||
const handleScaleTooltipEnter = () => {
|
||||
if (scaleTooltipTimer) clearTimeout(scaleTooltipTimer);
|
||||
setShowScaleTooltip(true);
|
||||
@@ -149,15 +172,36 @@ export default function RecipeCalculator({ components, units, basisUnitId, yield
|
||||
<div class="basis-input batch-multiplier-field">
|
||||
<span class="scale-label">Batch Size:</span>
|
||||
<span class="recipe-scale-control batch-size-control">
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="any"
|
||||
aria-label="Batch multiplier"
|
||||
value={roundForDisplay(factor)}
|
||||
onInput={(event) => setFactor(Number((event.currentTarget as HTMLInputElement).value))}
|
||||
/>
|
||||
<span class="batch-unit-suffix">x</span>
|
||||
<select
|
||||
aria-label="Batch size multiplier"
|
||||
class="meez-scale-select"
|
||||
data-testid="ScaleSelectorBase_scale_select"
|
||||
value={!showCustomInput && matchedScaleOption ? String(matchedScaleOption.value) : "custom"}
|
||||
onChange={handleScaleSelectChange}
|
||||
>
|
||||
{SCALE_OPTIONS.map((opt) => (
|
||||
<option key={opt.value} value={String(opt.value)}>{opt.label}</option>
|
||||
))}
|
||||
<option value="custom">Custom</option>
|
||||
</select>
|
||||
{showCustomInput && (
|
||||
<span class="custom-scale-wrap">
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="any"
|
||||
aria-label="Custom batch multiplier"
|
||||
class="custom-scale-input"
|
||||
value={roundForDisplay(factor)}
|
||||
onInput={(event) => {
|
||||
const val = Number((event.currentTarget as HTMLInputElement).value);
|
||||
if (!isNaN(val) && val > 0) setFactor(val);
|
||||
}}
|
||||
autoFocus
|
||||
/>
|
||||
<span class="batch-unit-suffix">x</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div class="basis-input finished-yield-field">
|
||||
|
||||
@@ -2956,6 +2956,60 @@ input[type="search"]::-webkit-search-results-decoration,
|
||||
.application-body .immersive-main .recipe-read-shell .recipe-view-formula .calculator-heading .recipe-scale-control:focus-within {
|
||||
border-bottom: 2px solid #3d5df6 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}.application-body .recipe-view-formula .calculator-heading .batch-size-control {
|
||||
border-bottom: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .meez-scale-select {
|
||||
font-family: var(--meez-font-sans) !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 500 !important;
|
||||
color: #050841 !important;
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
border-bottom: 1px solid #a5a9c1 !important;
|
||||
padding: 0 4px 1px 0 !important;
|
||||
cursor: pointer !important;
|
||||
outline: none !important;
|
||||
height: 24px !important;
|
||||
transition: border-color 0.15s ease !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .meez-scale-select:hover {
|
||||
border-bottom-color: #050841 !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .meez-scale-select:focus {
|
||||
border-bottom: 2px solid #3d5df6 !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .custom-scale-wrap {
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
margin-left: 6px !important;
|
||||
border-bottom: 1px solid #a5a9c1 !important;
|
||||
padding-bottom: 1px !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .custom-scale-wrap:focus-within {
|
||||
border-bottom: 2px solid #3d5df6 !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .custom-scale-input {
|
||||
width: 42px !important;
|
||||
min-width: 24px !important;
|
||||
max-width: 5ch !important;
|
||||
font-family: var(--meez-font-sans) !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 500 !important;
|
||||
color: #050841 !important;
|
||||
background: transparent !important;
|
||||
border: 0 !important;
|
||||
outline: 0 !important;
|
||||
padding: 0 !important;
|
||||
text-align: right !important;
|
||||
-moz-appearance: textfield !important;
|
||||
}
|
||||
|
||||
.application-body .recipe-view-formula .calculator-heading .recipe-scale-control input,
|
||||
|
||||
Reference in New Issue
Block a user