Updated recipe rendering

This commit is contained in:
Nicholas Jitkoff 2022-08-16 21:47:10 -07:00
parent 22937ea02b
commit 64d15d9049
5 changed files with 153 additions and 77 deletions

View file

@ -113,6 +113,7 @@ class DataURL {
let rawData = this.encoding ? await base64ToByteArray(this.data) : stringToByteArray(this.data);
let compressedData = await compressData(rawData, format);
var base64String = dataToBase64(compressedData);
base64String = base64String.replace(/=+$/, "");
this.data = base64String;
this.params.format = format;
return this;
@ -420,7 +421,7 @@ function encodePrettyComponent(s) {
let replacements = {' - ': '---', '-': '--', ' ' : '-'}
let re = new RegExp('(' + Object.keys(replacements).join('|') + ')', 'g');
return encodeURIComponent(s.replace(re, e => replacements[e] ?? '-'))
.replace(/\%2C/g, ",")
// .replace(/\%2C/g, ",")
.replace(/[!'()*]/g, (c) => '%' + c.charCodeAt(0).toString(16));
}

6
docs/js/qrious.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -38,15 +38,6 @@ const el = (selector, ...args) => {
};
window.el = el;
function loadScript(src, callback, type = "module") {
let script = el("script", { src, type });
script.addEventListener('load', function(e) {
console.debug("Loaded script", src);
if (callback) callback(e);
});
document.head.appendChild(script);
}
function async(u, c) {
var d = document, t = 'script',
o = d.createElement(t),
@ -56,11 +47,18 @@ function async(u, c) {
s.parentNode.insertBefore(o, s);
}
function loadScript(src, callback, type = "module") {
let promise = new Promise((resolve, reject) => {
document.head.appendChild(el("script", { src, type, onload:resolve}));
})
return callback ? promise.then(callback) : promise;
}
function loadSyle(href, callback) {
let promise = new Promise((resolve, reject) => {
document.head.appendChild(el("link", { type: "text/css", rel: "stylesheet", href, onload:resolve}));
})
return callback ? promise.then(callback) : promise;
return callback ? promise.then(callback) : promise;
}

View file

@ -53,10 +53,10 @@ body {
text-decoration-style: dotted;
box-sizing: border-box;
/* color: var(--background-color); */
border-bottom:1px solid transparent;
/* border-bottom:1px solid transparent; */
border-bottom-color: currentColor;
/* background-color: var(--text-color); */
font-weight: bold;
}
.timer:hover,
@ -85,6 +85,11 @@ body {
.timer.active .countdown {
display:inline-block;
}
.timer svg {
width: 1em;
vertical-align: sub;
margin-bottom: 1px;
}
}
@ -92,6 +97,9 @@ body {
.timer {
font-weight:800;
}
.timer svg {
display:none;
}
}
img.publisher {
@ -173,8 +181,12 @@ ul.step:after {
height: 0.5px;
background-color: currentColor;
opacity: 1;
border:none;
margin: 1em 0 0.2em 0 ;
border:
none;
margin: 1em 0 0.2em 0;
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
/* margin-left: -19em; */
}
ul.step.header:after,
@ -200,8 +212,10 @@ span.number {
/* line-height: 16px; */
opacity: 1;
user-select: none;
color:var(--accent-color)
/* background: black; */
color:
var(--accent-color)
/* background: black; */;
display: none;
}
@media screen {
@ -282,7 +296,7 @@ li:hover {
} */
.time:before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='22' fill='none' viewBox='0 0 18 22'%3E%3Cpath fill='%23000' d='M4.031 17.953C5.406 19.328 7.063 20.016 9 20.016c1.938 0 3.578-.688 4.922-2.063 1.375-1.375 2.062-3.031 2.062-4.969 0-1.937-.687-3.578-2.062-4.921C12.578 6.687 10.937 6 9 6c-1.938 0-3.594.688-4.969 2.063-1.343 1.343-2.015 2.984-2.015 4.921 0 1.938.671 3.594 2.015 4.97zm12-10.547c.532.688.985 1.578 1.36 2.672.406 1.063.609 2.031.609 2.906 0 2.47-.875 4.594-2.625 6.375-1.75 1.75-3.875 2.625-6.375 2.625s-4.625-.875-6.375-2.625C.875 17.58 0 15.453 0 12.984c0-2.468.875-4.578 2.625-6.328C4.375 4.875 6.5 3.984 9 3.984c.844 0 1.813.204 2.906.61C13.031 5 13.937 5.469 14.625 6l1.406-1.453c.5.406.969.875 1.407 1.406L16.03 7.406zm-8.015 6.61v-6h1.968v6H8.016zM12 .984V3H6V.984h6z'/%3E%3C/svg%3E%0A");
} */
}
.time {
background-size:18px;
@ -301,6 +315,7 @@ li:hover {
/* color: rgba(0,0,0,0.8); */
/* color:
rgb(0, 118, 173); */
max-width: 16em;
}
.noun {
@ -317,7 +332,7 @@ li:hover .noun {
white-space: pre-wrap;
/* line-height: 125%; */
/* font-size: 100%; */
flex: 0 1 65%;
flex: 1 1 65%;
/* margin-top: -0.7em; */
}
@ -328,8 +343,8 @@ li:hover .noun {
}
.instructions.numbered li {
padding-left: 3rem;
margin-left: 0;
/* padding-left: 3rem; */
/* margin-left: 0; */
}
.substep {
@ -362,6 +377,8 @@ li:hover .noun {
min-width: 3rem;
text-align:
right;
color: var(--accent-color);
/* font-weight: bold; */
}
.ingredient:hover {
@ -512,44 +529,19 @@ hr {
}
@media print {
body {
font-size: 14px;
min-height:100vh;
}
.print-hide {
display: none !important;
}
@page {
size: auto; /* auto is the initial value */
/* margin: 1cm; */
}
a[href]:after { content: none !important; }
img[src]:after { content: none !important; }
}
@media not print {
body {
color:var(--text-color);
}
.print-show {
display:none;
}
}
.instructions.numbered hr {/* margin: 0.7em -1px; *//* height: 1.5px; *//* opacity: 0.2; *//* width: auto; */}
.instructions.numbered {/* margin-top: -1.6em; */}
img.qr {
margin-top:2em;
position:absolute;
/* margin-top:2em; */
position:
absolute;
bottom:0;
right:0;
width:2in;
left: 0;
max-width: 1in;
height: auto;
}
@media screen and (max-width: 1199px) {
@ -561,6 +553,7 @@ img.qr {
.recipe-content {
max-width:50em;
padding: 1em 0;
/* padding-left: 2em; */
}
@media screen and (min-width: 1200px) {
body {
@ -745,4 +738,44 @@ a.publisherlink {
span.timer.active.expired {
background-color: rgb(221, 40, 0);
}
}
@media print {
body {
font-size: 14px;
min-height:100vh;
margin: 0;
padding: 0;
}
.print-hide {
display: none !important;
}
.recipe {
margin:0;
max-width:unset;
}
.recipe-content {
max-width:
unset;
padding-left: 2em;
}
@page {
size: auto; /* auto is the initial value */
/* margin: 1cm; */
}
a[href]:after { content: none !important; }
img[src]:after { content: none !important; }
}
@media not print {
body {
color:var(--text-color);
}
.print-show {
display:none;
}
}

View file

@ -24,7 +24,7 @@ let FRACTION_MAP = {
}
let ignoredTerms = [
"fresh", "out", "not", "sprig", "sprigs", "room", "temperature", "still", "see", "notes", "with", "beat", "together", "crust", "very", "cold", "hot", "top", "warm", "one", "note", "teaspoon", "teaspoons", "tablespoon", "tablespoons", "cup", "cups", "taste", "more", "melted", "into", "wide", "pound", "pounds", "gram", "grams", "you", "ounce", "ounces", "thinly", "sliced",
"broken", "pieces", "tbsp", "tsp", "peeled", "then", "can", "oz", "fresh", "out", "not", "sprig", "sprigs", "room", "temperature", "still", "see", "notes", "with", "beat", "together", "crust", "very", "cold", "hot", "top", "warm", "one", "note", "teaspoon", "teaspoons", "tablespoon", "tablespoons", "cup", "cups", "taste", "more", "melted", "into", "wide", "pound", "pounds", "gram", "grams", "you", "ounce", "ounces", "thinly", "sliced",
"pan", "cube", "cubes", "finely", "ground", "garnish", "about", "cut", "and", "smashed", "each", "the", "medium", "large", "small", "for", "chopped", "minced", "grated", "box", "softened", "directed", "shredded", "cooked", "from", "frozen", "thawed"
]
let emojiMap = {
@ -315,7 +315,7 @@ function highlightTimes(string) {
return string.replace(pattern, (match, t1, t2, tt, offset, groups) => {
// console.log("match", t1, t2, tt)
return `<span class="timer" onclick="startTimer(this, ${t1}, ${t2})"><span class="countdown"></span><span class="label">${match}</span></span>`
return `<span class="timer" onclick="startTimer(this, ${t1}, ${t2})">${icons.timer}<span class="countdown"></span><span class="label">${match}</span></span>`
});
}
@ -411,7 +411,8 @@ function render() {
image = image?.url || image;
let instructions = json.recipeInstructions;
let title = clean(json.name);
let description = clean(json.description?.replace(/\\n/g, "<br>"))
let description = json.description || json.articleBody;
description = clean(description?.replace(/\\n/g, "<br>"))
let favicon = faviconForTitle(title) || "🍴";
parent.postMessage({title:title, favicon:favicon, image:image, description:description, wakeLock:true, updateURL:true}, "*");
description = description?.split("\n").join("<p>")
@ -461,26 +462,49 @@ function render() {
m("span.substep",{innerHTML:highlightTimes(highlightTerms(FRACTION_MAP.replace(text.trim()), terms))}))
}
function stepsFromText(text) {
try {
let steps = []
let components = text.split(new RegExp("(?<=[\.\!\?]|[\.\!\?]\)|\))\s+(?!\()"));
let append = false;
while (components.length) {
let step = components.shift()
if (append) {
steps.push(steps.pop() + " " + step)
} else {
steps.push(step);
}
if (step.indexOf("(") >= 0) { append = true; }
if (step.includes(")")) { append = false; }
function stepsFromText(text) {
let abbreviations = ["tsp", "tbsp", "oz", "lb", "lbs"];
let steps = [];
let i = 0;
let start = 0;
let depth = 0;
let lastSpace = 0;
for (let i = 0; i < text.length; i++) {
switch (text[i]) {
case "(": depth++; break;
case ")": depth--; break;
case " ": lastSpace = i; break;
case ".":
case "!":
case "?":
let lastWord = text.substring(lastSpace, i).trim();
lastWord = lastWord.match(/\w+$/)?.pop().toLowerCase();
if (abbreviations.includes(lastWord)) { continue; }
let end;
if (text[i+1] == ")" && text[i+2] == " ") {
end = i + 2;
} else if (text[i+1] == " " && text[i+2] != "(" && depth == 0) {
end = i + 1;
}
if (end) {
let string = text.substring(start, end);
steps.push(string);
start = end;
}
break;
case "\n":
steps.push(text.substring(start, i));
start = i;
default:
}
return steps;
} catch (e) {
return text.replace(/(\.\)? )+/g,"$1\n").split("\n")
}
steps.push (text.substring(start));
console.log("step", steps)
return steps;
}
function flattenInstructions(instruction) {
if (instruction.itemListElement) {
@ -532,8 +556,11 @@ function render() {
let thumbnail = document.querySelector("#thumbnail");
let thumbnailContainer = document.querySelector("#thumbnail-container");
thumbnail.style.backgroundImage = 'url("' + bgImg.src + '")';
thumbnail.style.filter = `blur(${thumbnailContainer.offsetHeight / bgImg.naturalHeight * 1}px)`;
// thumbnail.style.transform = `scale(1.1)`;
let blur = 1;
blur = Math.max(blur, Math.max(thumbnailContainer.offsetHeight * window.devicePixelRatio / bgImg.naturalHeight, thumbnailContainer.offsetWidth * window.devicePixelRatio / bgImg.naturalWidth))
if (blur > 1) thumbnail.style.filter = `blur(${blur/2}px)`;
setTimeout(() => thumbnail.style.opacity = 1.0, 0);
if (window.scrollY == 0) setTimeout(() => {
const yOffset = -20;
@ -597,10 +624,11 @@ function render() {
),
m(".columns",
m("section.ingredients",
m("section.ingredients.hanging",
m("caption.ingredients-title", {onclick:(e) => {e.target.closest("section").classList.toggle("hanging")}},"Ingredients"),
ingredients,
qrImage ? m("img.qr.print-show", {src:qrImage}) : null
qrImage ? m("img#qr.qr.print-show", {src:qrImage}) : null,
// m("canvas#qr")
),
m(reformat ? "section.instructions.numbered" : "section.instructions",
m("caption.ingredients-title", {onclick:() => {reformat = !reformat; render(); return false;}},
@ -642,4 +670,14 @@ function keepAwake() {
var path = window.script.substring(0, window.script.lastIndexOf("."));
var cssURL = path + ".css";
loadScript(path + '/../../js/qrious.min.js', null, "").then(() => {
console.log("qrious loaded");
var qr = new QRious({
element: document.getElementById("qr"),
background: 'transparent',
foreground: 'currentColor',
size: 512,
value: params.originalUrl,
});
})
loadSyle(cssURL).then(render);