8.1 KiB
Hypnagaga - Eleventy Project
A vision quest, of sorts.
Quick Start
npm install # Install dependencies
npm start # Dev server at localhost:8080
npm run build # Production build
npm run colors # Regenerate color tokens
npm run test:a11y # Run accessibility tests
Key Files to Know:
eleventy.config.js- Main Eleventy config (imports fromsrc/_config/)src/_config/- Modular config (collections, filters, events, plugins, shortcodes)src/assets/scripts- scripts are built from heresrc/assets/css/global- global CSS is built from heresrc/assets/css/local- inline CSS for certain pages is built from heresrc/_data/designTokens/- Design tokens (colors, spacing, fonts)src/pages/- Contains written content (markdown files) that is processed as JavaScript Nunjuks templatedist/- the project builds to here
Configuration Architecture
ESM-based modular config in src/_config/ - all files use export syntax:
collections.js- Eleventy collections (getAllPosts, tagList, tracksByProject)events.js- Build hooks (CSS/JS compilation, pagefind indexing)filters.js- Template filters (dates, markdown, slugify)plugins.js- Eleventy plugins (image transform, WebC, RSS, syntax highlighting)shortcodes.js- Reusable functions, used within Nunjuks templates.
Each category imports from subdirectories (e.g., filters/dates.js) and exports a consolidated object.
CSS Architecture
-
Based on eleventy-excellent, which uses a progressive enhancement philosphy for a responsive design.
-
The global CSS bundle is organized with cascade layers. The local CSS bundle, used for per-page or omponent-specific styles, does not utilize cascade layers. As a result, all CSS blocks included have a higher specificity than global styles, regardless of the selector specificity in the global CSS bundle.
-
Tailwind is used primarily to generate utility classes on demand. It goes through each defined
group(groups) and then grabs the values > generates Custom Property values > sticks them to theresult. Finally, usingpostcssJsandpostcss, an object that Tailwind can understand is created. TheaddComponentsfunction sticks that custom properties block on the@componentslayer. Lastly, this function creates custom utilities that I can use in markup, such asgutter-morflow-space-s. It’s all rigged up to the design tokens Custom Property block. It’s damn useful, especially when tweaking layout compositions in context. -
Everything is built using PostCSS from
src/assets/css/.
. ├── src │ ├── css-utils │ │ ├── clamp-generator.js │ │ └── tokens-to-tailwind.js │ ├── css │ │ ├── blocks │ │ │ └── prose.css │ │ ├── compositions │ │ │ ├── cluster.css │ │ │ ├── flow.css │ │ │ ├── grid.css │ │ │ ├── repel.css │ │ │ ├── sidebar.css │ │ │ ├── switcher.css │ │ │ └── wrapper.css │ │ ├── global │ │ │ ├── fonts.css │ │ │ ├── global-styles.css │ │ │ ├── reset.css │ │ │ └── variables.css │ │ ├── utilities │ │ │ ├── region.css │ │ │ └── visually-hidden.css │ │ └── global.css │ └── design-tokens │ ├── colors.json │ ├── fonts.json │ ├── spacing.json │ ├── text-leading.json │ ├── text-sizes.json │ ├── text-weights.json │ └── viewports.json ├── tailwind.config.js └── postcss.config.js
-
I try to maintain a decent source order for specificity purposes as you can see. The
@importtailwindcss/componentsis where that block of Custom Properties generated in the Tailwind config gets put. Because everything else that layer does is disabled in config, it’s nice and clean. The CUBE parts are all imported using the extremely usefulimport-globPostCSS plugin. This allows new files to be added to directories and imported straight away. It’s very Sass-like, but I like that. -
There are layouts in
src/assets/css/global/compositions.
Image Handling
- ** Primarily accomplished** by extending the
{% imageKeys {...} %}shortcode processed from within content markdown files.
Images are processed to WebP/JPEG, multiple widths, and optimized. Source paths are prepended with ./src automatically in shortcodes.
Design Tokens & Tailwind
- We only use Tailwind to generate class names. All our CSS lives in
src/assets/css/and uses an opinionated, responsive design. It is bundled indist/bundle/ src/assets/css/local- Local inline CSS. Overrides inlined for one-off pages, sections of content, and other endevours.src/assets/css/globalis used for site-wide classes of core styling and animation features.- Design tokens stored as JSON in
src/_data/designTokens/(colors, spacing, fonts, viewports) tokensToTailwind()andclampGenerator()utilities convert tokens to Tailwind config- Tailwind is customized to generate utilities from design tokens (e.g.,
mt-xs-s,bg-magenta) - Custom properties generated via Tailwind plugin (e.g.,
--color-cyan,--space-m) - Run
npm run colorsafter editingcolorsBase.jsonto regeneratecolors.jsonwith shades - Tailwind's preflight/reset is disabled - custom reset in
src/assets/css/global/reset.css
Build Process
Before Eleventy runs (eleventy.before event):
buildAllCss()processes CSS with PostCSS (import-glob → tailwind → autoprefixer → cssnano)- Global CSS:
src/assets/css/global/global.css→src/_includes/css/global.css(inlined) - Local CSS:
src/assets/css/local/**/*.css→src/_includes/css/(per-page bundles) - Component CSS:
src/assets/css/components/**/*.css→dist/assets/css/components/
- Global CSS:
buildAllJs()bundles JS with esbuild- Inline bundle:
src/assets/scripts/bundle/**/*.js→src/_includes/scripts/ - Defer bundle: similar process
- Component scripts:
src/assets/scripts/components/**/*.js→dist/assets/components/
- Inline bundle:
After Eleventy builds (eleventy.after event):
buildPagefind()generates search index (only in production)
Watch targets: src/assets/**/*.{css,js,svg,png,jpeg}, src/_includes/**/*.webc, dist/
Text Animations
Use the animateText shortcode or markdown-it-attrs classes:
{% animateText "Hello", "shiver", "1.5" %} {# content, animation, speed #}
(defined in src/assets/css/global/utilities/text-animations.css)
Safelist these classes in tailwind.config.js so they're not purged.
Pages and Projects
Digital Mixed CD project
The project's core feature is a hierarchical music mix/track system:
- Projects (e.g., "TomorrowsBacon") contain multiple tracks
- Tracks are individual markdown files in
src/pages/projects/mixes/{project-name}/ - Tracks have frontmatter:
project,track_number,artist,album,albumArt,start_time - Collection
tracksByProject(defined insrc/_config/collections.js) groups and sorts tracks by project - Layouts:
mix.njkshows track list,mix-track.njkshows individual track with prev/next navigation - Turbo Drive provides SPA-like navigation between tracks without full page reloads
Collections
allPosts: All markdown files insrc/posts/**/*.md(reversed chronological)tagList: Unique tags across all content (excludes 'posts', 'docs', 'all', 'mix', 'project')goPages: Pages withgo:frontmatter for URL redirects (output to_redirects)tracksByProject: Tracks grouped by project, sorted by track_number
Turbo Drive Navigation
<turbo-frame id="main-content">in layouts wraps main content- Import Turbo in defer bundle:
{% js "defer" %} import * as Turbo from '/assets/components/turbo.js'; {% endjs %}