Skip to content

Commit

Permalink
Working version of recipe conversion calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilafian committed May 11, 2024
1 parent 8a81ebe commit d4f36c1
Show file tree
Hide file tree
Showing 17 changed files with 487 additions and 254 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ $ cd think-metric
$ npm install
$ npm run interactive
```
As you make edits to files in the **src** folder, your browser will automatically refresh to display the new changes.
As you make edits to files in the **src/website** folder, your browser will automatically refresh to display the new changes.

To publish merges to the live website:<br>
GitHub project page &#10132; _Actions_ &#10132; _Publish Website_ &#10132; _Run workflow_
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@
],
"build": [
"copy-file src/cname.txt build/CNAME",
"copy-folder src/website/graphics build/graphics",
"copy-folder src/website/article build/article --ext=.png,.jpg",
"copy-file src/website/app.js build/app.js",
"copy-folder src/website build --ext=.png,.jpg,.js",
"lessc src/website/style.less build/style.css",
"replacer src/website --ext=.html build",
"rev-web-assets build docs --meta-content-base=https://think-metric.org"
Expand Down
3 changes: 2 additions & 1 deletion src/templates/doc-begin.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<link rel=stylesheet href={{webRoot}}/style.css>
<script defer src=https://cdn.jsdelivr.net/npm/dna-engine@{{package.dependencies.dna-engine|version}}/dist/dna-engine.min.js></script>
<script defer src=https://cdn.jsdelivr.net/npm/web-ignition@{{package.dependencies.web-ignition|version}}/dist/lib-x.min.js></script>
<script defer src={{webRoot}}/calculator/ingredients-db.js></script>
<script defer src={{webRoot}}/app.js></script>
</head>
<body>
Expand All @@ -45,7 +46,7 @@
<a href={{webRoot}}/products>Products</a>
<a href={{webRoot}}/do-not-learn-metric>Just Use It</a>
<!--
<a href={{webRoot}}/recipe-converter-calculator>Calculator</a>
<a href={{webRoot}}/calculator>Calculator</a>
-->
<a href={{webRoot}}/elsewhere>Elsewhere</a>
</nav>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{% assign github = 'https://github.com/center-key/think-metric' %}
{% assign reddit = 'https://www.reddit.com/r/ThinkMetric' %}

<ol class=to-do-checklist data-on-click=app.checklist.save>
<ol class=metrication-checklist data-on-click=app.checklist.save>
<li id=phone> <p>Set your mobile device to metric</p> <label><input type=checkbox><b></b></label></li>
<li id=car> <p>Set the display in your car to Celsius (&deg;C)</p> <label><input type=checkbox><b></b></label></li>
<li id=home> <p>Set your home thermostat to Celsius (&deg;C)</p> <label><input type=checkbox><b></b></label></li>
Expand Down
43 changes: 27 additions & 16 deletions src/website/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const app = {
checklist: {
restore(checklistSection) {
// Set checklist task items according to previously saved values.
const listElem = checklistSection.querySelector('ol.to-do-checklist');
const listElem = checklistSection.querySelector('ol.metrication-checklist');
const checklist = JSON.parse(globalThis.localStorage.getItem('checklist'));
const getCheckbox = (li) => li.querySelector('input[type=checkbox]');
const setCheckbox = (li) => getCheckbox(li).checked = checklist[li.id];
Expand Down Expand Up @@ -35,13 +35,6 @@ const app = {
// <output>
// <span id=metric-ingredient class=dna-template>
// <b>~~grams~~</b> grams <b>~~form~~</b> <b>~~name~~</b>
ingredients: [
{ name: 'Almonds', form: 'Sliced', gramsPerCup: 110 },
{ name: 'Almonds', form: 'Raw', gramsPerCup: 130 },
{ name: 'Almonds', form: 'Roasted', gramsPerCup: 120 },
{ name: 'Butter', form: null, gramsPerCup: 227 },
{ name: 'Honey', form: null, gramsPerCup: 340 },
],
convertToGrams(elem) {
const calculatorForm = elem.closest('form');
const elemMap = {
Expand All @@ -56,17 +49,33 @@ const app = {
const unitsPerCup = Number(unitsOption.dataset.perCup);
const unitsGrams = Number(unitsOption.dataset.grams);
const ingredientName = elemMap.ingredient.value;
const ingredients = app.calculator.ingredients.filter(ingredient => ingredient.name === ingredientName);
ingredients.forEach(ingredient =>
ingredient.grams = quantity * (unitType === 'volume' ?
ingredient.gramsPerCup / unitsPerCup : unitsGrams)
);
if (!isNaN(quantity))
dna.clone('metric-ingredient', ingredients, {empty: true});
const ingredients = globalThis.ingredientsDB.filter(ingredient => ingredient.name === ingredientName);
const toGrams = (ingredient) => quantity * (unitType === 'volume' ?
ingredient.gramsPerCup / unitsPerCup : unitsGrams);
const toMetric = (ingredient) => ({ ingredient: ingredient, grams: toGrams(ingredient)});
const calculatorResult = () => ({
imperial: {
quantity: quantity,
units: unitsOption.textContent.replace(/\(.*/, '').trim().toLowerCase(),
name: elemMap.ingredient.value,
},
metric: ingredients.map(toMetric),
});
if (!isNaN(quantity) && quantity > 0 && elemMap.ingredient.selectedIndex > 0)
dna.clone('calculator-result', calculatorResult(), { empty: true });
},
updateTemperature(elem) {
const tempF = Number(elem.value);
const output = elem.closest('section').querySelector('output');
const toCelsius = () => Math.round((tempF - 32) * 5 / 9);
output.textContent = isNaN(tempF) ? 'N/A' : dna.util.round(toCelsius(), 2);
},
init() {
const allNames = app.calculator.ingredients.map(ingredient => ingredient.name);
const allNames = globalThis.ingredientsDB.map(ingredient => ingredient.name);
const ingredientNames = [...new Set(allNames)];
const ingredientPlaceholder = dna.clone('input-ingredient', 'Select...');
ingredientPlaceholder.selected = true;
ingredientPlaceholder.disabled = true;
dna.clone('input-ingredient', ingredientNames);
},
},
Expand Down Expand Up @@ -99,6 +108,8 @@ const app = {
},

start() {
globalThis.document.querySelectorAll('form:not([action])').forEach(
form => form.onsubmit = () => false); //disable submitting form on enter key
console.log('Think Metric');
console.log('🇺🇸 Americans for Metrication 🇺🇸');
app.article.init();
Expand Down
Binary file added src/website/calculator/banana-bread-by-nist.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions src/website/calculator/calculator.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
label:has(select) {
position: relative;
max-width: 25em;
text-align: left;
padding: 0px;
&::after {
content: "\276F"; //arrow: "❯" (Heavy Right-Pointing Angle Quotation Mark Ornament)
position: absolute;
right: 0.4em;
bottom: 0.03em;
font-size: 1.5em;
transform: rotate(90deg); //point down
pointer-events: none;
}
span {
}
select {
appearance: none;
background-color: mintcream;
border: 1px solid silver;
padding: 0.3em 2em 0.3em 0.3em;
margin: 0px;
&:invalid {
color: red;
}
}
}

section.calculator {
min-height: 600px; //prevent jitter when calculations refresh
>form {
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px 30px;
text-align: left;
background-color: lightblue;
border: 10px solid white;
border-radius: 30px;
padding: 20px 20px 40px 20px;
margin-bottom: 10px;
>label {
>span {
margin-bottom: 3px;
}
>input[name=quantity] {
max-width: 6em;
margin: 0px;
}
>select {
margin: 0px;
&[name=units] {
}
&[name=ingredient] {
}
option {
}
}
}
p {
position: absolute;
bottom: 5px;
font-size: 0.8rem;
margin: 0px;
}
}
>figure {
>figcaption {
font-style: normal;
margin-bottom: 15px;
}
>p {
font-size: 2rem;
color: royalblue;
margin-bottom: 15px;
}
>div {
>output {
display: block;
text-align: left;
font-style: normal;
b {
}
}
}
}
}

section.oven-temperature {
>div {
display: flex;
justify-content: center;
align-items: center;
gap: 0px 5px;
>form {
display: flex;
align-items: center;
background-color: lightblue;
border-radius: 10px;
padding: 10px 20px 10px 25px;
margin: 0px 20px 0px 0px;
.MobileMode({ margin-right: 5px; });
input {
width: 5em;
.MobileMode({ width: 3.5em; });
margin: 0px 0.3em 0px 0px;
}
}
>i.font-icon {
font-size: 2rem;
color: royalblue;
margin: 0px;
}
>figure {
font-size: 1.8rem;
padding: 0px;
margin: 0px;
output {
display: inline-block;
min-width: 3em;
.MobileMode({ min-width: 2em; });
text-align: right;
margin-right: 0.2em;
}
}
}
}
102 changes: 102 additions & 0 deletions src/website/calculator/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{% assign articleTitle = 'Recipe Converter Calculator' %}
{% assign heroImage = 'banana-bread-by-nist.jpg' %}
{% assign heroCaption = 'Convert ingredients to grams' %}
{% render 'src/templates/doc-begin.html', articleTitle: articleTitle, heroImage: heroImage, heroCaption: heroCaption %}

<main class=center-line>

<section class=calculator data-on-load=app.calculator.init>
<h2>{{articleTitle}}</h2>
<form>
<label>
<span>Quantity:</span>
<input name=quantity value=1 maxlength=8 required
data-on-input=app.calculator.convertToGrams placeholder=Quantity...>
</label>
<label>
<span>Units:</span>
<select name=units data-on-change=app.calculator.convertToGrams>
<option value=teaspoon data-type=volume data-per-cup=48> Teaspoons</option>
<option value=tablespoon data-type=volume data-per-cup=16> Tablespoons</option>
<option value=floz data-type=volume data-per-cup=8> Fluid Ounces (fl oz)</option>
<option value=stick data-type=volume data-per-cup=2> Sticks (4 oz)</option>
<option value=cup data-type=volume data-per-cup=1 selected>Cups</option>
<option value=block data-type=volume data-per-cup=0.5> Blocks (4 sticks)</option>
<option value=pint data-type=volume data-per-cup=0.5> Pints</option>
<option value=quart data-type=volume data-per-cup=0.25> Quarts</option>
<option value=gallon data-type=volume data-per-cup=0.0625> Gallons</option>
<option value=oz data-type=weight data-grams=28.3495> Ounces (oz weight)</option>
<option value=lb data-type=weight data-grams=453.592> Pounds (lb weight)</option>
</select>
</label>
<label>
<span>Ingredient:</span>
<select name=ingredient data-on-change=app.calculator.convertToGrams autofocus>
<option id=input-ingredient class=dna-template>~~[value]~~</option>
</select>
</label>
<p>Quantity can include fractions, such as: <i>3 1/2</i></p>
</form>
<figure id=calculator-result class=dna-template>
<figcaption>
<b data-format-number=#.###>~~imperial.quantity~~</b>
<b>~~imperial.units~~</b> <b>~~imperial.name~~</b>
</figcaption>
<p><i data-icon=arrow-alt-circle-down></i></p>
<div>
<output data-array=~~metric~~>
<b data-precision=2 data-format-number=#>~~grams~~</b> <b>grams</b>
<b>~~ingredient.form~~</b> <b>~~ingredient.name~~</b>
</output>
</div>
</figure>
</section>

<section class=oven-temperature>
<h2>Oven Temperature Conversion</h2>
<div>
<form><input value=350 data-on-input=app.calculator.updateTemperature>&deg;F</form>
<i data-icon=arrow-alt-circle-right></i>
<figure><output id=celsius class=dna->180</output>&deg;C</figure>
</div>
</section>

<section>
<h2>NIST Metric Kitchen</h2>
<figure>
<img src={{heroImage}} data-author=nist.gov data-license=public-domain alt=bread>
<figcaption>Metric Banana Bread</figcaption>
</figure>
<p>
Get helpful cooking and baking tips from the NIST* Metric Kitchen at:<br>
<a href=https://www.nist.gov/pml/owm/metric-si/metric-kitchen class=external-site>
nist.gov/pml/owm/metric-si/metric-kitchen
</a>
</p>
<p>
NIST has metric recipes for banana bread, mac and cheese, apple crisps, and more at:<br>
<a href=https://doi.org/10.6028/NIST.SP.1290 class=external-site>
doi.org/10.6028/NIST.SP.1290
</a>
</p>
<small><b>*NIST:</b> National Institute of Standards and Technology</small>
</section>

<section>
<i data-brand=github></i>
<h2>Open Source</h2>
<p>
The <i>Recipe Converter Calculator</i> is an open source community project.&nbsp;
You can help out by submitting corrections and additions.&nbsp;
</p>
<p>
Data for the calculator is on GitHub at:<br>
<a href=https://github.com/center-key/think-metric/blob/main/src/website/calculator/ingredients-db.js>
ingredients-db.js
</a>
</p>
</section>

</main>

{% render 'src/templates/doc-end.html' %}
9 changes: 9 additions & 0 deletions src/website/calculator/ingredients-db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Think Metric

globalThis.ingredientsDB = [
{ name: 'Almonds', form: 'Sliced', gramsPerCup: 110 },
{ name: 'Almonds', form: 'Raw', gramsPerCup: 130 },
{ name: 'Almonds', form: 'Roasted', gramsPerCup: 120 },
{ name: 'Butter', form: null, gramsPerCup: 227 },
{ name: 'Honey', form: null, gramsPerCup: 340 },
];
Loading

0 comments on commit d4f36c1

Please sign in to comment.