diff --git a/assets/css/site.css b/assets/css/site.css
index 74d01d0..af3c577 100644
--- a/assets/css/site.css
+++ b/assets/css/site.css
@@ -62,6 +62,6 @@
padding-left: 2%;
}
-.card {
+.card-homepage {
background-color: rgba(0, 0, 0, 0.1) !important;
}
diff --git a/assets/img/recipes/chocolateChipCookies.jpeg b/assets/img/recipes/chocolateChipCookies.jpeg
new file mode 100644
index 0000000..3785310
Binary files /dev/null and b/assets/img/recipes/chocolateChipCookies.jpeg differ
diff --git a/package-lock.json b/package-lock.json
index 925b88f..37f689b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"dynamic-scrollspy": "^0.2.0",
"ejs": "^3.1.8",
"express": "^4.17.1",
+ "markdown-it": "^13.0.1",
"mkdirp": "^1.0.4",
"showdown": "^2.1.0",
"showdown-highlight": "^3.0.0"
@@ -29,6 +30,11 @@
"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": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -224,6 +230,17 @@
"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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -432,6 +449,34 @@
"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": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -710,6 +755,11 @@
"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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -745,6 +795,11 @@
"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": {
"version": "1.1.1",
"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",
"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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1065,6 +1125,31 @@
"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": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -1272,6 +1357,11 @@
"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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
diff --git a/package.json b/package.json
index 82f2ef7..e3ae6c5 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"dynamic-scrollspy": "^0.2.0",
"ejs": "^3.1.8",
"express": "^4.17.1",
+ "markdown-it": "^13.0.1",
"mkdirp": "^1.0.4",
"showdown": "^2.1.0",
"showdown-highlight": "^3.0.0"
diff --git a/prestart.js b/prestart.js
index 988b34d..abbd692 100644
--- a/prestart.js
+++ b/prestart.js
@@ -13,43 +13,46 @@ const showdown = require('showdown'),
projectOutputDir = './views/partials/md/projects/',
recipeInputDir = './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
)
};
+const { assert } = require('console');
+
+
+function addClassToTag(text, classMap) {
+ var modifiedText = text;
+ Object.keys(classMap).forEach(function (key) {
+ var regex = new RegExp(`<(${key})(.*?)>`, 'g');
+ matcher = regex.exec(modifiedText);
+
+ // only proceed if we found a match, and the class we add isn't already on the tag somehow
+ while (matcher != null && !matcher[2].includes(classMap[key])) {
+ // add the class content WHILE preserving any other properties already in the tag!
+ console.log("adding class content in: " + matcher[0]);
+
+ var restOfTag = matcher[2];
+ modifiedText = modifiedText.replace(matcher[0], `<${key} class="${classMap[key]}" ${restOfTag}>`);
+
+ matcher = regex.exec(modifiedText);
+ }
+ });
+ return modifiedText;
+}
// handles adding classes to specific
-// tag types automatically
-const addClass = {
+// 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 => {
- var modifiedText = text;
- Object.keys(classMap).forEach(function (key) {
- var regex = new RegExp(`<${key}(.*?)>`, 'g');
- matcher = regex.exec(modifiedText);
-
- // 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])) {
- // add the class content WHILE preserving any other properties already in the tag!
- console.log("adding class content in: " + matcher[0]);
-
- var restOfTag = matcher[1];
- modifiedText = modifiedText.replace(matcher[0], `<${key} class="${classMap[key]}" ${restOfTag}>`);
-
- matcher = regex.exec(modifiedText);
- }
- });
- return modifiedText;
- }
+ filter: text => { return addClassToTag(text, projectClassMap); }
};
-// create our Showdown converter with our custom extension
-const converter = new showdown.Converter({
- extensions: [addClass, showdownHighlight],
+// create Showdown converters
+const projectsConverter = new showdown.Converter({
+ extensions: [projectsAddHeaderClass, showdownHighlight],
tables: true
});
-
-function convertMarkdownInDir(inputDir, outputDir) {
+function convertMarkdownInDirWithShowdown(inputDir, outputDir, converter) {
// make the directory for the html output if necessary
mkdirp.sync(outputDir);
fs.readdir(inputDir, (err, files) => {
@@ -74,5 +77,93 @@ function convertMarkdownInDir(inputDir, outputDir) {
});
}
-convertMarkdownInDir(projectInputDir, projectOutputDir);
-convertMarkdownInDir(recipeInputDir, recipeOutputDir);
+function convertRecipeMarkdown(inputDir, outputDir) {
+ 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
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(`
`, `g`);
+ matcher = regex.exec(html);
+ while (matcher != null && !matcher[1].includes("w-100")) {
+ var restOfTag = matcher[1];
+ html = html.replace(matcher[0], `
`);
+ matcher = regex.exec(html);
+ }
+ }
+ fs.writeFileSync(outputDir + fileNameNoExtension + '-' + mdSectionHtmlTitles[ii] + '.ejs', html, 'utf8');
+ }
+ }
+ });
+ }
+ });
+ });
+}
+
+convertMarkdownInDirWithShowdown(projectInputDir, projectOutputDir, projectsConverter);
+convertRecipeMarkdown(recipeInputDir, recipeOutputDir);
diff --git a/project_writeups/palletDesk.md b/project_writeups/palletDesk.md
index 2e178e4..ccbeb9c 100755
--- a/project_writeups/palletDesk.md
+++ b/project_writeups/palletDesk.md
@@ -28,15 +28,15 @@ 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:
-
+
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
-### 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.
If you have a smaller car, be prepared to potentially tear down the pallet on site. Pallets were a bit larger than I expected and some of them would not fit in my car! Because of this, I had to pass up on some of the nicer pallets out there. In all, I think this project took 2-3 pallets. It could be done with less, but my teardown methods were less than ideal.
@@ -44,9 +44,9 @@ The problem with pallet wood is that it's a bit of a mixed bag. Sometimes you ge
### Pallet Teardown
-The best way to get usable wood from a pallet is to use a jig saw. Period. If you don't have one, buy one online or borrow a friends. It's worth it especially if you want to do a lot of projects like this. With a jig saw, it's very easy to align the blade between the pallet planks and cut through the nails holding them in place. If you have room to spare, you could also use a table saw and just cut off the pallet planks before they're nailed into the base.
+The best way to get usable wood from a pallet is to use a jig saw. Period. If you don't have one, buy one online or borrow a friends. It's worth it especially if you want to do a lot of projects like this. With a jig saw, it's very easy to align the blade between the pallet planks and cut through the nails holding them in place. If you have room to spare, you could also use a table saw and just cut off the pallet planks before they're nailed into the base.
-If you're a poor college student as I was, the other option is a crowbar, hammer and *a lot* of patience. With this method you need to jimmy the crow bar in between the pallet plank and base and slowely wedge out the nails holding the plank in place. Making sure you dont strain one end of the plank too much and crack it. This is a delicate process that takes a long time and often ends in breaking the pallet planks much to the despair of the builder.
+If you're a poor college student as I was, the other option is a crowbar, hammer and *a lot* of patience. With this method you need to jimmy the crow bar in between the pallet plank and base and slowely wedge out the nails holding the plank in place. Making sure you dont strain one end of the plank too much and crack it. This is a delicate process that takes a long time and often ends in breaking the pallet planks much to the despair of the builder.
Because of this expense of learning, Perhaps only 50% of the 3 pallets I had turned out usable. Unfortunately I don't have any images of this stage of the process likely due to the rage-inducing nature of it all. I worked on this portion of the project at night after getting home from school across a couple of days.
@@ -70,7 +70,7 @@ Also, for this entire project, wood was cut to size using my friends chop saw. N

-With the basic frame in place, it was time to start building the visible part of the desktop. I started by bordering the exterior with pallet plants to make something like a picture frame for the middle. The chop saw came in handy, helping make angles that match.
+With the basic frame in place, it was time to start building the visible part of the desktop. I started by bordering the exterior with pallet plants to make something like a picture frame for the middle. The chop saw came in handy, helping make angles that match.

@@ -86,9 +86,9 @@ Once the crate paper was secured I started cutting and fitting pallet planks. I
Once a single board was pushed to the far right side, It would be secured on the 3 2x4 frame pieces with screws and glue. Once all the pieces were secured I went back and started sanding. The desktop was made from a combination of three different pallets, so the wood was vastly different in quality and thickness.
-My **biggest** regret in this project was not spending enough time sanding the top. Especially the middle of the desk, I should've spend multiple hours sanding it, with multiple passes at different levels of courseness to make sure it was smooth and flat. A planar and/or a really good electric sander should be a must for this portion of the project. A single board in the middle of my destop is slightly thicker than the others, which means my keyboard can not lie flat without wobbling.
+My **biggest** regret in this project was not spending enough time sanding the top. Especially the middle of the desk, I should've spend multiple hours sanding it, with multiple passes at different levels of courseness to make sure it was smooth and flat. A planar and/or a really good electric sander should be a must for this portion of the project. A single board in the middle of my destop is slightly thicker than the others, which means my keyboard can not lie flat without wobbling.
-If you plan on covering the top in epoxy as I did, this is also a good time to make *sure* any and all holes are filled with wood filler (I made wood filler by mixing wood glue with some sawdust). You dont want anywhere for the epoxy to escape so make sure all the old nail holes on the pallet boards are properly filled.
+If you plan on covering the top in epoxy as I did, this is also a good time to make *sure* any and all holes are filled with wood filler (I made wood filler by mixing wood glue with some sawdust). You dont want anywhere for the epoxy to escape so make sure all the old nail holes on the pallet boards are properly filled.
### Legs
@@ -138,4 +138,4 @@ And, in case you doubted, here's the desk broken down and in the trunk of my Cam
The desk works great, and overall the design is very forgiving to rookie mistakes. Make sure you have the proper tools (Jigsaw) for pallet dissassembly. Dont skimp on sanding the desktop, and if you're going to use epoxy, make *absolutely* sure that you have adequately filled in all the nail holes in the pallet wood before application.
-
\ No newline at end of file
+
diff --git a/recipes/chocolateChipCookies.md b/recipes/chocolateChipCookies.md
index 9abf539..dd8f900 100644
--- a/recipes/chocolateChipCookies.md
+++ b/recipes/chocolateChipCookies.md
@@ -2,6 +2,8 @@
*yields: ~4 dozen*
+
+
## Ingredients
Measure | Weight | Ingredient
@@ -16,7 +18,7 @@ Measure | Weight | Ingredient
2 3/4c | 370g | Flour
1 tsp | 7g | Baking Soda
1 tsp | 7g | Salt
-| 1g | Cinnamon
+1/4 tsp | 1g | Cinnamon
2c | | Chocolate Chip
## Instructions
diff --git a/views/pages/index.ejs b/views/pages/index.ejs
index 30e478a..ab5cb9a 100644
--- a/views/pages/index.ejs
+++ b/views/pages/index.ejs
@@ -40,7 +40,7 @@
-
+
Yama Crawler
Selenium-Based Web Crawler
@@ -52,7 +52,7 @@
Code
-
+
Mavlib Gen
Modern Mavlink C generator
@@ -63,7 +63,7 @@
See Code
-
+
Darkstar
Why buy a quad when you can build it
@@ -78,7 +78,7 @@
Code
-
+
Pallet Desk
Reliable and cheap desk
@@ -89,7 +89,7 @@
Read More
-
+
My Website
Is this meta
@@ -104,7 +104,7 @@
-
+
LS-1 Synth
Music to my ears
diff --git a/views/pages/recipe_navigator.ejs b/views/pages/recipe_navigator.ejs
index eaec7a0..4261646 100644
--- a/views/pages/recipe_navigator.ejs
+++ b/views/pages/recipe_navigator.ejs
@@ -11,15 +11,13 @@
<%- include('../partials/nav') %>
-
-
-
Recipes
-
+
diff --git a/views/pages/recipes/recipe_template.ejs b/views/pages/recipes/recipe_template.ejs
index eb84a65..d69b30b 100644
--- a/views/pages/recipes/recipe_template.ejs
+++ b/views/pages/recipes/recipe_template.ejs
@@ -12,20 +12,22 @@
<%- include(rootPath + 'partials/nav') %>
-
-
- <%- include(rootPath + page) %>
-
-
+
+
+
+ <%- include(rootPath + page + '-title') %>
+
+
+
+
+ <%- include(rootPath + page + '-ingredients') %>
+
+
+
+
- <%- include(rootPath + 'partials/footer') %>
- <%- include(rootPath + 'partials/post_html_include') %>
-
-
+ <%- include(rootPath + page + '-instructions') %>
+
<%- include(rootPath + 'partials/post_html_include') %>