diff --git a/src/helpers/setup-css.js b/src/helpers/setup-css.js index 106fd05..fe12ecc 100644 --- a/src/helpers/setup-css.js +++ b/src/helpers/setup-css.js @@ -1,28 +1,28 @@ -import postcss from 'postcss'; import autoprefixer from 'autoprefixer'; -import postCssImport from 'postcss-import'; -import postCssNesting from 'postcss-nesting'; -import postCssCsso from 'postcss-csso'; import { promises as fs } from 'node:fs'; import path from 'node:path'; +import postcss from 'postcss'; +import postCssCsso from 'postcss-csso'; +import postCssImport from 'postcss-import'; +import postCssNesting from 'postcss-nesting'; /** * Registers CSS build and watch logic for Eleventy using PostCSS pipeline. * @param {import('@11ty/eleventy').EleventyConfig} eleventyConfig - Eleventy config object */ export function setupCSS(eleventyConfig) { - const sourceFile = './src/styles/index.css'; - const compiledFile = './dist/style.css'; + const sourceFile = './src/styles/index.css'; + const compiledFile = './dist/style.css'; - // Process CSS before the build starts - eleventyConfig.on('beforeBuild', async () => { - await processCSS(sourceFile, compiledFile, false); - }); - - // Watch CSS source files for changes to trigger rebuild - eleventyConfig.addWatchTarget(sourceFile); - eleventyConfig.addWatchTarget('src/components/**/*.css'); + // Process CSS before the build starts + eleventyConfig.on('beforeBuild', async () => { + await processCSS(sourceFile, compiledFile, false); + }); + // Watch CSS source files for changes to trigger rebuild + eleventyConfig.addWatchTarget(sourceFile); + eleventyConfig.addWatchTarget('src/styles/**/*.css'); + eleventyConfig.addWatchTarget('src/components/**/*.css'); } /** @@ -32,34 +32,41 @@ export function setupCSS(eleventyConfig) { * @param {boolean} [debug=false] - Enable debug logging */ async function processCSS(sourceFile, compiledFile, debug = false) { - try { - // Remove old file if it exists - await fs.unlink(compiledFile).then(() => { - if (debug) console.log(`💥 Removed old CSS file: ${compiledFile}`); - }).catch((err) => { - if (err.code !== 'ENOENT') throw err; - }); + try { + // Remove old file if it exists + await fs + .unlink(compiledFile) + .then(() => { + if (debug) + console.log(`💥 Removed old CSS file: ${compiledFile}`); + }) + .catch((err) => { + if (err.code !== 'ENOENT') throw err; + }); + + // Ensure the output directory exists + const compiledDir = path.dirname(compiledFile); + await fs.mkdir(compiledDir, { recursive: true }); - // Ensure the output directory exists - const compiledDir = path.dirname(compiledFile); - await fs.mkdir(compiledDir, { recursive: true }); + // Read the source CSS + const css = await fs.readFile(sourceFile, 'utf8'); - // Read the source CSS - const css = await fs.readFile(sourceFile, 'utf8'); + // Process CSS with PostCSS plugins. Run the minifier only in production + const plugins = [postCssImport, postCssNesting, autoprefixer]; + if (process.env.NODE_ENV === 'production') { + plugins.push(postCssCsso); + } - // Process CSS with PostCSS plugins - const result = await postcss([ - postCssImport, - postCssNesting, - autoprefixer, - postCssCsso, - ]).process(css, { from: sourceFile, to: compiledFile }); + const result = await postcss(plugins).process(css, { + from: sourceFile, + to: compiledFile + }); - // Write processed CSS to compiledFile - await fs.writeFile(compiledFile, result.css); + // Write processed CSS to compiledFile + await fs.writeFile(compiledFile, result.css); - if (debug) console.log(`🎉 Compiled new CSS file: ${compiledFile}`); - } catch (error) { - console.error('⛔️ CSS processing error:', error); - } + if (debug) console.log(`🎉 Compiled new CSS file: ${compiledFile}`); + } catch (error) { + console.error('⛔️ CSS processing error:', error); + } } diff --git a/src/layouts/post.njk b/src/layouts/post.njk index 4c6a574..bf5844c 100644 --- a/src/layouts/post.njk +++ b/src/layouts/post.njk @@ -2,16 +2,10 @@ {% extends "main.njk" %} {% block content %}
-
-

{{ title }}

- -
-
{{ content | safe }}
-
{% endblock %} diff --git a/src/styles/base.css b/src/styles/base.css new file mode 100644 index 0000000..01ed301 --- /dev/null +++ b/src/styles/base.css @@ -0,0 +1,102 @@ +:root { + --colour-light: #efefef; + --colour-dark: #222222; + --colour-link: darkcyan; + --colour-link-alt: yellow; + --line-height: 1.9; + --character-width: 72ch; +} + +body { + box-sizing: border-box; + background-color: var(--colour-light); + color: var(--colour-dark); + font-family: var(--type-stack); + max-width: var(--character-width); + margin: auto; + padding: 20px; + width: 100%; +} + +h1 { + line-height: var(--line-height); +} + +a { + color: var(--colour-link); + font-weight: 600; +} + +img { + height: auto; + width: 100%; +} + +footer { + padding: 2rem 0; +} + +footer svg { + height: 1rem; + width: auto; +} + +footer a svg path { + fill: var(--colour-link); +} + +footer ul { + list-style: none; + text-align: right; +} + +footer li { + display: inline-block; + padding: 0 5px; +} + +@media (prefers-color-scheme: dark) { + body { + background-color: var(--colour-dark); + color: var(--colour-light); + } + + a { + color: var(--colour-link-alt); + } + + footer a svg path { + fill: var(--colour-link-alt); + } +} + +/* Accessible skip-to-content link (classless) */ +/* Target the page anchor used in templates: href="#main-content" */ +a[href='#main-content'] { + position: absolute; + left: -999px; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); /* legacy */ + white-space: nowrap; + border: 0; + padding: 0; +} + +a[href='#main-content']:focus, +a[href='#main-content']:focus-visible { + position: fixed; + top: 1rem; + left: 1rem; + width: auto; + height: auto; + overflow: visible; + clip: auto; + background: var(--colour-dark); + color: var(--colour-light); + padding: 0.25rem 0.5rem; + border-radius: 4px; + z-index: 1000; + text-decoration: none; +} diff --git a/src/styles/index.css b/src/styles/index.css index 1f218cb..e373dd0 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,124 +1,4 @@ -@layer reset, base; - -@layer reset { - @import "reset.css"; -} +@import 'reset.css' layer(reset); +@import 'base.css' layer(base); -@layer base { - :root { - --colour-light: #EFEFEF; - --colour-dark: #222222; - --colour-link: darkcyan; - --colour-link-alt: yellow; - --type-size: 100%; - --type-stack: 'system', sans-serif; - --line-height: 1.9; - --character-width: 72ch; - } - - @font-face { - font-family: system; - font-style: normal; - font-weight: 300; - src: local('.SFNSText-Light'), - local('.HelveticaNeueDeskInterface-Light'), - local('.LucidaGrandeUI'), - local('Ubuntu Light'), - local('Segoe UI Light'), - local('Roboto-Light'), - local('DroidSans'), - local('Tahoma'); - } - - body { - box-sizing: border-box; - background-color: var(--colour-light); - color: var(--colour-dark); - font-family: var(--type-stack); - font-size: var(--type-size); - line-height: var(--line-height); - max-width: var(--character-width); - margin: auto; - padding: 20px; - width: 100%; - } - - a { - color: var(--colour-link); - font-weight: 600; - } - - img { - height: auto; - width: 100%; - } - - footer { - padding: 2rem 0; - } - - footer svg { - height: 1rem; - width: auto; - } - - footer a svg path { - fill: var(--colour-link); - } - - footer ul { - list-style: none; - text-align: right; - } - - footer li { - display: inline-block; - padding: 0 5px; - } - - @media (prefers-color-scheme: dark) { - body { - background-color: var(--colour-dark); - color: var(--colour-light); - } - - a { - color: var(--colour-link-alt); - } - - footer a svg path { - fill: var(--colour-link-alt); - } - } - - /* Accessible skip-to-content link (classless) */ - /* Target the page anchor used in templates: href="#main-content" */ - a[href="#main-content"] { - position: absolute; - left: -999px; - width: 1px; - height: 1px; - overflow: hidden; - clip: rect(1px, 1px, 1px, 1px); /* legacy */ - white-space: nowrap; - border: 0; - padding: 0; - } - - a[href="#main-content"]:focus, - a[href="#main-content"]:focus-visible { - position: fixed; - top: 1rem; - left: 1rem; - width: auto; - height: auto; - overflow: visible; - clip: auto; - background: var(--colour-dark); - color: var(--colour-light); - padding: 0.25rem 0.5rem; - border-radius: 4px; - z-index: 1000; - text-decoration: none; - } -} +@layer reset, base; diff --git a/src/styles/reset.css b/src/styles/reset.css index 63e5ad0..9fef6b7 100644 --- a/src/styles/reset.css +++ b/src/styles/reset.css @@ -31,8 +31,8 @@ Notes for maintainers: html { color-scheme: light dark; font: - clamp(1rem, 1rem + 0.5vw, 2rem) / 1.4 system-ui, - sans-serif; + clamp(1rem, 1rem + 0.5vw, 2rem) / 1.4 system-ui, + sans-serif; tab-size: 4; hanging-punctuation: first allow-end last; word-break: break-word; @@ -87,7 +87,11 @@ a { text-underline-offset: 2px; &:not(:is(:hover, :focus)) { - text-decoration-color: color-mix(in srgb, currentColor, transparent 50%); + text-decoration-color: color-mix( + in srgb, + currentColor, + transparent 50% + ); } } @@ -112,7 +116,7 @@ ol, dl { margin: 0; padding: 0; - list-style: inside; + /* list-style: inside; */ ul, ol, dl { @@ -153,22 +157,18 @@ label { input:not( :where( - [type="submit"], - [type="checkbox"], - [type="radio"], - [type="button"], - [type="reset"] + [type='submit'], + [type='checkbox'], + [type='radio'], + [type='button'], + [type='reset'] ) ) { inline-size: 100%; } button, -input:where( - [type="submit"], - [type="reset"], - [type="button"] -) { +input:where([type='submit'], [type='reset'], [type='button']) { background: CanvasText; color: Canvas; border: 1px solid transparent; @@ -192,7 +192,7 @@ svg { fill: currentColor; } -[aria-disabled="true" i], +[aria-disabled='true' i], [disabled] { cursor: not-allowed; } @@ -237,7 +237,7 @@ table { td { font-size: 90%; } - + td, th { word-break: normal; @@ -246,7 +246,7 @@ table { } } -[role="region"][aria-labelledby][tabindex] { +[role='region'][aria-labelledby][tabindex] { overflow: auto; } @@ -272,7 +272,7 @@ caption { @view-transition { navigation: auto; } - + html { interpolate-size: allow-keywords; &:focus-within { @@ -280,4 +280,3 @@ caption { } } } -