generate recipes into multiple partials to fit nice formatting

This commit is contained in:
len0rd 2022-06-21 21:02:32 -04:00
parent cc054470a7
commit b2b500c3a0
10 changed files with 252 additions and 68 deletions

View file

@ -62,6 +62,6 @@
padding-left: 2%; padding-left: 2%;
} }
.card { .card-homepage {
background-color: rgba(0, 0, 0, 0.1) !important; background-color: rgba(0, 0, 0, 0.1) !important;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 MiB

90
package-lock.json generated
View file

@ -12,6 +12,7 @@
"dynamic-scrollspy": "^0.2.0", "dynamic-scrollspy": "^0.2.0",
"ejs": "^3.1.8", "ejs": "^3.1.8",
"express": "^4.17.1", "express": "^4.17.1",
"markdown-it": "^13.0.1",
"mkdirp": "^1.0.4", "mkdirp": "^1.0.4",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"showdown-highlight": "^3.0.0" "showdown-highlight": "^3.0.0"
@ -29,6 +30,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -224,6 +230,17 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/escape-html": { "node_modules/escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -432,6 +449,34 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -710,6 +755,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -745,6 +795,11 @@
"negotiator": "0.6.2" "negotiator": "0.6.2"
} }
}, },
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"array-flatten": { "array-flatten": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -897,6 +952,11 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
}, },
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
},
"escape-html": { "escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -1065,6 +1125,31 @@
"minimatch": "^3.0.4" "minimatch": "^3.0.4"
} }
}, },
"linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"requires": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
},
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"media-typer": { "media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -1272,6 +1357,11 @@
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
} }
}, },
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"unpipe": { "unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View file

@ -21,6 +21,7 @@
"dynamic-scrollspy": "^0.2.0", "dynamic-scrollspy": "^0.2.0",
"ejs": "^3.1.8", "ejs": "^3.1.8",
"express": "^4.17.1", "express": "^4.17.1",
"markdown-it": "^13.0.1",
"mkdirp": "^1.0.4", "mkdirp": "^1.0.4",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"showdown-highlight": "^3.0.0" "showdown-highlight": "^3.0.0"

View file

@ -13,26 +13,24 @@ const showdown = require('showdown'),
projectOutputDir = './views/partials/md/projects/', projectOutputDir = './views/partials/md/projects/',
recipeInputDir = './recipes/', recipeInputDir = './recipes/',
recipeOutputDir = './views/partials/md/recipes/', recipeOutputDir = './views/partials/md/recipes/',
classMap = { projectClassMap = {
h1: 'display-1' //tag type : class to add to all tags of that type (class="display-1" added to all <h1>) h1: 'display-1' //tag type : class to add to all tags of that type (class="display-1" added to all <h1>)
}; };
const { assert } = require('console');
// handles adding classes to specific
// tag types automatically function addClassToTag(text, classMap) {
const addClass = {
type: 'output', // when it's triggered -> output is at the very end when text is html
filter: text => {
var modifiedText = text; var modifiedText = text;
Object.keys(classMap).forEach(function (key) { Object.keys(classMap).forEach(function (key) {
var regex = new RegExp(`<${key}(.*?)>`, 'g'); var regex = new RegExp(`<(${key})(.*?)>`, 'g');
matcher = regex.exec(modifiedText); matcher = regex.exec(modifiedText);
// only proceed if we found a match, and the class we add isn't already on the tag somehow // only proceed if we found a match, and the class we add isn't already on the tag somehow
while (matcher != null && !matcher[0].includes(classMap[key])) { while (matcher != null && !matcher[2].includes(classMap[key])) {
// add the class content WHILE preserving any other properties already in the tag! // add the class content WHILE preserving any other properties already in the tag!
console.log("adding class content in: " + matcher[0]); console.log("adding class content in: " + matcher[0]);
var restOfTag = matcher[1]; var restOfTag = matcher[2];
modifiedText = modifiedText.replace(matcher[0], `<${key} class="${classMap[key]}" ${restOfTag}>`); modifiedText = modifiedText.replace(matcher[0], `<${key} class="${classMap[key]}" ${restOfTag}>`);
matcher = regex.exec(modifiedText); matcher = regex.exec(modifiedText);
@ -40,16 +38,21 @@ const addClass = {
}); });
return modifiedText; return modifiedText;
} }
// handles adding classes to specific
// tag types automatically in project writeups
const projectsAddHeaderClass = {
type: 'output', // when it's triggered -> output is at the very end when text is html
filter: text => { return addClassToTag(text, projectClassMap); }
}; };
// create our Showdown converter with our custom extension // create Showdown converters
const converter = new showdown.Converter({ const projectsConverter = new showdown.Converter({
extensions: [addClass, showdownHighlight], extensions: [projectsAddHeaderClass, showdownHighlight],
tables: true tables: true
}); });
function convertMarkdownInDirWithShowdown(inputDir, outputDir, converter) {
function convertMarkdownInDir(inputDir, outputDir) {
// make the directory for the html output if necessary // make the directory for the html output if necessary
mkdirp.sync(outputDir); mkdirp.sync(outputDir);
fs.readdir(inputDir, (err, files) => { fs.readdir(inputDir, (err, files) => {
@ -74,5 +77,93 @@ function convertMarkdownInDir(inputDir, outputDir) {
}); });
} }
convertMarkdownInDir(projectInputDir, projectOutputDir); function convertRecipeMarkdown(inputDir, outputDir) {
convertMarkdownInDir(recipeInputDir, recipeOutputDir); var md = require('markdown-it')();
// This is a hardcoded markdown header section number to html file name
//
// Example.md:
// """
// ... maybe some other header info here -| - exported as filename-title.ejs
// # Delicious Recipe Name -|
// Catch phrase or yield -|
// | - exported as filename-subtitle
// image of the food |
// -|
// ## Ingredients -|
// ... ingredients table, etc | - exported as filename-ingredients.ejs
// -|
// ## Instructions
// """
//
// NOTE: these titles are HARDCODED in recipe_template.ejs!
const mdSectionHtmlTitles = [
'title',
// 'subtitle',
'ingredients',
'instructions',
]
mkdirp.sync(outputDir);
fs.readdir(inputDir, (err, files) => {
files.forEach(file => {
if (file.endsWith('.md')) {
let fileNameNoExtension = file.slice(0, -3);
console.log('converting: ' + fileNameNoExtension);
fs.readFile(inputDir + file, 'utf8', (err, data) => {
if (err) {
console.error(err);
} else {
let tokens = md.parse(data)
let sections = []
sections.push([]); // start off the array and put everything before and including the first header in title
let numSections = 0;
for (const token of tokens) {
if (token.type === 'heading_open') {
if (numSections == 0) {
numSections++;
}
else if (numSections < mdSectionHtmlTitles.length) {
console.log("found heading open. start new section arr");
numSections++;
sections.push([]);
}
}
sections[sections.length - 1].push(token)
}
assert(sections.length <= mdSectionHtmlTitles.length);
// hardcode bootstrap class attribute to add to <table> tag in ingredients
for (let ii = 0; ii < sections[1].length; ii++) {
if (sections[1][ii].type == 'table_open') {
sections[1][ii].attrs = [["class", "table table-striped table-sm table-hover"]];
break;
}
}
// console.log(sections[0]);
for (let ii = 0; ii < sections.length; ii++) {
let html = md.renderer.render(sections[ii], md.options);
// hardcode making images in the title section larger
if (ii == 0) {
var regex = new RegExp(`<img (.*?)>`, `g`);
matcher = regex.exec(html);
while (matcher != null && !matcher[1].includes("w-100")) {
var restOfTag = matcher[1];
html = html.replace(matcher[0], `<img class="w-100" ${restOfTag}>`);
matcher = regex.exec(html);
}
}
fs.writeFileSync(outputDir + fileNameNoExtension + '-' + mdSectionHtmlTitles[ii] + '.ejs', html, 'utf8');
}
}
});
}
});
});
}
convertMarkdownInDirWithShowdown(projectInputDir, projectOutputDir, projectsConverter);
convertRecipeMarkdown(recipeInputDir, recipeOutputDir);

View file

@ -28,13 +28,13 @@ With the requirements thought out, I started planning how I was going to build e
There were some really cool designs online, but I needed something simple. This was my first woodworking project, and I knew I *would* (hehe) be making a lot of mistakes. All of these thoughts culminated into a single whiteboard sketch: There were some really cool designs online, but I needed something simple. This was my first woodworking project, and I knew I *would* (hehe) be making a lot of mistakes. All of these thoughts culminated into a single whiteboard sketch:
![Whiteboard sketch of ititial design](/img/writeup/palletDesk/plans-1-sm.jpg) ![Whiteboard sketch of initial design](/img/writeup/palletDesk/plans-1-sm.jpg)
Yep. That's it. It was all a lot clearer in my head. Essentially the red 'rectangles' are 2x4 cross beams that would support the desktop and create a structure to build onto. The measurements were mainly based on what would fit in my Camry. Note: this only fits in the car when I put the back seats down so the desk can go through the trunk and into the back of the car. pics further down. I also measured a few desks nearby to see what an appropriate depth for a monitor + keyboard would be. Yep. That's it. It was all a lot clearer in my head. Essentially the red 'rectangles' are 2x4 cross beams that would support the desktop and create a structure to build onto. The measurements were mainly based on what would fit in my Camry. Note: this only fits in the car when I put the back seats down so the desk can go through the trunk and into the back of the car. pics further down. I also measured a few desks nearby to see what an appropriate depth for a monitor + keyboard would be.
## Build ## Build
### Pallet Aquisition ### Pallet Acquisition
There are a lot of guides on how to get pallets online. If you're in the US, check the free section of Craigslist or your local classifieds. You can also just walk into local places and ask if they have any pallets that you can use. Alternatively, just drive behind businesses and see if they have pallets stacked near the dumpster. There are a lot of guides on how to get pallets online. If you're in the US, check the free section of Craigslist or your local classifieds. You can also just walk into local places and ask if they have any pallets that you can use. Alternatively, just drive behind businesses and see if they have pallets stacked near the dumpster.

View file

@ -2,6 +2,8 @@
*yields: ~4 dozen* *yields: ~4 dozen*
![Cookies](/img/recipes/chocolateChipCookies.jpeg)
## Ingredients ## Ingredients
Measure | Weight | Ingredient Measure | Weight | Ingredient
@ -16,7 +18,7 @@ Measure | Weight | Ingredient
2 3/4c | 370g | Flour 2 3/4c | 370g | Flour
1 tsp | 7g | Baking Soda 1 tsp | 7g | Baking Soda
1 tsp | 7g | Salt 1 tsp | 7g | Salt
| 1g | Cinnamon 1/4 tsp | 1g | Cinnamon
2c | | Chocolate Chip 2c | | Chocolate Chip
## Instructions ## Instructions

View file

@ -40,7 +40,7 @@
</div> </div>
<div class="container pb-5 pt-5"> <div class="container pb-5 pt-5">
<div class="card-columns"> <div class="card-columns">
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Yama Crawler</h5> <h5 class="card-title">Yama Crawler</h5>
<h6 class="card-subtitle mb-2 text-muted">Selenium-Based Web Crawler</h6> <h6 class="card-subtitle mb-2 text-muted">Selenium-Based Web Crawler</h6>
@ -52,7 +52,7 @@
Code</a> Code</a>
</div> </div>
</div> </div>
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Mavlib Gen</h5> <h5 class="card-title">Mavlib Gen</h5>
<h6 class="card-subtitle mb-2 text-muted">Modern Mavlink C generator</h6> <h6 class="card-subtitle mb-2 text-muted">Modern Mavlink C generator</h6>
@ -63,7 +63,7 @@
<a href="https://github.com/len0rd/mavlib_gen" class="card-link card-soft-link">See Code</a> <a href="https://github.com/len0rd/mavlib_gen" class="card-link card-soft-link">See Code</a>
</div> </div>
</div> </div>
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Darkstar</h5> <h5 class="card-title">Darkstar</h5>
<h6 class="card-subtitle mb-2 text-muted">Why buy a quad when you can build it</h6> <h6 class="card-subtitle mb-2 text-muted">Why buy a quad when you can build it</h6>
@ -78,7 +78,7 @@
Code</a> Code</a>
</div> </div>
</div> </div>
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Pallet Desk</h5> <h5 class="card-title">Pallet Desk</h5>
<h6 class="card-subtitle mb-2 text-muted">Reliable and cheap desk</h6> <h6 class="card-subtitle mb-2 text-muted">Reliable and cheap desk</h6>
@ -89,7 +89,7 @@
<a href="projects/palletDesk" class="btn btn-outline-light">Read More</a> <a href="projects/palletDesk" class="btn btn-outline-light">Read More</a>
</div> </div>
</div> </div>
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">My Website</h5> <h5 class="card-title">My Website</h5>
<h6 class="card-subtitle mb-2 text-muted">Is this meta</h6> <h6 class="card-subtitle mb-2 text-muted">Is this meta</h6>
@ -104,7 +104,7 @@
</div> </div>
</div> </div>
<div class="card bg-dark border-light text-white"> <div class="card bg-dark card-homepage border-light text-white">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">LS-1 Synth</h5> <h5 class="card-title">LS-1 Synth</h5>
<h6 class="card-subtitle mb-2 text-muted">Music to my ears</h6> <h6 class="card-subtitle mb-2 text-muted">Music to my ears</h6>

View file

@ -11,8 +11,7 @@
<%- include('../partials/nav') %> <%- include('../partials/nav') %>
</header> </header>
<div class="container mt-5"> <div class="container mt-5 topMargin">
<div class="topMargin">
<h1>Recipes</h1> <h1>Recipes</h1>
<div class="list-group"> <div class="list-group">
<a href="recipes/chocolateChipCookies" class="list-group-item list-group-item-action">Chocolate Chip Cookies</a> <a href="recipes/chocolateChipCookies" class="list-group-item list-group-item-action">Chocolate Chip Cookies</a>
@ -21,7 +20,6 @@
<a href="#" class="list-group-item list-group-item-action">Vestibulum at eros</a> <a href="#" class="list-group-item list-group-item-action">Vestibulum at eros</a>
</div> </div>
</div> </div>
</div>
<%- include('../partials/post_html_include') %> <%- include('../partials/post_html_include') %>
</body> </body>

View file

@ -12,20 +12,22 @@
<%- include(rootPath + 'partials/nav') %> <%- include(rootPath + 'partials/nav') %>
</header> </header>
<div class="container mt-5"> <div class="container mt-5 topMargin">
<div class="row"> <div class="row g-0">
<%- include(rootPath + page) %> <div class="col-md-8">
<%- include(rootPath + page + '-title') %>
</div>
<div class="col">
<div class="card">
<div class="card-body">
<%- include(rootPath + page + '-ingredients') %>
</div>
</div>
</div> </div>
</div> </div>
<%- include(rootPath + 'partials/footer') %> <%- include(rootPath + page + '-instructions') %>
<%- include(rootPath + 'partials/post_html_include') %> </div>
<script type="text/javascript" src="/script/dynamicscrollspy.min.js"></script>
<script>
$('#scrollBar').DynamicScrollspy({
ulClassNames: 'navbar navbar-light bg-light sticky-top sticky-offset'
});
</script>
<%- include(rootPath + 'partials/post_html_include') %> <%- include(rootPath + 'partials/post_html_include') %>
</body> </body>