Skeleton project wiand structure with confifgs, boilerplate functions, and licensing info

This commit is contained in:
Noah L. Schrick 2023-12-21 03:36:24 -06:00
parent 4a8d40b085
commit 9793dce7a5
15 changed files with 573 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -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

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
_site/
node_modules/
package-lock.json

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"cSpell.ignoreWords": [
"TheSchricks"
]
}

53
LICENSE.md Normal file
View File

@ -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.

View File

@ -0,0 +1,89 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ renderData.title or title or metadata.title }}</title>
<meta name="Description" content="{{ renderData.description or description or metadata.description }}">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="alternate" href="{{ metadata.feed.path | url }}" type="application/atom+xml" title="{{ metadata.title }}">
</head>
<style>
body, h1,h2,h3,h4,h5,h6 {font-family: "Montserrat", sans-serif}
.w3-row-padding img {margin-bottom: 12px}
/* Set the width of the sidebar to 120px */
.w3-sidebar {width: 120px;background: #222;}
/* Add a left margin to the "page content" that matches the width of the sidebar (120px) */
#main {margin-left: 120px}
/* Remove margins from "page content" on small screens TODO add back in*/
{% raw %}
@media only screen and (max-width:600px) {#main { margin-left:0}}
{% endraw %}
</style>
<body class="w3-black">
<!-- Icon Bar (Sidebar - hidden on small screens) -->
<nav class="w3-sidebar w3-bar-block w3-small w3-hide-small w3-center">
<!-- Avatar image in top left corner -->
<img src="{{ '/img/w3images/avatar_smoke.jpg' | url }}" style="width:100%">
{#- Read more about `eleventy-navigation` at https://www.11ty.dev/docs/plugins/navigation/ #}
{%- for entry in collections.all | eleventyNavigation %}
<a href="{{ entry.url | url }}" class="w3-bar-item w3-button w3-padding-large {% if entry.url == page.url %} w3-black {% else %} w3-hover-black {% endif %}">
<i class="fa {{ navFA[entry.title]}} w3-xxlarge"></i>
<p>{{ entry.title }}</p>
</a>
{%- endfor %}
</nav>
<!-- Navbar on small screens (Hidden on medium and large screens) -->
<div class="w3-top w3-hide-large w3-hide-medium" id="myNavbar">
<div class="w3-bar w3-black w3-opacity w3-hover-opacity-off w3-center w3-small">
{%- for entry in collections.all | eleventyNavigation %}
<a href="{{ entry.url | url }}" class="w3-bar-item w3-button" style="width:20% !important">{{ entry.title}}</a>
{%- endfor %}
</div>
</div>
<div class="w3-padding-large" id="main">
<main {% if templateClass %} class="{{ templateClass }}"{% endif %}>
<div class="warning">
<ol>
<li>Edit the <code>_data/metadata.json</code> with your blogs information.</li>
<li>(Optional) Edit <code>.eleventy.js</code> with your <a href="https://www.11ty.dev/docs/config/">configuration preferences</a>.</li>
<li>Delete this message from <code>_includes/layouts/base.njk</code>.</li>
</ol>
<p><em>This is an <a href="https://www.11ty.io/">Eleventy project</a> created from the <a href="https://github.com/11ty/eleventy-base-blog"><code>eleventy-base-blog</code> repo</a>.</em></p>
</div>
{{ content | safe }}
</main>
<!-- Footer -->
<footer class="w3-content w3-padding-64 w3-text-grey w3-xlarge">
<i class="fa fa-facebook-official w3-hover-opacity"></i>
<i class="fa fa-instagram w3-hover-opacity"></i>
<i class="fa fa-snapchat w3-hover-opacity"></i>
<i class="fa fa-pinterest-p w3-hover-opacity"></i>
<i class="fa fa-twitter w3-hover-opacity"></i>
<i class="fa fa-linkedin w3-hover-opacity"></i>
<p class="w3-medium">Powered by <a href="https://www.w3schools.com/w3css/default.asp" target="_blank" class="w3-hover-text-green">w3.css</a></p>
<!-- End footer -->
</footer>
<!-- Current page: {{ page.url | url }} -->
</body>
</html>

View File

@ -0,0 +1,5 @@
---
layout: layouts/base.njk
---
{{ content | safe }}

View File

@ -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 %}
<h1>{{ title }}</h1>
<ul class="post-metadata">
<li><time datetime="{{ page.date | htmlDateString }}">{{ page.date | readableDate }}</time></li>
{%- for tag in tags | filterTagList %}
{%- set tagUrl %}/tags/{{ tag | slugify }}/{% endset %}
<li><a href="{{ tagUrl }}" class="post-tag">{{ tag }}</a>{%- if not loop.last %}, {% endif %}</li>
{%- endfor %}
</ul>
{{ content | safe }}
{%- if collections.posts %}
{%- set previousPost = collections.posts | getPreviousCollectionItem %}
{%- set nextPost = collections.posts | getNextCollectionItem %}
{%- if nextPost or previousPost %}
<ul class="links-nextprev">
{%- if previousPost %}<li>Previous: <a href="{{ previousPost.url }}">{{ previousPost.data.title }}</a></li>{% endif %}
{%- if nextPost %}<li>Next: <a href="{{ nextPost.url }}">{{ nextPost.data.title }}</a></li>{% endif %}
</ul>
{%- endif %}
{%- endif %}

9
_includes/postslist.njk Normal file
View File

@ -0,0 +1,9 @@
{%- css %}.postlist { counter-reset: start-from {{ (postslistCounter or postslist.length) + 1 }} }{% endcss %}
<ol reversed class="postlist">
{% for post in postslist | reverse %}
<li class="postlist-item{% if post.url == url %} postlist-item-active{% endif %}">
<a href="{{ post.url }}" class="postlist-link">{% if post.data.title %}{{ post.data.title }}{% else %}<code>{{ post.url }}</code>{% endif %}</a>
<time class="postlist-date" datetime="{{ post.date | htmlDateString }}">{{ post.date | readableDate("LLLL yyyy") }}</time>
</li>
{% endfor %}
</ol>

View File

@ -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;
}

28
content/files/index.njk Normal file
View File

@ -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) %}
<h1>Latest {{ latestPostsCount }} Post{% if latestPostsCount != 1 %}s{% endif %}</h1>
{% set postslist = collections.posts | head(-1 * numberOfLatestPostsToShow) %}
{% set postslistCounter = postsCount %}
{% include "postslist.njk" %}
{% set morePosts = postsCount - numberOfLatestPostsToShow %}
{% if morePosts > 0 %}
<p>{{ morePosts }} more post{% if morePosts != 1 %}s{% endif %} can be found in <a href="/blog/">the archive</a>.</p>
{% endif %}
{# List every content page in the project #}
{#
<ul>
{%- for entry in collections.all %}
<li><a href="{{ entry.url }}"><code>{{ entry.url }}</code></a></li>
{%- endfor %}
</ul>
#}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

50
eleventy.config.drafts.js Normal file
View File

@ -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;
});
}

34
eleventy.config.images.js Normal file
View File

@ -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 were using addPlugin.
});
// TODO loading=eager and fetchpriority=high
let imageAttributes = {
alt,
sizes,
loading: "lazy",
decoding: "async",
};
return eleventyImage.generateHTML(metadata, imageAttributes);
});
};

139
eleventy.config.js Normal file
View File

@ -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 <base> 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: "/",
};
};

32
package.json Normal file
View File

@ -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"
}
}