mirror of
https://github.com/arfct/itty-bitty.git
synced 2026-03-11 08:54:33 +00:00
Updated recipe rendering
This commit is contained in:
parent
22937ea02b
commit
64d15d9049
5 changed files with 153 additions and 77 deletions
|
|
@ -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
6
docs/js/qrious.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
Loading…
Reference in a new issue