150 lines
No EOL
8.1 KiB
Markdown
150 lines
No EOL
8.1 KiB
Markdown
# Hypnagaga - Eleventy Project
|
||
|
||
A vision quest, of sorts.
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
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 from `src/_config/`)
|
||
- `src/_config/` - Modular config (collections, filters, events, plugins, shortcodes)
|
||
- `src/assets/scripts` - scripts are built from here
|
||
- `src/assets/css/global` - global CSS is built from here
|
||
- `src/assets/css/local` - inline CSS for certain pages is built from here
|
||
- `src/_data/designTokens/` - Design tokens (colors, spacing, fonts)
|
||
- `src/pages/` - Contains written content (markdown files) that is processed as JavaScript Nunjuks template
|
||
- `dist/` - 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
|
||
1. Based on [eleventy-excellent](https://github.com/madrilene/eleventy-excellent.git), which uses a [progressive enhancement](https://piccalil.li/blog/how-a-minimum-viable-experience-produces-a-resilient-inclusive-end-product/) philosphy for a responsive design.
|
||
|
||
2. 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.
|
||
|
||
3. 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 the `result`. Finally, using `postcssJs` and `postcss`, an object that Tailwind can understand is created. The `addComponents` function sticks that custom properties block on the `@components` layer. Lastly, this function creates custom utilities that I can use in markup, such as `gutter-m` or `flow-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.
|
||
|
||
4. 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
|
||
|
||
|
||
3. I try to maintain a decent source order for specificity purposes as you can see. The `@import` `tailwindcss/components` is 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 useful `import-glob` PostCSS plugin. This allows new files to be added to directories and imported straight away. It’s very Sass-like, but I like that.
|
||
|
||
4. There are layouts in `src/assets/css/global/compositions`.
|
||
|
||
### Image Handling
|
||
|
||
1. ** 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 in `dist/bundle/`
|
||
- `src/assets/css/local` - Local inline CSS. Overrides inlined for one-off pages, sections of content, and other endevours. `src/assets/css/global` is 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()` and `clampGenerator()` 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 colors`** after editing `colorsBase.json` to regenerate `colors.json` with shades
|
||
- Tailwind's preflight/reset is **disabled** - custom reset in `src/assets/css/global/reset.css`
|
||
|
||
|
||
### Build Process
|
||
**Before Eleventy runs** (`eleventy.before` event):
|
||
1. `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/`
|
||
2. `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/`
|
||
|
||
**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:
|
||
```ninjuks
|
||
{% 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 in `src/_config/collections.js`) groups and sorts tracks by project
|
||
- Layouts: `mix.njk` shows track list, `mix-track.njk` shows individual track with prev/next navigation
|
||
- Turbo Drive provides SPA-like navigation between tracks without full page reloads
|
||
|
||
|
||
#### Collections
|
||
- **`allPosts`**: All markdown files in `src/posts/**/*.md` (reversed chronological)
|
||
- **`tagList`**: Unique tags across all content (excludes 'posts', 'docs', 'all', 'mix', 'project')
|
||
- **`goPages`**: Pages with `go:` 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 %}` |