From 1883af321a26501975320a6124ea4325e483bf91 Mon Sep 17 00:00:00 2001 From: TheThomaas Date: Sat, 20 May 2023 22:35:38 +0200 Subject: [PATCH] Add files from local source --- .eleventy.js | 45 + .eleventyignore | 1 + 11ty-theme.code-workspace | 10 + 11ty/markdown.js | 10 + 11ty/shortcodes.js | 28 + gulp-tasks/_fonts.js | 20 + gulp-tasks/images.js | 24 + gulp-tasks/sass.js | 50 + gulpfile.js | 21 + package-lock.json | 17525 ++++++++++++++++ package.json | 28 + src/404.html | 20 + src/_data/Term.json | 11 + src/_data/global.js | 8 + src/_data/helpers.js | 74 + src/_data/navigation.json | 20 + src/_data/site.js | 17 + src/_includes/js/main.js | 1 + src/_includes/js/theme-toggle.js | 62 + src/_includes/layouts/article.html | 16 + src/_includes/layouts/base.html | 20 + src/_includes/layouts/home.html | 11 + src/_includes/layouts/list.html | 17 + src/_includes/partials/article-head.html | 22 + src/_includes/partials/footer.html | 14 + src/_includes/partials/header.html | 17 + src/_includes/partials/icons/github.html | 13 + src/_includes/partials/icons/rss.html | 12 + src/_includes/partials/metas.html | 76 + src/_includes/partials/post-list.html | 22 + src/_includes/partials/skip-link.html | 1 + src/_includes/partials/theme-toggle.html | 31 + src/_includes/partials/top-link.html | 6 + src/blog.md | 10 + src/filters/date.js | 43 + src/images/meta/favicon.ico | Bin 0 -> 15406 bytes src/images/meta/favicon.svg | 28 + src/index.md | 8 + src/posts/article.md | 96 + src/posts/article2.md | 88 + src/posts/posts.json | 4 + src/rss.html | 28 + src/scss/404.scss | 43 + src/scss/components/_config.scss | 2 + src/scss/components/_post.scss | 85 + src/scss/components/_reset.scss | 50 + src/scss/components/_skip-link.scss | 45 + src/scss/components/_superminimal.scss | 385 + src/scss/components/_top-button.scss | 31 + src/scss/components/_utilities.scss | 5 + src/scss/components/config/_general.scss | 17 + src/scss/components/config/_palette.scss | 69 + src/scss/components/utilities/_dummy.scss | 20 + src/scss/components/utilities/_focus.scss | 9 + .../components/utilities/_list-inline.scss | 31 + .../components/utilities/_visibility.scss | 15 + src/scss/components/utilities/_wrapper.scss | 29 + src/scss/critical.scss | 114 + src/tags.md | 35 + 59 files changed, 19543 insertions(+) create mode 100644 .eleventy.js create mode 100644 .eleventyignore create mode 100644 11ty-theme.code-workspace create mode 100644 11ty/markdown.js create mode 100644 11ty/shortcodes.js create mode 100644 gulp-tasks/_fonts.js create mode 100644 gulp-tasks/images.js create mode 100644 gulp-tasks/sass.js create mode 100644 gulpfile.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/404.html create mode 100644 src/_data/Term.json create mode 100644 src/_data/global.js create mode 100644 src/_data/helpers.js create mode 100644 src/_data/navigation.json create mode 100644 src/_data/site.js create mode 100644 src/_includes/js/main.js create mode 100644 src/_includes/js/theme-toggle.js create mode 100644 src/_includes/layouts/article.html create mode 100644 src/_includes/layouts/base.html create mode 100644 src/_includes/layouts/home.html create mode 100644 src/_includes/layouts/list.html create mode 100644 src/_includes/partials/article-head.html create mode 100644 src/_includes/partials/footer.html create mode 100644 src/_includes/partials/header.html create mode 100644 src/_includes/partials/icons/github.html create mode 100644 src/_includes/partials/icons/rss.html create mode 100644 src/_includes/partials/metas.html create mode 100644 src/_includes/partials/post-list.html create mode 100644 src/_includes/partials/skip-link.html create mode 100644 src/_includes/partials/theme-toggle.html create mode 100644 src/_includes/partials/top-link.html create mode 100644 src/blog.md create mode 100644 src/filters/date.js create mode 100644 src/images/meta/favicon.ico create mode 100644 src/images/meta/favicon.svg create mode 100644 src/index.md create mode 100644 src/posts/article.md create mode 100644 src/posts/article2.md create mode 100644 src/posts/posts.json create mode 100644 src/rss.html create mode 100644 src/scss/404.scss create mode 100644 src/scss/components/_config.scss create mode 100644 src/scss/components/_post.scss create mode 100644 src/scss/components/_reset.scss create mode 100644 src/scss/components/_skip-link.scss create mode 100644 src/scss/components/_superminimal.scss create mode 100644 src/scss/components/_top-button.scss create mode 100644 src/scss/components/_utilities.scss create mode 100644 src/scss/components/config/_general.scss create mode 100644 src/scss/components/config/_palette.scss create mode 100644 src/scss/components/utilities/_dummy.scss create mode 100644 src/scss/components/utilities/_focus.scss create mode 100644 src/scss/components/utilities/_list-inline.scss create mode 100644 src/scss/components/utilities/_visibility.scss create mode 100644 src/scss/components/utilities/_wrapper.scss create mode 100644 src/scss/critical.scss create mode 100644 src/tags.md diff --git a/.eleventy.js b/.eleventy.js new file mode 100644 index 0000000..24ff558 --- /dev/null +++ b/.eleventy.js @@ -0,0 +1,45 @@ +const pluginRss = require("@11ty/eleventy-plugin-rss"); +const markdownIt = require('./11ty/markdown.js'); +const customShortcodes = require('./11ty/shortcodes.js'); + +const { + getDatetime, + getMonthDay, + getYear, + toFullDate, +} = require("./src/filters/date.js") + +module.exports = config => { + config.setUseGitIgnore(false); + config.setLibrary('md', markdownIt); + + config.addPlugin(pluginRss); + + config.addFilter("getDatetime", getDatetime) + config.addFilter("getMonthDay", getMonthDay) + config.addFilter("getYear", getYear) + config.addFilter("toFullDate", toFullDate) + + config.addShortcode('fetch', customShortcodes.fetch); + config.addPairedShortcode('full', customShortcodes.full); + + config.addPassthroughCopy({"./src/_includes/js/" : "/js"}); + + config.addLayoutAlias('home', 'layouts/home.html'); + config.addLayoutAlias('post', 'layouts/article.html'); + config.addLayoutAlias('list', 'layouts/list.html'); + + config.addCollection('blog', collection => { + return [...collection.getFilteredByGlob('./src/posts/*.md')].reverse(); + }); + + return { + markdownTemplateEngine: 'njk', + dataTemplateEngine: 'njk', + htmlTemplateEngine: 'njk', + dir: { + input: 'src', + output: 'dist' + } + }; +}; \ No newline at end of file diff --git a/.eleventyignore b/.eleventyignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.eleventyignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/11ty-theme.code-workspace b/11ty-theme.code-workspace new file mode 100644 index 0000000..c153978 --- /dev/null +++ b/11ty-theme.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "editor.tabSize": 2 + } +} \ No newline at end of file diff --git a/11ty/markdown.js b/11ty/markdown.js new file mode 100644 index 0000000..9d84d60 --- /dev/null +++ b/11ty/markdown.js @@ -0,0 +1,10 @@ +const markdownItDefault = require('markdown-it'); + +// you can use any plugins and configs you want +const markdownIt = markdownItDefault({ + html: true, + breaks: false, + linkify: true, +}); + +module.exports = markdownIt; \ No newline at end of file diff --git a/11ty/shortcodes.js b/11ty/shortcodes.js new file mode 100644 index 0000000..35d5f77 --- /dev/null +++ b/11ty/shortcodes.js @@ -0,0 +1,28 @@ +const EleventyFetch = require("@11ty/eleventy-fetch"); +const markdownIt = require('./markdown.js'); +const outdent = require('outdent'); + +const full = (children) => { + const content = markdownIt.render(children); + return outdent`
${content}
` +}; + +const fetch = async (url, type) => { + try { + const text = await EleventyFetch(url, + { + duration: '*', + type: type + } + ); + return text; + } catch (ex) { + console.log(ex); + return ""; + } +}; + +module.exports = { + full, + fetch +}; \ No newline at end of file diff --git a/gulp-tasks/_fonts.js b/gulp-tasks/_fonts.js new file mode 100644 index 0000000..cedcf6f --- /dev/null +++ b/gulp-tasks/_fonts.js @@ -0,0 +1,20 @@ +const {dest, src} = require('gulp'); +const GetGoogleFonts = require('get-google-fonts'); + +const fonts = async () => { + // Setup of the library instance by setting where we want + // the output to go. CSS is relative to output font directory + const instance = new GetGoogleFonts({ + outputDir: './dist/fonts', + cssFile: './fonts.css' + }); + + // Grabs fonts and CSS from google and puts in the dist folder + const result = await instance.download( + 'https://fonts.googleapis.com/css2?family=Literata:ital,wght@0,400;0,700;1,400&family=Red+Hat+Display:wght@400;900' + ); + + return result; +}; + +module.exports = fonts; diff --git a/gulp-tasks/images.js b/gulp-tasks/images.js new file mode 100644 index 0000000..a2ab47a --- /dev/null +++ b/gulp-tasks/images.js @@ -0,0 +1,24 @@ +const {dest, src} = require('gulp'); +const imagemin = require('gulp-imagemin'); + +// Grabs all images, runs them through imagemin +// and plops them in the dist folder +const images = () => { + // We have specific configs for jpeg and png files to try + // to really pull down asset sizes + return src('./src/images/**/*') + .pipe( + imagemin( + [ + imagemin.mozjpeg({quality: 60, progressive: true}), + imagemin.optipng({optimizationLevel: 5, interlaced: null}) + ], + { + silent: true + } + ) + ) + .pipe(dest('./dist/images')); +}; + +module.exports = images; diff --git a/gulp-tasks/sass.js b/gulp-tasks/sass.js new file mode 100644 index 0000000..ca98ff2 --- /dev/null +++ b/gulp-tasks/sass.js @@ -0,0 +1,50 @@ +const {dest, src} = require('gulp'); +const cleanCSS = require('gulp-clean-css'); +const sassProcessor = require('gulp-sass')(require('sass')); + +// We want to be using canonical Sass, rather than node-sass +sassProcessor.compiler = require('sass'); + +// Flags whether we compress the output etc +const isProduction = process.env.NODE_ENV === 'production'; + +// An array of outputs that should be sent over to includes +const criticalStyles = ['critical.scss', 'home.scss', 'page.scss', 'work-item.scss']; + +// Takes the arguments passed by `dest` and determines where the output file goes +const calculateOutput = ({history}) => { + // By default, we want a CSS file in our dist directory, so the + // HTML can grab it with a + let response = './dist/css'; + + // Get everything after the last slash + const sourceFileName = /[^(/|\\)]*$/.exec(history[0])[0]; + + // If this is critical CSS though, we want it to go + // to the _includes directory, so nunjucks can include it + // directly in a + + +
+

{{ title }}

+

{{ description | safe }}

+
+ + \ No newline at end of file diff --git a/src/_data/Term.json b/src/_data/Term.json new file mode 100644 index 0000000..91e67d3 --- /dev/null +++ b/src/_data/Term.json @@ -0,0 +1,11 @@ +{ + "Site": { + "SkipLink": "Skip to content", + "ToggleTheme": "Toggle theme", + "TopLink": "Back to top", + "Footer": { + "lastDeployment": "Dernier déploiement le", + "createdWith": "Built with" + } + } +} \ No newline at end of file diff --git a/src/_data/global.js b/src/_data/global.js new file mode 100644 index 0000000..5bc4676 --- /dev/null +++ b/src/_data/global.js @@ -0,0 +1,8 @@ +module.exports = { + random() { + const segment = () => { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); + }; + return `${segment()}-${segment()}-${segment()}`; + } +}; \ No newline at end of file diff --git a/src/_data/helpers.js b/src/_data/helpers.js new file mode 100644 index 0000000..d5bf3e6 --- /dev/null +++ b/src/_data/helpers.js @@ -0,0 +1,74 @@ +module.exports = { + /** + * Returns back some attributes based on whether the + * link is active or a parent of an active item + * + * @param {String} itemUrl The link in question + * @param {String} pageUrl The page context + * @returns {String} The attributes or empty + */ + getLinkActiveState(itemUrl, pageUrl) { + let response = ''; + + if (itemUrl === pageUrl) { + response = ' aria-current="page"'; + } + + if (itemUrl.length > 1 && pageUrl.indexOf(itemUrl) === 0) { + response += ' data-state="active"'; + } + + return response; + }, + + /** + * Filters out the passed item from the passed collection + * and randomises and limits them based on flags + * + * @param {Array} collection The 11ty collection we want to take from + * @param {Object} item The item we want to exclude (often current page) + * @param {Number} limit=3 How many items we want back + * @param {Boolean} random=true Wether or not this should be randomised + * @returns {Array} The resulting collection + */ + getSiblingContent(collection, item, limit = 3, random = true) { + let filteredItems = collection.filter(x => x.url !== item.url); + + if (random) { + let counter = filteredItems.length; + + while (counter > 0) { + // Pick a random index + let index = Math.floor(Math.random() * counter); + + counter--; + + let temp = filteredItems[counter]; + + // Swap the last element with the random one + filteredItems[counter] = filteredItems[index]; + filteredItems[index] = temp; + } + } + + // Lastly, trim to length + if (limit > 0) { + filteredItems = filteredItems.slice(0, limit); + } + + return filteredItems; + }, + + /** + * Take an array of keys and return back items that match. + * Note: items in the collection must have a key attribute in + * Front Matter + * + * @param {Array} collection 11ty collection + * @param {Array} keys collection of keys + * @returns {Array} result collection or empty + */ + filterCollectionByKeys(collection, keys) { + return collection.filter(x => keys.includes(x.data.key)); + } +}; \ No newline at end of file diff --git a/src/_data/navigation.json b/src/_data/navigation.json new file mode 100644 index 0000000..f68a5ab --- /dev/null +++ b/src/_data/navigation.json @@ -0,0 +1,20 @@ +{ + "items": [ + { + "text": "Home", + "url": "/" + }, + { + "text": "About", + "url": "/about/" + }, + { + "text": "Blog", + "url": "/blog/" + }, + { + "text": "Contact", + "url": "/contact/" + } + ] +} diff --git a/src/_data/site.js b/src/_data/site.js new file mode 100644 index 0000000..ae6dee1 --- /dev/null +++ b/src/_data/site.js @@ -0,0 +1,17 @@ +module.exports = { + author: { + name: "Thomas", + mail: "", + about: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Distinctio doloribus, iure eum nostrum error tempora facilis ea." + }, + socials: { + github: "https://github.com/TheThomaas" + }, + buildTime: new Date(), + isProduction: process.env.NODE_ENV === 'production', + title: "SuperMinimalCSS", + description: "Superminimal Superminimal", + lang: "fr", + feed: "feed.xml", + url: "http://localhost:8080" +} \ No newline at end of file diff --git a/src/_includes/js/main.js b/src/_includes/js/main.js new file mode 100644 index 0000000..62a1cdc --- /dev/null +++ b/src/_includes/js/main.js @@ -0,0 +1 @@ +document.documentElement.classList.replace('no-js', 'js'); diff --git a/src/_includes/js/theme-toggle.js b/src/_includes/js/theme-toggle.js new file mode 100644 index 0000000..41f481a --- /dev/null +++ b/src/_includes/js/theme-toggle.js @@ -0,0 +1,62 @@ +const storageKey = 'theme-preference' + +const onClick = () => { + // flip current value + theme.value = theme.value === 'light' + ? 'dark' + : 'light'; + + document + .querySelector('.theme-toggle') + .classList.toggle('theme-toggle--toggled'); + + setPreference() +} + +const getColorPreference = () => { + if (localStorage.getItem(storageKey)) + return localStorage.getItem(storageKey) + else + return window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light' +} + +const setPreference = () => { + localStorage.setItem(storageKey, theme.value) + reflectPreference() +} + +const reflectPreference = () => { + document.firstElementChild + .setAttribute('data-theme', theme.value) + + document + .querySelector('#theme-toggle') + ?.setAttribute('aria-label', theme.value) +} + +const theme = { + value: getColorPreference(), +} + +// set early so no page flashes / CSS is made aware +reflectPreference() + +window.onload = () => { + // set on load so screen readers can see latest value on the button + reflectPreference() + + // now this script can find and listen for clicks on the control + document + .querySelector('.theme-toggle') + .addEventListener('click', onClick) +} + +// sync with system changes +window + .matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', ({matches:isDark}) => { + theme.value = isDark ? 'dark' : 'light' + setPreference() + }) \ No newline at end of file diff --git a/src/_includes/layouts/article.html b/src/_includes/layouts/article.html new file mode 100644 index 0000000..dd73673 --- /dev/null +++ b/src/_includes/layouts/article.html @@ -0,0 +1,16 @@ +{% extends "layouts/base.html" %} + +{% block content %} +
+ {% include "partials/article-head.html" %} + +
+ {% if leading %} +

{{ leading }}

+ {% endif %} + + {{ content | safe }} +
+
+ +{% endblock %} \ No newline at end of file diff --git a/src/_includes/layouts/base.html b/src/_includes/layouts/base.html new file mode 100644 index 0000000..6868c5b --- /dev/null +++ b/src/_includes/layouts/base.html @@ -0,0 +1,20 @@ +{% set assetHash = global.random() %} + + + + + {% include "partials/metas.html" %} + + + {% include "partials/header.html" %} + +
+ {% block content %}{% endblock %} + {% include "partials/top-link.html" %} +
+ + {% include "partials/footer.html" %} + + + + \ No newline at end of file diff --git a/src/_includes/layouts/home.html b/src/_includes/layouts/home.html new file mode 100644 index 0000000..3809ce5 --- /dev/null +++ b/src/_includes/layouts/home.html @@ -0,0 +1,11 @@ +{% extends "layouts/base.html" %} + +{% block content %} + + {% include "partials/article-head.html" %} +
+
+ {{ content | safe }} +
+ +{% endblock %} \ No newline at end of file diff --git a/src/_includes/layouts/list.html b/src/_includes/layouts/list.html new file mode 100644 index 0000000..9c5d0ef --- /dev/null +++ b/src/_includes/layouts/list.html @@ -0,0 +1,17 @@ +{% extends "layouts/base.html" %} + +{% set pageHeaderTitle = title %} +{% set pageHeaderSummary = content %} +{% set postListItems = pagination.items %} + +{# If this is a tag, grab those items instead as one large collection #} +{% if tag %} + {% set postListItems = collections[tag] %} + {% set pageHeaderTitle = 'Blog posts filed under "' + tag + '"' %} +{% endif %} + +{% block content %} +
+ {{ content | safe }} +
+{% endblock %} \ No newline at end of file diff --git a/src/_includes/partials/article-head.html b/src/_includes/partials/article-head.html new file mode 100644 index 0000000..c2505c5 --- /dev/null +++ b/src/_includes/partials/article-head.html @@ -0,0 +1,22 @@ +
+
+

{{ title }}

+ {% if description %} +

{{ description }}

+ {% endif %} + {% if date or tags %} +
    + {% if date %} +
  • + {% endif %} + {% if tags %} + {% for tag in tags %} +
  • + {{ tag | title }} +
  • + {% endfor %} + {% endif %} +
+ {% endif %} +
+
\ No newline at end of file diff --git a/src/_includes/partials/footer.html b/src/_includes/partials/footer.html new file mode 100644 index 0000000..efbafc3 --- /dev/null +++ b/src/_includes/partials/footer.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/src/_includes/partials/header.html b/src/_includes/partials/header.html new file mode 100644 index 0000000..a514d2f --- /dev/null +++ b/src/_includes/partials/header.html @@ -0,0 +1,17 @@ +{% include "partials/skip-link.html" %} + \ No newline at end of file diff --git a/src/_includes/partials/icons/github.html b/src/_includes/partials/icons/github.html new file mode 100644 index 0000000..0bbc46c --- /dev/null +++ b/src/_includes/partials/icons/github.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/src/_includes/partials/icons/rss.html b/src/_includes/partials/icons/rss.html new file mode 100644 index 0000000..4c05125 --- /dev/null +++ b/src/_includes/partials/icons/rss.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/_includes/partials/metas.html b/src/_includes/partials/metas.html new file mode 100644 index 0000000..98a22cc --- /dev/null +++ b/src/_includes/partials/metas.html @@ -0,0 +1,76 @@ +{% set pageTitle = title + ' - ' + site.title %} + +{# We don't want any duplication. This is likely for the home page. #} +{% if site.title === title %} + {% set pageTitle = title %} +{% endif %} + +{% set siteTitle = site.title %} +{% set currentUrl = site.url + page.url %} + +{% if not socialImage %} + {% set socialImage = site.url + '/images/meta/social-share.png' %} +{% endif %} + +{# If the page's Front Matter has specific metaTitle and/or metaDesc items, switch them into the mix. #} +{% if metaTitle %} + {% set pageTitle = metaTitle %} +{% endif %} + +{% if not metaDesc %} + {% set metaDesc = summary %} +{% endif %} + + + + + + +{{ pageTitle }} + + + + + + + +{% if socialImage %} + + + + + +{% endif %} + +{% if metaDesc %} + + + +{% endif %} + + + + + + + + + + + +{# Add facility for pages to delare an array of critical styles #} +{% if pageCriticalStyles %} + {% for item in pageCriticalStyles %} + + {% endfor %} +{% endif %} + +{# Add facility for pages to declare an array of stylesheet paths #} +{% if pageStylesheets %} + {% for item in pageStylesheets %} + + {% endfor %} +{% endif %} \ No newline at end of file diff --git a/src/_includes/partials/post-list.html b/src/_includes/partials/post-list.html new file mode 100644 index 0000000..9129196 --- /dev/null +++ b/src/_includes/partials/post-list.html @@ -0,0 +1,22 @@ +
+
    + {%- asyncEach blog in collections.blog -%} +
  1. +

    {{ blog.data.title }}

    +
      +
    • + {%- if blog.data.tags -%} + {%- for tag in blog.data.tags -%} +
    • + {{ tag | title }} +
    • + {%- endfor -%} + {%- endif -%} +
    + {%- if blog.data.leading -%} +

    {{ blog.data.leading }}

    + {%- endif -%} +
  2. + {%- endeach -%} +
+
\ No newline at end of file diff --git a/src/_includes/partials/skip-link.html b/src/_includes/partials/skip-link.html new file mode 100644 index 0000000..34e5826 --- /dev/null +++ b/src/_includes/partials/skip-link.html @@ -0,0 +1 @@ +{{Term.Site.SkipLink}} \ No newline at end of file diff --git a/src/_includes/partials/theme-toggle.html b/src/_includes/partials/theme-toggle.html new file mode 100644 index 0000000..00730fa --- /dev/null +++ b/src/_includes/partials/theme-toggle.html @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/src/_includes/partials/top-link.html b/src/_includes/partials/top-link.html new file mode 100644 index 0000000..53a0a8b --- /dev/null +++ b/src/_includes/partials/top-link.html @@ -0,0 +1,6 @@ +
+ + {{Term.Site.TopLink}} + + +
\ No newline at end of file diff --git a/src/blog.md b/src/blog.md new file mode 100644 index 0000000..1c40e94 --- /dev/null +++ b/src/blog.md @@ -0,0 +1,10 @@ +--- +title: 'Blog' +layout: 'list' +--- +# Blog + +The latest articles from around the studio, demonstrating our design +thinking, strategy and expertise. + +{% include "partials/post-list.html" %} \ No newline at end of file diff --git a/src/filters/date.js b/src/filters/date.js new file mode 100644 index 0000000..24654b1 --- /dev/null +++ b/src/filters/date.js @@ -0,0 +1,43 @@ +const siteData = require("../_data/site.js") + +function toFullDate(value) { + const dateObject = new Date(value) + + const dateParts = new Intl.DateTimeFormat(siteData.lang, { + year: "numeric", + day: "numeric", + month: "long", + }).formatToParts(dateObject) + + const dayPart = dateParts.find((part) => part.type === "day").value + const monthPart = dateParts.find((part) => part.type === "month").value + const yearPart = dateParts.find((part) => part.type === "year").value + + return `${dayPart} ${monthPart} ${yearPart}` +} + +function getMonthDay(value) { + const dateObject = new Date(value) + + const month = new Intl.DateTimeFormat(siteData.lang, { + month: "long", + }).format(dateObject) + + return `${dateObject.getDate()} ${month}` +} + +function getYear(value) { + const dateObject = new Date(value) + return dateObject.getFullYear() +} + +function getDatetime(value) { + return new Date(value).toISOString().split("T")[0] +} + +module.exports = { + getDatetime, + getMonthDay, + getYear, + toFullDate, +} diff --git a/src/images/meta/favicon.ico b/src/images/meta/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d72208f2c2c569e810415c2a11b1bcbfe657e3ba GIT binary patch literal 15406 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 literal 0 HcmV?d00001 diff --git a/src/images/meta/favicon.svg b/src/images/meta/favicon.svg new file mode 100644 index 0000000..da7a8bb --- /dev/null +++ b/src/images/meta/favicon.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/index.md b/src/index.md new file mode 100644 index 0000000..2168035 --- /dev/null +++ b/src/index.md @@ -0,0 +1,8 @@ +--- +title: 'Home' +description: 'A made up agency site that you build if you take Learn Eleventy From Scratch, by Piccalilli' +metaDesc: 'A made up agency site that you build if you take Learn Eleventy From Scratch, by Piccalilli' +layout: 'home' +--- + +{% include "partials/post-list.html" %} \ No newline at end of file diff --git a/src/posts/article.md b/src/posts/article.md new file mode 100644 index 0000000..9cc920d --- /dev/null +++ b/src/posts/article.md @@ -0,0 +1,96 @@ +--- +title: 'The IndieWeb for Everyone 2' +leading: 'Super­Minimal­CSS is pure black & white CSS awesomeness with nice typography (for both English and Chinese). Less is more is the main principle of this mini design system.' +date: '2022-01-14' +tags: ['Tips And Tricks'] +--- + +For *decades*, **South Florida** ***schoolchildren*** and adults fascinated by far-off galaxies, earthly ecosystems, the properties of light and sound and other wonders of science had only a quaint, antiquated museum here in which to explore their interests. "Now, with the long-delayed opening of a vast new science museum downtown set for Monday, visitors will be able to stand underneath a suspended, 500,000-gallon aquarium tank and gaze at hammerhead and tiger sharks, mahi mahi, devil rays and other creatures through a 60,000-pound oculus, a lens that will give the impression of seeing the fish from the bottom of a huge cocktail glass." + +{% full %} +## This is a heading level 2 +This contains some [**Markdown**](https://www.11ty.dev/docs/languages/markdown/). +```css +.ranger--texas { color: chucknorris; } +``` +{% endfull %} + +Swimming hundreds of feet beneath the ocean’s surface in many parts of the world are prolific architects called `giant larvaceans`. These zooplankton are not particularly giant themselves (they resemble tadpoles and are about the size of a pinkie finger), but every day, they construct one or more spacious houses that can exceed three feet in length. The houses are transparent mucus structures that encase the creatures inside. Giant larvaceans beat their tails to pump seawater through these structures, which filter tiny bits of dead or drifting organic matter for the animals to eat. When their filters get clogged, the larvaceans abandon ship and construct a new house. Laden with debris from the water column, old houses rapidly sink to the seafloor. + +
+ Placeholder +
+ Fig 1: The recording starts with the patter of a summer squall. +
+
+ +## In Science Advances on Wednesday +Scientists near California’s Monterey Bay have found that, through this process, giant larvaceans can filter all of the bay’s water from about 300 to 1,000 feet deep in less than two weeks, making them the fastest known zooplankton filter feeders. In doing so, the creatures help transfer carbon that has been removed from the atmosphere by photosynthesizing organisms to the deep sea, where it can be buried and stored long term. And given their abundance in other parts of the world, these organisms likely play a crucial role in the global carbon cycle. When it comes to the flow of carbon in the ocean, we don’t know nearly as much as we should,” said Kakani Katija, a principal engineer at the Monterey Bay Aquarium Research Institute and the study’s lead author. If we really want to understand how the system works, we have to look at all the players involved. Giant larvaceans are one important group we need to learn more about.” enter + +
+

+ My favorite book is The Elements of Typographic Style. +

+
+ + — Mike Mai + +
+
+ +### In The Past +Other scientists have tried studying giant larvaceans in the laboratory. But these efforts always failed because the animals’ houses were too fragile to be harvested and collected specimens were never able to build houses outside the ocean. To study the zooplankton in their natural habitat, Dr. Katija and her collaborators developed a new deep-sea imaging instrument, called DeepPIV, which they paired with a remotely operated vehicle. DeepPIV projects a sheet of laser light that cuts straight through a larvacean’s mucus house. +```css +.ranger--texas { color: chucknorris; } +``` + +* A high-definition camera on the remotely operated vehicle +* can then capture the inner pumping mechanisms +* illuminated by the laser. + +The recording starts with the patter of a summer squall. Later, a drifting tone like that of a not-quite-tuned-in radio station rises and for a while drowns out the patter. These are the sounds encountered by NASA’s Cassini spacecraft as it dove through the gap between Saturn and its innermost ring on April 26, the first of 22 such encounters before it will plunge into Saturn’s atmosphere in September. + +### What Cassini Did Not Detect +Were many of the collisions of dust particles hitting the spacecraft as it passed through the plane of the rings. You can hear a couple of clicks,” said William S. Kurth, a research scientist at the University of Iowa who is the principal investigator for Cassini’s radio and plasma science instrument. The few dust hits that were recorded sounded like the small pops caused by dust on a LP record, he said. What he had expected was something more like the din of driving through Iowa in a hailstorm,” Dr. Kurth said. Since Cassini had not passed through this region before, scientists and engineers did not know for certain what it would encounter. Cassini would be traveling at more than 70,000 miles per hour as it passed within 2,000 miles of the cloud tops, and a chance hit with a sand grain could be trouble. The analysis indicated that the chances of such a collision were slim, but still risky enough that mission managers did not send Cassini here until the mission’s final months. As a better-safe-than-sorry precaution, the spacecraft was pointed with its big radio dish facing forward, like a shield. Not only was there nothing catastrophic, there was hardly anything at all. The few clicking sounds were generated by dust the size of cigarette smoke particles about a micron, or one-25,000th of an inch, in diameter. To be clear: Cassini did not actually hear any sounds. + +1. It is, after all, flying +2. through space where there is no air +3. and thus no vibrating air molecules to convey sound waves. + +But space is full of radio waves, recorded by Dr. Kurth’s instrument, and those waves, just like the ones bouncing through the Earth’s atmosphere to broadcast the songs of Bruno Mars, Beyoncé and Taylor Swift, can be converted into audible sounds. Dr. Kurth said the background patter was likely oscillations of charged particles in the upper part of Saturn’s ionosphere where atoms are broken apart by solar and cosmic radiation. The louder tones were almost certainly whistler mode emissions” when the charged particles oscillate in unison. + +## Sifting Through Teaspoons of Clay +And sand scraped from the floors of caves, German researchers have managed to isolate ancient human DNA — without turning up a single bone. Their new technique, described in a study published on Thursday in the journal Science, promises to open new avenues of research into human prehistory and was met with excitement by geneticists and archaeologists. It’s a bit like discovering that you can extract gold dust from the air,” said Adam Siepel, a population geneticist at Cold Spring Harbor Laboratory.An absolutely amazing and exciting paper,” added David Reich, a genetics professor at Harvard who focuses on ancient DNA. Until recently, the only way to study the genes of ancient humans like the Neanderthals and their cousins, the Denisovans, was to recover DNA from fossil bones. But they are scarce and hard to find, which has greatly limited research into where early humans lived and how widely they ranged. The only Denisovan bones and teeth that scientists have, for example, come from a single cave in Siberia. + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
NameGenderAge
Player 1Mike MaiMale25
Player 2Angi CheungFemale25
Fig 5: Available players.
+
+ +## Looking for These Genetic Signposts +In sediment has become possible only in the last few years, with recent developments in technology, including rapid sequencing of DNA. Although DNA sticks to minerals and decayed plants in soil, scientists did not know whether it would ever be possible to fish out gene fragments that were tens of thousands of years old and buried deep among other genetic debris. Bits of genes from ancient humans make up just a minute fraction of the DNA floating around in the natural world. But the German scientists, led by Matthias Meyer at the Max Planck Institute for Developmental Biology in Tübingen, have spent years developing methods to find DNA even where it seemed impossibly scarce and degraded. There’s been a real revolution in technology invented by this lab,” Dr. Reich said. Matthias is kind of a wizard in pushing the envelope.” Scientists began by retrieving DNA from ancient bones: first Neanderthals, then Denisovans. To identify the Denisovans, Svante Paabo, a geneticist at the Planck Institute and a co-author of the new paper, had only a child’s pinkie bone to work with. His group surprised the world in 2010 by reporting that it had extracted DNA from the bone, finding that it belonged to a group of humans distinct from both Neanderthals and modern humans. But that sort of analysis is limited by the availability of fossil bones. In a lot of cases, you can get bones, but not enough,” said Hendrik Poinar, an evolutionary geneticist at McMaster University. + +If you just have one small piece of bone from one site, curators do not want you to grind it up. \ No newline at end of file diff --git a/src/posts/article2.md b/src/posts/article2.md new file mode 100644 index 0000000..c8e4dc1 --- /dev/null +++ b/src/posts/article2.md @@ -0,0 +1,88 @@ +--- +title: 'The IndieWeb for Everyone 4' +leading: 'Super­Minimal­CSS is pure black & white CSS awesomeness with nice typography (for both English and Chinese). Less is more is the main principle of this mini design system.' +date: '2023-01-14' +tags: ['Tips And Tricks', 'Demo'] +--- + +For decades, South Florida schoolchildren and adults fascinated by far-off galaxies, earthly ecosystems, the properties of light and sound and other wonders of science had only a quaint, antiquated museum here in which to explore their interests. "Now, with the long-delayed opening of a vast new science museum downtown set for Monday, visitors will be able to stand underneath a suspended, 500,000-gallon aquarium tank and gaze at hammerhead and tiger sharks, mahi mahi, devil rays and other creatures through a 60,000-pound oculus, a lens that will give the impression of seeing the fish from the bottom of a huge cocktail glass." + +
+ Placeholder +
+ Fig 1: The recording starts with the patter of a summer squall. +
+
+ +Swimming hundreds of feet beneath the ocean’s surface in many parts of the world are prolific architects called `giant larvaceans`. These zooplankton are not particularly giant themselves (they resemble tadpoles and are about the size of a pinkie finger), but every day, they construct one or more spacious houses that can exceed three feet in length. The houses are transparent mucus structures that encase the creatures inside. Giant larvaceans beat their tails to pump seawater through these structures, which filter tiny bits of dead or drifting organic matter for the animals to eat. When their filters get clogged, the larvaceans abandon ship and construct a new house. Laden with debris from the water column, old houses rapidly sink to the seafloor. + +## In Science Advances on Wednesday +Scientists near California’s Monterey Bay have found that, through this process, giant larvaceans can filter all of the bay’s water from about 300 to 1,000 feet deep in less than two weeks, making them the fastest known zooplankton filter feeders. In doing so, the creatures help transfer carbon that has been removed from the atmosphere by photosynthesizing organisms to the deep sea, where it can be buried and stored long term. And given their abundance in other parts of the world, these organisms likely play a crucial role in the global carbon cycle. When it comes to the flow of carbon in the ocean, we don’t know nearly as much as we should,” said Kakani Katija, a principal engineer at the Monterey Bay Aquarium Research Institute and the study’s lead author. If we really want to understand how the system works, we have to look at all the players involved. Giant larvaceans are one important group we need to learn more about.” enter + +
+

+ My favorite book is The Elements of Typographic Style. +

+
+ + — Mike Mai + +
+
+ +### In The Past +Other scientists have tried studying giant larvaceans in the laboratory. But these efforts always failed because the animals’ houses were too fragile to be harvested and collected specimens were never able to build houses outside the ocean. To study the zooplankton in their natural habitat, Dr. Katija and her collaborators developed a new deep-sea imaging instrument, called DeepPIV, which they paired with a remotely operated vehicle. DeepPIV projects a sheet of laser light that cuts straight through a larvacean’s mucus house. +```css +.ranger--texas { color: chucknorris; } +``` + +* A high-definition camera on the remotely operated vehicle +* can then capture the inner pumping mechanisms +* illuminated by the laser. + +The recording starts with the patter of a summer squall. Later, a drifting tone like that of a not-quite-tuned-in radio station rises and for a while drowns out the patter. These are the sounds encountered by NASA’s Cassini spacecraft as it dove through the gap between Saturn and its innermost ring on April 26, the first of 22 such encounters before it will plunge into Saturn’s atmosphere in September. + +### What Cassini Did Not Detect +Were many of the collisions of dust particles hitting the spacecraft as it passed through the plane of the rings. You can hear a couple of clicks,” said William S. Kurth, a research scientist at the University of Iowa who is the principal investigator for Cassini’s radio and plasma science instrument. The few dust hits that were recorded sounded like the small pops caused by dust on a LP record, he said. What he had expected was something more like the din of driving through Iowa in a hailstorm,” Dr. Kurth said. Since Cassini had not passed through this region before, scientists and engineers did not know for certain what it would encounter. Cassini would be traveling at more than 70,000 miles per hour as it passed within 2,000 miles of the cloud tops, and a chance hit with a sand grain could be trouble. The analysis indicated that the chances of such a collision were slim, but still risky enough that mission managers did not send Cassini here until the mission’s final months. As a better-safe-than-sorry precaution, the spacecraft was pointed with its big radio dish facing forward, like a shield. Not only was there nothing catastrophic, there was hardly anything at all. The few clicking sounds were generated by dust the size of cigarette smoke particles about a micron, or one-25,000th of an inch, in diameter. To be clear: Cassini did not actually hear any sounds. + +1. It is, after all, flying +2. through space where there is no air +3. and thus no vibrating air molecules to convey sound waves. + +But space is full of radio waves, recorded by Dr. Kurth’s instrument, and those waves, just like the ones bouncing through the Earth’s atmosphere to broadcast the songs of Bruno Mars, Beyoncé and Taylor Swift, can be converted into audible sounds. Dr. Kurth said the background patter was likely oscillations of charged particles in the upper part of Saturn’s ionosphere where atoms are broken apart by solar and cosmic radiation. The louder tones were almost certainly whistler mode emissions” when the charged particles oscillate in unison. + +## Sifting Through Teaspoons of Clay +And sand scraped from the floors of caves, German researchers have managed to isolate ancient human DNA — without turning up a single bone. Their new technique, described in a study published on Thursday in the journal Science, promises to open new avenues of research into human prehistory and was met with excitement by geneticists and archaeologists. It’s a bit like discovering that you can extract gold dust from the air,” said Adam Siepel, a population geneticist at Cold Spring Harbor Laboratory.An absolutely amazing and exciting paper,” added David Reich, a genetics professor at Harvard who focuses on ancient DNA. Until recently, the only way to study the genes of ancient humans like the Neanderthals and their cousins, the Denisovans, was to recover DNA from fossil bones. But they are scarce and hard to find, which has greatly limited research into where early humans lived and how widely they ranged. The only Denisovan bones and teeth that scientists have, for example, come from a single cave in Siberia. + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
NameGenderAge
Player 1Mike MaiMale25
Player 2Angi CheungFemale25
Fig 5: Available players.
+
+ +## Looking for These Genetic Signposts +In sediment has become possible only in the last few years, with recent developments in technology, including rapid sequencing of DNA. Although DNA sticks to minerals and decayed plants in soil, scientists did not know whether it would ever be possible to fish out gene fragments that were tens of thousands of years old and buried deep among other genetic debris. Bits of genes from ancient humans make up just a minute fraction of the DNA floating around in the natural world. But the German scientists, led by Matthias Meyer at the Max Planck Institute for Developmental Biology in Tübingen, have spent years developing methods to find DNA even where it seemed impossibly scarce and degraded. There’s been a real revolution in technology invented by this lab,” Dr. Reich said. Matthias is kind of a wizard in pushing the envelope.” Scientists began by retrieving DNA from ancient bones: first Neanderthals, then Denisovans. To identify the Denisovans, Svante Paabo, a geneticist at the Planck Institute and a co-author of the new paper, had only a child’s pinkie bone to work with. His group surprised the world in 2010 by reporting that it had extracted DNA from the bone, finding that it belonged to a group of humans distinct from both Neanderthals and modern humans. But that sort of analysis is limited by the availability of fossil bones. In a lot of cases, you can get bones, but not enough,” said Hendrik Poinar, an evolutionary geneticist at McMaster University. + +If you just have one small piece of bone from one site, curators do not want you to grind it up. \ No newline at end of file diff --git a/src/posts/posts.json b/src/posts/posts.json new file mode 100644 index 0000000..5912712 --- /dev/null +++ b/src/posts/posts.json @@ -0,0 +1,4 @@ +{ + "layout": "post", + "permalink": "/blog/{{ title | slug }}/index.html" +} diff --git a/src/rss.html b/src/rss.html new file mode 100644 index 0000000..1795540 --- /dev/null +++ b/src/rss.html @@ -0,0 +1,28 @@ +--- +permalink: '/{{ site.feed }}' +--- + + + {% if title %}{{ title }}{% else %}{{ site.title }}{% endif %} + {% if summary %}{{ summary }}{% else %}{{ site.description }}{% endif %} + + + {{ collections.blog | rssLastUpdatedDate }} + {{ site.url }} + + {{ site.author.name }} + {{ site.author.mail }} + + {% for post in collections.blog %} + {% set absolutePostUrl %}{{ site.url }}{{ post.url | url }}{% endset %} + + {{ post.data.title }} + + {{ post.date | rssDate }} + {{ absolutePostUrl }} + + + {% endfor %} + \ No newline at end of file diff --git a/src/scss/404.scss b/src/scss/404.scss new file mode 100644 index 0000000..f18da69 --- /dev/null +++ b/src/scss/404.scss @@ -0,0 +1,43 @@ +* { + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", sans-serif;; +} + +:root { + color-scheme: light; +} + +body { + background-color: hsl(24, 10%, 90%); + margin: 0; + display: grid; + place-items: center; + min-height: 100vh; + + > div { + text-align: center; + + > p { + font-size: 1.6rem; + } + } +} + +h1 { + color: red; + font-size: 4rem; +} + +@media (prefers-color-scheme: dark) { + :root { + color-scheme: dark; + } + + body { + background-color: hsl(24, 0%, 10%); + } + + h1 { + color: rgb(255, 69, 69); + font-size: 4rem; + } +} diff --git a/src/scss/components/_config.scss b/src/scss/components/_config.scss new file mode 100644 index 0000000..55abf48 --- /dev/null +++ b/src/scss/components/_config.scss @@ -0,0 +1,2 @@ +@use './config/general'; +@use './config/palette'; \ No newline at end of file diff --git a/src/scss/components/_post.scss b/src/scss/components/_post.scss new file mode 100644 index 0000000..c8aa109 --- /dev/null +++ b/src/scss/components/_post.scss @@ -0,0 +1,85 @@ +.lead { + font-size: clamp(1.2rem, 2vw + 1rem, 1.6rem); + font-weight: 300; + line-height: 1.4; + margin-block-end: 1rem; +} + +article { + header { + > div { + display: flex; + flex-direction: column; + padding-block: 0 1.5rem; + + @media screen and (min-width: 768px) { + padding-block: 2rem 3rem; + align-items: center; + } + } + } + + h1 { + font-size: 3.5rem; + font-size: clamp(2.5rem, 5vw + 1.25rem, 4.5rem); + letter-spacing: -2px; + font-weight: 500; + margin: 0; + + @media screen and (min-width: 768px) { + margin-block-end: 1.2rem; + text-align: center; + } + } + + ul a { + font-family: var(--font-italic); + text-transform: uppercase; + letter-spacing: 2px; + } +} + +.postlist { + margin: 0; + padding: 0; + + &.grid { + margin: 0 auto; + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + + } + + > * { + margin-block-end: 3rem; + } + + h2 { + font-size: 2rem; + font-size: clamp(1.8rem, 2vw + 1.25rem, 2rem); + letter-spacing: -2px; + font-weight: 500; + margin: 0; + + a { + text-decoration: none; + color: var(--brand); + transition: color .2s ease; + + &:hover { + color: var(--brand-variant); + } + } + } + + ul { + font-size: clamp(.6rem, 2vw + 1.25rem, 1rem); + + a { + font-family: var(--font-italic); + text-transform: uppercase; + letter-spacing: 2px; + } + } +} \ No newline at end of file diff --git a/src/scss/components/_reset.scss b/src/scss/components/_reset.scss new file mode 100644 index 0000000..ce3619d --- /dev/null +++ b/src/scss/components/_reset.scss @@ -0,0 +1,50 @@ +/* + Josh's Custom CSS Reset + https://www.joshwcomeau.com/css/custom-css-reset/ +*/ +*, *::before, *::after { + box-sizing: border-box; +} +* { + margin: 0; +} +:where(html) { + overflow-x: hidden; +} +:where(html, body) { + block-size: 100%; +} +:where(body) { + text-rendering: optimizeSpeed; + line-height: 1.5; +} +:where(img, picture, video, canvas) { + display: block; + max-inline-size: 100%; +} +:where(input, button, textarea, select, a) { + font: inherit; +} +:where(p, h1, h2, h3, h4, h5, h6) { + overflow-wrap: break-word; +} +:where(ul, ol):where([role='list'], [class]) { + list-style: none; +} +:where(html:focus-within) { + scroll-behavior: smooth; +} +:where(img, picture) { + block-size: auto; +} + +@media (prefers-reduced-motion: reduce) { + * { + animation-play-state: paused !important; + transition: none !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } +} \ No newline at end of file diff --git a/src/scss/components/_skip-link.scss b/src/scss/components/_skip-link.scss new file mode 100644 index 0000000..d16694d --- /dev/null +++ b/src/scss/components/_skip-link.scss @@ -0,0 +1,45 @@ +:where([href="#main-content"], button, [type="submit"], [type="button"], [type="reset"]) { + background-color: var(--surface1); + padding: .2rem .5rem; + text-decoration: none; + font-weight: bold; + border: 2px solid var(--text2); + color: var(--text1); + width: auto; + display: inline-block; + --outline-border-radius: var(--border-radius); + --outline-offset: .1rem; + + &:hover { + text-decoration: underline; + cursor: pointer; + } +} + +:where([href="#main-content"], [type="submit"]) { + background-color: var(--brand); +} + +body > a { + $link-offset: .3rem; + position: absolute; + inset-block-start: $link-offset; + inset-inline-start: $link-offset; + z-index: 99999; + padding: .4rem 1rem; + + --outline-color: var(--text2); + --outline-offset: .15rem; + + &:not(:focus) { + size: 1px; + margin: -1px; + padding: 0; + white-space: nowrap; + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; + } + +} \ No newline at end of file diff --git a/src/scss/components/_superminimal.scss b/src/scss/components/_superminimal.scss new file mode 100644 index 0000000..6d99446 --- /dev/null +++ b/src/scss/components/_superminimal.scss @@ -0,0 +1,385 @@ +/* ------------------------------------ *\ + https://codepen.io/mikemai2awesome/full/KKvMZVz +\* ------------------------------------ */ + +:root { + color: var(--text1); + background-color: var(--surface1); + accent-color: var(--text1); +} + +:where(a) { + color: var(--text1); +} + +:where(input, textarea, select) { + color: var(--text1); + background-color: var(--surface1); +} + +:where(button) { + color: var(--surface1); + background-color: var(--text1); +} + +:where(code) { + color: var(--text1); + background-color: var(--surface3); +} + +/* ------------------------------------ *\ + Typography +\* ------------------------------------ */ + +:root { + font-size: clamp( + var(--font-size), + var(--font-size) * 0.9 + 0.25vw, + var(--font-size) * 2 + ); // % ensures browser zoom is supported. + font-family: var(--font); // Use system UI font. + font-weight: var(--font-weight-regular); + line-height: var(--leading); // Standard leading for good legibility. + letter-spacing: var(--tracking); +} + +:where(a) { + text-decoration: underline; + text-decoration-thickness: var(--border-width); + text-underline-offset: calc(var(--border-width) * 2); +} + +:where(a):hover { + text-decoration-thickness: calc(var(--border-width) * 3); +} + +:where(pre, code, kbd, dl, figcaption, abbr, table) { + font-family: var( + --font-code + ); // Differentiate preformatted, code, description, and table text from body text. + + font-size: 0.8em; // Make monospace and small text smaller than body text. +} + +:where(big) { + font-size: 1.2em; // is technically deprecated, but I love using it. This creates a fallback if a browser doesn't support it. + letter-spacing: 0.006em; +} + +:where(pre code) { + display: block; // Define block code. + font-size: 1em; // Prevent cascading. +} + +:where(blockquote, em, i, cite) { + font-family: var( + --font-italic + ); // Differentiate blockquote, citation, idiomatic, and emphasisized text from body text. Also, sans-serif italic is ugly. + font-weight: var( + --font-weight-regular + ); // Prevent italics to be bold. Bold italic is also ugly and unnecessary. +} + +:where(blockquote) { + font-size: clamp(1.5rem, 1.25rem + 1vw, 3rem); + letter-spacing: 0; +} + +:where(blockquote p) { + max-inline-size: 35ch; +} + +:where(blockquote q):before { + position: absolute; + transform: translateX(-100%); +} + +:where(strong, b, th, button) { + font-weight: var( + --font-weight-semibold + ); // Make non-heading emphasized text less bold than heading text. +} + +:where(h1, h2, h3, h4, h5, h6, summary strong, legend) { + font-weight: var(--font-weight-bold); +} + +:where(h1, h2, h3, h4, h5, h6, summary strong, legend, big) { + font-stretch: var(--font-stretch, expanded); +} + +:where(button, input[type="file"]) { + font-stretch: var(--font-stretch, condensed); +} + +:where(abbr) { + text-decoration: underline; + text-decoration-style: dotted; // Differentiate abbreviaions from links. + text-underline-offset: calc(var(--border-width) * 2); +} + +:where(button, label, select, summary) { + cursor: pointer; +} + +:where(summary:hover > *) { + text-decoration: underline; + text-underline-offset: calc(var(--border-width) * 2); +} + +:where(figcaption) { + text-align: center; +} + +:where(th) { + text-align: start; +} + +:where(th, td) { + vertical-align: baseline; +} + +:where(fieldset > ol) { + list-style: none; +} + +/* ------------------------------------ *\ + Spacing +\* ------------------------------------ */ + +:where(h1, h2, h3, h4, h5, h6, p, figure, form, pre, blockquote, ul, ol, dl, li, details) { + margin-block-end: 0; +} + +:where(h1, h2, h3, h4, h5, h6) { + margin-block-start: calc(var(--stack) * 1.75); +} + +:where(p, figure, form, fieldset, pre, blockquote, ul, ol, dl, details) { + margin-inline: 0; + margin-block-start: var(--stack); +} + +:where(h1, h2, h3, h4, h5, h6, p, figure, form, fieldset, pre, blockquote, ul, ol, dl, details):first-child, +:where(legend + *) { + margin-block-start: 0; +} + +:where(h1, h2, h3, h4, h5, h6) + * { + margin-block-start: calc(var(--stack) / 5); +} + +// :where(ul, ol) { +// padding: 0; +// } + +:where(li > ul, li > ol) { + margin-block-start: calc(var(--stack) / 5); +} + +:where(details ul, details ol) { + margin-inline-start: 4ch; // Unify indent for all lists inside details. +} + +:where(li > ul, li > ol, fieldset ul, fieldset ol) { + margin-inline-start: 2.25ch; // Unify indent for all nested lists. +} + +:where(li + li) { + margin-block-start: calc(var(--stack) / 5); +} + +:where(fieldset > ol li + li) { + margin-block-start: calc(var(--stack) / 2); +} + +:where(fieldset > ol) { + margin-inline: 0; +} + +:where(hr) { + margin-block-start: calc(var(--stack) * 3); + margin-block-end: calc(var(--stack) * 3); +} + +:where(hr + *) { + margin-block-start: 0; +} + +:where(figure > img, table) { + margin-inline: auto; +} + +:where(blockquote > *) { + margin-block-start: calc(var(--stack) / 4); +} + +:where(blockquote:not(:last-child)) { + padding-block-end: calc(var(--stack) / 2); +} + +:where(button, dd, th, td) { + // Unify inset spacing on bordered elements. + padding-block: calc(var(--stack) / 6); + padding-inline: calc(var(--gutter) / 3); +} + +:where(input, textarea) { + padding-inline: 2px; +} + +:where(caption, figcaption) { + padding-block: calc(var(--stack) / 2); +} + +:where(code, kbd) { + padding-block: 0.25ex; + padding-inline: 0.5ch; +} + +:where(figure, pre) { + padding-block-start: calc( + var(--stack) / 2.5 + ); // Line up top of images/codeblocks with text in an adjacent column layout. +} + +:where(pre) { + padding-block-end: calc(var(--stack) / 2.5); +} + +:where(pre code) { + padding-block: var(--stack); + padding-inline: var(--gutter); +} + +details[open] summary + * { + margin-block-start: calc(var(--stack) / 4); +} + +/* ------------------------------------ *\ + General +\* ------------------------------------ */ + +*, +*:before, +*:after { + font-feature-settings: "kern"; + font-kerning: normal; + -moz-osx-font-smoothing: grayscale !important; + -webkit-font-smoothing: antialiased !important; + box-sizing: border-box; +} + +:where(input, textarea, select, fieldset, button, kbd, dd, table, th, td) { + // Unify border styles. + border: var(--border-width) solid var(--text1); +} + +:where(input, textarea, select, fieldset, button, kbd) { + // Unify interactive elements border radius. + border-radius: var(--border-radius); +} + +:where(pre) { + white-space: -moz-pre-wrap; + white-space: -o-pre-wrap; + white-space: pre-wrap; + word-spacing: normal; + word-break: normal; + word-wrap: break-word; +} + +:where(dl) { + display: grid; + grid-template-columns: auto minmax(75%, 1fr); + gap: calc(var(--gutter) / 2); + align-items: baseline; +} + +:where(dt) { + border-block-end: var(--border-width) dotted; +} + +:where(dd) { + block-size: 100%; + margin-inline-start: 0; +} + +:where(input:not([type="checkbox"]):not([type="radio"]), select, textarea) { + display: block; + inline-size: 100%; +} + +:where(input[type="radio"], input[type="checkbox"]) { + size: 1.5ex; + vertical-align: baseline; +} + +:where(input[type="file"]) { + padding-inline: 0; + border: 0; +} + +::-webkit-file-upload-button { + appearance: button; + cursor: pointer; + font: inherit; +} + +:where(input, textarea, select) ~ * { + margin-block-start: 0; + font-size: 0.8em; +} + +:where(input:required + mark) { + display: none; + color: var(--text1); + background-color: transparent; +} + +:where(input:required:invalid + mark) { + display: block; +} + +:where(hr) { + block-size: 0; + border: 0; + border-block-start: var(--border-width) dashed var(--text1); +} + +:where(figure, figure table) { + inline-size: 100%; +} + +:where(figure) { + overflow-x: auto; +} + +:where(figure > img) { + display: block; +} + +:where(table) { + caption-side: bottom; + border-collapse: collapse; + border-spacing: 0; +} + +:where(tr > *:first-child) { + white-space: nowrap; +} + +:where(summary > *) { + display: inline; + vertical-align: middle; +} + +/* ------------------------------------ *\ + Add-ons + - Requires data attributes. + - Remove to do your own layouts. +\* ------------------------------------ */ + +:where(body main) { + padding-block-start: clamp(var(--stack) * 1, 10vmax, var(--stack) * 2); +} diff --git a/src/scss/components/_top-button.scss b/src/scss/components/_top-button.scss new file mode 100644 index 0000000..f017d24 --- /dev/null +++ b/src/scss/components/_top-button.scss @@ -0,0 +1,31 @@ +.scroll-top { + $button-size: 32px; + + position: absolute; + inset: 120vh 0 0 auto; + pointer-events: none; + overflow: clip; + + a { + position: sticky; + inset-block-start: 94vh; + text-decoration:none; + padding:0 calc(var(--button-size, $button-size ) / 2) 0 0; + color: white; + font-weight:700; + pointer-events: auto; + } + + svg { + transition: fill .3s; + fill: var(--button-fill, var(--text2)); + background: var(--button-background, var(--surface2)); + border-radius: 100%; + inline-size: var(--button-size, $button-size); + block-size: var(--button-size, $button-size); + + &:hover { + fill: var(--button-fill-hover, var(--text1)); + } + } +} diff --git a/src/scss/components/_utilities.scss b/src/scss/components/_utilities.scss new file mode 100644 index 0000000..1c7e0a5 --- /dev/null +++ b/src/scss/components/_utilities.scss @@ -0,0 +1,5 @@ +@use './utilities/wrapper'; +@use './utilities/visibility'; +@use './utilities/list-inline'; +@use './utilities/focus'; +@use './utilities/dummy'; \ No newline at end of file diff --git a/src/scss/components/config/_general.scss b/src/scss/components/config/_general.scss new file mode 100644 index 0000000..5e6834b --- /dev/null +++ b/src/scss/components/config/_general.scss @@ -0,0 +1,17 @@ +:root { + --font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", sans-serif; + --font-italic: "Georgia", serif; + --font-code: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; + --font-size: 1.2rem; + --font-weight-semibold: 700; + --font-weight-bold: 900; + --leading: 1.45; + --gutter: clamp(1ch, 2.5vmax, 3ch); + --stack: clamp(1.25ex, 1ex + 2.5vmax, 1.75ex); + --line-length-small: 30ch; + --line-length: 75ch; + --line-length-large: 115ch; + --page-padding-inline: calc((100vw - min(var(--line-length), 80vw)) / 2); + --border-width: 1px; + --border-radius: 4px; +} \ No newline at end of file diff --git a/src/scss/components/config/_palette.scss b/src/scss/components/config/_palette.scss new file mode 100644 index 0000000..60adbd6 --- /dev/null +++ b/src/scss/components/config/_palette.scss @@ -0,0 +1,69 @@ +@mixin light-theme-font { + --font-weight-regular: 400; + --tracking: -0.006em; +} + +@mixin dark-theme-font { + --font-weight-regular: 300; + --tracking: 0; +} + +/** + * Palette + */ + @mixin light-theme { + color-scheme: light; + + --brand: hsl(22, 60%, 60%); + --brand-variant: hsl(22, 60%, 50%); + --primary-accent: hsl(232, 60%, 60%); + --secondary-accent: hsl(172, 35%, 35%); + --text1: hsl(22, 96%, 6%); + --text2: hsl(20, 10%, 30%); + --surface1: hsl(20, 12%, 95%); + --surface2: hsl(24, 10%, 90%); + --surface3: hsl(22, 11%, 85%); + --surface4: hsl(24, 10%, 80%); + --img-opacity: 1; + --shadow: 0 2px 5px rgba(0, 0, 0, 0.3); + + @include light-theme-font; +} + +@mixin dark-theme { + color-scheme: dark; + + --brand: hsl(22, 45%, 45%); + --brand-variant: hsl(22, 45%, 55%); + --primary-accent: hsl(232, 65%, 65%); + --secondary-accent: hsl(172, 65%, 65%); + --text1: hsl(22, 22%, 90%); + --text2: hsl(20, 10%, 70%); + --surface1: hsl(24, 0%, 10%); + --surface2: hsl(23, 0%, 15%); + --surface3: hsl(24, 0%, 20%); + --surface4: hsl(23, 0%, 25%); + --img-opacity: .8; + --shadow: 0 0 0 rgba(0, 0, 0, 0); + + @include dark-theme-font; +} + + +:root { + @include light-theme; +} + +@media (prefers-color-scheme: dark) { + :root { + @include dark-theme; + } +} + +[data-theme="light"] { + @include light-theme; +} + +[data-theme="dark"] { + @include dark-theme; +} \ No newline at end of file diff --git a/src/scss/components/utilities/_dummy.scss b/src/scss/components/utilities/_dummy.scss new file mode 100644 index 0000000..c27afe4 --- /dev/null +++ b/src/scss/components/utilities/_dummy.scss @@ -0,0 +1,20 @@ +.dummy-content p { + display: inline; + background: rgba(var(--dummy-color, black), 0.12); + color: transparent; + user-select: none; + border-radius: 2px; + box-decoration-break: clone; + + [data-theme="dark"] & { + --dummy-color: white; + } + + + p { + &:before { + visibility: hidden; + content: "."; + display: block; + } + } +} \ No newline at end of file diff --git a/src/scss/components/utilities/_focus.scss b/src/scss/components/utilities/_focus.scss new file mode 100644 index 0000000..6d8abfe --- /dev/null +++ b/src/scss/components/utilities/_focus.scss @@ -0,0 +1,9 @@ +:focus { + outline: var(--outline, var(--outline-width, .125rem) var(--outline-style, dashed) var(--outline-color, var(--brand))); + outline-offset: var(--outline-offset, .25rem); + border-radius: var(--outline-border-radius, 8px); +} + +:focus:not(:focus-visible) { + outline: none; +} \ No newline at end of file diff --git a/src/scss/components/utilities/_list-inline.scss b/src/scss/components/utilities/_list-inline.scss new file mode 100644 index 0000000..36590f8 --- /dev/null +++ b/src/scss/components/utilities/_list-inline.scss @@ -0,0 +1,31 @@ +.list-inline { + $item-gap : 1ch; + display: flex; + flex-wrap: wrap; + padding-left: 0; + list-style: none; + margin-left: calc(var(--item-gap, $item-gap) * 3 * -1); + clip-path: inset(0 0 0 calc(var(--item-gap, $item-gap) * 3)); + align-items: center; + color: var(--item-color, var(--text2)); + + li { + padding-left: var(--item-gap, $item-gap); + &::before { + content: var(--item-separator, '•'); + display: inline-block; + margin-right: var(--item-gap, $item-gap); + width: var(--item-gap, $item-gap); + text-align: center; + } + } + + a { + color: var(--item-color, var(--text2)); + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } +} \ No newline at end of file diff --git a/src/scss/components/utilities/_visibility.scss b/src/scss/components/utilities/_visibility.scss new file mode 100644 index 0000000..9be3211 --- /dev/null +++ b/src/scss/components/utilities/_visibility.scss @@ -0,0 +1,15 @@ +.sr-only { + position: absolute !important; + block-size: 1px !important; + inline-size: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.invisible { + visibility: hidden !important; +} \ No newline at end of file diff --git a/src/scss/components/utilities/_wrapper.scss b/src/scss/components/utilities/_wrapper.scss new file mode 100644 index 0000000..56fadba --- /dev/null +++ b/src/scss/components/utilities/_wrapper.scss @@ -0,0 +1,29 @@ +.wrapper { + $wrapper-gap: var(--gutter); + display: grid; + grid-template-columns: + 1fr + min(var(--wrapper-max-length, var(--line-length)), calc(100% - var(--wrapper-gap, $wrapper-gap) * 2)) + 1fr; + grid-column-gap: var(--wrapper-gap, $wrapper-gap); + + > * { + grid-column: 2; + } +} + +.wrapper-lg { + @extend .wrapper; + $wrapper-gap: var(--gutter); + grid-template-columns: + 1fr + min(var(--wrapper-max-length, var(--line-length-large)), calc(100% - var(--wrapper-gap, $wrapper-gap) * 2)) + 1fr; +} + +.full-bleed { + inline-size: 100%; + grid-column: 1 / -1; + padding: var(--padding-block, 1rem) var(--padding-inline, 2rem); + background-color: var(--background-color, none); +} \ No newline at end of file diff --git a/src/scss/critical.scss b/src/scss/critical.scss new file mode 100644 index 0000000..7ded03e --- /dev/null +++ b/src/scss/critical.scss @@ -0,0 +1,114 @@ +@use './components/config'; +@use './components/reset'; +@use './components/utilities'; +@use './components/superminimal'; +@use './components/top-button'; +@use './components/skip-link'; +@use './components/post'; + +:root { + @media screen and (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } +} + +body { + min-height: 100vh; + + > header { + display: flex; + justify-content: space-between; + padding: .2rem 1rem; + flex-direction: column; + + @media screen and (min-width: 768px) { + align-items: center; + flex-direction: row; + } + + nav { + ul { + list-style-type: none; + margin: 0; + padding: 0; + } + li { + padding: 6px 20px; + + @media screen and (min-width: 768px) { + display: inline-block; + } + } + + a[aria-current="page"] { + color: var(--brand-variant); + } + } + } + + > footer { + display: flex; + justify-content: space-between; + padding: 1rem; + flex-direction: column; + align-items: center; + + .list-inline { + --item-separator: ""; + --item-gap: .25ch; + + a:hover { + --item-color: var(--text1) + } + } + + @media (min-width: 768px) { + flex-direction: row; + } + + &:has(.site-footer__part:only-child) { + flex-direction: column; + align-items: center; + } + } + +} + +main { + position: relative; +} + +img { + vertical-align: middle; + opacity: var(--img-opacity); + + &:hover { + opacity: 1; + } +} + +/** + * Header anchor + */ +.header-anchor { + opacity: 0; + text-decoration: none; + color: var(--text2); + font-size: .85em; + float: left; + margin-left: -0.87em; + padding-right: 0.23em; + margin-top: 0.125em; + + &:hover { + text-decoration: underline; + } + + :where(h2, h3, h4):hover & { + opacity: 1; + } +} + +.theme-toggle { + color: var(--text1); +} \ No newline at end of file diff --git a/src/tags.md b/src/tags.md new file mode 100644 index 0000000..9d17f8c --- /dev/null +++ b/src/tags.md @@ -0,0 +1,35 @@ +--- +title: 'Tag Archive' +layout: 'list' +pagination: + data: collections + size: 1 + alias: tag +permalink: '/tag/{{ tag | slug }}/' +--- + +

Tagged “{{ tag }}”

+ +
+
    + {% set taglist = collections[ tag ] %} + {% for blog in taglist | reverse %} +
  1. +

    {{ blog.data.title }}

    +
      +
    • + {%- if blog.data.tags -%} + {%- for tag in blog.data.tags -%} +
    • + {{ tag | title }} +
    • + {%- endfor -%} + {%- endif -%} +
    + {%- if blog.data.leading -%} +

    {{ blog.data.leading }}

    + {%- endif -%} +
  2. + {%- endfor -%} +
+
\ No newline at end of file