diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4d8715f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +indent_style = tab +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab338d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +_site/ +node_modules/ +package-lock.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..94f4350 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.ignoreWords": [ + "TheSchricks" + ] +} \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a469e0c --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,53 @@ +# Articles + +All files under the `/content/files` directory (and likewise, the corresponding and respective files in /_site) are licensed under +[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). The attribution requirement is appropriately met under the following conditions as specified by the license: + +1. Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made . You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. +Whereby the following terms shall mean: +- Appropriate credit — If supplied, you must provide the name of the creator and attribution parties, a copyright notice, a license notice, a disclaimer notice, and a link to the material. CC licenses prior to Version 4.0 also require you to provide the title of the material if supplied, and may have other slight differences. +- Indicate if changes were made — You must indicate if you modified the material and retain an indication of previous modifications. +2. NonCommercial — You may not use the material for commercial purposes. +3. ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. +4. No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. +Whereby "technological measures" shall mean: +- The license prohibits application of effective technological measures, defined with reference to Article 11 of the WIPO Copyright Treaty. + +# Images + +## Images +All files under the `/content/images/site/` directory (and likewise, the corresponding and respective files in /_site) are copyrighted to Noah L. Schrick. All rights reserved. + +## Screenshots + +No licensing is provided for any files under `/content/images/screenshots` (and likewise, the corresponding and respective files in /_site) due to potential conflicts with copyright claims with the publisher, developer, artist, or other in any relevant screenshot. + +## Logos + +All files under the `/content/images/logos` directory (and likewise, the corresponding and respective files in /public) are copyrighted to their respective holders. + +# Other files + +All other files not mentioned are licensed under the MIT License. + +## MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/_includes/layouts/base.njk b/_includes/layouts/base.njk new file mode 100644 index 0000000..19d028e --- /dev/null +++ b/_includes/layouts/base.njk @@ -0,0 +1,89 @@ + + + + + + {{ renderData.title or title or metadata.title }} + + + + + + + + + + + + + + + + + +
+
+ {%- for entry in collections.all | eleventyNavigation %} + {{ entry.title}} + {%- endfor %} +
+
+
+ + +
+
+
    +
  1. Edit the _data/metadata.json with your blog’s information.
  2. +
  3. (Optional) Edit .eleventy.js with your configuration preferences.
  4. +
  5. Delete this message from _includes/layouts/base.njk.
  6. +
+

This is an Eleventy project created from the eleventy-base-blog repo.

+
+ + {{ content | safe }} +
+ + + + + + + \ No newline at end of file diff --git a/_includes/layouts/home.njk b/_includes/layouts/home.njk new file mode 100644 index 0000000..cf8dc9c --- /dev/null +++ b/_includes/layouts/home.njk @@ -0,0 +1,5 @@ +--- +layout: layouts/base.njk +--- + +{{ content | safe }} \ No newline at end of file diff --git a/_includes/layouts/post.njk b/_includes/layouts/post.njk new file mode 100644 index 0000000..6237584 --- /dev/null +++ b/_includes/layouts/post.njk @@ -0,0 +1,28 @@ +--- +layout: layouts/base.njk +--- +{# Only include the syntax highlighter CSS on blog posts #} +{%- css %}{% include "node_modules/prismjs/themes/prism-okaidia.css" %}{% endcss %} +{%- css %}{% include "public/css/prism-diff.css" %}{%- endcss %} +

{{ title }}

+ + + +{{ content | safe }} + +{%- if collections.posts %} +{%- set previousPost = collections.posts | getPreviousCollectionItem %} +{%- set nextPost = collections.posts | getNextCollectionItem %} +{%- if nextPost or previousPost %} + +{%- endif %} +{%- endif %} \ No newline at end of file diff --git a/_includes/postslist.njk b/_includes/postslist.njk new file mode 100644 index 0000000..1af346f --- /dev/null +++ b/_includes/postslist.njk @@ -0,0 +1,9 @@ +{%- css %}.postlist { counter-reset: start-from {{ (postslistCounter or postslist.length) + 1 }} }{% endcss %} +
    +{% for post in postslist | reverse %} +
  1. + {% if post.data.title %}{{ post.data.title }}{% else %}{{ post.url }}{% endif %} + +
  2. +{% endfor %} +
\ No newline at end of file diff --git a/content/css/prism-base16-monokai.dark.css b/content/css/prism-base16-monokai.dark.css new file mode 100644 index 0000000..c60b1b4 --- /dev/null +++ b/content/css/prism-base16-monokai.dark.css @@ -0,0 +1,89 @@ +code[class*="language-"], pre[class*="language-"] { + font-size: 14px; + line-height: 1.375; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; + background: #272822; + color: #f8f8f2; +} +pre[class*="language-"] { + padding: 1.5em 0; + margin: .5em 0; + overflow: auto; +} +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; +} +.token.comment, .token.prolog, .token.doctype, .token.cdata { + color: #75715e; +} +.token.punctuation { + color: #f8f8f2; +} +.token.namespace { + opacity: .7; +} +.token.operator, .token.boolean, .token.number { + color: #fd971f; +} +.token.property { + color: #f4bf75; +} +.token.tag { + color: #66d9ef; +} +.token.string { + color: #a1efe4; +} +.token.selector { + color: #ae81ff; +} +.token.attr-name { + color: #fd971f; +} +.token.entity, .token.url, .language-css .token.string, .style .token.string { + color: #a1efe4; +} +.token.attr-value, .token.keyword, .token.control, .token.directive, .token.unit { + color: #a6e22e; +} +.token.statement, .token.regex, .token.atrule { + color: #a1efe4; +} +.token.placeholder, .token.variable { + color: #66d9ef; +} +.token.deleted { + text-decoration: line-through; +} +.token.inserted { + border-bottom: 1px dotted #f9f8f5; + text-decoration: none; +} +.token.italic { + font-style: italic; +} +.token.important, .token.bold { + font-weight: bold; +} +.token.important { + color: #f92672; +} +.token.entity { + cursor: help; +} +pre > code.highlight { + outline: 0.4em solid #f92672; + outline-offset: .4em; +} \ No newline at end of file diff --git a/content/files/index.njk b/content/files/index.njk new file mode 100644 index 0000000..0174b26 --- /dev/null +++ b/content/files/index.njk @@ -0,0 +1,28 @@ +--- +layout: layouts/home.njk +eleventyNavigation: + key: Home + order: 1 +numberOfLatestPostsToShow: 3 +--- +{% set postsCount = collections.posts | length %} +{% set latestPostsCount = postsCount | min(numberOfLatestPostsToShow) %} +

Latest {{ latestPostsCount }} Post{% if latestPostsCount != 1 %}s{% endif %}

+ +{% set postslist = collections.posts | head(-1 * numberOfLatestPostsToShow) %} +{% set postslistCounter = postsCount %} +{% include "postslist.njk" %} + +{% set morePosts = postsCount - numberOfLatestPostsToShow %} +{% if morePosts > 0 %} +

{{ morePosts }} more post{% if morePosts != 1 %}s{% endif %} can be found in the archive.

+{% endif %} + +{# List every content page in the project #} +{# + +#} \ No newline at end of file diff --git a/content/images/logos/TheSchricks.png b/content/images/logos/TheSchricks.png new file mode 100644 index 0000000..5a8406c Binary files /dev/null and b/content/images/logos/TheSchricks.png differ diff --git a/eleventy.config.drafts.js b/eleventy.config.drafts.js new file mode 100644 index 0000000..95ad60a --- /dev/null +++ b/eleventy.config.drafts.js @@ -0,0 +1,50 @@ +function eleventyComputedPermalink() { + // When using `addGlobalData` and you *want* to return a function, you must nest functions like this. + // `addGlobalData` acts like a global data file and runs the top level function it receives. + return (data) => { + // Always skip during non-watch/serve builds + if(data.draft && !process.env.BUILD_DRAFTS) { + return false; + } + + return data.permalink; + } +}; + +function eleventyComputedExcludeFromCollections() { + // When using `addGlobalData` and you *want* to return a function, you must nest functions like this. + // `addGlobalData` acts like a global data file and runs the top level function it receives. + return (data) => { + // Always exclude from non-watch/serve builds + if(data.draft && !process.env.BUILD_DRAFTS) { + return true; + } + + return data.eleventyExcludeFromCollections; + } +}; + +module.exports.eleventyComputedPermalink = eleventyComputedPermalink; +module.exports.eleventyComputedExcludeFromCollections = eleventyComputedExcludeFromCollections; + +module.exports = eleventyConfig => { + eleventyConfig.addGlobalData("eleventyComputed.permalink", eleventyComputedPermalink); + eleventyConfig.addGlobalData("eleventyComputed.eleventyExcludeFromCollections", eleventyComputedExcludeFromCollections); + + let logged = false; + eleventyConfig.on("eleventy.before", ({runMode}) => { + let text = "Excluding"; + // Only show drafts in serve/watch modes + if(runMode === "serve" || runMode === "watch") { + process.env.BUILD_DRAFTS = true; + text = "Including"; + } + + // Only log once. + if(!logged) { + console.log( `[11ty/eleventy-base-blog] ${text} drafts.` ); + } + + logged = true; + }); +} \ No newline at end of file diff --git a/eleventy.config.images.js b/eleventy.config.images.js new file mode 100644 index 0000000..eb435cb --- /dev/null +++ b/eleventy.config.images.js @@ -0,0 +1,34 @@ +const path = require("path"); +const eleventyImage = require("@11ty/eleventy-img"); + +module.exports = eleventyConfig => { + function relativeToInputPath(inputPath, relativeFilePath) { + let split = inputPath.split("/"); + split.pop(); + + return path.resolve(split.join(path.sep), relativeFilePath); + } + + // Eleventy Image shortcode + // https://www.11ty.dev/docs/plugins/image/ + eleventyConfig.addAsyncShortcode("image", async function imageShortcode(src, alt, widths, sizes) { + // Full list of formats here: https://www.11ty.dev/docs/plugins/image/#output-formats + // Warning: Avif can be resource-intensive so take care! + let formats = ["avif", "webp", "auto"]; + let file = relativeToInputPath(this.page.inputPath, src); + let metadata = await eleventyImage(file, { + widths: widths || ["auto"], + formats, + outputDir: path.join(eleventyConfig.dir.output, "img"), // Advanced usage note: `eleventyConfig.dir` works here because we’re using addPlugin. + }); + + // TODO loading=eager and fetchpriority=high + let imageAttributes = { + alt, + sizes, + loading: "lazy", + decoding: "async", + }; + return eleventyImage.generateHTML(metadata, imageAttributes); + }); +}; \ No newline at end of file diff --git a/eleventy.config.js b/eleventy.config.js new file mode 100644 index 0000000..d35612f --- /dev/null +++ b/eleventy.config.js @@ -0,0 +1,139 @@ +const { DateTime } = require("luxon"); +const markdownItAnchor = require("markdown-it-anchor"); + +const pluginRss = require("@11ty/eleventy-plugin-rss"); +const pluginSyntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight"); +const pluginBundle = require("@11ty/eleventy-plugin-bundle"); +const pluginNavigation = require("@11ty/eleventy-navigation"); +const { EleventyHtmlBasePlugin } = require("@11ty/eleventy"); + +const pluginDrafts = require("./eleventy.config.drafts.js"); +const pluginImages = require("./eleventy.config.images.js"); + +module.exports = function(eleventyConfig) { + // Copy the contents of the `public` folder to the output folder + // For example, `./public/css/` ends up in `_site/css/` + eleventyConfig.addPassthroughCopy({ + "./public/": "/", + "./node_modules/prismjs/themes/prism-okaidia.css": "/css/prism-okaidia.css" + }); + + // Run Eleventy when these files change: + // https://www.11ty.dev/docs/watch-serve/#add-your-own-watch-targets + + // Watch content images for the image pipeline. + eleventyConfig.addWatchTarget("content/**/*.{svg,webp,png,jpeg}"); + + // App plugins + eleventyConfig.addPlugin(pluginDrafts); + eleventyConfig.addPlugin(pluginImages); + + // Official plugins + eleventyConfig.addPlugin(pluginRss); + eleventyConfig.addPlugin(pluginSyntaxHighlight, { + preAttributes: { tabindex: 0 } + }); + eleventyConfig.addPlugin(pluginNavigation); + eleventyConfig.addPlugin(EleventyHtmlBasePlugin); + eleventyConfig.addPlugin(pluginBundle); + + // Filters + eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => { + // Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens + return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy"); + }); + + eleventyConfig.addFilter('htmlDateString', (dateObj) => { + // dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string + return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('yyyy-LL-dd'); + }); + + // Get the first `n` elements of a collection. + eleventyConfig.addFilter("head", (array, n) => { + if(!Array.isArray(array) || array.length === 0) { + return []; + } + if( n < 0 ) { + return array.slice(n); + } + + return array.slice(0, n); + }); + + // Return the smallest number argument + eleventyConfig.addFilter("min", (...numbers) => { + return Math.min.apply(null, numbers); + }); + + // Return all the tags used in a collection + eleventyConfig.addFilter("getAllTags", collection => { + let tagSet = new Set(); + for(let item of collection) { + (item.data.tags || []).forEach(tag => tagSet.add(tag)); + } + return Array.from(tagSet); + }); + + eleventyConfig.addFilter("filterTagList", function filterTagList(tags) { + return (tags || []).filter(tag => ["all", "nav", "post", "posts"].indexOf(tag) === -1); + }); + + // Customize Markdown library settings: + eleventyConfig.amendLibrary("md", mdLib => { + mdLib.use(markdownItAnchor, { + permalink: markdownItAnchor.permalink.ariaHidden({ + placement: "after", + class: "header-anchor", + symbol: "#", + ariaHidden: false, + }), + level: [1,2,3,4], + slugify: eleventyConfig.getFilter("slugify") + }); + }); + + // Features to make your build faster (when you need them) + + // If your passthrough copy gets heavy and cumbersome, add this line + // to emulate the file copy on the dev server. Learn more: + // https://www.11ty.dev/docs/copy/#emulate-passthrough-copy-during-serve + + // eleventyConfig.setServerPassthroughCopyBehavior("passthrough"); + + return { + // Control which files Eleventy will process + // e.g.: *.md, *.njk, *.html, *.liquid + templateFormats: [ + "md", + "njk", + "html", + "liquid", + ], + + // Pre-process *.md files with: (default: `liquid`) + markdownTemplateEngine: "njk", + + // Pre-process *.html files with: (default: `liquid`) + htmlTemplateEngine: "njk", + + // These are all optional: + dir: { + input: "content", // default: "." + includes: "../_includes", // default: "_includes" + data: "../_data", // default: "_data" + output: "_site" + }, + + // ----------------------------------------------------------------- + // Optional items: + // ----------------------------------------------------------------- + + // If your site deploys to a subdirectory, change `pathPrefix`. + // Read more: https://www.11ty.dev/docs/config/#deploy-to-a-subdirectory-with-a-path-prefix + + // When paired with the HTML plugin https://www.11ty.dev/docs/plugins/html-base/ + // it will transform any absolute URLs in your HTML to include this + // folder name and does **not** affect where things go in the output folder. + pathPrefix: "/", + }; +}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..be2c036 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "TheSchricks", + "version": "1.0.0", + "description": "First iteration site using Eleventy site generator.", + "scripts": { + "build": "npx @11ty/eleventy", + "build-ghpages": "npx @11ty/eleventy --pathprefix=/eleventy-base-blog/", + "start": "npx @11ty/eleventy --serve --quiet", + "debug": "DEBUG=Eleventy* npx @11ty/eleventy", + "debugstart": "DEBUG=Eleventy* npx @11ty/eleventy --serve --quiet", + "benchmark": "DEBUG=Eleventy:Benchmark* npx @11ty/eleventy" + }, + "repository": { + "type": "git", + "url": "git://git.theschricks.com/noah/Website.git" + }, + "engines": { + "node": ">=14" + }, + "homepage": "https://git.theschricks.com/noah/Website#readme", + "author": "Noah L. Schrick", + "devDependencies": { + "@11ty/eleventy": "^2.0.1", + "@11ty/eleventy-img": "^3.1.8", + "@11ty/eleventy-navigation": "^0.3.5", + "@11ty/eleventy-plugin-bundle": "^1.0.5", + "@11ty/eleventy-plugin-rss": "^1.2.0", + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", + "luxon": "^3.4.4", + "markdown-it-anchor": "^8.6.7" + } +}