My personal website powered by:
- Eleventy (aka 11ty) with:
- eleventy-plugin-rss: a pack of plugins for generating an RSS feed (actually an Atom feed, but who’s counting) using the Nunjucks templating engine.
- eleventy-plugin-reading-time: provides a template tag which prints the number of minutes or seconds required to read the given text.
- TailwindCSS for styling with:
- postcss for preprocessing
- @tailwindcss-typography to "autostyle" markdown
- @tailwindcss-forms to beautify form elements
- Static CMS with:
example.com # → Root of your project
|
├── src/ # → Source directory
│ │
│ ├── admin/ # → Static CMS
│ │ ├── collections/
│ │ ├── partials/
│ │ │ └── fields/ # → Configure fields used in multiple places a single time (i.e. Hero Image)
│ │ ├── previews/
│ │ │ └── index.js # → Register preview templates and styles
│ │ ├── config.js # → Manual initialization (https://www.staticcms.org/docs/add-to-your-site-cdn#configuration)
│ │ └── index.html
│ │
│ ├── assets/ # → Site assets
│ │ ├── fonts/
│ │ ├── images/
│ │ ├── scripts/
│ │ ├── styles/
│ │ │ └── tailwind.css
│ │ │
│ │ └── views/ # → Templatize with nunjucks!
│ │ ├── components/ # → Each component has a folder with a base njk component, njk macro, and story.
│ │ | └── component/ # → 3 possible flavors, depending on how/what it's used for
│ │ | ├── component.js
│ │ | ├── component.njk
│ │ | └── component.macro.njk
│ │ |
│ │ ├── layouts/ # → Combine partials and components (e.g. pages)
│ │ └── partials/ # → Combine components (e.g. navigation)
│ │
│ ├── config/ # → Eleventy configuration
│ │ ├── collections.js # → Add and configure collections (https://www.11ty.dev/docs/collections/)
│ │ ├── filters.js # → Add and configure filters (https://www.11ty.dev/docs/filters/)
│ │ ├── passthroughs.js # → Add and configure passthroughs (https://www.11ty.dev/docs/copy/)
│ │ ├── plugins.js # → Add and configure plugins (https://www.11ty.dev/docs/plugins/)
│ │ ├── shortcodes.js # → Add and configure shortcodes (https://www.11ty.dev/docs/shortcodes/)
│ │ └── watchtargets.js # → Add and configure watch targets (https://www.11ty.dev/docs/watch-serve/)
│ │
│ ├── data # → Customize site data (https://www.11ty.dev/docs/data/)
│ │ ├── navigation.json # → Site navigation configuration
│ │ └── site.json # → Site metadata configuration
│ │
│ ├── pages # → Add "pages" collection items here
│ │ ├── index.md # → Default index page
│ │ └── pages.json # → Shared pages attributes
│ │
│ └── posts # → Add "posts" collection items here
│ ├── index.md # → Default index page
│ ├── posts.11tydata.js # → Calculate if posts are drafts and skip publishing
│ └── posts.json # → Shared posts attributes
│
├── .eleventy.js # → Configure: Eleventy
├── .gitignore # → Ignores all the node stuff that doesn't need to take up space on GitHub
├── LICENSE # → Project license (for example: MIT)
├── netlify.toml # → Netlify deployment and plugin configuration (optional)
├── package.json # → Your project's metadata, dependencies, etc. for Node.js to do its thing
├── postcss.config.js # → Configure: PostCSS
├── README.md # → This file you're reading!
└── tailwind.config.js # → Configure: TailwindCSS
Clone this repo, then via command line go to the project's directory to install the dependencies.
cd directory/to/the/project
npm install
After installing, run the site with live reload and a local backend.
npm start
Build a production version of the site (1) with clean CSS and (2) no drafts.
This is the build command for Netlify.
npm run build:prod
Build a staging version of the site (1) with clean CSS and (2) include all drafts. I use this for Netlify Deploy Previews so I can proof my drafts but with lean styles.
npm run build:staging
Build a development version of the site (1) without purging CSS and (2) include all drafts. The output will be the same as when you use npm run watch:dev
but without live reloading.
npm run build:dev
Filter | Description | Example/Usage |
---|---|---|
content | markdown body of a collection item | {{ content }} |
raw | allows processing njk within markdown | {{ content | raw }} |
readingTime | calculates time to read, i.e. content |
{{ content | readingTime }} |
Filter | Description | Example/Usage |
---|---|---|
date | default unformatted date | {{ date }} |
iso | display date in ISO format | {{ date | iso }} |
readableDate | display date in 'dd MMMM yyyy' format | {{ date | readableDate }} |
readableDate custom | or set a custom format | {{ date | readableDate('yyyy-LL-dd') }} |
toIso | Used in meta for published time | {{ date | toIso }} |
toRFC2822 | For RSS Feed | {{ date | toRFC2822 }} |
Shortcode: Add an image to a page or post with alt
text, caption, and image credit.
Parameter | Value |
---|---|
url | /path/to/the/image (required) |
alt | alt text (required, unless it is decoration only) |
credit* | image credit (optional) |
caption | describe the image in a caption (optional) |
fit | default: cover ; additional values are contain , fill , scale-down , none ) |
Example Usage:
<!-- Example input -->
{% Image {
src: 'https://images.unsplash.com/photo-1500754088824-ce0582cfe45f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1776&q=80',
alt: 'Latern Fest',
caption: 'Lift off at Lantern Fest 2015',
fit: 'contain'
} %}
<!-- Example output -->
<figure class="mb-8 media max-w-screen">
<img src="https://images.unsplash.com/photo-1500754088824-ce0582cfe45f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1776&q=80" alt="Latern Fest" class="object-contain mb-3 aspect-w-4 aspect-h-3">
<figcaption>Lift off at Lantern Fest 2015</figcaption>
</figure>
<!-- Example input -->
{% ExternalLink {
url: 'https://google.com',
text: 'External Link via shortcode'
} %}
<!-- Example output -->
<a class="external-link" href="https://google.com" title="Open external link in new tab" target="_blank" rel="noopener">External Link via shortcode</a>
Enable additional CSS and Scripts under blocks
in a post's YAML. Options available: youtube
, twitch
.
# List the webcomponent blocks to load on this page
blocks:
- youtube
- twitch
<!-- Example input: YouTube -->
{% YouTube {
id: 'UO2gTHLwzSg',
title: 'BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant'
} %}
<!-- Example output: YouTube -->
<youtube-embed
videoid="UO2gTHLwzSg"
videotitle="BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant"
style="background-image: url('https://i.ytimg.com/vi/UO2gTHLwzSg/hqdefault.jpg');">
<a href="https://youtube-nocookie.com/watch?v=UO2gTHLwzSg" class="lty-playbtn">
<span class="visually-hidden">Play: BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant</span>
</a>
</youtube-embed>
<a
href="https://youtube-nocookie.com/watch?v=UO2gTHLwzSg"
title="opens in new tab, watch 'BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant' on youtube-nocookie.com"
target="_blank">
Watch on YouTube
</a>
<!-- Example input: Twitch -->
{% Twitch {
id: '0WkbOP5xexWgGw',
title: 'Project: Shatter [Ship Saturday]',
type: 'collection',
thumbnail: '[optional, has fallback]'
} %}
<!-- Example output: Twitch -->
<twitch-embed
videoid="0WkbOP5xexWgGw"
videotitle="Project: Shatter [Ship Saturday]"
videotype="collection"
class="twitch-playbtn mb-2" style="background-image:url('https://static-cdn.jtvnw.net/cf_vods/d2nvs31859zcd8/a16daa79e340800357c7_eli_archgirl_32268743152_1085421880/thumb/custom-45341f1f-72f0-4c76-9ed4-1b2628cf7f31-320x180.jpeg')">
<a href="https://www.twitch.tv/collections/0WkbOP5xexWgGw">
<span class="visually-hidden">Play Project: Shatter [Ship Saturday]</span>
</a>
</twitch-embed>
<a href="https://www.twitch.tv/collections/0WkbOP5xexWgGw"
title="opens in new tab, watch collection 'Project: Shatter [Ship Saturday]' on twitch.tv"
target="_blank">
Watch collection on Twitch
</a>
<!-- Example input: Transistor -->
{% Transistor {
id: 'f44edcde',
title: 'BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant'
} %}
<!-- Example output: Transistor -->
<iframe
width="100%"
height="180"
frameborder="no"
scrolling="no"
seamless
class="mb-2"
src="https://share.transistor.fm/e/f44edcde"
></iframe>
<a
href="https://share.transistor.fm/s/f44edcde"
title="opens in new tab, listen to 'BuiltOnAir [All Things Airtable] S03:E08 - Melanie Magdalena, Digital Consultant' on transistor.fm"
target="_blank">
Listen on Transistor
</a>
The following resources assisted in the creation of my site!
- About the Conventional Commits specification
- Nunjucks templating features (general documentation)
- "Flexible components in Eleventy with Nunjucks macros" by Iain Bean is a comprehensive guide to macros with plenty of examples.
- "Using parameters in your eleventy includes with nunjucks macros" by Thomas Michael Semmler showcases a parameter approach for macros. I haven't figured out how to use this and keep args in stories functioning.
I removed Storybook... but here's my reading list from when I got it working.
- On using nunjucks as a valid component format... This buried issue and reply was open on my phone for about six months until I finally got around to setting up Storybook on an 11ty project. Radum, thank you for sharing your knowledge.
- IMPORTANT: You have to use version
^2.*
for the loader, not^3.*
because Storybook uses Webpack 4. I only wasted an hour of my life with errors cuz I failed to read the nice notice on the loader's README. :face_palm:
- IMPORTANT: You have to use version
- Nunjucks-ifying: eleventy-starter-storybook is a great proof-of-concept for how to use njk components in stories. Plus it has a cool macro output that is only used in the story!
- tailwind-ui-alpinejs-storybook has a great visual for how to add Tailwind and Alpine to Storybook and have the thing actually work.
This site started with Netlify CMS which was renamed to Decap CMS with new maintainers. I switched to the actively developed fork Static CMS due do its MOBILE support (since v3.0.0)! I've decided to keep the running log of resources for Netlify CMS because they did help me at one point in time :)
Manual initialization:
- [Netlify CMS] "Consolidating Netlify CMS" by Zach Schnackel is a quick introduction to Manual Initialization for Netlify CMS, instead of using YAML.
- [Netlify CMS] "DRY Netlify CMS config with Manual Initialization" by Wojciech Kałużny has great examples for how to create and use partials for collections.
- [Netlify CMS] "Splitting huge NetlifyCMS config.yml file to multiple JS files" by Ilias Trichopoulos has more complex examples of partials. I haven't gone this deep yet... but it's an option.
Customizing the preview pane:
- Official documentation by Static CMS - they are functional components now
- [Decap CMS] Official documentation
- [Netlify CMS] Inspiration, plus how to "query" data from the widgets so it shows up the preview: eleventy-netlify-boilerplate and spacebook
Make your own widgets and editor components:
- Official documentation by Static CMS - they are functional components now
- Official documentation: Editor Shortcodes with Preview by Static CMS
- [Decap CMS] Offical documentation
- [Netlify CMS] "Master Netlify CMS: custom editor components" by Monica Norris explains how to make a custom Editor Component for video (Hugo-focused).
- [Netlify CMS] "Creating Custom Netlify Editor Components" by Lukas Murdock is an example of how to make a blockquote Editor Component.
- [Netlify CMS] "Styling custom Netlify CMS widgets is confusing" by Dave Meyer expands on the official documentation to explain how to load stylesheets explictly into widgets and preview components.