Resurrected from the basement…

This commit is contained in:
Ben Aultowski 2025-12-26 16:37:29 -05:00
parent 9a724a2c43
commit f8f9d3eb20
23 changed files with 762 additions and 68 deletions

View file

@ -69,6 +69,8 @@ export default async function (eleventyConfig) {
}
});
eleventyConfig.addPlugin(plugins.EleventyNavigationPlugin);
// --------------------- bundle
eleventyConfig.addBundle('css', {hoist: true});
@ -117,6 +119,11 @@ export default async function (eleventyConfig) {
eleventyConfig.on('eleventy.after', events.svgToJpeg);
}
// Pagefind search index
if (process.env.ELEVENTY_RUN_MODE === 'build') {
eleventyConfig.on('eleventy.after', events.buildPagefind);
}
// --------------------- Passthrough File Copy
// -- same path

24
package-lock.json generated
View file

@ -1,17 +1,18 @@
{
"name": "eleventy-excellent",
"version": "4.5.0",
"name": "hypnagaga",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "eleventy-excellent",
"version": "4.5.0",
"name": "hypnagaga",
"version": "0.0.1",
"license": "ISC",
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"@11ty/eleventy-fetch": "^5.1.0",
"@11ty/eleventy-img": "^6.0.4",
"@11ty/eleventy-navigation": "^1.0.4",
"@11ty/eleventy-plugin-rss": "^2.0.4",
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2",
"@11ty/eleventy-plugin-webc": "^0.11.2",
@ -42,6 +43,7 @@
"markdown-it-prism": "^3.0.1",
"netlify-plugin-cache": "^1.0.3",
"pa11y-ci": "^4.0.1",
"pagefind": "^1.4.0",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1",
@ -604,6 +606,19 @@
"@img/sharp-win32-x64": "0.33.5"
}
},
"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==",
"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",
@ -2786,7 +2801,6 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"license": "MIT",
"peer": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",

View file

@ -1,8 +1,8 @@
{
"name": "eleventy-excellent",
"version": "4.5.0",
"description": "Eleventy starter built around the workflow suggested by Andy Bell's buildexcellentwebsit.es.",
"author": "Lene Saile",
"name": "hypnagaga",
"version": "0.0.1",
"description": "A web site.",
"author": "Ben Aultowski",
"license": "ISC",
"type": "module",
"engines": {
@ -16,8 +16,9 @@
"screenshots": "node ./src/_config/setup/generate-screenshots.js",
"dev:11ty": "cross-env ELEVENTY_ENV=development eleventy --serve",
"build:11ty": "cross-env ELEVENTY_ENV=production eleventy",
"build:search": "pagefind --site 'dist' --glob '**/*.html'",
"start": "npm run dev:11ty",
"build": "npm run clean && npm run build:11ty",
"build": "npm run clean && npm run build:11ty && npm run build:search",
"pa11y:build": "npm run clean && cross-env ELEVENTY_ENV=test eleventy",
"pa11y:test": "sleep 3 && pa11y-ci --config ./dist/pa11y.json",
"pa11y:serve": "ELEVENTY_ENV=test eleventy --serve --ignore-initial",
@ -26,12 +27,13 @@
"keywords": [],
"repository": {
"type": "git",
"url": "https://github.com/madrilene/eleventy-excellent.git"
"url": "https://git.hypnagaga.com/wires/hypnagaga.git"
},
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"@11ty/eleventy-fetch": "^5.1.0",
"@11ty/eleventy-img": "^6.0.4",
"@11ty/eleventy-navigation": "^1.0.4",
"@11ty/eleventy-plugin-rss": "^2.0.4",
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.2",
"@11ty/eleventy-plugin-webc": "^0.11.2",
@ -62,6 +64,7 @@
"markdown-it-prism": "^3.0.1",
"netlify-plugin-cache": "^1.0.3",
"pa11y-ci": "^4.0.1",
"pagefind": "^1.4.0",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"postcss-import": "^16.1.1",

View file

@ -1,9 +1,11 @@
import {svgToJpeg} from './events/svg-to-jpeg.js';
import {buildAllCss} from './events/build-css.js';
import {buildAllJs} from './events/build-js.js';
import {buildPagefind} from './events/build-pagefind-index.js';
export default {
svgToJpeg,
buildAllCss,
buildAllJs
buildAllJs,
buildPagefind
};

View file

@ -0,0 +1,13 @@
import {execSync} from 'node:child_process';
export const buildPagefind = () => {
console.log('Building Pagefind index...');
try {
execSync(`npx pagefind --site dist --glob "**/*.html"`, {
encoding: 'utf-8',
stdio: 'inherit'
});
} catch (error) {
console.error('Pagefind build failed: ', error.message);
}
};

View file

@ -4,6 +4,7 @@ import rss from '@11ty/eleventy-plugin-rss';
import syntaxHighlight from '@11ty/eleventy-plugin-syntaxhighlight';
import webc from '@11ty/eleventy-plugin-webc';
import {eleventyImageTransformPlugin} from '@11ty/eleventy-img';
import EleventyNavigationPlugin from '@11ty/eleventy-navigation';
// custom
import {markdownLib} from './plugins/markdown.js';
@ -18,6 +19,7 @@ export default {
syntaxHighlight,
webc,
eleventyImageTransformPlugin,
EleventyNavigationPlugin,
markdownLib,
drafts,
htmlConfig

View file

@ -1,24 +1,24 @@
export const url = process.env.URL || 'http://localhost:8080';
// Extract domain from `url`
export const domain = new URL(url).hostname;
export const siteName = 'Eleventy Excellent';
export const siteDescription = 'Eleventy starter for building modern, resilient websites';
export const siteName = 'Hypnagaga';
export const siteDescription = 'A vision quest.';
export const siteType = 'Person'; // schema
export const locale = 'en_EN';
export const lang = 'en';
export const skipContent = 'Skip to content';
export const author = {
name: 'Lene Saile', // i.e. Lene Saile - page / blog author's name. Must be set.
name: 'Ben Aultowski',
avatar: '/icon-512x512.png', // path to the author's avatar. In this case just using a favicon.
email: 'hola@lenesaile.com', // i.e. hola@lenesaile.com - email of the author
website: 'https://www.lenesaile.com', // i.e. https.://www.lenesaile.com - the personal site of the author
fediverse: '@lene@front-end.social' // used for highlighting journalism on the fediverse. Can be Mastodon, Flipboard, Threads, WordPress (with the ActivityPub plugin installed), PeerTube, Pixelfed, etc. https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/
email: 'benaultowski@proton.me',
website: 'https://www.hypnagaga.com',
fediverse: '' // used for highlighting journalism on the fediverse. Can be Mastodon, Flipboard, Threads, WordPress (with the ActivityPub plugin installed), PeerTube, Pixelfed, etc. https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/
};
export const creator = {
name: 'Lene Saile', // i.e. Lene Saile - creator's (developer) name.
email: 'hola@lenesaile.com',
website: 'https://www.lenesaile.com',
social: 'https://front-end.social/@lene'
name: 'Ben Aultowski', // i.e. Lene Saile - creator's (developer) name.
email: 'benaultowski@proton.me',
website: 'https://www.hypnagaga.com',
social: ''
};
export const pathToSvgLogo = 'src/assets/svg/misc/logo.svg'; // used for favicon generation
export const themeColor = '#dd4462'; // used in manifest, for example primary color value

View file

@ -1,38 +1,26 @@
export default {
top: [
{
text: 'About',
url: '/about/'
text: 'Why',
url: '/why/'
},
{
text: 'Docs',
url: '/get-started/'
text: 'Thoughts',
url: '/thoughts/'
},
{
text: 'Built with',
url: '/built-with/'
text: 'Stories',
url: '/stories/'
},
{
text: 'Blog',
url: '/blog/'
text: 'Search',
url: '/search/'
}
],
bottom: [
{
text: 'Style guide',
url: '/styleguide/'
},
{
text: 'Imprint',
url: '/imprint/'
},
{
text: 'Privacy',
url: '/privacy/'
},
{
text: 'Accessibility',
url: '/accessibility/'
}
]
};

View file

@ -25,7 +25,7 @@ schema: BlogPosting
%}
<!-- tags -->
{% for tag in tags %}{% if tag != "posts" %}
<a class="button" href="/tags/{{ tag | slugify }}/" data-small-button> {{ tag }} </a>
<a class="button" href="/tags/{{ tag | slugify }}/" data-pagefind-filter="tag:{{ tag }}" data-pagefind-meta="tag:{{ tag }}" data-small-button> {{ tag }} </a>
{% endif %}{% endfor %}
{% endif %}
</p>

View file

@ -0,0 +1,255 @@
/*=============================================
= Search Form =
=============================================*/
.search-form {
display: flex;
gap: var(--space-xs);
}
.search-form__input {
flex-grow: 1;
padding: var(--space-xs) var(--space-s);
border: 1px solid var(--color-primary);
border-radius: var(--rounded);
font-size: var(--text-base);
background-color: var(--color-bg);
color: var(--color-text);
}
.search-form__input:focus {
outline: 2px solid var(--color-secondary);
outline-offset: 2px;
}
.search-form__button {
padding: var(--space-xs) var(--space-s);
border: 1px solid var(--color-primary);
border-radius: var(--rounded);
background-color: var(--color-primary);
color: var(--color-bg);
cursor: pointer;
font-size: var(--text-base);
}
.search-form__button:hover {
background-color: var(--color-secondary);
}
/*=============================================
= Search Results =
=============================================*/
.search-results-summary {
margin-block-end: var(--space-l);
font-size: var(--text-l);
font-weight: var(--font-bold);
}
.search-results-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: var(--space-l);
}
.search-result {
padding: var(--space-m);
border: 1px solid var(--color-bg-accent);
border-radius: var(--rounded-lg);
background-color: var(--color-bg-accent);
}
.search-result__title {
margin-block-start: 0;
margin-block-end: var(--space-xs);
font-size: var(--text-xl);
}
.search-result__title a {
text-decoration: none;
color: var(--color-primary);
}
.search-result__title a:hover {
text-decoration: underline;
}
.search-result__excerpt {
margin: 0;
}
.search-results-list custom-card p mark {
background-color: var(--color-highlight);
color: var(--color-text);
padding: 0.1em 0.2em;
border-radius: var(--rounded-sm);
}
/*=============================================
= Search Filters =
=============================================*/
#custom-search-filters {
margin-block-start: var(--space-l);
padding: var(--space-m);
border: 1px solid var(--color-bg-accent);
border-radius: var(--rounded-lg);
background-color: var(--color-bg-accent);
}
#custom-search-filters h3 {
margin-block-start: 0;
margin-block-end: var(--space-m);
font-size: var(--text-l);
font-weight: var(--font-bold);
}
.filter-group {
display: flex;
flex-wrap: wrap;
gap: var(--space-s);
}
.filter-group label {
display: flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-s);
border: 1px solid var(--color-bg-accent);
border-radius: var(--rounded);
cursor: pointer;
user-select: none;
transition: background-color 0.2s ease;
}
.filter-group label:hover {
background-color: var(--color-bg-accent);
}
.filter-group input[type="checkbox"] {
/* Hide the default checkbox */
appearance: none;
-webkit-appearance: none;
width: 1em;
height: 1em;
border: 1px solid var(--color-primary);
border-radius: var(--rounded-sm);
vertical-align: middle;
position: relative;
}
.filter-group input[type="checkbox"]:checked {
background-color: var(--color-primary);
}
.filter-group input[type="checkbox"]:checked::after {
content: '✔';
color: var(--color-bg);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 0.8em;
line-height: 1;
}
/*=============================================
= Search Result Cards (custom-card styling) =
=============================================*/
.search-results-list custom-card {
--gutter: var(--space-xs-s);
background-color: var(--card-bg, var(--color-bg-accent));
border: 4px solid var(--color-bg-accent);
color: var(--color-text);
padding: var(--space-s-m);
border-radius: var(--border-radius-medium);
max-inline-size: unset;
display: grid;
grid-template-rows: [image] max-content [headline] max-content [meta] max-content [desc] auto [footer] max-content;
position: relative;
text-decoration: none;
transition: border-color 0.2s ease;
}
/* avoid flow space being added to unused elements */
.search-results-list custom-card > :empty {
display: none;
}
.search-results-list custom-card ::selection {
color: var(--color-dark);
background-color: var(--color-secondary);
}
.search-results-list custom-card :is(h2, h3) {
--flow-space: var(--space-m);
grid-row: headline;
}
.search-results-list custom-card :is(h2, h3) a {
text-decoration: none;
}
.search-results-list custom-card > :is(picture, figure) {
grid-row: image;
--flow-space: 0;
}
.search-results-list custom-card img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
}
.search-results-list custom-card > .meta {
grid-row: meta;
font-size: var(--size-step-min-1);
}
.search-results-list custom-card > p {
grid-row: desc;
}
.search-results-list custom-card > footer {
grid-row: footer;
font-size: var(--size-step-min-2);
}
/* avoid overflow of long words */
.search-results-list custom-card :is(a, p, h2, h3) {
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
}
/* squared image variant */
.search-results-list custom-card[img-square] img {
aspect-ratio: 1;
}
/* clickable variant */
.search-results-list custom-card[clickable]:hover,
.search-results-list custom-card[clickable]:focus-within {
border: 4px solid var(--color-primary);
}
.search-results-list custom-card[clickable]:focus-within a:focus {
outline: none;
}
.search-results-list custom-card[clickable] {
position: relative;
}
.search-results-list custom-card[clickable] a:after {
bottom: 0;
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}

View file

@ -0,0 +1,33 @@
form#search {
.filter-and-results {
display: flex;
flex-direction: row;
&.filter-and-results--hidden {
display: none;
}
fieldset.types {
display: flex;
flex-direction: column;
width: fit-content;
font-size: smaller;
}
.results-area {
padding-right: 0.7em;
}
}
}
@media screen(ltsm) {
form#search {
.filter-and-results {
flex-direction: column;
.results-area {
padding-right: 0;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -0,0 +1,226 @@
import dayjs from 'dayjs';
const allTypes = ['Page', 'Post'];
async function ensurePagefind() {
if (window.pagefind) return Promise.resolve(window.pagefind);
return import('/pagefind/pagefind.js')
.then(function (mod) {
mod.options({
highlightParam: 'highlight'
});
window.pagefind = mod;
return window.pagefind || mod.pagefind || mod.default || mod;
})
.catch(function () {
return new Promise(function (resolve) {
const s = document.createElement('script');
s.src = '/pagefind/pagefind.js';
s.type = 'module';
s.onload = function () {
resolve(window.pagefind);
};
s.onerror = function () {
resolve(undefined);
};
document.head.appendChild(s);
});
});
}
function renderItem(item) {
let {
url,
excerpt,
meta: {author, date, title, type, image, image_alt, tag}
} = item;
//debugging
console.log(item.meta);
// create date
const dateHTML = date ? `<span slot="date">${dayjs(date).format('MMMM D, YYYY') }</span>` : '';
// create hero image preview
let imageHTML = '';
if (item.meta.image) {
// Try to get alt text from Pagefind metadata, fallback to title, then generic text
const altText = item.meta['image[alt]'] || item.meta.title || 'Search result image';
imageHTML = `<picture><img src="${item.meta.image}" alt="${altText}"></picture>`;
}
// create tags
let tagsHTML = '';
if (item.filters && item.filters.tag && item.filters.tag.length > 0) {
tagsHTML = `
${item.filters.tag.map(tag => `<span class="button" data-small-button>${tag}</span>`).join('')}
`;
}
let variant;
switch (type) {
case 'Page':
variant = 'secondary';
break;
default:
variant = 'primary';
break;
}
//output the search result
return `
<custom-card clickable class="mt-s-m">
${imageHTML}
<h2 slot="headline" class="text-step-2">
<a href="${url}">${title}</a>
</h2>
${dateHTML}
<div slot="type" class="meta | cluster gutter-xs-s" webc:nokeep>
<span class="button" data-small-button data-button-variant=${variant}>${type}</span> ${tagsHTML}
</div>
<div slot="content" webc:nokeep>${excerpt}</div>
</custom-card>
`;
}
function renderItems(q, items) {
var results = items.length == 1 ? 'result' : 'results';
document.querySelector('#results-count').innerHTML = `${items.length} ${results} for ${q}`;
let content = items.map(renderItem).join('');
document.querySelector('#results').innerHTML = content;
}
function doSearch(isPopEvent = false) {
let form = document.querySelector('form#search');
// Clear current content
document.querySelector('#results').innerHTML = '';
document.querySelector('#results-count').innerHTML = '';
// Get form data
let formData = new FormData(form);
let q = formData.get('q');
let types = [];
allTypes.map(possibleFilter => {
if (formData.get(possibleFilter)) {
types.push(possibleFilter);
}
});
let tags = [];
formData.getAll('tag').forEach(tag => {
if (tag) tags.push(tag);
});
// Only do a search if there's a query
if (q) {
// Update url unless it's a popstate event
if (!isPopEvent) {
setWindowLocation(q, types, tags, isPopEvent);
}
// Show results area
form.querySelector('#filter-and-results').classList.remove('filter-and-results--hidden');
// Find and display results
window.pagefind
.search(q, {
filters: {
type: { any: types },
tag: { any: tags }
}
})
.then(search =>
Promise.all(search.results.map(result => result.data()))
.then(data => renderItems(q, data))
.catch(console.error)
)
.catch(console.error);
}
}
function setWindowLocation(q, types, tags) {
const url = new URL(window.location);
if (q) {
url.searchParams.set('q', q);
}
url.searchParams.delete('types');
for (const type of types) {
url.searchParams.append('types', type);
}
url.searchParams.delete('tags');
for (const tag of tags) {
url.searchParams.append('tags', tag);
}
window.history.pushState({search: url.searchParams.toString()}, '', url);
}
function setFormFromLocation() {
const url = new URL(window.location);
let searchParams = url.searchParams;
setFormFromSearchParams(searchParams);
}
function setFormFromSearchParams(searchParams) {
let q = searchParams.get('q');
document.querySelector('form#search input#q').value = q;
let types = searchParams.getAll('types');
for (const type of allTypes) {
document.querySelector(`form#search input[name="${type}"]`).checked = types.includes(type);
}
let tags = searchParams.getAll('tags');
document.querySelectorAll('form#search input[name="tag"]').forEach(input => {
input.checked = tags.includes(input.value);
});
}
window.addEventListener('DOMContentLoaded', _ => {
ensurePagefind()
.then(_ => {
setFormFromLocation();
doSearch();
})
.catch(e => console.error('page find error', e));
let form = document.querySelector('form#search');
form.addEventListener('submit', e => {
e.preventDefault();
doSearch();
});
// Submit form on post type change
let checkboxes = form.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', _ => {
doSearch();
});
});
// Using browser back or forward button
window.addEventListener('popstate', event => {
// Only intercept if on search page
if (!['/search/', '/search'].includes(window.location.pathname)) return;
ensurePagefind()
.then(_ => {
let searchParams = new URLSearchParams(event.state?.search ?? '');
setFormFromSearchParams(searchParams);
// Don't update history as we're navigating through history!
doSearch(true);
})
.catch(e => console.error('page find error', e));
});
});

View file

@ -0,0 +1,9 @@
<svg
width="1em"
height="1em"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 100"
>
<g fill="#000"><path d="M1000 100C500 100 500 64 0 64V0h1000v100Z" opacity=".5"></path><path d="M1000 100C500 100 500 34 0 34V0h1000v100Z" opacity=".5"></path><path d="M1000 100C500 100 500 4 0 4V0h1000v100Z"></path></g>
</svg>

After

Width:  |  Height:  |  Size: 356 B

View file

@ -0,0 +1,9 @@
<svg
width="1em"
height="1em"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 100"
>
<path d="M0 0h1000v4H0zM10 100 0 4h20l-10 96zM30 100 20 4h20l-10 96zM50 100 40 4h20l-10 96zM70 100 60 4h20l-10 96zM90 100 80 4h20l-10 96zM110 100 100 4h20l-10 96zM130 100 120 4h20l-10 96zM150 100 140 4h20l-10 96zM170 100 160 4h20l-10 96zM190 100 180 4h20l-10 96zM210 100 200 4h20l-10 96zM230 100 220 4h20l-10 96zM250 100 240 4h20l-10 96zM270 100 260 4h20l-10 96zM290 100 280 4h20l-10 96zM310 100 300 4h20l-10 96zM330 100 320 4h20l-10 96zM350 100 340 4h20l-10 96zM370 100 360 4h20l-10 96zM390 100 380 4h20l-10 96zM410 100 400 4h20l-10 96zM430 100 420 4h20l-10 96zM450 100 440 4h20l-10 96zM470 100 460 4h20l-10 96zM490 100 480 4h20l-10 96zM510 100 500 4h20l-10 96zM530 100 520 4h20l-10 96zM550 100 540 4h20l-10 96zM570 100 560 4h20l-10 96zM590 100 580 4h20l-10 96zM610 100 600 4h20l-10 96zM630 100 620 4h20l-10 96zM650 100 640 4h20l-10 96zM670 100 660 4h20l-10 96zM690 100 680 4h20l-10 96zM710 100 700 4h20l-10 96zM730 100 720 4h20l-10 96zM750 100 740 4h20l-10 96zM770 100 760 4h20l-10 96zM790 100 780 4h20l-10 96zM810 100 800 4h20l-10 96zM830 100 820 4h20l-10 96zM850 100 840 4h20l-10 96zM870 100 860 4h20l-10 96zM890 100 880 4h20l-10 96zM910 100 900 4h20l-10 96zM930 100 920 4h20l-10 96zM950 100 940 4h20l-10 96zM970 100 960 4h20l-10 96zM990 100 980 4h20l-10 96z" fill="#000"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,9 @@
<svg
width="1em"
height="1em"
preserveAspectRatio="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 100"
>
<path d="M0 0v4l500 96 500-96V0H0z" fill="#000"></path>
</svg>

After

Width:  |  Height:  |  Size: 191 B

View file

@ -1,7 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1em" height="1em" fill="#DD4462">
<path
fill-rule="evenodd"
d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.007 5.404.433c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.433 2.082-5.006z"
clip-rule="evenodd"
/>
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024">
<!-- Generator: Adobe Illustrator 29.6.0, SVG Export Plug-In . SVG Version: 2.1.1 Build 207) -->
<defs>
<style>
.st0 {
fill: #4800ff;
}
.st1 {
fill: #ff00b4;
}
</style>
</defs>
<ellipse class="st0" cx="498.56" cy="513.53" rx="575.6" ry="570.45" transform="translate(-27.04 999.36) rotate(-88.6)"/>
<circle class="st1" cx="504" cy="504" r="504"/>
<circle class="st0" cx="504" cy="504" r="432"/>
<ellipse class="st1" cx="504" cy="505" rx="360" ry="359"/>
<circle class="st0" cx="504" cy="504" r="288"/>
<circle class="st1" cx="512" cy="512" r="216"/>
<circle class="st0" cx="512" cy="512" r="155.04"/>
</svg>

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 807 B

View file

@ -7,6 +7,9 @@ pagination:
permalink: /tags/{{ tag | slugify }}/
eleventyComputed:
title: '{{ meta.blog.tagSingle }}: {{ tag }}'
eleventyNavigation:
key: '{{ tag }}'
parent: Stories
---
<custom-masonry layout="50-50">

View file

@ -1,22 +1,8 @@
---
title: About
permalink: /about/index.html
description: 'Eleventy Excellent is inspired bythe companion website of Andy Bells talk "Be the browsers mentor, not its micromanager".'
title: Why Create?
permalink: /why/index.html
description: 'Why create?'
layout: page
---
This starter uses modern CSS, fluid type & space, flexible Layouts and Progressive Enhancement, wrapped in a basic template.
It is built around the CSS boilerplate by Andy Bell and inspired by Andy's talk **'Be the browsers mentor, not its micromanager'**.
If you want to know exactly how it all works, [read this article on piccalil.li](https://piccalil.li/blog/a-css-project-boilerplate/).
The aim is to spread the idea and use of this _excellent_ workflow. To work with it efficiently you should be familiar with [cube.fyi](https://cube.fyi/), [utopia.fyi](https://utopia.fyi/) and [every-layout.dev](https://every-layout.dev/).
- buildexcellentwebsit.es
- Study the [original CSS boilerplate](https://github.com/Set-Creative-Studio/cube-boilerplate/tree/main)
## Watch the talk
<div><custom-youtube @slug="JqnMI1AXl6w" @label="Andy Bell Be the browsers mentor, not its micromanager"> </custom-youtube></div>
Hypngaga is a vision quest by forty-something year old captive of a culture seemingly bent upon self-destruction.

44
src/pages/search.njk Normal file
View file

@ -0,0 +1,44 @@
---
title: Search
permalink: /search/index.html
description: 'Sift through this rubble. '
layout: page
---
<search>
<form role="search" method="GET" id="search">
<fieldset>
<label for="q" class="hidden">Search</label>
<input id="q" type="search" name="q" placeholder="Search" autofocus>
<input type="hidden" name="sites" value="{{meta.domain}}">
<input type="submit" value="Search" class="hidden">
</fieldset>
<div class="filter-and-results filter-and-results--hidden" id="filter-and-results">
<fieldset class="types">
<label><input type="checkbox" name="Page">Page</label>
<label><input type="checkbox" name="Post">Post</label>
</fieldset>
<fieldset class="tags">
{% for tag in collections.tagList %}
<label><input type="checkbox" name="tag" value="{{ tag }}">{{ tag }}</label>
{% endfor %}
</fieldset>
<script id="all-tags" type="application/json">{{ collections.tagList | dump | safe }}</script>
<div class="results-area">
<header id="results-count"></header>
<div class="results" id="results"></div>
</div>
</div>
</form>
</search>
{% css "local" %}
{% include "css/forms.css" %}
{% include "css/search.css" %}
{% include "css/custom-card.css" %}
{% endcss %}
{% js "defer" %}
{% include "scripts/search.js" %}
{% endjs %}

23
src/pages/stories.njk Normal file
View file

@ -0,0 +1,23 @@
---
layout: base
permalink: /stories/
title: 'Stories'
description: 'asdf'
eleventyNavigation:
key: Stories
---
<div class="wrapper">
<header class="full | section" style="--spot-color: var(--color-secondary)">
<div class="section__inner flow region" style="--region-space-top: var(--space-xl-2xl)">
<h1 class="text-center" style="color: var(--color-light);">{{ title }}</h1>
</div>
{% svg "divider/triangle", null, "divider" %}
</header>
<div class="region flow prose" style="--region-space-top: var(--space-xl-2xl)">
{{ collections.all | eleventyNavigation('Stories') | eleventyNavigationToHtml | safe }}
</div>

42
src/pages/thoughts.njk Normal file
View file

@ -0,0 +1,42 @@
---
layout: base
title: Thoughts
description: 'Sift through the posts.'
pagination:
data: collections.allPosts
size: 8
permalink: 'thoughts/{% if pagination.pageNumber >=1 %}page-{{ pagination.pageNumber + 1 }}/{% endif %}index.html'
---
<div class="wrapper">
<header class="full | section" style="--spot-color: var(--color-secondary)">
<div class="section__inner flow region" style="--region-space-top: var(--space-xl-2xl)">
<h1 class="text-center" style="color: var(--color-light);">{{ title }}</h1>
</div>
{% svg "divider/triangle", null, "divider" %}
</header>
<div class="region flow prose" style="--region-space-top: var(--space-xl-2xl)">
<p>This blog has a pagination of <strong>{{ pagination.size }}</strong> posts per page.<br>
The pagination is only shown if there are more posts ({{ collections.posts.length }}) than items per
page ({{ pagination.size }}).
</p>
</div>
<custom-masonry layout="50-50">
{% asyncEach item in pagination.items %}
{% include "partials/card-blog.njk" %}
{% endeach %}
</custom-masonry>
<!-- set collection to paginate -->
{% set collectionToPaginate = collections.posts %}
<!-- set target pagination settings in meta.js -->
{% set metaKey = "blog" %}
<!-- if the number of items in the collection is greater than the number of items shown on one page -->
{% if collectionToPaginate.length > pagination.size %}
<!-- include pagination -->
{% include 'partials/pagination.njk' %}
{% endif %}
</div>

View file

@ -0,0 +1,11 @@
---
title: 'Gasheyes Creek'
description: "A story about a creek."
date: 2025-11-11
tags: ['place']
eleventyNavigation:
key: Oakington Peninsula
parent: Harford County
---
Begin here.