diff --git a/.editorconfig b/.editorconfig index a4d523e..69e2c6d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,5 +8,5 @@ charset = utf-8 indent_style = tab indent_size = 2 -[.{yaml,yml,md,njk}] +[*.{yaml,yml,md,njk}] indent_style = space diff --git a/_includes/footer.njk b/_includes/footer.njk new file mode 100644 index 0000000..4afee14 --- /dev/null +++ b/_includes/footer.njk @@ -0,0 +1,24 @@ + diff --git a/_includes/header.njk b/_includes/header.njk new file mode 100644 index 0000000..e40a95c --- /dev/null +++ b/_includes/header.njk @@ -0,0 +1,22 @@ +
+ + + + + +
diff --git a/_includes/base.njk b/_includes/layouts/base.njk similarity index 88% rename from _includes/base.njk rename to _includes/layouts/base.njk index e7c4a07..33d59e9 100644 --- a/_includes/base.njk +++ b/_includes/layouts/base.njk @@ -16,6 +16,7 @@ {# Styles #} + {# Fonts #} @@ -26,5 +27,11 @@ - {{ content | safe }} + {% include "header.njk" %} + +
+ {{ content | safe }} +
+ + {% include "footer.njk" %} diff --git a/_includes/layouts/page.njk b/_includes/layouts/page.njk new file mode 100644 index 0000000..4112e92 --- /dev/null +++ b/_includes/layouts/page.njk @@ -0,0 +1,6 @@ +--- +layout: base.njk +--- +

{{ title }}

+ +{{ content | safe }} diff --git a/_includes/layouts/post.njk b/_includes/layouts/post.njk new file mode 100644 index 0000000..24b2445 --- /dev/null +++ b/_includes/layouts/post.njk @@ -0,0 +1,8 @@ +--- +layout: base.njk +--- +
+

{{ title }}

+ + {{ content | safe }} +
diff --git a/_includes/postlist.njk b/_includes/postlist.njk index 4007a32..cb892d6 100644 --- a/_includes/postlist.njk +++ b/_includes/postlist.njk @@ -7,7 +7,7 @@ {% endif %}

{{ post.data.title }}

diff --git a/css/main.css b/css/main.css index 714cafc..c616143 100644 --- a/css/main.css +++ b/css/main.css @@ -3,10 +3,12 @@ --font-family: 'Atkinson Hyperlegible Next', sans-serif; --font-family-code: 'Atkinson Hyperlegible Mono', monospace; + --color-dark: #2e303e; --color-dark-alt: #3c3f52; --color-light: #ebeeef; --color-light-alt: #dbe1e3; + --color-teal-dark: #18737b; --color-teal-light: #25b0bc; --color-pink-dark: #94195d; @@ -47,8 +49,12 @@ --color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light)); --color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light)); --color-grey: light-dark(var(--color-grey-dark), var(--color-grey-light)); + + --header-offset: 3.1rem; } +/* Base */ + * { box-sizing: border-box; margin: 0; @@ -59,6 +65,195 @@ body { font-family: var(--font-family); color: var(--color-text); background-color: var(--color-bg); - max-width: 60vw; - margin: 0 auto; } + +main { + width: 60vw; + margin: 0 auto; + scroll-margin-top: var(--header-offset); +} + +@media (max-width: 650px) { + main { + width: 92vw; + } +} + +/* Headers */ +h1, h2, h3, h4, h5, h6 { + line-height: 1.25; + color: var(--color-teal); + scroll-margin-top: var(--header-offset); +} + +h1 { + margin-top: 3rem; + font-size: 3.5rem; +} +h2 { + margin-top: 1rem; + font-size: 2.2rem; +} +h3 { + margin-top: 1.5rem; + font-size: 1.6rem; +} +h4, h5, h6 { + margin-top: 1rem; + font-size: 1.2rem; +} + +/* Images */ +img { + display: block; + max-width: 100%; + height: auto; + border-radius: 1rem; +} + +/* Paragraphs */ +p { + margin: 1.25rem 0; + line-height: 1.4; +} + +strong, +b { + font-weight: 900; +} + +/* Links */ +a { + color: var(--color-font); + border-radius: 1rem; + text-decoration: underline; + text-decoration-style: solid; + text-decoration-thickness: .2em; + text-decoration-color: var(--color-teal); + transition: text-decoration-thickness .5s; + padding: 0 .1rem; /* These stop the focus outline from covering text */ + margin: 0 .1rem; +} + +a:focus-visible { + text-decoration: none; + outline: .15rem solid var(--color-teal); +} + +@media (any-hover: hover) { + a:hover { + text-decoration-thickness: .4em; + } +} + +a:active { + text-decoration-thickness: .4em; +} + +/* Lists */ +::marker { + color: var(--color-pink); +} + +ul, ol, li { + margin-left: 1rem; +} + +li { + line-height: 1.5; +} + +li ul, li ol { + margin: .5rem 0; +} + +/* Blockquotes */ +blockquote { + margin: .5rem 1rem; + padding: 0 1rem; + border-radius: .25rem 1rem 1rem .25rem; + line-height: 1.25; + border-left: .5rem solid var(--color-pink); +} + +blockquote, +blockquote p, +blockquote ol, +blockquote ul { + background-color: var(--color-bg-alt); + padding: .5rem; +} + +blockquote p { + margin: 0; +} + +/* Tables */ +table { + width: 100%; + border-spacing: 0; /* border collapse doesn't play nice with radii */ + border-radius: .3rem; + border: thin solid var(--color-pink); +} + +th { + color: var(--color-bg); + background-color: var(--color-pink); +} + +th, td { + padding: .5rem; + text-align: left; +} + +tr:nth-child(even) { background-color: var(--color-bg-alt); } +th:not(:first-child) { border-left: thin solid var(--color-bg); } +th:first-child { border-top-left-radius: .25rem; } +th:last-child { border-top-right-radius: .25rem; } +td:not(:first-child) { border-left: thin solid var(--color-pink); } + +/* Code */ +/* Syntax highlighting in highlighting.css */ +code, +pre { + font-family: var(--font-family-code); + background-color: var(--color-bg-alt); + font-size: .9rem; +} + +code { + padding: .2rem; + border-radius: .25rem; +} + +pre { + display: block; + margin: 1rem 0; + padding: 1rem; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + overflow-wrap: break-word; + tab-size: 4; + border-radius: .5rem; +} + +pre code { + padding: 0; +} + +/* Times */ +time { + color: var(--color-grey); +} + +/* Horizontal rules */ +hr { + color: var(--color-teal); + border: .25rem solid var(--color-teal); + margin: 2rem 0; +} +hr:last-child { + margin-bottom: 0; +} + diff --git a/css/nav.css b/css/nav.css new file mode 100644 index 0000000..a1b3d03 --- /dev/null +++ b/css/nav.css @@ -0,0 +1,190 @@ +/* Header */ +header { + position: sticky; + top: 0; + background-color: var(--color-bg); + box-shadow: 0 .25rem .15rem var(--color-shadow); + padding: .75rem 0; +} + +/* Header links */ +header a { + border-radius: 1rem; + border: .125rem solid var(--color-pink); + color: var(--color-pink); + text-decoration: none; + padding: 0 .25rem; + box-shadow: .15rem .15rem var(--color-shadow); + font-size: 1.2rem; + padding-right: .35rem; + /* click animation handling */ + position: relative; + top: 0; + left: 0; + transition: top .05s ease-in, left .05s ease-in; +} + +header a:focus-visible { + color: var(--color-bg); + border-color: var(--color-pink); + background-color: var(--color-pink); + outline: none; +} + +@media (any-hover: hover) { + header a:hover { + color: var(--color-bg); + border-color: var(--color-pink); + background-color: var(--color-pink); + } +} + +@media (forced-colors: active) { + .site-header a:focus-visible { + outline-offset: .125rem; + outline: .125rem solid; + } + + @media (any-hover: hover) { + .site-header a:hover { + outline-offset: .125rem; + outline: .125rem solid; + } + } +} + +/* Click animation */ +header a:active { + top: .1rem; + left: .1rem; + box-shadow: .05rem .05rem var(--color-shadow); +} + +/* Current page */ +header a[aria-current="page"] { + border-color: var(--color-teal); + color: var(--color-teal); +} + +header a[aria-current="page"]:focus-visible { + color: var(--color-bg); + border-color: var(--color-teal); + background-color: var(--color-teal); +} + +@media (any-hover: hover) { + header a[aria-current="page"]:hover { + color: var(--color-bg); + background-color: var(--color-teal); + border-color: var(--color-teal); + } +} + +/* Header link icons */ +header i { + color: var(--color-teal); + padding-left: .25rem; +} + +header a[aria-current="page"] i { + color: var(--color-pink); +} + +header a:focus-visible i, +a[aria-current="page"] a:focus-visible i { + color: var(--color-bg); +} + +@media (any-hover: hover) { + header a:hover i, + header a[aria-current="page"]:hover i { + color: var(--color-bg); + } +} + +/* Skip link */ +#skip { + left: -999px; + position: absolute; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; + z-index: -99; +} + +#skip:focus-visible { + display: inline-block; + left: auto; + top: auto; + width: auto; + height: auto; + overflow: auto; + margin: 0 10%; + z-index: 999; +} + +/* Nav */ +header ul { + display: flex; + list-style: none; + gap: 1rem; + justify-content: center; +} + +@media (max-width: 650px) { + .menu-text { + display: none; /* Icons only on small screens */ + } + + header a { + padding: .15rem .5rem; + } + + header i { + padding: 0; + } +} + +/* Footer */ +footer { + padding: 1rem 0; + font-size: .9rem; +} + +footer ul { + display: flex; + list-style: none; + gap: .5rem; + justify-content: center; +} + +footer li { + margin: 0; +} + +footer li:nth-child(2)::before, +footer li:nth-child(2)::after { + content: " ● " / ""; + color: var(--color-teal); +} + +@media (max-width: 650px) { + footer ul { + flex-flow: column; + text-align: center; + } + + footer li:nth-child(2)::before, + footer li:nth-child(2)::after { + content: none; + } +} + +footer a { + text-decoration-color: var(--color-pink); +} + +footer a:focus-visible { + outline-color: var(--color-pink); +} diff --git a/eleventy.config.js b/eleventy.config.js index 7ff7ade..f54c3d7 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,7 +1,14 @@ -import { feedPlugin } from "@11ty/eleventy-plugin-rss"; import { eleventyImageTransformPlugin } from "@11ty/eleventy-img"; +import eleventyNavigationPlugin from "@11ty/eleventy-navigation"; +import { feedPlugin } from "@11ty/eleventy-plugin-rss"; +import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight"; export default async function(eleventyConfig) { + /* Filters */ + eleventyConfig.addFilter("removeBasicTags", (tags) => { + return tags.filter(tag => ["all", "posts", "gallery", "reference"].indexOf(tag) === -1); + }); + /* Passthroughs */ eleventyConfig.addPassthroughCopy({"css": "assets/css"}); @@ -43,6 +50,12 @@ export default async function(eleventyConfig) { }, }); + /* Navigation */ + eleventyConfig.addPlugin(eleventyNavigationPlugin); + + /* Syntax highlighting */ + eleventyConfig.addPlugin(syntaxHighlight); + /* Watch when serving */ eleventyConfig.addWatchTarget("css"); }; @@ -51,6 +64,7 @@ export const config = { dir: { input: "src", includes: "../_includes", + layouts: "../_includes/layouts", data: "../_data" }, markdownTemplateEngine: "njk", diff --git a/package-lock.json b/package-lock.json index af81979..933318b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "devDependencies": { "@11ty/eleventy": "^3.1.2", "@11ty/eleventy-img": "^6.0.4", - "@11ty/eleventy-plugin-rss": "^2.0.4" + "@11ty/eleventy-navigation": "^1.0.5", + "@11ty/eleventy-plugin-rss": "^2.0.4", + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2" } }, "node_modules/@11ty/dependency-tree": { @@ -165,6 +167,20 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/eleventy-navigation": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-navigation/-/eleventy-navigation-1.0.5.tgz", + "integrity": "sha512-zb6xe29cM9viSdYtZywKIkJw2HIROyBINdBcFWC9uD0c/jYOTAex5nwy3HNEuh5t6/Ld/S9V4gEizfmeYuYpCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dependency-graph": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@11ty/eleventy-plugin-bundle": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.7.tgz", @@ -201,6 +217,20 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/eleventy-plugin-syntaxhighlight": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-syntaxhighlight/-/eleventy-plugin-syntaxhighlight-5.0.2.tgz", + "integrity": "sha512-T6xVVRDJuHlrFMHbUiZkHjj5o1IlLzZW+1IL9eUsyXFU7rY2ztcYhZew/64vmceFFpQwzuSfxQOXxTJYmKkQ+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "prismjs": "^1.30.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@11ty/eleventy-utils": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-2.0.7.tgz", @@ -2059,6 +2089,16 @@ "node": ">=12" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", diff --git a/package.json b/package.json index 0b7f06f..6286483 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Lee's personal website, take 2, built with 11ty", "main": "index.js", "scripts": { - "serve": "rm -rf _site && npx @11ty/eleventy --serve" + "start": "rm -rf _site && npx @11ty/eleventy --serve --quiet" }, "keywords": [], "author": "Lee Cattarin", @@ -13,6 +13,8 @@ "devDependencies": { "@11ty/eleventy": "^3.1.2", "@11ty/eleventy-img": "^6.0.4", - "@11ty/eleventy-plugin-rss": "^2.0.4" + "@11ty/eleventy-navigation": "^1.0.5", + "@11ty/eleventy-plugin-rss": "^2.0.4", + "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2" } } diff --git a/src/img/2026/cormorant.jpg b/src/img/2026/cormorant.jpg new file mode 100644 index 0000000..eedff75 Binary files /dev/null and b/src/img/2026/cormorant.jpg differ diff --git a/src/index.njk b/src/index.njk index 19eaf5e..00ad05f 100644 --- a/src/index.njk +++ b/src/index.njk @@ -1,11 +1,14 @@ --- -layout: base.njk -eleventyExcludeFromCollections: true pagination: data: collections.posts size: 13 reverse: true alias: postlist +eleventyNavigation: + key: home + order: 3 +icon: fa fa-solid fa-crow +title: home ---

Home

diff --git a/src/pages/about.md b/src/pages/about.md new file mode 100644 index 0000000..e133ec8 --- /dev/null +++ b/src/pages/about.md @@ -0,0 +1,8 @@ +--- +eleventyNavigation: + key: about + order: 4 +title: about +icon: fa-regular fa-user +label: about Lee +--- diff --git a/src/pages/colophon.md b/src/pages/colophon.md new file mode 100644 index 0000000..c8fc1c4 --- /dev/null +++ b/src/pages/colophon.md @@ -0,0 +1,3 @@ +--- +title: colophon +--- diff --git a/src/pages/contact.md b/src/pages/contact.md new file mode 100644 index 0000000..edb4cb4 --- /dev/null +++ b/src/pages/contact.md @@ -0,0 +1,8 @@ +--- +eleventyNavigation: + key: contact + order: 5 +title: contact +icon: fa-solid fa-envelope-open-text +label: contact Lee +--- diff --git a/src/pages/gallery.njk b/src/pages/gallery.njk new file mode 100644 index 0000000..b9dd769 --- /dev/null +++ b/src/pages/gallery.njk @@ -0,0 +1,16 @@ +--- +pagination: + data: collections["gallery"] + size: 13 + reverse: true + alias: postlist +eleventyNavigation: + key: gallery + order: 2 +title: gallery +icon: fa-regular fa-images +label: view the gallery +--- +

the gallery page is for finished art

+ +{% include "postlist.njk" %} diff --git a/src/pages/pages.11tydata.js b/src/pages/pages.11tydata.js new file mode 100644 index 0000000..647410f --- /dev/null +++ b/src/pages/pages.11tydata.js @@ -0,0 +1,6 @@ +export default { + permalink: function ({ title }) { + return `/${this.slugify(title)}/index.html`; + }, + layout: "page.njk" +}; diff --git a/src/pages/reference.njk b/src/pages/reference.njk new file mode 100644 index 0000000..52da598 --- /dev/null +++ b/src/pages/reference.njk @@ -0,0 +1,16 @@ +--- +pagination: + data: collections["reference"] + size: 13 + reverse: true + alias: postlist +eleventyNavigation: + key: reference + order: 2 +title: reference +icon: fa-regular fa-folder-open +label: read reference posts +--- +

the reference page is for informational posts

+ +{% include "postlist.njk" %} diff --git a/src/pages/style.md b/src/pages/style.md new file mode 100644 index 0000000..1fdbd82 --- /dev/null +++ b/src/pages/style.md @@ -0,0 +1,123 @@ +--- +title: style +--- + +Adaped from an introduction to Markdown in order to test and display styling of basic components of the site. + +## Heading level 2 + +Since your title (defined in the front matter) is your heading level 1, you should never use another heading level 1 in your body. + +### Heading level 3 + +The number of pound signs determines the heading level. + +#### Heading level 4 + +It's also important not to skip heading levels. Don't jump from a 2 to a 4 or similar. + +## Paragraphs + +You'll notice that I am putting blank lines between headings and plain text. This is necessary, or they won't render correctly. + +It's also important to put a blank line in between each paragraph. See what happens without it: +This is supposed to be a new paragraph, but it isn't. + +### Inline styles + +We can, of course, create **bold** and *italicized* text, or `inline monospace text`. + +We can also create links, like this [link to the home page](/). + +## Horizontal lines + +Sometimes you want to insert a visual break in your text that isn't just a new paragraph. You can use three dashes to create a horizontal line: + +--- + +This text will be below the line. + +## Lists + +### Unordered lists + +Unordered lists can be created with dashes or asterisks. With dashes: + +- this is an item +- this is another item + +With asterisks: + +* this is an item +* this is another item + +### Ordered lists + +Ordered (numbered) lists can be created with (surprise!) numbers. You can write numbers as you would normally, *or* you can just write the number 1 over and over, like so: + +1. this is item 1 +1. despite being written with a 1, this is item 2 + +This allows you to insert more information into lists in the future without having to renumber every following item. + +### Nested lists + +Both unordered and ordered lists can be nested. Just tab the nested section inwards: + +- this is an item + - this is nested below it + - this is also nested +- this is another item + +You can mix unordered and ordered lists when you nest. + +## Quotes + +You can always just use quotation marks, of course, but if you are quoting a larger chunk of text it can be nice to use a blockquote. + +You format a blockquote by starting the line with a caret: + +> This is a quote, and it will render differently than a paragraph. + +If you want a quote to have multiple separate paragraphs, and still contiguously display as one quote, make sure to put a caret on the empty line between the paragraphs. + +> This is a multi-paragraph quote. +> +> Here's the second paragraph. +> +> - Blockquotes can also have lists +> - They still have the caret at the front + +## Monospace + +You can write single words `in monospace`, or create code blocks: + +``` +3 backticks surround code blocks +``` + +Code blocks can have syntax highlighting: + +```html +

Hello, world

+``` + +## Tables + +Tables in Markdown are kind of annoying to format. You use the pipe (`|`) character as well as dashes. + +``` +| Header 1 | Header 2 | +|---|---| +| data 1a | data 1b | +| data 2a | data 2b | +| data 3a | data 3b | +``` + +When I remove the monospace block, you can see how this formats: + +| Header 1 | Header 2 | +|---|---| +| data 1a | data 1b | +| data 2a | data 2b | +| data 3a | data 3b | diff --git a/src/posts/2026/2026-01-05-moving-images.md b/src/posts/2026/2026-01-05-moving-images.md new file mode 100644 index 0000000..1130028 --- /dev/null +++ b/src/posts/2026/2026-01-05-moving-images.md @@ -0,0 +1,137 @@ +--- +title: moving images +image: + src: 2026/cormorant.jpg + alt: "Image unrelated to post. A cormorant, a type of black waterfowl, poses with wings spread on a buoy in Puget Sound. Off to the left, another bird floats." +tags: + - reference + - software +--- + +## problem statement + +today I decided to finally clean up the `assets/img` directory for this site. Since 2022, when I started this project, I've just been adding images directly to that directory with no further segmentation - messy of me, I know! It's gotten unwieldy and I'm starting to get worried about generic names leading to duplicates at some point, particularly for the non-gallery images where I have a tendency to [use](/stationery-exchange) [lots](/favorite-git-flag) [of](/trans-networks) [mushroom](/no-politics) [images](/domain-and-site-setup). + +so it's time to move them into year-based folders. Let's talk about how I did that. `bash` away! + +(want to [skip right to the completed script?](#result)) + +## find + +let's start with the basics: a list of posts. `find` gets us everything under a specific directory - in this case, the `_posts` directory. We can filter out the directories a few different ways, but I piped the `find` output through a basic `grep` looking for `.md` in the filename. + +```sh +for FILE in $(find _posts | grep .md) +do + # TBD +done +``` + +## grep + +`grep` can also help us get image names with the regex `"name:.+jpg|png"`. I add `name:` to the regex because there are *very occasionally* images that aren't the featured image for the post, and those don't fit the pattern of `name: `. Since there's so few of those, I ended up handling them manually. + +to make `grep` work with regex, it needs the `-E` flag. + +```sh +# gives us +# name: +# note the 4 spaces at the beginning of the line +IMAGE_LINE=$(cat $FILE | grep -E "name:.+jpg|png$") +``` + +## cut + +that output gets us the full line of text that includes the image filename. Let's trim out what we actually want. + +below, `-d` sets a delimiter, and `-f` chooses what field we want to return. Because there's 4 spaces before `name`, our field index is actually pretty high - `cut` is creating 4 empty strings. + +```sh +IMAGE=$(echo $IMAGE_LINE | cut -d ' ' -f 6 -) +``` + +or, for brevity: + +```sh +IMAGE=$(cat $FILE | grep -E "name:.+jpg|png$" | cut -d ' ' -f 6 -) +``` + +with `cut`, we can also get the year of the post: + +```sh +YEAR=$(echo $FILE | cut -d '/' -f 2 -) +``` + +## sed + +there's two major things we need to do with the information we've gathered: + +1. replace the image filename in-place in the post's markdown file +1. move the image file from its original location into a new directory + +we can do replacement with `sed`, where our pattern should be something like this: `s/$IMAGE/$YEAR\/&\` (the `&` subs in the found string - in this case `$IMAGE`). We could also use comma separators if we don't want to escape the slash, like `s,$IMAGE,$YEAR/&,` - I did this for ease of reading. + +by default, `sed` prints to standard output, so we'll tell it to edit in-place instead with `-i`. Here's our full `sed` command: + +```sh +sed "s,$IMAGE,$YEAR/&," -i $FILE +``` + +## mving and shaking + +(my mom thinks I'm funny.) + +now we'll handle moving the image file from its original location into a new directory. let's create our image paths, source and destination: + +```sh +IMG_DIR=assets/img +NEW_IMAGE=$IMG_DIR/$YEAR/$IMAGE +IMAGE=$IMG_DIR/$IMAGE +``` + +trying to `mv` the images will immediately cause problems, because the year directories don't exist yet. A simple check gets us past that: + +```sh +if [ ! -d $IMG_DIR/$YEAR ] +then + mkdir $IMG_DIR/$YEAR +fi +``` + +finally, we can `mv` the image: + +```sh +mv $IMAGE $NEW_IMAGE +``` + +## result + +here's our final script: + +```sh +for FILE in $(find _posts | grep .md) +do + # parse image and year info + IMAGE=$(cat $FILE | grep -E "name:.+jpg|png$" | cut -d ' ' -f 6 -) + YEAR=$(echo $FILE | cut -d '/' -f 2 -) + + # replace in-place in file + sed "s,$IMAGE,$YEAR/&," -i $FILE + + # path creation + IMG_DIR=assets/img + NEW_IMAGE=$IMG_DIR/$YEAR/$IMAGE + IMAGE=$IMG_DIR/$IMAGE + + # create dir for year if it doesn't exist + if [ ! -d $IMG_DIR/$YEAR ] + then + mkdir $IMG_DIR/$YEAR + fi + + # move image + mv $IMAGE $NEW_IMAGE +done +``` + +questions? errors? [ping me!](/contact) diff --git a/src/posts/2026/2026-02-17-sample.md b/src/posts/2026/2026-02-17-sample.md index 809001c..6cd1ff2 100644 --- a/src/posts/2026/2026-02-17-sample.md +++ b/src/posts/2026/2026-02-17-sample.md @@ -2,7 +2,7 @@ title: Sample date: 2026-02-17 tags: -- test + - gallery image: src: 2026/sample-0.jpg alt: filler diff --git a/src/posts/posts.11tydata.js b/src/posts/posts.11tydata.js index 33e2e32..da7e93a 100644 --- a/src/posts/posts.11tydata.js +++ b/src/posts/posts.11tydata.js @@ -5,5 +5,5 @@ export default { tags: [ "posts" ], - layout: "base.njk" + layout: "post.njk" }; diff --git a/src/src.11tydata.js b/src/src.11tydata.js new file mode 100644 index 0000000..3ebf645 --- /dev/null +++ b/src/src.11tydata.js @@ -0,0 +1,3 @@ +export default { + layout: "base.njk" +};