The fifth version of chriskrycho.com, built in Eleventy.

Update with a year's worth of changes

+53 -56
+6 -12
eleventy/config.ts
··· 26 26 27 27 import './feed'; // for extension of types -- TODO: move those types elsewhere! 28 28 29 - type Not = <A extends unknown[]>( 30 - pred: (...args: A) => boolean, 31 - ) => (...args: A) => boolean; 32 - const not: Not = 33 - (fn) => 34 - (...args) => 35 - !fn(...args); 29 + type Not = <A extends unknown[]>(fn: (...args: A) => boolean) => (...args: A) => boolean; 30 + // prettier-ignore 31 + const not: Not = (fn) => (...args) => !fn(...args); 36 32 37 - const filter = 38 - <T>(pred: (t: T) => boolean) => 39 - (values: T[]) => 40 - values.filter(pred); 33 + type Filter = <T>(pred: (t: T) => boolean) => (values: T[]) => T[]; 34 + const filter: Filter = (pred) => (values) => values.filter(pred); 41 35 42 36 const BUILD_TIME = DateTime.fromJSDate(new Date(), TZ).toSeconds(); 43 37 ··· 235 229 }; 236 230 } 237 231 238 - // Needs to be this way so that the import resolves as expected in `.eleventy.js`. 232 + // Needs to be this way so that the import resolves as expected in `.eleventy`. 239 233 module.exports = config;
+10 -7
eleventy/feed.ts
··· 1 - import stripTags from 'striptags'; 1 + import striptags from 'striptags'; 2 + import { DateTime } from 'luxon'; 3 + import { Result } from 'true-myth'; 2 4 3 5 import { Dict, EleventyClass, Item } from '../types/eleventy'; 4 6 import JsonFeed, { FeedItem } from '../types/json-feed'; ··· 9 11 import { toRootCollection } from './collection'; 10 12 import markdown from './markdown'; 11 13 import localeDate from './locale-date'; 12 - import { DateTime } from 'luxon'; 13 - import { Result } from 'true-myth'; 14 14 15 15 type BuildInfo = typeof import('../site/_data/build'); 16 16 type SiteConfig = typeof import('../site/_data/config'); ··· 177 177 ${item.data.updates 178 178 .map( 179 179 ({ at, changes }) => 180 - `<li><b>${localeDate(at, 'yyyy/MM/dd HH:mm')}:</b> ${markdown.renderInline(changes)}</li>`, 180 + `<li><b>${localeDate( 181 + at, 182 + 'yyyy/MM/dd HH:mm', 183 + )}:</b> ${markdown.renderInline(changes)}</li>`, 181 184 ) 182 185 .join('\n')} 183 186 </ul>` ··· 226 229 ) ?? false; 227 230 const photoTitleAllowed = !(isPhoto && photoItemTitles === 'off'); 228 231 const showTitle = sectionMarker && title && photoTitleAllowed; 229 - return showTitle ? `[${sectionMarker}] ${stripTags(title)}` : undefined; 232 + return showTitle ? `[${sectionMarker}] ${striptags(title)}` : undefined; 230 233 } 231 234 232 235 function summaryFor(item: Item): string { 233 - return item.data?.summary ?? item.data?.subtitle ?? stripTags(item.templateContent); 236 + return item.data?.summary ?? item.data?.subtitle ?? striptags(item.templateContent); 234 237 } 235 238 236 239 /** ··· 344 347 permalink: (/* _: EleventyData */): string => { 345 348 return ( 346 349 this.permalink ?? 347 - (this.collection ? `/${this.collection}/feed.json` : '/feed.json') 350 + (this.collection ? `/${this.collection}/feedon` : '/feedon') 348 351 ); 349 352 }, 350 353 };
+4 -1
package-lock.json
··· 9878 9878 }, 9879 9879 "node_modules/true-myth": { 9880 9880 "version": "4.1.1", 9881 + "resolved": "https://registry.npmjs.org/true-myth/-/true-myth-4.1.1.tgz", 9882 + "integrity": "sha512-rqy30BSpxPznbbTcAcci90oZ1YR4DqvKcNXNerG5gQBU2v4jk0cygheiul5J6ExIMrgDVuanv/MkGfqZbKrNNg==", 9881 9883 "dev": true, 9882 - "license": "MIT", 9883 9884 "engines": { 9884 9885 "node": "10.* || >= 12.*" 9885 9886 } ··· 17729 17730 }, 17730 17731 "true-myth": { 17731 17732 "version": "4.1.1", 17733 + "resolved": "https://registry.npmjs.org/true-myth/-/true-myth-4.1.1.tgz", 17734 + "integrity": "sha512-rqy30BSpxPznbbTcAcci90oZ1YR4DqvKcNXNerG5gQBU2v4jk0cygheiul5J6ExIMrgDVuanv/MkGfqZbKrNNg==", 17732 17735 "dev": true 17733 17736 }, 17734 17737 "ts-node": {
+1 -4
rollup.config.js
··· 12 12 sourcemap: true, 13 13 format: 'iife', 14 14 name: 'app', 15 - file: './site/assets/js/main.js', 15 + file: './site/_assets/js/main.js', 16 16 }, 17 17 plugins: [ 18 18 // teach rollup how to handle typescript imports ··· 23 23 svelte({ 24 24 preprocess: autoPreprocess({ 25 25 sourceMap: true, 26 - defaults: { 27 - script: 'typescript', 28 - }, 29 26 typescript: '', 30 27 }), 31 28 compilerOptions: {
+4 -7
scripts/ColorScheme.svelte
··· 1 1 <script lang="ts"> 2 - import { stringIsTheme, Theme } from './preferences'; 2 + import { isTheme, Theme } from './preferences'; 3 3 import { assert } from './utils'; 4 4 5 5 const themes = [Theme.System, Theme.Light, Theme.Dark] as const; ··· 10 10 dark: 'dark', 11 11 }; 12 12 13 - let selectTheme = (event: Event) => { 14 - assert(event.target instanceof HTMLInputElement, 'badly configured theme chooser'); 15 - assert(stringIsTheme(event.target.value), 'badly configured theme component'); 16 - 17 - onSelectTheme(event.target.value); 13 + let selectTheme: svelte.JSX.FormEventHandler<HTMLInputElement> = (event) => { 14 + assert(isTheme(event.currentTarget.value), 'badly configured theme component'); 15 + onSelectTheme(event.currentTarget.value); 18 16 }; 19 17 20 18 export let selectedTheme: Theme = Theme.System; 21 19 export let onSelectTheme: (newTheme: Theme) => void; 22 - 23 20 </script> 24 21 25 22 <fieldset>
+1 -2
scripts/Preferences.svelte
··· 1 - <script> 1 + <script lang="ts"> 2 2 import ColorScheme from './ColorScheme.svelte'; 3 3 import Adjust from './Icons/Adjust.svelte'; 4 4 import Close from './Icons/Close.svelte'; ··· 27 27 persistReadingMode(newValue); 28 28 readingMode = newValue; 29 29 }; 30 - 31 30 </script> 32 31 33 32 {#if !showPreferences}
+5 -10
scripts/ReadingMode.svelte
··· 1 - <script lang="typescript"> 2 - import { assert } from './utils' 1 + <script lang="ts"> 2 + import { assert } from './utils'; 3 3 4 - function setReadingMode(event: Event) { 5 - assert(event.target instanceof HTMLInputElement, 'badly configured reading mode') 6 - onSetReadingMode(event.target.checked) 7 - } 8 - 9 - export let onSetReadingMode: (newValue: boolean) => void 10 - export let inReadingMode: boolean 4 + export let onSetReadingMode: (newValue: boolean) => void; 5 + export let inReadingMode: boolean; 11 6 </script> 12 7 13 8 <fieldset> ··· 17 12 name="reading-mode" 18 13 id="reading-mode" 19 14 checked={inReadingMode} 20 - on:change={setReadingMode} 15 + on:change={(event) => onSetReadingMode(event.currentTarget.checked)} 21 16 /> 22 17 </fieldset>
+4 -4
scripts/main.js
··· 1 - import Preferences from './Preferences.svelte' 2 - import { selectorFor } from './utils' 1 + import Preferences from './Preferences.svelte'; 2 + import { selectorFor } from './utils.js'; 3 3 4 4 const preferences = new Preferences({ 5 5 target: document.querySelector(selectorFor('preferences')), 6 - }) 6 + }); 7 7 8 - export default preferences 8 + export default preferences;
+1 -1
scripts/tsconfig.json
··· 5 5 "removeComments": true, 6 6 "lib": ["dom", "es2019"], 7 7 "noEmit": false, 8 - "inlineSources": true, 8 + "inlineSources": false, 9 9 "sourceMap": true, 10 10 "baseUrl": "scripts" 11 11 },
+2 -2
site/_includes/base.njk
··· 56 56 57 57 <link rel='preload' as='script' type='application/javascript' href='/assets/js/main.js'> 58 58 59 - <meta name="author" content="Chris Krycho" /> 59 + <meta name="author" content="Chris Krycho"/> 60 60 61 61 {% block meta %} 62 62 {{ social.meta(page, config) }} ··· 96 96 <div data-sympolymathesy='preferences' class='preferences no-js-hidden'></div> 97 97 <script src='/assets/js/main.js'></script> 98 98 </body> 99 - </html> 99 + </html>
+2
site/_includes/styles/_components.scss
··· 9 9 @import 'components/note'; 10 10 @import 'components/post-meta'; 11 11 @import 'components/site-nav'; 12 + 13 + @import 'components/preferences';
+10 -4
site/_includes/styles/components/_preferences.scss
··· 1 1 .preferences { 2 2 font: var(--sans); 3 - position: absolute; 3 + position: fixed; 4 4 top: 1em; 5 5 right: 1em; 6 + 7 + background: var(--bg); 8 + color: var(--fg); 6 9 } 7 10 8 11 .preferences-button { 9 - position: absolute; 10 - top: 0; 11 - right: 0; 12 + position: fixed; 13 + top: 1em; 14 + right: 1em; 15 + background: var(--bg); 16 + color: var(--fg); 17 + border: none; 12 18 }
+2
tsconfig.base.json
··· 5 5 "lib": ["es2019"] /* Specify library files to be included in the compilation. */, 6 6 "checkJs": true /* Report errors in .js files. */, 7 7 "allowJs": true, 8 + "moduleResolution": "node", 9 + "module": "node12", 8 10 9 11 /* Strict Type-Checking Options */ 10 12 "strict": true /* Enable all strict type-checking options. */,
+1 -2
types/markdown-it-sup.d.ts
··· 6 6 7 7 import MarkdownIt = require('markdown-it'); 8 8 9 - declare function sup(md: MarkdownIt): void; 10 - export = sup; 9 + export default function sup(md: MarkdownIt): void;